|
29 | 29 | import java.io.PrintStream;
|
30 | 30 | import java.io.PrintWriter;
|
31 | 31 | import java.io.StringWriter;
|
32 |
| -import java.lang.annotation.Annotation; |
33 | 32 | import java.lang.annotation.Retention;
|
34 | 33 | import java.lang.annotation.RetentionPolicy;
|
35 | 34 | import java.lang.ref.SoftReference;
|
|
59 | 58 | import java.util.regex.Pattern;
|
60 | 59 | import java.util.stream.Collectors;
|
61 | 60 | import java.util.stream.Stream;
|
| 61 | + |
62 | 62 | import javax.tools.StandardJavaFileManager;
|
63 | 63 |
|
| 64 | +//import jdk.lang.classfile.Classfile; |
| 65 | + |
64 | 66 |
|
65 | 67 | /**
|
66 | 68 | * Test framework for running javadoc and performing tests on the resulting output.
|
@@ -292,16 +294,75 @@ public void runTests() throws Exception {
|
292 | 294 | * @throws Exception if any errors occurred while executing a test method
|
293 | 295 | */
|
294 | 296 | public void runTests(Function<Method, Object[]> f) throws Exception {
|
295 |
| - for (Method m : getClass().getDeclaredMethods()) { |
296 |
| - Annotation a = m.getAnnotation(Test.class); |
297 |
| - if (a != null) { |
298 |
| - runTest(m, f); |
299 |
| - out.println(); |
300 |
| - } |
| 297 | + var methods = List.of(getClass().getDeclaredMethods()).stream() |
| 298 | + .filter(m -> m.isAnnotationPresent(Test.class)) |
| 299 | + .collect(Collectors.toCollection(() -> new ArrayList<>())); |
| 300 | + var methodOrderComparator = getMethodComparator(); |
| 301 | + if (methodOrderComparator != null) { |
| 302 | + methods.sort(methodOrderComparator); |
| 303 | + } |
| 304 | + for (Method m : methods) { |
| 305 | + runTest(m, f); |
| 306 | + out.println(); |
301 | 307 | }
|
302 | 308 | printSummary();
|
303 | 309 | }
|
304 | 310 |
|
| 311 | +// The following is for when the Classfile library is generally available. |
| 312 | +// private Comparator<Method> getClassOrderMethodComparator(Class<?> c) { |
| 313 | +// try { |
| 314 | +// var url = c.getProtectionDomain().getCodeSource().getLocation(); |
| 315 | +// var path = Path.of(url.toURI()).resolve(c.getName().replace(".", "/") + ".class"); |
| 316 | +// var cf = Classfile.of().parse(path); |
| 317 | +// var map = new HashMap<String, Integer>(); |
| 318 | +// var index = 0; |
| 319 | +// for (var m : cf.methods()) { |
| 320 | +// map.putIfAbsent(m.methodName().stringValue(), index++); |
| 321 | +// } |
| 322 | +// return Comparator.<Method>comparingInt(m -> map.getOrDefault(m.getName(), -1)); |
| 323 | +// } catch (URISyntaxException | IOException e) { |
| 324 | +// throw new Error("Cannot sort methods: " + e, e); |
| 325 | +// } |
| 326 | +// } |
| 327 | + |
| 328 | + /** |
| 329 | + * {@return the comparator used to sort the default set of methods to be executed, |
| 330 | + * or {@code null} if the methods should not be sorted } |
| 331 | + * |
| 332 | + * @implSpec This implementation returns a source-order comparator. |
| 333 | + */ |
| 334 | + public Comparator<Method> getMethodComparator() { |
| 335 | + return getSourceOrderMethodComparator(getClass()); |
| 336 | + } |
| 337 | + |
| 338 | + /** |
| 339 | + * {@return the source-order method comparator for methods in the given class} |
| 340 | + * @param c the class |
| 341 | + */ |
| 342 | + public static Comparator<Method> getSourceOrderMethodComparator(Class<?> c) { |
| 343 | + var path = Path.of(testSrc) |
| 344 | + .resolve(c.getName() |
| 345 | + .replace(".", "/") |
| 346 | + .replaceAll("\\$.*", "") |
| 347 | + + ".java"); |
| 348 | + try { |
| 349 | + var src = Files.readString(path); |
| 350 | + // Fuzzy match for test method declarations. |
| 351 | + // It doesn't matter if there are false positives, as long as the true positives are in the correct order. |
| 352 | + // It doesn't matter too much if there are false negatives: they'll just be executed first. |
| 353 | + var isMethodDecl = Pattern.compile("public +void +(?<name>[A-Za-z][A-Za-z0-9_]*)\\("); |
| 354 | + var matcher = isMethodDecl.matcher(src); |
| 355 | + var map = new HashMap<String, Integer>(); |
| 356 | + var index = 0; |
| 357 | + while (matcher.find()) { |
| 358 | + map.putIfAbsent(matcher.group("name"), index++); |
| 359 | + } |
| 360 | + return Comparator.<Method>comparingInt(m -> map.getOrDefault(m.getName(), -1)); |
| 361 | + } catch (IOException e) { |
| 362 | + throw new Error("Cannot sort methods: " + e, e); |
| 363 | + } |
| 364 | + } |
| 365 | + |
305 | 366 | /**
|
306 | 367 | * Run the specified methods annotated with @Test, or all methods annotated
|
307 | 368 | * with @Test if none are specified, followed by printSummary.
|
|
0 commit comments