21 * questions. |
21 * questions. |
22 */ |
22 */ |
23 |
23 |
24 package jdk.jpackage.test; |
24 package jdk.jpackage.test; |
25 |
25 |
|
26 import java.lang.reflect.Array; |
26 import java.lang.reflect.Method; |
27 import java.lang.reflect.Method; |
27 import java.nio.file.Files; |
28 import java.nio.file.Files; |
28 import java.util.Collections; |
29 import java.nio.file.Path; |
29 import java.util.List; |
30 import java.util.*; |
|
31 import java.util.function.Predicate; |
|
32 import java.util.function.Supplier; |
30 import java.util.stream.Collectors; |
33 import java.util.stream.Collectors; |
31 import java.util.stream.Stream; |
34 import java.util.stream.Stream; |
32 import jdk.jpackage.test.Functional.ThrowingConsumer; |
35 import jdk.jpackage.test.Functional.ThrowingConsumer; |
33 import jdk.jpackage.test.Functional.ThrowingFunction; |
36 import jdk.jpackage.test.Functional.ThrowingFunction; |
34 import jdk.jpackage.test.Functional.ThrowingRunnable; |
37 import jdk.jpackage.test.Functional.ThrowingRunnable; |
35 import jdk.jpackage.test.Functional.ThrowingSupplier; |
38 |
36 |
39 final class TestInstance implements ThrowingRunnable { |
37 class TestInstance implements ThrowingRunnable { |
|
38 |
40 |
39 static class TestDesc { |
41 static class TestDesc { |
40 private TestDesc() { |
42 private TestDesc() { |
41 } |
43 } |
42 |
44 |
43 String testFullName() { |
45 String testFullName() { |
44 StringBuilder sb = new StringBuilder(); |
46 StringBuilder sb = new StringBuilder(); |
45 sb.append(clazz.getSimpleName()); |
47 sb.append(clazz.getSimpleName()); |
|
48 if (instanceArgs != null) { |
|
49 sb.append('(').append(instanceArgs).append(')'); |
|
50 } |
46 if (functionName != null) { |
51 if (functionName != null) { |
47 sb.append('.'); |
52 sb.append('.'); |
48 sb.append(functionName); |
53 sb.append(functionName); |
49 if (args != null) { |
54 if (functionArgs != null) { |
50 sb.append('(').append(args).append(')'); |
55 sb.append('(').append(functionArgs).append(')'); |
51 } |
56 } |
52 } |
57 } |
53 return sb.toString(); |
58 return sb.toString(); |
54 } |
59 } |
55 |
60 |
56 private Class clazz; |
61 static Builder createBuilder() { |
57 private String functionName; |
62 return new Builder(); |
58 private String args; |
63 } |
59 |
64 |
60 private static TestDesc create() { |
65 static final class Builder implements Supplier<TestDesc> { |
61 TestDesc desc = new TestDesc(); |
66 private Builder() { |
62 desc.clazz = enclosingMainMethodClass(); |
67 } |
63 return desc; |
68 |
|
69 Builder method(Method v) { |
|
70 method = v; |
|
71 return this; |
|
72 } |
|
73 |
|
74 Builder ctorArgs(Object... v) { |
|
75 ctorArgs = ofNullable(v); |
|
76 return this; |
|
77 } |
|
78 |
|
79 Builder methodArgs(Object... v) { |
|
80 methodArgs = ofNullable(v); |
|
81 return this; |
|
82 } |
|
83 |
|
84 @Override |
|
85 public TestDesc get() { |
|
86 TestDesc desc = new TestDesc(); |
|
87 if (method == null) { |
|
88 desc.clazz = enclosingMainMethodClass(); |
|
89 } else { |
|
90 desc.clazz = method.getDeclaringClass(); |
|
91 desc.functionName = method.getName(); |
|
92 desc.functionArgs = formatArgs(methodArgs); |
|
93 desc.instanceArgs = formatArgs(ctorArgs); |
|
94 } |
|
95 return desc; |
|
96 } |
|
97 |
|
98 private static String formatArgs(List<Object> values) { |
|
99 if (values == null) { |
|
100 return null; |
|
101 } |
|
102 return values.stream().map(v -> { |
|
103 if (v != null && v.getClass().isArray()) { |
|
104 return String.format("%s(length=%d)", |
|
105 Arrays.deepToString((Object[]) v), |
|
106 Array.getLength(v)); |
|
107 } |
|
108 return String.format("%s", v); |
|
109 }).collect(Collectors.joining(", ")); |
|
110 } |
|
111 |
|
112 private static List<Object> ofNullable(Object... values) { |
|
113 List<Object> result = new ArrayList(); |
|
114 for (var v: values) { |
|
115 result.add(v); |
|
116 } |
|
117 return result; |
|
118 } |
|
119 |
|
120 private List<Object> ctorArgs; |
|
121 private List<Object> methodArgs; |
|
122 private Method method; |
64 } |
123 } |
65 |
124 |
66 static TestDesc create(Method m, Object... args) { |
125 static TestDesc create(Method m, Object... args) { |
67 TestDesc desc = new TestDesc(); |
126 TestDesc desc = new TestDesc(); |
68 desc.clazz = m.getDeclaringClass(); |
127 desc.clazz = m.getDeclaringClass(); |
69 desc.functionName = m.getName(); |
128 desc.functionName = m.getName(); |
70 if (args.length != 0) { |
129 if (args.length != 0) { |
71 desc.args = Stream.of(args).map(Object::toString).collect( |
130 desc.functionArgs = Stream.of(args).map(v -> { |
72 Collectors.joining(",")); |
131 if (v.getClass().isArray()) { |
|
132 return String.format("%s(length=%d)", |
|
133 Arrays.deepToString((Object[]) v), |
|
134 Array.getLength(v)); |
|
135 } |
|
136 return String.format("%s", v); |
|
137 }).collect(Collectors.joining(", ")); |
73 } |
138 } |
74 return desc; |
139 return desc; |
75 } |
140 } |
|
141 |
|
142 private Class clazz; |
|
143 private String functionName; |
|
144 private String functionArgs; |
|
145 private String instanceArgs; |
76 } |
146 } |
77 |
147 |
78 TestInstance(ThrowingRunnable testBody) { |
148 TestInstance(ThrowingRunnable testBody) { |
79 assertCount = 0; |
149 assertCount = 0; |
80 this.testConstructor = (unused) -> null; |
150 this.testConstructor = (unused) -> null; |
81 this.testBody = (unused) -> testBody.run(); |
151 this.testBody = (unused) -> testBody.run(); |
82 this.beforeActions = Collections.emptyList(); |
152 this.beforeActions = Collections.emptyList(); |
83 this.afterActions = Collections.emptyList(); |
153 this.afterActions = Collections.emptyList(); |
84 this.testDesc = TestDesc.create(); |
154 this.testDesc = TestDesc.createBuilder().get(); |
85 } |
155 this.dryRun = false; |
86 |
156 } |
87 TestInstance(ThrowingFunction testConstructor, MethodCall testBody, |
157 |
88 List<ThrowingConsumer> beforeActions, |
158 TestInstance(MethodCall testBody, List<ThrowingConsumer> beforeActions, |
89 List<ThrowingConsumer> afterActions) { |
159 List<ThrowingConsumer> afterActions, boolean dryRun) { |
90 assertCount = 0; |
160 assertCount = 0; |
91 this.testConstructor = testConstructor; |
161 this.testConstructor = v -> ((MethodCall)v).newInstance(); |
92 this.testBody = testBody; |
162 this.testBody = testBody; |
93 this.beforeActions = beforeActions; |
163 this.beforeActions = beforeActions; |
94 this.afterActions = afterActions; |
164 this.afterActions = afterActions; |
95 this.testDesc = testBody.createDescription(); |
165 this.testDesc = testBody.createDescription(); |
|
166 this.dryRun = dryRun; |
96 } |
167 } |
97 |
168 |
98 void notifyAssert() { |
169 void notifyAssert() { |
99 assertCount++; |
170 assertCount++; |
100 } |
171 } |
131 if (skippedTestException != null) { |
202 if (skippedTestException != null) { |
132 throw skippedTestException; |
203 throw skippedTestException; |
133 } |
204 } |
134 } |
205 } |
135 |
206 |
|
207 Path workDir() { |
|
208 Path result = Path.of("."); |
|
209 List<String> components = new ArrayList<>(); |
|
210 |
|
211 String testFunctionName = functionName(); |
|
212 if (testFunctionName != null) { |
|
213 components.add(testFunctionName); |
|
214 } |
|
215 |
|
216 if (isPrametrized()) { |
|
217 components.add(String.format("%08x", fullName().hashCode())); |
|
218 } |
|
219 |
|
220 if (!components.isEmpty()) { |
|
221 result = result.resolve(String.join(".", components)); |
|
222 } |
|
223 |
|
224 return result; |
|
225 } |
|
226 |
|
227 boolean isPrametrized() { |
|
228 return Stream.of(testDesc.functionArgs, testDesc.instanceArgs).anyMatch( |
|
229 Objects::nonNull); |
|
230 } |
|
231 |
136 @Override |
232 @Override |
137 public void run() throws Throwable { |
233 public void run() throws Throwable { |
138 final String fullName = testDesc.testFullName(); |
234 final String fullName = fullName(); |
139 TKit.log(String.format("[ RUN ] %s", fullName)); |
235 TKit.log(String.format("[ RUN ] %s", fullName)); |
140 try { |
236 try { |
141 Object testInstance = testConstructor.apply(testBody); |
237 Object testInstance = testConstructor.apply(testBody); |
142 beforeActions.forEach((a) -> ThrowingConsumer.toConsumer(a).accept( |
238 beforeActions.forEach(a -> ThrowingConsumer.toConsumer(a).accept( |
143 testInstance)); |
239 testInstance)); |
144 Files.createDirectories(TKit.workDir()); |
|
145 try { |
240 try { |
146 testBody.accept(testInstance); |
241 if (!dryRun) { |
|
242 Files.createDirectories(workDir()); |
|
243 testBody.accept(testInstance); |
|
244 } |
147 } finally { |
245 } finally { |
148 afterActions.forEach(a -> TKit.ignoreExceptions(() -> a.accept( |
246 afterActions.forEach(a -> TKit.ignoreExceptions(() -> a.accept( |
149 testInstance))); |
247 testInstance))); |
150 } |
248 } |
151 status = Status.Passed; |
249 status = Status.Passed; |