/
JUnit5TestableFactory.java
145 lines (123 loc) · 5.42 KB
/
JUnit5TestableFactory.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
* Copyright 2015-2016 the original author or authors.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.junit.gen5.engine.junit5.discovery;
import static java.lang.String.format;
import static org.junit.gen5.commons.util.ReflectionUtils.loadClass;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.junit.gen5.commons.util.PreconditionViolationException;
import org.junit.gen5.commons.util.Preconditions;
import org.junit.gen5.commons.util.ReflectionUtils;
import org.junit.gen5.commons.util.StringUtils;
import org.junit.gen5.engine.UniqueId;
/**
* @since 5.0
*/
class JUnit5TestableFactory {
private static final Logger LOG = Logger.getLogger(JUnit5TestableFactory.class.getName());
private static final IsPotentialTestContainer isPotentialTestContainer = new IsPotentialTestContainer();
private static final IsNestedTestClass isNestedTestClass = new IsNestedTestClass();
private static final IsTestMethod isTestMethod = new IsTestMethod();
public static final String TYPE_CLASS = "class";
public static final String TYPE_NESTED_CLASS = "nested-class";
public static final String TYPE_METHOD = "method";
JUnit5Testable fromUniqueId(UniqueId uniqueId, UniqueId engineId) {
Preconditions.notNull(uniqueId, "Unique ID must not be null");
List<UniqueId.Segment> parts = uniqueId.getSegments();
//Engine ID is not used
parts.remove(0);
return createTestable(uniqueId, engineId, parts, null);
}
JUnit5Testable fromClass(Class<?> clazz, UniqueId engineId) {
Preconditions.notNull(clazz, "Class must not be null");
Preconditions.notNull(engineId, "Engine ID must not be null");
if (isPotentialTestContainer.test(clazz)) {
UniqueId uniqueId = engineId.append(TYPE_CLASS, clazz.getName());
return new JUnit5Class(uniqueId, clazz);
}
if (isNestedTestClass.test(clazz)) {
return createNestedClassTestable(clazz, clazz.getEnclosingClass(), engineId);
}
LOG.warning(() -> {
String classDescription = clazz.getName();
return format("Class '%s' is not a test container", classDescription);
});
return JUnit5Testable.doNothing();
}
private JUnit5Testable createNestedClassTestable(Class<?> testClass, Class<?> container, UniqueId engineId) {
UniqueId uniqueId = fromClass(container, engineId).getUniqueId().append(TYPE_NESTED_CLASS,
testClass.getSimpleName());
return new JUnit5NestedClass(uniqueId, testClass, container);
}
JUnit5Testable fromMethod(Method testMethod, Class<?> clazz, UniqueId engineId) {
if (!isTestMethod.test(testMethod)) {
LOG.warning(() -> {
String methodDescription = testMethod.getDeclaringClass().getName() + "#" + testMethod.getName();
return format("Method '%s' is not a test method", methodDescription);
});
return JUnit5Testable.doNothing();
}
String methodId = String.format("%s(%s)", testMethod.getName(),
StringUtils.nullSafeToString(testMethod.getParameterTypes()));
UniqueId uniqueId = fromClass(clazz, engineId).getUniqueId().append(TYPE_METHOD, methodId);
return new JUnit5Method(uniqueId, testMethod, clazz);
}
private JUnit5Testable createTestable(UniqueId uniqueId, UniqueId engineId, List<UniqueId.Segment> parts,
JUnit5Testable last) {
if (parts.isEmpty())
return last;
JUnit5Testable next = null;
UniqueId.Segment head = parts.remove(0);
switch (head.getType()) {
case TYPE_CLASS:
next = fromClass(findTopLevelClass(head.getValue()), engineId);
break;
case TYPE_NESTED_CLASS: {
Class<?> container = ((JUnit5Class) last).getJavaClass();
next = fromClass(findNestedClass(head.getValue(), container), engineId);
break;
}
case TYPE_METHOD: {
Class<?> container = ((JUnit5Class) last).getJavaClass();
next = fromMethod(findMethod(head.getValue(), container, uniqueId), container, engineId);
break;
}
default:
throw createCannotResolveUniqueIdException(uniqueId, head.toString());
}
return createTestable(uniqueId, engineId, parts, next);
}
private Method findMethod(String methodSpecPart, Class<?> clazz, UniqueId uniqueId) {
Optional<Method> optionalMethod = new MethodFinder().findMethod(methodSpecPart, clazz);
return optionalMethod.orElseThrow(() -> createCannotResolveUniqueIdException(uniqueId, methodSpecPart));
}
private Class<?> findNestedClass(String nameExtension, Class<?> containerClass) {
return classByName(containerClass.getName() + "$" + nameExtension);
}
private Class<?> findTopLevelClass(String classNamePart) {
return loadClassByName(classNamePart);
}
private Class<?> classByName(String className) {
return loadClass(className).orElseThrow(
() -> new PreconditionViolationException(String.format("Cannot resolve class name '%s'", className)));
}
private Class<?> loadClassByName(String className) {
return ReflectionUtils.loadClass(className).orElseThrow(
() -> new PreconditionViolationException(String.format("Cannot load class '%s'", className)));
}
private static RuntimeException createCannotResolveUniqueIdException(UniqueId fullUniqueId, String uniqueIdPart) {
return new PreconditionViolationException(
String.format("Cannot resolve part '%s' of unique ID '%s'", uniqueIdPart, fullUniqueId.getUniqueString()));
}
}