diff -r 000000000000 -r 959103a6100f test/tools/javac/annotations/repeatingAnnotations/combo/TargetAnnoCombo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tools/javac/annotations/repeatingAnnotations/combo/TargetAnnoCombo.java Wed Apr 27 01:34:52 2016 +0800 @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2013, 2014, 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. + */ + +/* + * @test + * @bug 7151010 8006547 8007766 8029017 + * @summary Default test cases for running combinations for Target values + * @build Helper + * @run main TargetAnnoCombo + */ + +import java.util.Set; +import java.util.List; +import java.io.IOException; +import java.lang.annotation.ElementType; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EnumSet; +import javax.tools.Diagnostic; +import javax.tools.DiagnosticCollector; +import javax.tools.JavaFileObject; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.CONSTRUCTOR; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.ElementType.PACKAGE; +import static java.lang.annotation.ElementType.LOCAL_VARIABLE; +import static java.lang.annotation.ElementType.TYPE_USE; +import static java.lang.annotation.ElementType.TYPE_PARAMETER; + +public class TargetAnnoCombo { + + static final String TESTPKG = "testpkg"; + + // Set it to true to get more debug information including base and container + // target sets for a given test case. + static final boolean DEBUG = false; + + // Define constant target sets to be used for the combination of the target values. + final static Set noSet = null; + final static Set empty = EnumSet.noneOf(ElementType.class); + + // [TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, + // PACKAGE, TYPE_PARAMETER, TYPE_USE] + final static Set allTargets = EnumSet.allOf(ElementType.class); + + // [TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, + // PACKAGE] + final static Set jdk7 = EnumSet.range(TYPE, PACKAGE); + + // [TYPE_USE, TYPE_PARAMETER] + final static Set jdk8 = EnumSet.range(TYPE_PARAMETER, TYPE_USE); + + // List of test cases to run. This list is created in generate(). + // To run a specific test cases add case number in @run main line. + List testCases = new ArrayList(); + + int errors = 0; + + // Identify test cases that fail. + enum IgnoreKind { + RUN, + IGNORE + }; + + private class TestCase { + + private Set baseAnnotations; + private Set containerAnnotations; + private IgnoreKind ignore; + + public TestCase(Set baseAnnotations, Set containerAnnotations) { + this(baseAnnotations, containerAnnotations, IgnoreKind.RUN); + } + + public TestCase(Set baseAnnotations, Set containerAnnotations, + IgnoreKind ignoreKind) { + this.baseAnnotations = baseAnnotations; + this.containerAnnotations = containerAnnotations; + this.ignore = ignoreKind; + } + + public Set getBaseAnnotations() { + return baseAnnotations; + } + + public Set getContainerAnnotations() { + return containerAnnotations; + } + + public boolean isIgnored() { + return ignore == IgnoreKind.IGNORE; + } + + // Determine if a testCase should compile or not. + private boolean isValidSubSet() { + /* + * RULE 1: conAnnoTarget should be a subset of baseAnnoTarget + * RULE 2: For empty @Target ({}) - annotation cannot be applied anywhere + * - Empty sets for both is valid + * - Empty baseTarget set is invalid with non-empty conTarget set + * - Non-empty baseTarget set is valid with empty conTarget set + * RULE 3: For no @Target specified - annotation can be applied to any JDK 7 targets + * - No @Target for both is valid + * - No @Target for baseTarget set with @Target conTarget set is valid + * - @Target for baseTarget set with no @Target for conTarget is invalid + */ + + + /* If baseAnno has no @Target, Foo can be either applied to @Target specified + * for container annotation else will be applicable for all default targets + * if no @Target is present for container annotation. + * In both cases, the set will be a valid set with no @Target for base annotation + */ + if (baseAnnotations == null) { + if (containerAnnotations == null) { + return true; + } + return !(containerAnnotations.contains(TYPE_USE) || + containerAnnotations.contains(TYPE_PARAMETER)); + } + + Set tempBaseSet = EnumSet.noneOf(ElementType.class); + tempBaseSet.addAll(baseAnnotations); + + // If BaseAnno has TYPE, then ANNOTATION_TYPE is allowed by default. + if (baseAnnotations.contains(TYPE)) { + tempBaseSet.add(ANNOTATION_TYPE); + } + + // If BaseAnno has TYPE_USE, then add the extra allowed types + if (baseAnnotations.contains(TYPE_USE)) { + tempBaseSet.add(ANNOTATION_TYPE); + tempBaseSet.add(TYPE); + tempBaseSet.add(TYPE_PARAMETER); + } + + // If containerAnno has no @Target, only valid case if baseAnnoTarget has + // all targets defined else invalid set. + if (containerAnnotations == null) { + return tempBaseSet.containsAll(jdk7); + } + + // At this point, neither conAnnoTarget or baseAnnoTarget are null. + if (containerAnnotations.isEmpty()) { + return true; + } + + // At this point, conAnnoTarget is non-empty. + if (baseAnnotations.isEmpty()) { + return false; + } + + // At this point, neither conAnnoTarget or baseAnnoTarget are empty. + return tempBaseSet.containsAll(containerAnnotations); + } + } + + public static void main(String args[]) throws Exception { + TargetAnnoCombo tac = new TargetAnnoCombo(); + // Generates all test cases to be run. + tac.generate(); + List cases = new ArrayList(); + for (int i = 0; i < args.length; i++) { + cases.add(Integer.parseInt(args[i])); + } + if (cases.isEmpty()) { + tac.run(); + } else { + for (int index : cases) { + tac.executeTestCase(tac.testCases.get(index), index); + } + } + } + + private void generate() { + // Adding test cases to run. + testCases.addAll(Arrays.asList( + // No base target against no container target. + new TestCase(noSet, noSet), + // No base target against empty container target. + new TestCase(noSet, empty), + // No base target against TYPE_USE only container target. + new TestCase(noSet, less(jdk8, TYPE_PARAMETER)), + // No base target against TYPE_PARAMETER only container target. + new TestCase(noSet, less(jdk8, TYPE_USE)), + // No base target against TYPE_USE + TYPE_PARAMETER only container target. + new TestCase(noSet, jdk8), + // No base target against TYPE_USE + some selection of jdk7 targets. + new TestCase(noSet, + plus(EnumSet.range(TYPE, LOCAL_VARIABLE), TYPE_USE)), + // No base target against TYPE_PARAMETER + some selection of jdk7 targets. + new TestCase(noSet, + plus(EnumSet.range(TYPE, LOCAL_VARIABLE), TYPE_PARAMETER)), + // No base target against each jdk7 target alone as container target. + new TestCase(noSet, plus(empty, TYPE)), + new TestCase(noSet, plus(empty, PARAMETER)), + new TestCase(noSet, plus(empty, PACKAGE)), + new TestCase(noSet, plus(empty, METHOD)), + new TestCase(noSet, plus(empty, LOCAL_VARIABLE)), + new TestCase(noSet, plus(empty, FIELD)), + new TestCase(noSet, plus(empty, CONSTRUCTOR)), + new TestCase(noSet, plus(empty, ANNOTATION_TYPE)), + // Empty base target against no container target. + new TestCase(empty, noSet), + // Empty base target against empty container target. + new TestCase(empty, empty), + // Empty base target against any lone container target. + new TestCase(empty, plus(empty, TYPE)), + new TestCase(empty, plus(empty, PARAMETER)), + new TestCase(empty, plus(empty, PACKAGE)), + new TestCase(empty, plus(empty, METHOD)), + new TestCase(empty, plus(empty, LOCAL_VARIABLE)), + new TestCase(empty, plus(empty, FIELD)), + new TestCase(empty, plus(empty, CONSTRUCTOR)), + new TestCase(empty, plus(empty, ANNOTATION_TYPE)), + new TestCase(empty, less(jdk8, TYPE_USE)), + new TestCase(empty, less(jdk8, TYPE_PARAMETER)), + // No container target against all all-but one jdk7 targets. + new TestCase(less(jdk7, TYPE), noSet), + new TestCase(less(jdk7, PARAMETER), noSet), + new TestCase(less(jdk7, PACKAGE), noSet), + new TestCase(less(jdk7, METHOD), noSet), + new TestCase(less(jdk7, LOCAL_VARIABLE), noSet), + new TestCase(less(jdk7, FIELD), noSet), + new TestCase(less(jdk7, CONSTRUCTOR), noSet), + new TestCase(less(jdk7, ANNOTATION_TYPE), noSet), + // No container against all but TYPE and ANNOTATION_TYPE + new TestCase(less(jdk7, TYPE, ANNOTATION_TYPE), noSet), + // No container against jdk7 targets. + new TestCase(jdk7, noSet), + // No container against jdk7 targets plus one or both of TYPE_USE, TYPE_PARAMETER + new TestCase(plus(jdk7, TYPE_USE), noSet), + new TestCase(plus(jdk7, TYPE_PARAMETER), noSet), + new TestCase(allTargets, noSet), + // Empty container target against any lone target. + new TestCase(plus(empty, TYPE), empty), + new TestCase(plus(empty, PARAMETER), empty), + new TestCase(plus(empty, PACKAGE), empty), + new TestCase(plus(empty, METHOD), empty), + new TestCase(plus(empty, LOCAL_VARIABLE), empty), + new TestCase(plus(empty, FIELD), empty), + new TestCase(plus(empty, CONSTRUCTOR), empty), + new TestCase(plus(empty, ANNOTATION_TYPE), empty), + new TestCase(plus(empty, TYPE_USE), empty), + new TestCase(plus(empty, TYPE_PARAMETER), empty), + // All base targets against all container targets. + new TestCase(allTargets, allTargets), + // All base targets against all but one container targets. + new TestCase(allTargets, less(allTargets, TYPE)), + new TestCase(allTargets, less(allTargets, PARAMETER)), + new TestCase(allTargets, less(allTargets, PACKAGE)), + new TestCase(allTargets, less(allTargets, METHOD)), + new TestCase(allTargets, less(allTargets, LOCAL_VARIABLE)), + new TestCase(allTargets, less(allTargets, FIELD)), + new TestCase(allTargets, less(allTargets, CONSTRUCTOR)), + new TestCase(allTargets, less(allTargets, ANNOTATION_TYPE)), + new TestCase(allTargets, less(allTargets, TYPE_USE)), + new TestCase(allTargets, less(allTargets, TYPE_PARAMETER)), + // All container targets against all but one base targets. + new TestCase(less(allTargets, TYPE), allTargets), + new TestCase(less(allTargets, PARAMETER), allTargets), + new TestCase(less(allTargets, PACKAGE), allTargets), + new TestCase(less(allTargets, METHOD), allTargets), + new TestCase(less(allTargets, LOCAL_VARIABLE), allTargets), + new TestCase(less(allTargets, FIELD), allTargets), + new TestCase(less(allTargets, CONSTRUCTOR), allTargets), + new TestCase(less(allTargets, ANNOTATION_TYPE), allTargets), + new TestCase(less(allTargets, TYPE_USE), allTargets), + new TestCase(less(allTargets, TYPE_PARAMETER), allTargets))); + // Generates 100 test cases for any lone base target contained in Set + // allTargets against any lone container target. + for (ElementType b : allTargets) { + for (ElementType c : allTargets) { + testCases.add(new TestCase(plus(empty, b), plus(empty, c))); + } + } + } + + void run() throws Exception { + int testCtr = 0; + for (TestCase tc : testCases) { + if (!tc.isIgnored()) { + executeTestCase(tc, testCases.indexOf(tc)); + testCtr++; + } + } + System.out.println("Total tests run: " + testCtr); + if (errors > 0) { + throw new Exception(errors + " errors found"); + } + } + + private void executeTestCase(TestCase testCase, int index) { + debugPrint("Test case number = " + index); + debugPrint(" => baseAnnoTarget = " + testCase.getBaseAnnotations()); + debugPrint(" => containerAnnoTarget = " + testCase.getContainerAnnotations()); + + String className = "TC" + index; + boolean shouldCompile = testCase.isValidSubSet(); + Iterable files = getFileList(className, testCase, shouldCompile); + // Get result of compiling test src file(s). + boolean result = getCompileResult(className, shouldCompile, files); + // List test src code if test fails. + if (!result) { + System.out.println("FAIL: Test " + index); + try { + for (JavaFileObject f : files) { + System.out.println("File: " + f.getName() + "\n" + f.getCharContent(true)); + } + } catch (IOException ioe) { + System.out.println("Exception: " + ioe); + } + } else { + debugPrint("PASS: Test " + index); + } + + } + + // Create src code and corresponding JavaFileObjects. + private Iterable getFileList(String className, + TestCase testCase, boolean shouldCompile) { + Set baseAnnoTarget = testCase.getBaseAnnotations(); + Set conAnnoTarget = testCase.getContainerAnnotations(); + String srcContent = ""; + String pkgInfoContent = ""; + String template = Helper.template; + String baseTarget = "", conTarget = ""; + + String target = Helper.ContentVars.TARGET.getVal(); + if (baseAnnoTarget != null) { + String tmp = target.replace("#VAL", convertToString(baseAnnoTarget).toString()); + baseTarget = tmp.replace("[", "{").replace("]", "}"); + } + if (conAnnoTarget != null) { + String tmp = target.replace("#VAL", convertToString(conAnnoTarget).toString()); + conTarget = tmp.replace("[", "{").replace("]", "}"); + } + + String annoData = Helper.ContentVars.IMPORTSTMTS.getVal() + + conTarget + + Helper.ContentVars.CONTAINER.getVal() + + baseTarget + + Helper.ContentVars.REPEATABLE.getVal() + + Helper.ContentVars.BASE.getVal(); + + JavaFileObject pkgInfoFile = null; + + // If shouldCompile = true and no @Target is specified for container annotation, + // then all 8 ElementType enum constants are applicable as targets for + // container annotation. + if (shouldCompile && conAnnoTarget == null) { + Set copySet = EnumSet.noneOf(ElementType.class); + copySet.addAll(jdk7); + conAnnoTarget = copySet; + } + + if (shouldCompile) { + boolean isPkgCasePresent = conAnnoTarget.contains(PACKAGE); + String repeatableAnno = Helper.ContentVars.BASEANNO.getVal() + + " " + Helper.ContentVars.BASEANNO.getVal(); + for (ElementType s : conAnnoTarget) { + String replaceStr = "/*" + s.name() + "*/"; + if (s.name().equalsIgnoreCase("PACKAGE")) { + //Create packageInfo file. + String pkgInfoName = TESTPKG + "." + "package-info"; + pkgInfoContent = repeatableAnno + "\npackage " + TESTPKG + ";" + annoData; + pkgInfoFile = Helper.getFile(pkgInfoName, pkgInfoContent); + } else { + template = template.replace(replaceStr, repeatableAnno); + if (!isPkgCasePresent) { + srcContent = template.replace( + "/*ANNODATA*/", annoData).replace("#ClassName", className); + } else { + replaceStr = "/*PACKAGE*/"; + String tmp = template.replace(replaceStr, "package " + TESTPKG + ";"); + srcContent = tmp.replace("#ClassName", className); + } + } + } + } else { + // For invalid cases, compilation should fail at declaration site. + template = "class #ClassName {}"; + srcContent = annoData + template.replace("#ClassName", className); + } + JavaFileObject srcFile = Helper.getFile(className, srcContent); + Iterable files = null; + if (pkgInfoFile != null) { + files = Arrays.asList(pkgInfoFile, srcFile); + } else { + files = Arrays.asList(srcFile); + } + return files; + } + + // Compile the test source file(s) and return test result. + private boolean getCompileResult(String className, boolean shouldCompile, + Iterable files) { + + DiagnosticCollector diagnostics = + new DiagnosticCollector(); + Helper.compileCode(diagnostics, files); + // Test case pass or fail. + boolean ok = false; + String errMesg = ""; + int numDiags = diagnostics.getDiagnostics().size(); + if (numDiags == 0) { + if (shouldCompile) { + debugPrint("Test passed, compiled as expected."); + ok = true; + } else { + errMesg = "Test failed, compiled unexpectedly."; + ok = false; + } + } else { + if (shouldCompile) { + // did not compile. + errMesg = "Test failed, did not compile."; + ok = false; + } else { + // Error in compilation as expected. + String expectedErrKey = "compiler.err.invalid.repeatable." + + "annotation.incompatible.target"; + for (Diagnostic d : diagnostics.getDiagnostics()) { + if ((d.getKind() == Diagnostic.Kind.ERROR) + && d.getCode().contains(expectedErrKey)) { + // Error message as expected. + debugPrint("Error message as expected."); + ok = true; + break; + } else { + // error message is incorrect. + ok = false; + } + } + if (!ok) { + errMesg = "Incorrect error received when compiling " + + className + ", expected: " + expectedErrKey; + } + } + } + + if (!ok) { + error(errMesg); + for (Diagnostic d : diagnostics.getDiagnostics()) { + System.out.println(" Diags: " + d); + } + } + return ok; + } + + private Set less(Set base, ElementType... sub) { + Set res = EnumSet.noneOf(ElementType.class); + res.addAll(base); + for (ElementType t : sub) { + res.remove(t); + } + return res; + } + + private Set plus(Set base, ElementType... add) { + Set res = EnumSet.noneOf(ElementType.class); + res.addAll(base); + for (ElementType t : add) { + res.add(t); + } + return res; + } + + // Iterate target set and add "ElementType." in front of every target type. + private List convertToString(Set annoTarget) { + if (annoTarget == null) { + return null; + } + List annoTargets = new ArrayList(); + for (ElementType e : annoTarget) { + annoTargets.add("ElementType." + e.name()); + } + return annoTargets; + } + + private void debugPrint(String string) { + if (DEBUG) { + System.out.println(string); + } + } + + private void error(String msg) { + System.out.println("ERROR: " + msg); + errors++; + } +} +