--- old/test/java/lang/reflect/PublicMethods/PublicMethodsTest.java 2016-12-26 10:22:52.507992065 +0100 +++ /dev/null 2016-12-26 10:06:56.915898959 +0100 @@ -1,529 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import javax.tools.Diagnostic; -import javax.tools.DiagnosticListener; -import javax.tools.FileObject; -import javax.tools.ForwardingJavaFileManager; -import javax.tools.JavaCompiler; -import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; -import javax.tools.StandardJavaFileManager; -import javax.tools.StandardLocation; -import javax.tools.ToolProvider; -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.UncheckedIOException; -import java.lang.reflect.Method; -import java.net.URI; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.IntStream; -import java.util.stream.Stream; - -import static java.util.stream.Collectors.joining; -import static java.util.stream.Collectors.toMap; - -/* - * @test - * @bug 8062389 - * @summary Nearly exhaustive test of Class.getMethod() and Class.getMethods() - * @run main PublicMethodsTest - */ -public class PublicMethodsTest { - - public static void main(String[] args) { - Case c = new Case1(); - - int[] diffs = new int[1]; - try (Stream>> - expected = expectedResults(c)) { - diffResults(c, expected) - .forEach(diff -> { - System.out.println(diff); - diffs[0]++; - }); - } - - if (diffs[0] > 0) { - throw new RuntimeException( - "There were " + diffs[0] + " differences."); - } - } - - // use this to generate .results file for particular case - public static class Generate { - public static void main(String[] args) { - Case c = new Case1(); - dumpResults(generateResults(c)) - .forEach(System.out::println); - } - } - - interface Case { - Pattern PLACEHOLDER_PATTERN = Pattern.compile("\\$\\{(.+?)}"); - - // possible variants of interface method - List INTERFACE_METHODS = List.of( - "", "void m();", "default void m() {}", "static void m() {}" - ); - - // possible variants of class method - List CLASS_METHODS = List.of( - "", "public abstract void m();", - "public void m() {}", "public static void m() {}" - ); - - // template with placeholders parsed with PLACEHOLDER_PATTERN - String template(); - - // map of replacementKey (== PLACEHOLDER_PATTERN captured group #1) -> - // list of possible replacements - Map> replacements(); - - // ordered list of replacement keys - List replacementKeys(); - - // names of types occurring in the template - List classNames(); - } - - static class Case1 implements Case { - - private static final String TEMPLATE = Stream.of( - "interface I { ${I} }", - "interface J { ${J} }", - "interface K extends I, J { ${K} }", - "abstract class C { ${C} }", - "abstract class D extends C implements I { ${D} }", - "abstract class E extends D implements J, K { ${E} }" - ).collect(joining("\n")); - - private static final Map> REPLACEMENTS = Map.of( - "I", INTERFACE_METHODS, - "J", INTERFACE_METHODS, - "K", INTERFACE_METHODS, - "C", CLASS_METHODS, - "D", CLASS_METHODS, - "E", CLASS_METHODS - ); - - private static final List REPLACEMENT_KEYS = REPLACEMENTS - .keySet().stream().sorted().collect(Collectors.toList()); - - @Override - public String template() { - return TEMPLATE; - } - - @Override - public Map> replacements() { - return REPLACEMENTS; - } - - @Override - public List replacementKeys() { - return REPLACEMENT_KEYS; - } - - @Override - public List classNames() { - // just by accident, names of classes are equal to replacement keys - // (this need not be the case in general) - return REPLACEMENT_KEYS; - } - } - - // generate all combinations as a tuple of indexes into lists of - // replacements. The index of the element in int[] tuple represents the index - // of the key in replacementKeys() list. The value of the element in int[] tuple - // represents the index of the replacement string in list of strings in the - // value of the entry of replacements() map with the corresponding key. - static Stream combinations(Case c) { - int[] sizes = c.replacementKeys().stream() - .mapToInt(key -> c.replacements().get(key).size()) - .toArray(); - - return Stream.iterate( - new int[sizes.length], - state -> state != null, - state -> { - int[] newState = state.clone(); - for (int i = 0; i < state.length; i++) { - if (++newState[i] < sizes[i]) { - return newState; - } - newState[i] = 0; - } - // wrapped-around - return null; - } - ); - } - - // given the combination of indexes, return the expanded template - static String expandTemplate(Case c, int[] combination) { - - // 1st create a map: key -> replacement string - Map map = new HashMap<>(combination.length * 4 / 3 + 1); - for (int i = 0; i < combination.length; i++) { - String key = c.replacementKeys().get(i); - String repl = c.replacements().get(key).get(combination[i]); - map.put(key, repl); - } - - return Case.PLACEHOLDER_PATTERN - .matcher(c.template()) - .replaceAll(match -> map.get(match.group(1))); - } - - /** - * compile expanded template into a ClassLoader that sees compiled classes - */ - static ClassLoader compile(String source) throws CompileException { - JavaCompiler javac = ToolProvider.getSystemJavaCompiler(); - if (javac == null) { - throw new AssertionError("No Java compiler tool found."); - } - - ErrorsCollector errorsCollector = new ErrorsCollector(); - StandardJavaFileManager standardJavaFileManager = - javac.getStandardFileManager(errorsCollector, Locale.ROOT, - Charset.forName("UTF-8")); - TestFileManager testFileManager = new TestFileManager( - standardJavaFileManager, source); - - JavaCompiler.CompilationTask javacTask; - try { - javacTask = javac.getTask( - null, // use System.err - testFileManager, - errorsCollector, - null, - null, - List.of(testFileManager.getJavaFileForInput( - StandardLocation.SOURCE_PATH, - TestFileManager.TEST_CLASS_NAME, - JavaFileObject.Kind.SOURCE)) - ); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - - javacTask.call(); - - if (errorsCollector.hasError()) { - throw new CompileException(errorsCollector.getErrors()); - } - - return new TestClassLoader(ClassLoader.getSystemClassLoader(), - testFileManager); - } - - static class CompileException extends Exception { - CompileException(List> diagnostics) { - super(diagnostics.stream() - .map(diag -> diag.toString()) - .collect(Collectors.joining("\n"))); - } - } - - static class TestFileManager - extends ForwardingJavaFileManager { - static final String TEST_CLASS_NAME = "Test"; - - private final String testSource; - private final Map classes = new HashMap<>(); - - TestFileManager(StandardJavaFileManager fileManager, String source) { - super(fileManager); - testSource = "public class " + TEST_CLASS_NAME + " {}\n" + - source; // the rest of classes are package-private - } - - @Override - public JavaFileObject getJavaFileForInput(Location location, - String className, - JavaFileObject.Kind kind) - throws IOException { - if (location == StandardLocation.SOURCE_PATH && - kind == JavaFileObject.Kind.SOURCE && - TEST_CLASS_NAME.equals(className)) { - return new SourceFileObject(className, testSource); - } - return super.getJavaFileForInput(location, className, kind); - } - - private static class SourceFileObject extends SimpleJavaFileObject { - private final String source; - - SourceFileObject(String className, String source) { - super( - URI.create("memory:/src/" + - className.replace('.', '/') + ".java"), - Kind.SOURCE - ); - this.source = source; - } - - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) { - return source; - } - } - - @Override - public JavaFileObject getJavaFileForOutput(Location location, - String className, - JavaFileObject.Kind kind, - FileObject sibling) - throws IOException { - if (kind == JavaFileObject.Kind.CLASS) { - ClassFileObject cfo = new ClassFileObject(className); - classes.put(className, cfo); - return cfo; - } - return super.getJavaFileForOutput(location, className, kind, sibling); - } - - private static class ClassFileObject extends SimpleJavaFileObject { - final String className; - ByteArrayOutputStream byteArrayOutputStream; - - ClassFileObject(String className) { - super( - URI.create("memory:/out/" + - className.replace('.', '/') + ".class"), - Kind.CLASS - ); - this.className = className; - } - - @Override - public OutputStream openOutputStream() throws IOException { - return byteArrayOutputStream = new ByteArrayOutputStream(); - } - - byte[] getBytes() { - if (byteArrayOutputStream == null) { - throw new IllegalStateException( - "No class file written for class: " + className); - } - return byteArrayOutputStream.toByteArray(); - } - } - - byte[] getClassBytes(String className) { - ClassFileObject cfo = classes.get(className); - return (cfo == null) ? null : cfo.getBytes(); - } - } - - static class ErrorsCollector implements DiagnosticListener { - private final List> errors = new ArrayList<>(); - - @Override - public void report(Diagnostic diagnostic) { - if (diagnostic.getKind() == Diagnostic.Kind.ERROR) { - errors.add(diagnostic); - } - } - - boolean hasError() { - return !errors.isEmpty(); - } - - List> getErrors() { - return errors; - } - } - - static class TestClassLoader extends ClassLoader { - private final TestFileManager fileManager; - - public TestClassLoader(ClassLoader parent, TestFileManager fileManager) { - super(parent); - this.fileManager = fileManager; - } - - @Override - protected Class findClass(String name) throws ClassNotFoundException { - byte[] classBytes = fileManager.getClassBytes(name); - if (classBytes == null) { - throw new ClassNotFoundException(name); - } - return defineClass(name, classBytes, 0, classBytes.length); - } - } - - static Map generateResult(Case c, ClassLoader cl) { - return - c.classNames() - .stream() - .map(cn -> { - try { - return Class.forName(cn, false, cl); - } catch (ClassNotFoundException e) { - throw new RuntimeException("Class not found: " + cn, e); - } - }) - .flatMap(clazz -> Stream.of( - Map.entry(clazz.getName() + ".gM", generateGetMethodResult(clazz)), - Map.entry(clazz.getName() + ".gMs", generateGetMethodsResult(clazz)) - )) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - } - - static String generateGetMethodResult(Class clazz) { - try { - Method m = clazz.getMethod("m"); - return m.getDeclaringClass().getName() + "." + m.getName(); - } catch (NoSuchMethodException e) { - return "-"; - } - } - - static String generateGetMethodsResult(Class clazz) { - return Stream.of(clazz.getMethods()) - .filter(m -> m.getDeclaringClass() != Object.class) - .map(m -> m.getDeclaringClass().getName() - + "." + m.getName()) - .collect(Collectors.joining(", ", "[", "]")); - } - - static Stream>> generateResults(Case c) { - return combinations(c) - .flatMap(comb -> { - String src = expandTemplate(c, comb); - ClassLoader cl; - try { - cl = compile(src); - } catch (CompileException e) { - // ignore uncompilable combinations - return Stream.empty(); - } - // compilation was successful -> generate result - return Stream.of(Map.entry( - comb, - generateResult(c, cl) - )); - }); - } - - static Stream>> expectedResults(Case c) { - try { - BufferedReader r = new BufferedReader(new InputStreamReader( - c.getClass().getResourceAsStream( - c.getClass().getSimpleName() + ".results"), - "UTF-8" - )); - - return parseResults(r.lines()) - .onClose(() -> { - try { - r.close(); - } catch (IOException ioe) { - throw new UncheckedIOException(ioe); - } - }); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - static Stream>> parseResults( - Stream lines - ) { - return lines - .map(l -> l.split(Pattern.quote("#"))) - .map(lkv -> Map.entry( - Stream.of(lkv[0].split(Pattern.quote(","))) - .mapToInt(Integer::parseInt) - .toArray(), - Stream.of(lkv[1].split(Pattern.quote("|"))) - .map(e -> e.split(Pattern.quote("="))) - .collect(toMap(ekv -> ekv[0], ekv -> ekv[1])) - )); - } - - static Stream dumpResults( - Stream>> results - ) { - return results - .map(le -> - IntStream.of(le.getKey()) - .mapToObj(String::valueOf) - .collect(joining(",")) - + "#" + - le.getValue().entrySet().stream() - .map(e -> e.getKey() + "=" + e.getValue()) - .collect(joining("|")) - ); - } - - static Stream diffResults( - Case c, - Stream>> expectedResults - ) { - return expectedResults - .flatMap(exp -> { - int[] comb = exp.getKey(); - Map expected = exp.getValue(); - - String src = expandTemplate(c, comb); - ClassLoader cl; - try { - cl = compile(src); - } catch (CompileException ce) { - return Stream.of(src + "\n" + - "got compilation error: " + ce); - } - - Map actual = generateResult(c, cl); - if (actual.equals(expected)) { - return Stream.empty(); - } else { - Map diff = new HashMap<>(expected); - diff.entrySet().removeAll(actual.entrySet()); - return Stream.of( - diff.entrySet() - .stream() - .map(e -> "expected: " + e.getKey() + ": " + - e.getValue() + "\n" + - " actual: " + e.getKey() + ": " + - actual.get(e.getKey()) + "\n") - .collect(joining("\n", src + "\n\n", "\n")) - ); - } - }); - } -}