Skip to content

Commit

Permalink
consolidated Method and Class descriptors
Browse files Browse the repository at this point in the history
  • Loading branch information
jlink committed Oct 29, 2015
1 parent 12aa0fb commit afbeaf0
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 154 deletions.
Expand Up @@ -54,13 +54,13 @@ public List<TestDescriptor> discoverTests(TestPlanSpecification specification) {
// @formatter:off // @formatter:off
testDescriptors.addAll(Arrays.stream(testClass.getDeclaredMethods()) testDescriptors.addAll(Arrays.stream(testClass.getDeclaredMethods())
.filter(method -> method.isAnnotationPresent(Test.class)) .filter(method -> method.isAnnotationPresent(Test.class))
.map(method -> new JavaMethodTestDescriptor(getId(), testClass, method, parent)) .map(method -> new JavaMethodTestDescriptor( method, parent))
.collect(toList())); .collect(toList()));
// @formatter:on // @formatter:on
} }
else if (element instanceof UniqueIdSpecification) { else if (element instanceof UniqueIdSpecification) {
UniqueIdSpecification uniqueIdSpecification = (UniqueIdSpecification) element; UniqueIdSpecification uniqueIdSpecification = (UniqueIdSpecification) element;
testDescriptors.add(JavaMethodTestDescriptor.from(uniqueIdSpecification.getUniqueId())); testDescriptors.add(JavaTestDescriptorFactory.from(uniqueIdSpecification.getUniqueId()));
} }
} }


Expand Down
Expand Up @@ -10,12 +10,8 @@


package org.junit.gen5.engine.junit5; package org.junit.gen5.engine.junit5;


import java.util.regex.Matcher;
import java.util.regex.Pattern;

import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;

import org.junit.gen5.commons.util.Preconditions; import org.junit.gen5.commons.util.Preconditions;
import org.junit.gen5.engine.TestDescriptor; import org.junit.gen5.engine.TestDescriptor;


Expand All @@ -31,32 +27,7 @@
@EqualsAndHashCode @EqualsAndHashCode
public class JavaClassTestDescriptor implements TestDescriptor { public class JavaClassTestDescriptor implements TestDescriptor {


// The following pattern only supports descriptors for test methods.
// TODO Support descriptors for test classes.
// TODO Decide if we want to support descriptors for packages.
private static final Pattern UID_PATTERN = Pattern.compile("^(.+):(.+)$");


public static JavaClassTestDescriptor from(final String uid) throws RuntimeException {
Preconditions.notNull(uid, "TestDescriptor UID must not be null");

Matcher matcher = UID_PATTERN.matcher(uid);
Preconditions.condition(matcher.matches(),
() -> String.format("Invalid format for %s UID: %s", JavaClassTestDescriptor.class.getSimpleName(), uid));

// TODO Validate contents of matched groups.
String engineId = matcher.group(1);
String className = matcher.group(2);

Class<?> clazz = loadClass(className);

return new JavaClassTestDescriptor(engineId, clazz);
}


private final String engineId; private final String engineId;
private final String testId;
private final String displayName;
private final TestDescriptor parent; private final TestDescriptor parent;
private final Class<?> testClass; private final Class<?> testClass;


Expand All @@ -66,27 +37,18 @@ public JavaClassTestDescriptor(String engineId, Class<?> testClass) {
Preconditions.notNull(testClass, "testClass must not be null"); Preconditions.notNull(testClass, "testClass must not be null");


this.testClass = testClass; this.testClass = testClass;
this.displayName = determineDisplayName(testClass); //todo there could be parents (eg. packages)
this.parent = null; this.parent = null;
this.engineId = engineId; this.engineId = engineId;
this.testId = createTestId(testClass);
}

private static Class<?> loadClass(String name) {
try {
// TODO Add support for primitive types and arrays.
return JavaClassTestDescriptor.class.getClassLoader().loadClass(name);
}
catch (ClassNotFoundException e) {
throw new IllegalStateException("Failed to load class with name '" + name + "'.", e);
}
} }


private static String createTestId(Class<?> testClass) { @Override
public String getTestId() {
return testClass.getName(); return testClass.getName();
} }


private static String determineDisplayName(Class<?> testClass) { @Override
public String getDisplayName() {
return testClass.getSimpleName(); return testClass.getSimpleName();
} }


Expand Down
Expand Up @@ -13,14 +13,8 @@
import static org.junit.gen5.commons.util.ObjectUtils.nullSafeToString; import static org.junit.gen5.commons.util.ObjectUtils.nullSafeToString;


import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;

import org.junit.gen5.api.Test; import org.junit.gen5.api.Test;
import org.junit.gen5.commons.util.ObjectUtils; import org.junit.gen5.commons.util.ObjectUtils;
import org.junit.gen5.commons.util.Preconditions; import org.junit.gen5.commons.util.Preconditions;
Expand All @@ -29,124 +23,52 @@
/** /**
* {@link TestDescriptor} for tests based on Java methods. * {@link TestDescriptor} for tests based on Java methods.
* *
* <p>The pattern of the {@link #getTestId test ID} takes the form of
* <code>{fully qualified class name}#{method name}({comma separated list
* of method parameter types})</code>, where each method parameter type is
* a fully qualified class name or a primitive type. For example,
* {@code org.example.MyTests#test()} references the {@code test()} method
* in the {@code org.example.MyTests} class that does not accept parameters.
* Similarly, {@code org.example.MyTests#test(java.lang.String, java.math.BigDecimal)}
* references the {@code test()} method in the {@code org.example.MyTests}
* class that requires a {@code String} and {@code BigDecimal} as parameters.
*
* @author Sam Brannen * @author Sam Brannen
* @since 5.0 * @since 5.0
*/ */
@Data @Data
@EqualsAndHashCode @EqualsAndHashCode
public class JavaMethodTestDescriptor implements TestDescriptor { public class JavaMethodTestDescriptor implements TestDescriptor {


// The following pattern only supports descriptors for test methods.
// TODO Support descriptors for test classes.
// TODO Decide if we want to support descriptors for packages.
private static final Pattern UID_PATTERN = Pattern.compile("^(.+):(.+)#(.+)\\((.*)\\)$");


public static JavaMethodTestDescriptor from(final String uid) throws RuntimeException {
Preconditions.notNull(uid, "TestDescriptor UID must not be null");

Matcher matcher = UID_PATTERN.matcher(uid);
Preconditions.condition(matcher.matches(),
() -> String.format("Invalid format for %s UID: %s", JavaMethodTestDescriptor.class.getSimpleName(), uid));

// TODO Validate contents of matched groups.
String engineId = matcher.group(1);
String className = matcher.group(2);
String methodName = matcher.group(3);
String methodParameters = matcher.group(4);

Class<?> clazz = loadClass(className);

System.out.println("DEBUG - method params: " + methodParameters);

List<Class<?>> paramTypeList = new ArrayList<>();
for (String type : methodParameters.split(",")) {
type = type.trim();
if (!type.isEmpty()) {
paramTypeList.add(loadClass(type));
}
}

Class<?>[] parameterTypes = paramTypeList.toArray(new Class<?>[paramTypeList.size()]);

try {
Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
return new JavaMethodTestDescriptor(engineId, clazz, method);
}
catch (NoSuchMethodException e) {
throw new IllegalStateException("Failed to get method with name '" + methodName + "'.", e);
}
}



private final String engineId;
private final String testId; private final String testId;
private final String displayName; private final String displayName;
private final JavaClassTestDescriptor parent; private final JavaClassTestDescriptor parent;
private final Class<?> testClass;


private final Method testMethod; private final Method testMethod;




public JavaMethodTestDescriptor(String engineId, Class<?> testClass, Method testMethod) { public JavaMethodTestDescriptor(Method testMethod, JavaClassTestDescriptor parent) {
this(engineId, testClass, testMethod, null);
}

public JavaMethodTestDescriptor(String engineId, Class<?> testClass, Method testMethod,
JavaClassTestDescriptor parent) {


Preconditions.notEmpty(engineId, "engineId must not be null or empty");
Preconditions.notNull(testClass, "testClass must not be null");
Preconditions.notNull(testMethod, "testMethod must not be null"); Preconditions.notNull(testMethod, "testMethod must not be null");
Preconditions.notNull(parent, "parent must not be null");


this.testClass = testClass;
this.testMethod = testMethod; this.testMethod = testMethod;
this.displayName = determineDisplayName(testClass, testMethod); this.displayName = determineDisplayName();
this.parent = parent; this.parent = parent;
this.engineId = engineId; this.testId = createTestId();
this.testId = createTestId(testClass, testMethod);
}

private static Class<?> loadClass(String name) {
try {
// TODO Use correct classloader
// TODO Add support for primitive types and arrays.
return JavaMethodTestDescriptor.class.getClassLoader().loadClass(name);
}
catch (ClassNotFoundException e) {
throw new IllegalStateException("Failed to load class with name '" + name + "'.", e);
}
} }


private static String createTestId(Class<?> testClass, Method testMethod) { private String createTestId() {
return (testMethod != null ? String.format("%s#%s(%s)", testClass.getName(), testMethod.getName(), return String.format("%s#%s(%s)", getParent().getTestId(), testMethod.getName(),
nullSafeToString(testMethod.getParameterTypes())) : testClass.getName()); nullSafeToString(testMethod.getParameterTypes()));
} }


private static String determineDisplayName(Class<?> testClass, Method testMethod) { private String determineDisplayName() {
if (testMethod != null) { Test test = testMethod.getAnnotation(Test.class);
Test test = testMethod.getAnnotation(Test.class); if (test != null) {
if (test != null) { String customName = test.name();
String customName = test.name(); if (!ObjectUtils.isEmpty(customName)) {
if (!ObjectUtils.isEmpty(customName)) { return customName;
return customName;
}
} }
return testMethod.getName();
}
else {
return testClass.getSimpleName();
} }
return testMethod.getName();

}

@Override
public String getEngineId() {
return getParent().getEngineId();
} }


} }
@@ -0,0 +1,85 @@
package org.junit.gen5.engine.junit5;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.junit.gen5.commons.util.Preconditions;
import org.junit.gen5.engine.TestDescriptor;

/**
* <p>The pattern of the {@link #getTestId test ID} takes the form of
* <code>{fully qualified class name}#{method name}({comma separated list
* of method parameter types})</code>, where each method parameter type is
* a fully qualified class name or a primitive type. For example,
* {@code org.example.MyTests#test()} references the {@code test()} method
* in the {@code org.example.MyTests} class that does not accept parameters.
* Similarly, {@code org.example.MyTests#test(java.lang.String, java.math.BigDecimal)}
* references the {@code test()} method in the {@code org.example.MyTests}
* class that requires a {@code String} and {@code BigDecimal} as parameters.
*
* @author Sam Brannen
* @since 5.0
*/

public class JavaTestDescriptorFactory {

// The following pattern only supports descriptors for test methods.
// TODO Support descriptors for test classes.
// TODO Decide if we want to support descriptors for packages.
private static final Pattern UID_PATTERN = Pattern.compile("^(.+):(.+)#(.+)\\((.*)\\)$");


//Todo must be able to create any kind of JavaTestDescriptor
public static JavaMethodTestDescriptor from(final String uid) throws RuntimeException {
Preconditions.notNull(uid, "TestDescriptor UID must not be null");

Matcher matcher = UID_PATTERN.matcher(uid);
Preconditions.condition(matcher.matches(),
() -> String.format("Invalid format for %s UID: %s", JavaMethodTestDescriptor.class.getSimpleName(), uid));

// TODO Validate contents of matched groups.
String engineId = matcher.group(1);
String className = matcher.group(2);
String methodName = matcher.group(3);
String methodParameters = matcher.group(4);

Class<?> clazz = loadClass(className);

System.out.println("DEBUG - method params: " + methodParameters);

List<Class<?>> paramTypeList = new ArrayList<>();
for (String type : methodParameters.split(",")) {
type = type.trim();
if (!type.isEmpty()) {
paramTypeList.add(loadClass(type));
}
}

Class<?>[] parameterTypes = paramTypeList.toArray(new Class<?>[paramTypeList.size()]);

try {
JavaClassTestDescriptor parent = new JavaClassTestDescriptor(engineId, clazz);
Method method = clazz.getDeclaredMethod(methodName, parameterTypes);
return new JavaMethodTestDescriptor(method, parent);
}
catch (NoSuchMethodException e) {
throw new IllegalStateException("Failed to get method with name '" + methodName + "'.", e);
}
}

private static Class<?> loadClass(String name) {
try {
// TODO Use correct classloader
// TODO Add support for primitive types and arrays.
return JavaMethodTestDescriptor.class.getClassLoader().loadClass(name);
}
catch (ClassNotFoundException e) {
throw new IllegalStateException("Failed to load class with name '" + name + "'.", e);
}
}



}
Expand Up @@ -36,7 +36,7 @@ class TestExecutor {
} }


void execute() throws Exception { void execute() throws Exception {
Class<?> testClass = this.testDescriptor.getTestClass(); Class<?> testClass = this.testDescriptor.getParent().getTestClass();


// TODO Extract test instantiation // TODO Extract test instantiation
Object testInstance = newInstance(testClass); Object testInstance = newInstance(testClass);
Expand Down

0 comments on commit afbeaf0

Please sign in to comment.