From c86592d38d651beac40f1da43c718a2d4b17bd19 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Wed, 1 Nov 2023 15:48:31 +0000 Subject: [PATCH] 8319046: Execute tests in source/class-file order in JavadocTester Reviewed-by: hannesw --- .../lib/javadoc/tester/JavadocTester.java | 75 +++++++++++++++++-- 1 file changed, 68 insertions(+), 7 deletions(-) diff --git a/test/langtools/jdk/javadoc/lib/javadoc/tester/JavadocTester.java b/test/langtools/jdk/javadoc/lib/javadoc/tester/JavadocTester.java index b4bb8a319df..f31da1a6edd 100644 --- a/test/langtools/jdk/javadoc/lib/javadoc/tester/JavadocTester.java +++ b/test/langtools/jdk/javadoc/lib/javadoc/tester/JavadocTester.java @@ -29,7 +29,6 @@ import java.io.IOException; import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringWriter; -import java.lang.annotation.Annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.ref.SoftReference; @@ -59,8 +58,11 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; + import javax.tools.StandardJavaFileManager; +//import jdk.lang.classfile.Classfile; + /** * Test framework for running javadoc and performing tests on the resulting output. @@ -292,16 +294,75 @@ public abstract class JavadocTester { * @throws Exception if any errors occurred while executing a test method */ public void runTests(Function f) throws Exception { - for (Method m : getClass().getDeclaredMethods()) { - Annotation a = m.getAnnotation(Test.class); - if (a != null) { - runTest(m, f); - out.println(); - } + var methods = List.of(getClass().getDeclaredMethods()).stream() + .filter(m -> m.isAnnotationPresent(Test.class)) + .collect(Collectors.toCollection(() -> new ArrayList<>())); + var methodOrderComparator = getMethodComparator(); + if (methodOrderComparator != null) { + methods.sort(methodOrderComparator); + } + for (Method m : methods) { + runTest(m, f); + out.println(); } printSummary(); } +// The following is for when the Classfile library is generally available. +// private Comparator getClassOrderMethodComparator(Class c) { +// try { +// var url = c.getProtectionDomain().getCodeSource().getLocation(); +// var path = Path.of(url.toURI()).resolve(c.getName().replace(".", "/") + ".class"); +// var cf = Classfile.of().parse(path); +// var map = new HashMap(); +// var index = 0; +// for (var m : cf.methods()) { +// map.putIfAbsent(m.methodName().stringValue(), index++); +// } +// return Comparator.comparingInt(m -> map.getOrDefault(m.getName(), -1)); +// } catch (URISyntaxException | IOException e) { +// throw new Error("Cannot sort methods: " + e, e); +// } +// } + + /** + * {@return the comparator used to sort the default set of methods to be executed, + * or {@code null} if the methods should not be sorted } + * + * @implSpec This implementation returns a source-order comparator. + */ + public Comparator getMethodComparator() { + return getSourceOrderMethodComparator(getClass()); + } + + /** + * {@return the source-order method comparator for methods in the given class} + * @param c the class + */ + public static Comparator getSourceOrderMethodComparator(Class c) { + var path = Path.of(testSrc) + .resolve(c.getName() + .replace(".", "/") + .replaceAll("\\$.*", "") + + ".java"); + try { + var src = Files.readString(path); + // Fuzzy match for test method declarations. + // It doesn't matter if there are false positives, as long as the true positives are in the correct order. + // It doesn't matter too much if there are false negatives: they'll just be executed first. + var isMethodDecl = Pattern.compile("public +void +(?[A-Za-z][A-Za-z0-9_]*)\\("); + var matcher = isMethodDecl.matcher(src); + var map = new HashMap(); + var index = 0; + while (matcher.find()) { + map.putIfAbsent(matcher.group("name"), index++); + } + return Comparator.comparingInt(m -> map.getOrDefault(m.getName(), -1)); + } catch (IOException e) { + throw new Error("Cannot sort methods: " + e, e); + } + } + /** * Run the specified methods annotated with @Test, or all methods annotated * with @Test if none are specified, followed by printSummary.