8044411: Implement classfile tests for RuntimeAnnotations and RuntimeParameterAnnotations attribute

Reviewed-by: jjg, shurailine, anazarov
This commit is contained in:
Andrei Eremeev 2015-07-10 12:42:00 +03:00
parent 7c256783a5
commit a7cf8786ff
19 changed files with 2651 additions and 45 deletions

View File

@ -0,0 +1,258 @@
/*
* Copyright (c) 2015, 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 com.sun.tools.classfile.Attribute;
import com.sun.tools.classfile.ConstantPoolException;
import com.sun.tools.classfile.Descriptor;
import javax.tools.JavaFileObject;
import java.io.IOException;
import java.lang.annotation.RetentionPolicy;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public abstract class AnnotationsTestBase extends TestResult {
/**
* Element values which are used in generation of annotations.
*/
private static final TestAnnotationInfo.Pair[] elementValues = {
new TestAnnotationInfo.Pair("booleanValue", new TestAnnotationInfo.TestBooleanElementValue(true)),
new TestAnnotationInfo.Pair("byteValue", new TestAnnotationInfo.TestIntegerElementValue('B', 83)),
new TestAnnotationInfo.Pair("charValue", new TestAnnotationInfo.TestCharElementValue('H')),
new TestAnnotationInfo.Pair("shortValue", new TestAnnotationInfo.TestIntegerElementValue('S', 14)),
new TestAnnotationInfo.Pair("intValue", new TestAnnotationInfo.TestIntegerElementValue('I', 18)),
new TestAnnotationInfo.Pair("longValue", new TestAnnotationInfo.TestLongElementValue(14)),
new TestAnnotationInfo.Pair("floatValue", new TestAnnotationInfo.TestFloatElementValue(-1)),
new TestAnnotationInfo.Pair("doubleValue", new TestAnnotationInfo.TestDoubleElementValue(-83)),
new TestAnnotationInfo.Pair("stringValue", new TestAnnotationInfo.TestStringElementValue("///")),
new TestAnnotationInfo.Pair("arrayValue1", new TestAnnotationInfo.TestArrayElementValue(
new TestAnnotationInfo.TestIntegerElementValue('I', 1),
new TestAnnotationInfo.TestIntegerElementValue('I', 4),
new TestAnnotationInfo.TestIntegerElementValue('I', 8),
new TestAnnotationInfo.TestIntegerElementValue('I', 3))),
new TestAnnotationInfo.Pair("arrayValue2", new TestAnnotationInfo.TestArrayElementValue(
new TestAnnotationInfo.TestStringElementValue("AAA"),
new TestAnnotationInfo.TestStringElementValue("BBB"))),
new TestAnnotationInfo.Pair("enumValue", new TestAnnotationInfo.TestEnumElementValue("EnumValue", "VALUE2")),
new TestAnnotationInfo.Pair("classValue1", new TestAnnotationInfo.TestClassElementValue("void.class")),
new TestAnnotationInfo.Pair("classValue2", new TestAnnotationInfo.TestClassElementValue("Character.class")),
new TestAnnotationInfo.Pair("annoValue", new TestAnnotationInfo.TestAnnotationElementValue("AnnotationValue",
new TestAnnotationInfo("AnnotationValue", RetentionPolicy.CLASS,
new TestAnnotationInfo.Pair("stringValue",
new TestAnnotationInfo.TestStringElementValue("StringValue1"))))),
new TestAnnotationInfo.Pair("annoArrayValue", new TestAnnotationInfo.TestArrayElementValue(
new TestAnnotationInfo.TestAnnotationElementValue("AnnotationValue",
new TestAnnotationInfo("AnnotationValue", RetentionPolicy.CLASS,
new TestAnnotationInfo.Pair("stringValue",
new TestAnnotationInfo.TestStringElementValue("StringValue1")))),
new TestAnnotationInfo.TestAnnotationElementValue("AnnotationValue",
new TestAnnotationInfo("AnnotationValue", RetentionPolicy.CLASS,
new TestAnnotationInfo.Pair("stringValue",
new TestAnnotationInfo.TestStringElementValue("StringValue1"))))))
};
/**
* Masks which are used in generation of annotations.
* E.g. mask 0 corresponds to an annotation without element values.
*/
private static final int[] elementValuesCombinations;
static {
List<Integer> combinations = new ArrayList<>();
combinations.add(0);
for (int i = 0; i < elementValues.length; ++i) {
combinations.add(1 << i);
}
// pairs int value and another value
for (int i = 0; i < elementValues.length; ++i) {
combinations.add((1 << 5) | (1 << i));
}
combinations.add((1 << elementValues.length) - 1);
elementValuesCombinations = combinations.stream().mapToInt(Integer::intValue).toArray();
}
/**
* Method generates a list of test cases.
* Method is called in the method {@code call()}.
*
* @return a list of test cases
*/
public abstract List<TestCase> generateTestCases();
public abstract void test(TestCase testCase, Map<String, ? extends JavaFileObject> classes)
throws IOException, ConstantPoolException, Descriptor.InvalidDescriptor;
/**
* The method is used to create a repeatable annotation.
*/
private TestAnnotationInfo createSomeAnnotation(String annotationName) {
return new TestAnnotationInfo(annotationName, getRetentionPolicy(annotationName),
new TestAnnotationInfo.Pair("booleanValue",
new TestAnnotationInfo.TestBooleanElementValue(true)),
new TestAnnotationInfo.Pair("intValue",
new TestAnnotationInfo.TestIntegerElementValue('I', 1)),
new TestAnnotationInfo.Pair("enumValue",
new TestAnnotationInfo.TestEnumElementValue("EnumValue", "VALUE1")));
}
private TestAnnotationInfo getAnnotationByMask(String annotationName, int mask) {
List<TestAnnotationInfo.Pair> pairs = new ArrayList<>();
for (int i = 0; i < elementValues.length; ++i) {
if ((mask & (1 << i)) != 0) {
pairs.add(elementValues[i]);
}
}
return new TestAnnotationInfo(
annotationName,
getRetentionPolicy(annotationName),
pairs.toArray(new TestAnnotationInfo.Pair[pairs.size()]));
}
/**
* Class represents annotations which will be applied to one method.
*/
public static class TestAnnotationInfos {
public final List<TestAnnotationInfo> annotations;
public TestAnnotationInfos(List<TestAnnotationInfo> a) {
this.annotations = a;
}
public void annotate(TestCase.TestMemberInfo memberInfo) {
annotations.forEach(memberInfo::addAnnotation);
}
}
/**
* Convenience method to group test cases.
* Increases speed of tests.
*/
public List<List<TestAnnotationInfos>> groupAnnotations(List<TestAnnotationInfos> annotations) {
List<List<TestAnnotationInfos>> groupedAnnotations = new ArrayList<>();
int size = 32;
List<TestAnnotationInfos> current = null;
for (TestAnnotationInfos infos : annotations) {
if (current == null || current.size() == size) {
current = new ArrayList<>();
groupedAnnotations.add(current);
}
current.add(infos);
}
return groupedAnnotations;
}
public List<TestAnnotationInfos> getAllCombinationsOfAnnotations() {
List<TestAnnotationInfos> combinations = new ArrayList<>();
for (Annotations annotationName1 : Annotations.values()) {
List<TestAnnotationInfo> list = IntStream.of(elementValuesCombinations)
.mapToObj(e -> getAnnotationByMask(annotationName1.getAnnotationName(), e))
.collect(Collectors.toList());
// add cases with a single annotation
combinations.addAll(list.stream()
.map(Collections::singletonList)
.map(TestAnnotationInfos::new)
.collect(Collectors.toList()));
// add cases with a repeatable annotation
for (Annotations annotationName2 : Annotations.values()) {
if (annotationName1 == annotationName2 && !annotationName1.isRepeatable()) {
continue;
}
TestAnnotationInfo annotation2 = createSomeAnnotation(annotationName2.getAnnotationName());
for (TestAnnotationInfo annotation1 : list) {
List<TestAnnotationInfo> list1 = new ArrayList<>();
Collections.addAll(list1, annotation1, annotation2);
combinations.add(new TestAnnotationInfos(list1));
}
}
}
return combinations;
}
protected RetentionPolicy getRetentionPolicy(String name) {
if (name.contains("Visible")) {
return RetentionPolicy.RUNTIME;
} else if (name.contains("Invisible")) {
return RetentionPolicy.CLASS;
}
throw new IllegalArgumentException(name);
}
protected long countNumberOfAttributes(Attribute[] attrs,
Class<? extends Attribute> clazz) {
return Stream.of(attrs)
.filter(clazz::isInstance)
.count();
}
public void test() throws TestFailedException {
try {
List<TestCase> testCases = generateTestCases();
for (int i = 0; i < testCases.size(); ++i) {
TestCase testCase = testCases.get(i);
String source = testCase.generateSource();
Path sourceFile = Paths.get(getClass().getSimpleName() + i + ".java");
addTestCase(sourceFile.toAbsolutePath().toString());
writeToFile(sourceFile, source);
echo("Testing: " + sourceFile.toString());
try {
test(testCase, compile(source).getClasses());
} catch (Exception e) {
addFailure(e);
}
}
} catch (RuntimeException | IOException e) {
addFailure(e);
} finally {
checkStatus();
}
}
public enum Annotations {
RUNTIME_INVISIBLE_REPEATABLE("RuntimeInvisibleRepeatable", true),
RUNTIME_INVISIBLE_NOT_REPEATABLE("RuntimeInvisibleNotRepeatable", false),
RUNTIME_VISIBLE_REPEATABLE("RuntimeVisibleRepeatable", true),
RUNTIME_VISIBLE_NOT_REPEATABLE("RuntimeVisibleNotRepeatable", false);
private final String annotationName;
private final boolean isRepeatable;
Annotations(String annotationName, boolean isRepeatable) {
this.annotationName = annotationName;
this.isRepeatable = isRepeatable;
}
public String getAnnotationName() {
return annotationName;
}
public boolean isRepeatable() {
return isRepeatable;
}
}
}

View File

@ -0,0 +1,130 @@
/*
* Copyright (c) 2015, 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 java.util.Collection;
import java.util.stream.Collectors;
public enum ClassType {
CLASS("class"),
INTERFACE("interface") {
@Override
public String methodToString(TestCase.TestMethodInfo method) {
String modifiers = method.mods.stream()
.collect(Collectors.joining(" "));
boolean hasBody = modifiers.contains("static") || modifiers.contains("default");
String parameters = method.parameters.stream()
.map(TestCase.TestMemberInfo::generateSource)
.collect(Collectors.joining(", "));
return String.format("%s %s %s(%s) %s",
method.indention() + modifiers,
"int",
method.getName(),
parameters,
hasBody ? "{return 0;}" : ";");
}
},
ANNOTATION("@interface") {
@Override
public String methodToString(TestCase.TestMethodInfo method) {
String modifiers = method.mods.stream()
.collect(Collectors.joining(" "));
return String.format("%s %s %s() %s",
method.indention() + modifiers,
"int",
method.getName(),
";");
}
},
ENUM("enum") {
@Override
public String fieldToString(TestCase.TestFieldInfo field) {
return field.indention() + field.name;
}
@Override
public String collectFields(Collection<TestCase.TestFieldInfo> fields) {
return fields.stream()
.map(TestCase.TestMemberInfo::generateSource)
.collect(Collectors.joining(",\n")) + ";\n";
}
};
private final String classType;
ClassType(String classType) {
this.classType = classType;
}
private String collectSrc(Collection<? extends TestCase.TestMemberInfo> members) {
String src = members.stream()
.map(TestCase.TestMemberInfo::generateSource)
.collect(Collectors.joining("\n"));
return src.trim().isEmpty() ? "" : src + "\n\n";
}
public String collectInnerClasses(Collection<TestCase.TestClassInfo> innerClasses) {
return collectSrc(innerClasses);
}
public String collectFields(Collection<TestCase.TestFieldInfo> fields) {
return collectSrc(fields);
}
public String collectMethods(Collection<TestCase.TestMethodInfo> methods) {
return collectSrc(methods);
}
public String methodToString(TestCase.TestMethodInfo method) {
String modifiers = method.mods.stream()
.collect(Collectors.joining(" "));
String parameters = method.parameters.stream()
.map(TestCase.TestMemberInfo::generateSource)
.collect(Collectors.joining(", "));
String localClasses = collectInnerClasses(method.localClasses.values());
String methodBody = modifiers.contains("abstract") ? ";" :
String.format("{%n%s%s%n%s}",
localClasses,
method.isConstructor
? ""
: method.indention() + "return false;",
method.indention());
return String.format("%s %s %s(%s) %s",
method.indention() + modifiers,
method.isConstructor ? "" : "boolean",
method.getName(),
parameters,
methodBody);
}
public String fieldToString(TestCase.TestFieldInfo field) {
String modifiers = field.mods.stream()
.collect(Collectors.joining(" "));
return String.format("%s int %s = 0;",
field.indention() + modifiers,
field.name);
}
public String getDescription() {
return classType;
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2015, 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.
*/
== Description of tests for RuntimeVisibleAnnotations, RuntimeInVisibleAnnotations
RuntimeVisibleParameterAnnotations and RuntimeInvisibleParameterAnnotations attributes ==
* AnnotationsTestBase class is a base class for the Annotations attribute tests.
It contains some convenience methods which might be used in derived classes.
* ClassType is a enum which is used for convenience code generation (see TestCase).
* TestCase is a class which represent a test case. TestCase contains TestClassInfo,
which represents a class, TestMethodInfo, which represents a method, TestFieldInfo,
which represents a field, and TestParameterInfo, which represents a method's parameter.
The class is used as test case builder. For example, the following code creates
the top-level class Test with method classMethod() and local class Local.
Each program member is annotated by some annotation which is an instance of
TestAnnotationInfo (see TestAnnotationInfo):
TestCase test = new TestCase(ClassType.CLASS, "Test", "public");
test.clazz.addAnnotation(annotations);
TestCase.TestMethodInfo classMethod = test.clazz.addMethod("classMethod()");
classMethod.addAnnotation(annotation);
TestCase.TestClassInfo localClassInClassMethod = classMethod.addLocalClass("Local");
localClassInClassMethod.addAnnotation(annotations);
Let "annotations" be a list of annotations A, B(i = 2). Thus, a test will generate the
following code:
@A
@B(i = 2)
public class Test {
@A
@B(i = 2)
void classMethod() {
@A
@B(i = 2)
class Local {
}
}
}
Thus, TestCase contains information about structure of classes and golden data
about annotations. Thereafter, sources can be generated from this class representation
by calling method generateSource(). Enum ClassType is used to handle "class type specific"
code generation. For example, not-abstract method in a class always has body,
while not-static and not-default method in an interface does not.

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2015, 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 8044411
* @summary Tests the RuntimeVisibleAnnotations/RuntimeInvisibleAnnotations attribute.
* Checks that the attribute is generated for bridge method.
* @library /tools/lib /tools/javac/lib ../lib
* @build WorkAnnotations TestBase TestResult InMemoryFileManager ToolBox
* @build TestCase ClassType TestAnnotationInfo
* @build RuntimeAnnotationsForGenericMethodTest AnnotationsTestBase RuntimeAnnotationsTestBase
* @run main RuntimeAnnotationsForGenericMethodTest
*/
import java.util.ArrayList;
import java.util.List;
/**
* RuntimeAnnotationsGenericMethodTest is a test which check that
* RuntimeVisibleAnnotationsAttribute and RuntimeInvisibleAnnotationsAttribute
* are generated for both generic and appropriate bridge methods.
* All possible combinations of retention policies are tested.
*
* The test generates class which looks as follows:
*
* public class Test extends java.util.ArrayList&lt;Integer&gt; {
* here some annotations
* public boolean add(java.lang.Integer) {
* return false;
* }
* }
*
* Thereafter, various of combinations of annotations are applied
* to the add, the source is compiled and the generated byte code is checked.
*
* See README.txt for more information.
*/
public class RuntimeAnnotationsForGenericMethodTest extends RuntimeAnnotationsTestBase {
@Override
public List<TestCase> generateTestCases() {
List<TestCase> testCases = new ArrayList<>();
for (List<TestAnnotationInfos> groupedAnnotations : groupAnnotations(getAllCombinationsOfAnnotations())) {
TestCase testCase = new TestCase();
for (int i = 0; i < groupedAnnotations.size(); ++i) {
TestAnnotationInfos annotations = groupedAnnotations.get(i);
// generate: public class Test extends java.util.ArrayList<Integer>
TestCase.TestClassInfo clazz = testCase.addClassInfo("java.util.ArrayList<Integer>", ClassType.CLASS, "Test" + i);
TestCase.TestMethodInfo method = clazz.addMethodInfo("add(java.lang.Integer)", "public");
method.addParameter("Integer", "i");
annotations.annotate(method);
TestCase.TestMethodInfo synMethod = clazz.addMethodInfo("add(java.lang.Object)", true, "public");
annotations.annotate(synMethod);
}
testCases.add(testCase);
}
return testCases;
}
public static void main(String[] args) throws TestFailedException {
new RuntimeAnnotationsForGenericMethodTest().test();
}
}

View File

@ -0,0 +1,75 @@
/*
* Copyright (c) 2015, 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 8044411
* @summary Tests the RuntimeVisibleAnnotations/RuntimeInvisibleAnnotations attribute.
* @library /tools/lib /tools/javac/lib ../lib
* @build WorkAnnotations TestBase TestResult InMemoryFileManager ToolBox
* @build TestCase ClassType TestAnnotationInfo
* @build RuntimeAnnotationsForInnerAnnotationTest AnnotationsTestBase RuntimeAnnotationsTestBase
* @run main RuntimeAnnotationsForInnerAnnotationTest
*/
import java.util.ArrayList;
import java.util.List;
/**
* The test checks that RuntimeVisibleAnnotationsAttribute and RuntimeInvisibleAnnotationsAttribute
* are generated properly for inner classes annotations, for methods, for fields
*
* The test checks both single and repeatable annotations. In addition, all possible combinations
* of retention policies are tested. The test generates source code, compiles it and checks the byte code.
*
* See README.txt for more information.
*/
public class RuntimeAnnotationsForInnerAnnotationTest extends RuntimeAnnotationsTestBase {
@Override
public List<TestCase> generateTestCases() {
List<TestCase> testCases = new ArrayList<>();
for (List<TestAnnotationInfos> groupedAnnotations : groupAnnotations(getAllCombinationsOfAnnotations())) {
for (ClassType outerClassType : ClassType.values()) {
TestCase test = new TestCase();
TestCase.TestClassInfo clazz = test.addClassInfo(outerClassType, "Test");
for (int i = 0; i < groupedAnnotations.size(); ++i) {
TestCase.TestClassInfo anno = clazz.addInnerClassInfo(ClassType.ANNOTATION, "InnerAnnotation" + i);
TestAnnotationInfos annotations = groupedAnnotations.get(i);
annotations.annotate(anno);
TestCase.TestMethodInfo annoMethod = anno.addMethodInfo("interMethod" + i + "()");
annotations.annotate(annoMethod);
TestCase.TestFieldInfo annoField = anno.addFieldInfo("annoField" + i);
annotations.annotate(annoField);
}
testCases.add(test);
}
}
return testCases;
}
public static void main(String[] args) throws TestFailedException {
new RuntimeAnnotationsForInnerAnnotationTest().test();
}
}

View File

@ -0,0 +1,88 @@
/*
* Copyright (c) 2015, 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 8044411
* @summary Tests the RuntimeVisibleAnnotations/RuntimeInvisibleAnnotations attribute.
* @library /tools/lib /tools/javac/lib ../lib
* @build WorkAnnotations TestBase TestResult InMemoryFileManager ToolBox
* @build TestCase ClassType TestAnnotationInfo
* @build RuntimeAnnotationsForInnerClassTest AnnotationsTestBase RuntimeAnnotationsTestBase
* @run main RuntimeAnnotationsForInnerClassTest
*/
import java.util.ArrayList;
import java.util.List;
/**
* The test checks that RuntimeVisibleAnnotationsAttribute and RuntimeInvisibleAnnotationsAttribute
* are generated properly for inner classes, for constructors, for methods, for fields.
* The test checks both single and repeatable annotations. In addition, all possible combinations
* of retention policies are tested.
*
* The test generates source code, compiles it and checks the byte code.
*
* See README.txt for more information.
*/
public class RuntimeAnnotationsForInnerClassTest extends RuntimeAnnotationsTestBase {
@Override
public List<TestCase> generateTestCases() {
List<TestCase> testCases = new ArrayList<>();
for (List<TestAnnotationInfos> groupedAnnotations : groupAnnotations(getAllCombinationsOfAnnotations())) {
for (ClassType outerClassType : ClassType.values()) {
TestCase test = new TestCase();
TestCase.TestClassInfo outerClazz = test.addClassInfo(outerClassType, "Test");
for (int i = 0; i < groupedAnnotations.size(); ++i) {
TestAnnotationInfos annotations = groupedAnnotations.get(i);
TestCase.TestClassInfo clazz = outerClazz.addInnerClassInfo(ClassType.CLASS, "InnerClass" + i, "static");
annotations.annotate(clazz);
TestCase.TestMethodInfo constructor = clazz.addMethodInfo("<init>()");
annotations.annotate(constructor);
TestCase.TestClassInfo localClassInConstructor = constructor.addLocalClassInfo("Local1" + i);
annotations.annotate(localClassInConstructor);
TestCase.TestMethodInfo innerClazzMethod = clazz.addMethodInfo("innerClassMethod" + i + "()");
annotations.annotate(innerClazzMethod);
TestCase.TestClassInfo localClassInClassMethod = innerClazzMethod.addLocalClassInfo("Local2" + i);
annotations.annotate(localClassInClassMethod);
TestCase.TestMethodInfo innerStaticClazzMethod = clazz.addMethodInfo("innerStaticClassMethod" + i + "()", "static");
annotations.annotate(innerStaticClazzMethod);
TestCase.TestClassInfo localClassInStaticMethod = innerStaticClazzMethod.addLocalClassInfo("Local3" + i);
annotations.annotate(localClassInStaticMethod);
}
testCases.add(test);
}
}
return testCases;
}
public static void main(String[] args) throws TestFailedException {
new RuntimeAnnotationsForInnerClassTest().test();
}
}

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2015, 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 8044411
* @summary Tests the RuntimeVisibleAnnotations/RuntimeInvisibleAnnotations attribute.
* @library /tools/lib /tools/javac/lib ../lib
* @build WorkAnnotations TestBase TestResult InMemoryFileManager ToolBox
* @build TestCase ClassType TestAnnotationInfo
* @build RuntimeAnnotationsForInnerEnumTest AnnotationsTestBase RuntimeAnnotationsTestBase
* @run main RuntimeAnnotationsForInnerEnumTest
*/
import java.util.ArrayList;
import java.util.List;
/**
* The test checks that RuntimeVisibleAnnotationsAttribute and RuntimeInvisibleAnnotationsAttribute
* are generated properly for inner classes enums, for constructors, for methods,
* for fields (enum, class, annotation, interface). The test checks both
* single and repeatable annotations. In addition, all possible combinations
* of retention policies are tested.
*
* The test generates source code, compiles it and checks the byte code.
*
* See README.txt for more information.
*/
public class RuntimeAnnotationsForInnerEnumTest extends RuntimeAnnotationsTestBase {
@Override
public List<TestCase> generateTestCases() {
List<TestCase> testCases = new ArrayList<>();
for (List<TestAnnotationInfos> groupedAnnotations : groupAnnotations(getAllCombinationsOfAnnotations())) {
for (ClassType outerClassType : ClassType.values()) {
TestCase test = new TestCase();
TestCase.TestClassInfo outerClassInfo = test.addClassInfo(outerClassType, "Test");
for (int i = 0; i < groupedAnnotations.size(); i++) {
TestAnnotationInfos annotations = groupedAnnotations.get(i);
TestCase.TestClassInfo clazz = outerClassInfo.addInnerClassInfo(ClassType.ENUM, "Enum" + i);
annotations.annotate(clazz);
TestCase.TestMethodInfo innerClazzMethod = clazz.addMethodInfo("innerClassMethod" + i + "()");
annotations.annotate(innerClazzMethod);
TestCase.TestClassInfo localClassInClassMethod = innerClazzMethod.addLocalClassInfo("Local1" + i);
annotations.annotate(localClassInClassMethod);
TestCase.TestMethodInfo innerStaticClazzMethod = clazz.addMethodInfo("innerStaticClassMethod" + i + "()", "static");
annotations.annotate(innerStaticClazzMethod);
TestCase.TestClassInfo localClassInStaticMethod = innerStaticClazzMethod.addLocalClassInfo("Local2" + i);
annotations.annotate(localClassInStaticMethod);
TestCase.TestFieldInfo valueA = clazz.addFieldInfo("A" + i);
annotations.annotate(valueA);
TestCase.TestFieldInfo valueB = clazz.addFieldInfo("B" + i);
annotations.annotate(valueB);
}
testCases.add(test);
}
}
return testCases;
}
public static void main(String[] args) throws TestFailedException {
new RuntimeAnnotationsForInnerEnumTest().test();
}
}

View File

@ -0,0 +1,88 @@
/*
* Copyright (c) 2015, 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 8044411
* @summary Tests the RuntimeVisibleAnnotations/RuntimeInvisibleAnnotations attribute.
* @library /tools/lib /tools/javac/lib ../lib
* @build WorkAnnotations TestBase TestResult InMemoryFileManager ToolBox
* @build TestCase ClassType TestAnnotationInfo
* @build RuntimeAnnotationsForInnerInterfaceTest AnnotationsTestBase RuntimeAnnotationsTestBase
* @run main RuntimeAnnotationsForInnerInterfaceTest
*/
import java.util.ArrayList;
import java.util.List;
/**
* The test checks that RuntimeVisibleAnnotationsAttribute and RuntimeInvisibleAnnotationsAttribute
* are generated properly for inner interfaces, for methods, for fields. The test checks both
* single and repeatable annotations. In addition, all possible combinations
* of retention policies are tested.
*
* The test generates source code, compiles it and checks the byte code.
*
* See README.txt for more information.
*/
public class RuntimeAnnotationsForInnerInterfaceTest extends RuntimeAnnotationsTestBase {
@Override
public List<TestCase> generateTestCases() {
List<TestCase> testCases = new ArrayList<>();
for (List<TestAnnotationInfos> groupedAnnotations : groupAnnotations(getAllCombinationsOfAnnotations())) {
for (ClassType outerClassType : ClassType.values()) {
TestCase test = new TestCase();
TestCase.TestClassInfo outerClass = test.addClassInfo(outerClassType, "Test");
for (int i = 0; i < groupedAnnotations.size(); ++i) {
TestAnnotationInfos annotations = groupedAnnotations.get(i);
TestCase.TestClassInfo inter = outerClass.addInnerClassInfo(ClassType.INTERFACE, "InnerInterface" + i);
annotations.annotate(inter);
TestCase.TestFieldInfo interField = inter.addFieldInfo("interField" + i);
annotations.annotate(interField);
TestCase.TestMethodInfo interMethod = inter.addMethodInfo("interMethod" + i + "()");
annotations.annotate(interMethod);
TestCase.TestMethodInfo interStaticMethod = inter.addMethodInfo("interStaticMethod" + i + "()", "static");
annotations.annotate(interStaticMethod);
TestCase.TestClassInfo localClassInStaticMethod = interStaticMethod.addLocalClassInfo("Local1" + i);
annotations.annotate(localClassInStaticMethod);
TestCase.TestMethodInfo interDefaultMethod = inter.addMethodInfo("interDefaultMethod" + i + "()", "default");
annotations.annotate(interDefaultMethod);
TestCase.TestClassInfo localClassInDefaultMethod = interDefaultMethod.addLocalClassInfo("Local2" + i);
annotations.annotate(localClassInDefaultMethod);
}
testCases.add(test);
}
}
return testCases;
}
public static void main(String[] args) throws TestFailedException {
new RuntimeAnnotationsForInnerInterfaceTest().test();
}
}

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2015, 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 8044411
* @summary Tests the RuntimeVisibleAnnotations/RuntimeInvisibleAnnotations attribute.
* @library /tools/lib /tools/javac/lib ../lib
* @build WorkAnnotations TestBase TestResult InMemoryFileManager ToolBox
* @build TestCase ClassType TestAnnotationInfo
* @build RuntimeAnnotationsForTopLevelClassTest AnnotationsTestBase RuntimeAnnotationsTestBase
* @run main RuntimeAnnotationsForTopLevelClassTest
*/
import java.util.ArrayList;
import java.util.List;
/**
* The test checks that RuntimeVisibleAnnotationsAttribute and RuntimeInvisibleAnnotationsAttribute
* are generated properly for top-level class (class, enum, annotation, interface),
* for constructors (in enum and in class), for methods (abstract methods, static and default methods in interface),
* for fields. The test checks both single and repeatable annotations.
* In addition, all possible combinations of retention policies are tested.
*
* The test generates source code, compiles it and checks the byte code.
*
* See README.txt for more information.
*/
public class RuntimeAnnotationsForTopLevelClassTest extends RuntimeAnnotationsTestBase {
@Override
public List<TestCase> generateTestCases() {
List<TestCase> testCases = new ArrayList<>();
for (List<TestAnnotationInfos> groupedAnnotations : groupAnnotations(getAllCombinationsOfAnnotations())) {
for (ClassType classType : ClassType.values()) {
TestCase test = new TestCase();
for (int i = 0; i < groupedAnnotations.size(); ++i) {
TestAnnotationInfos annotations = groupedAnnotations.get(i);
TestCase.TestClassInfo clazz = test.addClassInfo(classType, "Test" + i);
annotations.annotate(clazz);
if (classType != ClassType.ENUM) {
TestCase.TestMethodInfo constructor = clazz.addMethodInfo("<init>()");
annotations.annotate(constructor);
TestCase.TestClassInfo localClass = constructor.addLocalClassInfo("Local1" + i);
annotations.annotate(localClass);
}
if (classType != ClassType.ANNOTATION) {
TestCase.TestMethodInfo staticClassMethod = clazz.addMethodInfo("staticClassMethod" + i + "()", "static");
annotations.annotate(staticClassMethod);
TestCase.TestClassInfo localClassInStaticMethod = staticClassMethod.addLocalClassInfo("Local2" + i);
annotations.annotate(localClassInStaticMethod);
}
TestCase.TestMethodInfo classMethod = clazz.addMethodInfo("classMethod" + i + "()");
annotations.annotate(classMethod);
TestCase.TestClassInfo localClassInClassMethod = classMethod.addLocalClassInfo("Local3" + i);
annotations.annotate(localClassInClassMethod);
TestCase.TestFieldInfo field = clazz.addFieldInfo("field" + i);
annotations.annotate(field);
TestCase.TestFieldInfo staticField = clazz.addFieldInfo("staticField" + i, "static");
annotations.annotate(staticField);
}
testCases.add(test);
}
}
return testCases;
}
public static void main(String[] args) throws TestFailedException {
new RuntimeAnnotationsForTopLevelClassTest().test();
}
}

View File

@ -0,0 +1,158 @@
/*
* Copyright (c) 2015, 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 com.sun.tools.classfile.*;
import java.io.IOException;
import java.lang.annotation.RetentionPolicy;
import java.util.*;
import java.util.function.Supplier;
import javax.tools.JavaFileObject;
public abstract class RuntimeAnnotationsTestBase extends AnnotationsTestBase {
@Override
public void test(TestCase testCase, Map<String, ? extends JavaFileObject> classes)
throws IOException, ConstantPoolException, Descriptor.InvalidDescriptor {
for (Map.Entry<String, ? extends JavaFileObject> entry : classes.entrySet()) {
String className = entry.getKey();
TestCase.TestClassInfo clazz = testCase.getTestClassInfo(className);
echo("Testing class : " + className);
ClassFile classFile = readClassFile(entry.getValue());
testAttributes(clazz, classFile, () -> classFile.attributes);
testMethods(clazz, classFile);
testFields(clazz, classFile);
}
}
private void testMethods(TestCase.TestClassInfo clazz, ClassFile classFile)
throws ConstantPoolException, Descriptor.InvalidDescriptor {
String className = clazz.getName();
Set<String> foundMethods = new HashSet<>();
for (Method method : classFile.methods) {
String methodName = method.getName(classFile.constant_pool) +
method.descriptor.getParameterTypes(classFile.constant_pool);
if (methodName.startsWith("<init>")) {
String constructorName = className.replaceAll(".*\\$", "");
methodName = methodName.replace("<init>", constructorName);
}
echo("Testing method : " + methodName);
TestCase.TestMethodInfo testMethod = clazz.getTestMethodInfo(methodName);
foundMethods.add(methodName);
if (testMethod == null) {
continue;
}
testAttributes(testMethod, classFile, () -> method.attributes);
}
checkContains(foundMethods, clazz.methods.keySet(), "Methods in class : " + className);
}
private void testFields(TestCase.TestClassInfo clazz, ClassFile classFile)
throws ConstantPoolException {
Set<String> foundFields = new HashSet<>();
for (Field field : classFile.fields) {
String fieldName = field.getName(classFile.constant_pool);
echo("Testing field : " + fieldName);
TestCase.TestFieldInfo testField = clazz.getTestFieldInfo(fieldName);
foundFields.add(fieldName);
if (testField == null) {
continue;
}
testAttributes(testField, classFile, () -> field.attributes);
}
checkContains(foundFields, clazz.fields.keySet(), "Fields in class : " + clazz.getName());
}
private void testAttributes(
TestCase.TestMemberInfo member,
ClassFile classFile,
Supplier<Attributes> attributes)
throws ConstantPoolException {
Map<String, Annotation> actualInvisible = collectAnnotations(
classFile,
member,
attributes.get(),
Attribute.RuntimeInvisibleAnnotations);
Map<String, Annotation> actualVisible = collectAnnotations(
classFile,
member,
attributes.get(),
Attribute.RuntimeVisibleAnnotations);
checkEquals(actualInvisible.keySet(),
member.getRuntimeInvisibleAnnotations(), "RuntimeInvisibleAnnotations");
checkEquals(actualVisible.keySet(),
member.getRuntimeVisibleAnnotations(), "RuntimeVisibleAnnotations");
for (TestAnnotationInfo expectedAnnotation : member.annotations.values()) {
RetentionPolicy policy = getRetentionPolicy(expectedAnnotation.annotationName);
if (policy == RetentionPolicy.SOURCE) {
continue;
}
printf("Testing: isVisible: %s %s%n", policy.toString(), expectedAnnotation.annotationName);
Annotation actualAnnotation =
(policy == RetentionPolicy.RUNTIME ? actualVisible : actualInvisible)
.get(expectedAnnotation.annotationName);
if (checkNotNull(actualAnnotation, "Annotation is found : "
+ expectedAnnotation.annotationName)) {
expectedAnnotation.testAnnotation(this, classFile, actualAnnotation);
}
}
}
private Map<String, Annotation> collectAnnotations(
ClassFile classFile,
TestCase.TestMemberInfo member,
Attributes attributes,
String attribute) throws ConstantPoolException {
RuntimeAnnotations_attribute attr = (RuntimeAnnotations_attribute) attributes.get(attribute);
Map<String, Annotation> actualAnnotations = new HashMap<>();
RetentionPolicy policy = getRetentionPolicy(attribute);
if (member.isAnnotated(policy)) {
if (!checkNotNull(attr, String.format("%s should be not null value", attribute))) {
// test case failed, stop checking
return actualAnnotations;
}
for (Annotation ann : attr.annotations) {
String name = classFile.constant_pool.getUTF8Value(ann.type_index);
actualAnnotations.put(name.substring(1, name.length() - 1), ann);
}
checkEquals(countNumberOfAttributes(attributes.attrs,
getRetentionPolicy(attribute) == RetentionPolicy.RUNTIME
? RuntimeVisibleAnnotations_attribute.class
: RuntimeInvisibleAnnotations_attribute.class),
1l,
String.format("Number of %s", attribute));
} else {
checkNull(attr, String.format("%s should be null", attribute));
}
return actualAnnotations;
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright (c) 2015, 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 8044411
* @summary Tests the RuntimeParameterVisibleAnnotations/RuntimeParameterInvisibleAnnotations attribute.
* Checks that the attribute is generated for bridge method.
* @library /tools/lib /tools/javac/lib ../lib
* @build WorkAnnotations TestBase TestResult InMemoryFileManager ToolBox
* @build TestCase ClassType TestAnnotationInfo
* @build RuntimeParameterAnnotationsForGenericMethodTest AnnotationsTestBase RuntimeParameterAnnotationsTestBase
* @run main RuntimeParameterAnnotationsForGenericMethodTest
*/
import java.util.ArrayList;
import java.util.List;
/**
* RuntimeParameterAnnotationsGenericMethodTest is a test which check that
* RuntimeVisibleParameterAnnotationsAttribute and
* RuntimeInvisibleParameterAnnotationsAttribute are generated for both
* generic and appropriate bridge methods.
* All possible combinations of retention policies are tested.
*
* The test generates class which looks as follows:
*
* public class Test extends java.util.ArrayList&lt;Integer&gt; {
*
* public boolean add(here some annotations java.lang.Integer) {
* return false;
* }
* }
*
* Thereafter, various of combinations of annotations are applied
* to the add, the source is compiled and the generated byte code is checked.
*
* See README.txt for more information.
*/
public class RuntimeParameterAnnotationsForGenericMethodTest extends RuntimeParameterAnnotationsTestBase {
@Override
public List<TestCase> generateTestCases() {
List<TestCase> testCases = new ArrayList<>();
for (TestAnnotationInfos annotations : getAllCombinationsOfAnnotations()) {
// generate: public class Test extends java.util.ArrayList<Integer>
TestCase testCase = new TestCase();
TestCase.TestClassInfo clazz = testCase.addClassInfo("java.util.ArrayList<Integer>", ClassType.CLASS, "Test");
TestCase.TestParameterInfo parameter = clazz.addMethodInfo("add(java.lang.Integer)", "public").addParameter("Integer", "i");
annotations.annotate(parameter);
TestCase.TestParameterInfo synParameter = clazz.addMethodInfo("add(java.lang.Object)", true, "public").addParameter("Object", "i");
annotations.annotate(synParameter);
testCases.add(testCase);
}
return testCases;
}
public static void main(String[] args) throws TestFailedException {
new RuntimeParameterAnnotationsForGenericMethodTest().test();
}
}

View File

@ -0,0 +1,107 @@
/*
* Copyright (c) 2015, 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 8044411 8079060
* @summary Tests the RuntimeParameterVisibleAnnotations/RuntimeParameterInvisibleAnnotations attribute.
* @library /tools/lib /tools/javac/lib ../lib
* @ignore 8079060 javac does not generate RuntimeParameterAnnotation attributes for lambda expressions
* @build WorkAnnotations TestBase TestResult InMemoryFileManager ToolBox
* @build TestCase ClassType TestAnnotationInfo
* @build RuntimeParameterAnnotationsForLambdaTest AnnotationsTestBase RuntimeParameterAnnotationsTestBase
* @run main RuntimeParameterAnnotationsForLambdaTest
*/
import java.util.List;
import java.util.stream.Collectors;
import com.sun.tools.classfile.ClassFile;
import com.sun.tools.classfile.Method;
/**
* RuntimeParameterAnnotationsForLambdaTest is a test which checks that RuntimeVisibleParameterAnnotationsAttribute
* and RuntimeInvisibleParameterAnnotationsAttribute are generated properly for lambda expressions.
* The test checks both single and repeatable annotations.
* All possible combinations of retention policies are tested.
*
* The test generates source code, compiles it and checks the byte code.
*
* See README.txt for more information.
*/
public class RuntimeParameterAnnotationsForLambdaTest extends RuntimeParameterAnnotationsTestBase {
private static final String CLASS_NAME = "Test";
private static final String SOURCE_TEMPLATE =
"public class " + CLASS_NAME + " {\n" +
" interface I { void method(int a, double b, String c); }\n" +
" %SOURCE%\n" +
"}";
public static void main(String[] args) throws TestFailedException {
new RuntimeParameterAnnotationsForLambdaTest().test();
}
@Override
public void test() throws TestFailedException {
try {
for (TestAnnotationInfos annotations : getAllCombinationsOfAnnotations()) {
try {
TestCase.TestMethodInfo testMethodInfo = new TestCase.TestMethodInfo(0, null, "lambda", false, false);
TestCase.TestParameterInfo p1 = testMethodInfo.addParameter("int", "a");
annotations.annotate(p1);
testMethodInfo.addParameter("double", "b");
TestCase.TestParameterInfo p3 = testMethodInfo.addParameter("String", "c");
annotations.annotate(p3);
String source = SOURCE_TEMPLATE.replace("%SOURCE%", generateLambdaSource(testMethodInfo));
echo("Testing:\n" + source);
addTestCase(source);
ClassFile classFile = readClassFile(compile(source).getClasses().get(CLASS_NAME));
boolean isFoundLambda = false;
for (Method method : classFile.methods) {
if (method.getName(classFile.constant_pool).startsWith("lambda$")) {
isFoundLambda = true;
testAttributes(testMethodInfo, classFile, method);
}
}
checkTrue(isFoundLambda, "The tested lambda method was not found.");
} catch (Exception e) {
addFailure(e);
}
}
} finally {
checkStatus();
}
}
public String generateLambdaSource(TestCase.TestMethodInfo method) {
return method.parameters.stream()
.map(TestCase.TestParameterInfo::generateSource)
.collect(Collectors.joining(", ", "I i = (", ") -> {};"));
}
@Override
public List<TestCase> generateTestCases() {
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2015, 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 8044411
* @summary Tests the RuntimeParameterVisibleAnnotations/RuntimeParameterInvisibleAnnotations attribute.
* @library /tools/lib /tools/javac/lib ../lib
* @build WorkAnnotations TestBase TestResult InMemoryFileManager ToolBox
* @build TestCase ClassType TestAnnotationInfo
* @build RuntimeParameterAnnotationsTest AnnotationsTestBase RuntimeParameterAnnotationsTestBase
* @run main RuntimeParameterAnnotationsTest
*/
import java.util.ArrayList;
import java.util.List;
/**
* RuntimeParameterAnnotationsTest is a test which checks that RuntimeVisibleParameterAnnotationsAttribute
* and RuntimeInvisibleParameterAnnotationsAttribute are generated properly for constructors,
* for static and abstract methods of class, for abstract, default and static methods of interface.
* The test checks both single and repeatable annotations.
* All possible combinations of retention policies are tested.
*
* The test generates source code, compiles it and checks the byte code.
*
* See README.txt for more information.
*/
public class RuntimeParameterAnnotationsTest extends RuntimeParameterAnnotationsTestBase {
@Override
public List<TestCase> generateTestCases() {
List<TestCase> testCases = new ArrayList<>();
for (List<TestAnnotationInfos> groupedAnnotations : groupAnnotations(getAllCombinationsOfAnnotations())) {
for (ClassType classType : new ClassType[]{ClassType.CLASS, ClassType.INTERFACE}) {
TestCase test = new TestCase();
for (int i = 0; i < groupedAnnotations.size(); i++) {
TestAnnotationInfos annotations = groupedAnnotations.get(i);
TestCase.TestClassInfo clazz = test.addClassInfo(classType, "Test" + i, "abstract");
initMethod(annotations, clazz, "<init>");
initMethod(annotations, clazz, "method1");
initMethod(annotations, clazz, "method2",
classType == ClassType.CLASS ? "abstract" : "default");
initMethod(annotations, clazz, "staticMethod", "static");
}
testCases.add(test);
}
}
return testCases;
}
/**
* Adds a method to the {@code testCase} with {@code methodName}.
*
* @param annotations a list of annotations
* @param clazz a test class
* @param methodName a method name
* @param mods an array of modifiers
*/
private void initMethod(TestAnnotationInfos annotations, TestCase.TestClassInfo clazz, String methodName, String...mods) {
String methodDescriptor = methodName + "(int, double, java.lang.String)";
TestCase.TestMethodInfo method = clazz.addMethodInfo(methodDescriptor, mods);
TestCase.TestParameterInfo p1 = method.addParameter("int", "a");
annotations.annotate(p1);
method.addParameter("double", "b");
TestCase.TestParameterInfo p3 = method.addParameter("String", "c");
annotations.annotate(p3);
}
public static void main(String[] args) throws TestFailedException {
new RuntimeParameterAnnotationsTest().test();
}
}

View File

@ -0,0 +1,142 @@
/*
* Copyright (c) 2015, 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 com.sun.tools.classfile.*;
import javax.tools.JavaFileObject;
import java.io.IOException;
import java.lang.annotation.RetentionPolicy;
import java.util.*;
public abstract class RuntimeParameterAnnotationsTestBase extends AnnotationsTestBase {
@Override
public void test(TestCase testCase, Map<String, ? extends JavaFileObject> classes)
throws IOException, ConstantPoolException, Descriptor.InvalidDescriptor {
for (Map.Entry<String, ? extends JavaFileObject> entry : classes.entrySet()) {
ClassFile classFile = readClassFile(classes.get(entry.getKey()));
Set<String> foundMethods = new HashSet<>();
String className = classFile.getName();
TestCase.TestClassInfo testClassInfo = testCase.classes.get(className);
for (Method method : classFile.methods) {
String methodName = method.getName(classFile.constant_pool) +
method.descriptor.getParameterTypes(classFile.constant_pool);
if (methodName.startsWith("<init>")) {
methodName = methodName.replace("<init>", className);
}
foundMethods.add(methodName);
echo("Testing method : " + methodName);
TestCase.TestMethodInfo testMethod = testClassInfo.getTestMethodInfo(methodName);
if (testMethod == null) {
continue;
}
testAttributes(testMethod, classFile, method);
}
checkContains(foundMethods, testClassInfo.methods.keySet(), "Methods in " + className);
}
}
protected void testAttributes(
TestCase.TestMethodInfo testMethod,
ClassFile classFile,
Method method) throws ConstantPoolException {
List<Map<String, Annotation>> actualInvisible = collectAnnotations(
classFile,
testMethod,
method,
Attribute.RuntimeInvisibleParameterAnnotations);
List<Map<String, Annotation>> actualVisible = collectAnnotations(
classFile,
testMethod,
method,
Attribute.RuntimeVisibleParameterAnnotations);
List<TestCase.TestParameterInfo> parameters = testMethod.parameters;
for (int i = 0; i < parameters.size(); ++i) {
TestCase.TestParameterInfo parameter = parameters.get(i);
checkEquals(actualInvisible.get(i).keySet(), parameter.getRuntimeInvisibleAnnotations(),
"RuntimeInvisibleParameterAnnotations");
checkEquals(actualVisible.get(i).keySet(), parameter.getRuntimeVisibleAnnotations(),
"RuntimeVisibleParameterAnnotations");
}
for (int i = 0; i < parameters.size(); ++i) {
TestCase.TestParameterInfo parameter = parameters.get(i);
for (TestAnnotationInfo expectedAnnotation : parameter.annotations.values()) {
RetentionPolicy policy = getRetentionPolicy(expectedAnnotation.annotationName);
if (policy == RetentionPolicy.SOURCE) {
continue;
}
printf("Testing: isVisible: %s %s%n", policy.toString(), expectedAnnotation.annotationName);
Annotation actualAnnotation =
(policy == RetentionPolicy.RUNTIME
? actualVisible
: actualInvisible)
.get(i).get(expectedAnnotation.annotationName);
if (checkNotNull(actualAnnotation, "Annotation is found : "
+ expectedAnnotation.annotationName)) {
expectedAnnotation.testAnnotation(this, classFile,
actualAnnotation);
}
}
}
}
private List<Map<String, Annotation>> collectAnnotations(
ClassFile classFile,
TestCase.TestMethodInfo testMethod,
Method method,
String attribute) throws ConstantPoolException {
Attributes attributes = method.attributes;
RuntimeParameterAnnotations_attribute attr = (RuntimeParameterAnnotations_attribute) attributes.get(attribute);
List<Map<String, Annotation>> actualAnnotations = new ArrayList<>();
RetentionPolicy policy = getRetentionPolicy(attribute);
if (testMethod.isParameterAnnotated(policy)) {
if (!checkNotNull(attr, "Attribute " + attribute + " must not be null")) {
testMethod.parameters.forEach($ -> actualAnnotations.add(new HashMap<>()));
return actualAnnotations;
}
for (Annotation[] anns : attr.parameter_annotations) {
Map<String, Annotation> annotations = new HashMap<>();
for (Annotation ann : anns) {
String name = classFile.constant_pool.getUTF8Value(ann.type_index);
annotations.put(name.substring(1, name.length() - 1), ann);
}
actualAnnotations.add(annotations);
}
checkEquals(countNumberOfAttributes(attributes.attrs,
getRetentionPolicy(attribute) == RetentionPolicy.RUNTIME
? RuntimeVisibleParameterAnnotations_attribute.class
: RuntimeInvisibleParameterAnnotations_attribute.class),
1l,
String.format("Number of %s", attribute));
} else {
checkNull(attr, String.format("%s should be null", attribute));
testMethod.parameters.forEach($ -> actualAnnotations.add(new HashMap<>()));
}
return actualAnnotations;
}
}

View File

@ -0,0 +1,441 @@
/*
* Copyright (c) 2015, 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 com.sun.tools.classfile.Annotation;
import com.sun.tools.classfile.ClassFile;
import com.sun.tools.classfile.ConstantPool;
import com.sun.tools.classfile.ConstantPoolException;
import java.lang.annotation.RetentionPolicy;
import java.util.*;
import java.util.stream.Collectors;
public class TestAnnotationInfo {
public final String annotationName;
public final RetentionPolicy policy;
public final boolean isContainer;
public final List<Pair> elementValues;
public TestAnnotationInfo(String typeIndexName, RetentionPolicy policy, Pair... values) {
this(typeIndexName, policy, false, values);
}
public TestAnnotationInfo(String typeIndexName, RetentionPolicy policy, boolean isRepeatable, Pair... values) {
this.annotationName = typeIndexName;
this.policy = policy;
this.isContainer = isRepeatable;
elementValues = Arrays.asList(values);
}
public void testAnnotation(TestResult testResult, ClassFile classFile, Annotation annotation)
throws ConstantPoolException {
testResult.checkEquals(classFile.constant_pool.getUTF8Value(annotation.type_index),
String.format("L%s;", annotationName), "Testing annotation name : " + annotationName);
testResult.checkEquals(annotation.num_element_value_pairs,
elementValues.size(), "Number of element values");
if (!testResult.checkEquals(annotation.num_element_value_pairs, elementValues.size(),
"Number of element value pairs")) {
return;
}
for (int i = 0; i < annotation.num_element_value_pairs; ++i) {
Annotation.element_value_pair pair = annotation.element_value_pairs[i];
testResult.checkEquals(classFile.constant_pool.getUTF8Value(pair.element_name_index),
elementValues.get(i).elementName, "element_name_index : " + elementValues.get(i).elementName);
elementValues.get(i).elementValue.testElementValue(testResult, classFile, pair.value);
}
}
@Override
public String toString() {
return String.format("@%s(%s)", annotationName,
elementValues.stream()
.map(Pair::toString)
.filter(s -> !s.isEmpty())
.collect(Collectors.joining(", ")));
}
public static class Pair {
public final String elementName;
public final TestElementValue elementValue;
public Pair(String elementName, TestElementValue elementValue) {
this.elementName = elementName;
this.elementValue = elementValue;
}
@Override
public String toString() {
return elementName + "=" + elementValue;
}
}
public static abstract class TestElementValue {
private final int tag;
public TestElementValue(int tag) {
this.tag = tag;
}
public void testTag(TestResult testCase, int actualTag) {
testCase.checkEquals(actualTag, tag, "tag " + (char) tag);
}
public abstract void testElementValue(TestResult testResult,
ClassFile classFile,
Annotation.element_value element_value)
throws ConstantPoolException;
}
public static class TestIntegerElementValue extends TestElementValue {
private final int value;
public TestIntegerElementValue(int tag, int value) {
super(tag);
this.value = value;
}
@Override
public void testElementValue(TestResult testResult,
ClassFile classFile,
Annotation.element_value element_value)
throws ConstantPoolException {
testTag(testResult, element_value.tag);
Annotation.Primitive_element_value ev =
(Annotation.Primitive_element_value) element_value;
ConstantPool.CONSTANT_Integer_info info =
(ConstantPool.CONSTANT_Integer_info) classFile.constant_pool.get(ev.const_value_index);
testResult.checkEquals(info.value, value, "const_value_index : " + value);
}
@Override
public String toString() {
return String.valueOf(value);
}
}
public static class TestBooleanElementValue extends TestElementValue {
private final boolean value;
public TestBooleanElementValue(boolean value) {
super('Z');
this.value = value;
}
@Override
public void testElementValue(TestResult testResult,
ClassFile classFile,
Annotation.element_value element_value)
throws ConstantPoolException {
testTag(testResult, element_value.tag);
Annotation.Primitive_element_value ev =
(Annotation.Primitive_element_value) element_value;
ConstantPool.CONSTANT_Integer_info info =
(ConstantPool.CONSTANT_Integer_info) classFile.constant_pool.get(ev.const_value_index);
testResult.checkEquals(info.value, value ? 1 : 0, "const_value_index : " + value);
}
@Override
public String toString() {
return String.valueOf(value);
}
}
public static class TestCharElementValue extends TestElementValue {
private final char value;
public TestCharElementValue(char value) {
super('C');
this.value = value;
}
@Override
public void testElementValue(TestResult testResult,
ClassFile classFile,
Annotation.element_value element_value)
throws ConstantPoolException {
testTag(testResult, element_value.tag);
Annotation.Primitive_element_value ev =
(Annotation.Primitive_element_value) element_value;
ConstantPool.CONSTANT_Integer_info info =
(ConstantPool.CONSTANT_Integer_info)
classFile.constant_pool.get(ev.const_value_index);
testResult.checkEquals(info.value, (int) value, "const_value_index : " + value);
}
@Override
public String toString() {
return String.format("\'%c\'", value);
}
}
public static class TestLongElementValue extends TestElementValue {
private final long value;
public TestLongElementValue(long value) {
super('J');
this.value = value;
}
@Override
public void testElementValue(TestResult testResult,
ClassFile classFile,
Annotation.element_value element_value)
throws ConstantPool.InvalidIndex {
testTag(testResult, element_value.tag);
Annotation.Primitive_element_value ev =
(Annotation.Primitive_element_value) element_value;
ConstantPool.CONSTANT_Long_info info =
(ConstantPool.CONSTANT_Long_info) classFile.constant_pool.get(ev.const_value_index);
testResult.checkEquals(info.value, value, "const_value_index");
}
@Override
public String toString() {
return String.valueOf(value);
}
}
public static class TestFloatElementValue extends TestElementValue {
private final float value;
public TestFloatElementValue(float value) {
super('F');
this.value = value;
}
@Override
public void testElementValue(TestResult testResult,
ClassFile classFile,
Annotation.element_value element_value)
throws ConstantPool.InvalidIndex {
testTag(testResult, element_value.tag);
Annotation.Primitive_element_value ev =
(Annotation.Primitive_element_value) element_value;
ConstantPool.CONSTANT_Float_info info =
(ConstantPool.CONSTANT_Float_info) classFile.constant_pool.get(ev.const_value_index);
testResult.checkEquals(info.value, value, "const_value_index");
}
@Override
public String toString() {
return String.valueOf(value) + "f";
}
}
public static class TestDoubleElementValue extends TestElementValue {
private final double value;
public TestDoubleElementValue(double value) {
super('D');
this.value = value;
}
@Override
public void testElementValue(TestResult testResult,
ClassFile classFile,
Annotation.element_value element_value)
throws ConstantPoolException {
testTag(testResult, element_value.tag);
Annotation.Primitive_element_value ev =
(Annotation.Primitive_element_value) element_value;
ConstantPool.CONSTANT_Double_info info = (ConstantPool.CONSTANT_Double_info)
classFile.constant_pool.get(ev.const_value_index);
testResult.checkEquals(info.value, value, "const_value_index");
}
@Override
public String toString() {
return String.valueOf(value);
}
}
public static class TestStringElementValue extends TestElementValue {
private final String value;
public TestStringElementValue(String value) {
super('s');
this.value = value;
}
@Override
public void testElementValue(TestResult testResult,
ClassFile classFile,
Annotation.element_value element_value)
throws ConstantPoolException {
testTag(testResult, element_value.tag);
Annotation.Primitive_element_value ev =
(Annotation.Primitive_element_value) element_value;
ConstantPool.CONSTANT_Utf8_info info =
(ConstantPool.CONSTANT_Utf8_info) classFile.constant_pool.get(ev.const_value_index);
testResult.checkEquals(info.value, value, "const_value_index");
}
@Override
public String toString() {
return String.format("\"%s\"", value);
}
}
public static class TestEnumElementValue extends TestElementValue {
private final String typeName;
private final String constName;
public TestEnumElementValue(String typeName, String constName) {
super('e');
this.typeName = typeName;
this.constName = constName;
}
@Override
public void testElementValue(
TestResult testResult,
ClassFile classFile,
Annotation.element_value element_value)
throws ConstantPoolException {
testTag(testResult, element_value.tag);
Annotation.Enum_element_value ev = (Annotation.Enum_element_value) element_value;
testResult.checkEquals(classFile.constant_pool.getUTF8Info(ev.type_name_index).value,
String.format("L%s;", typeName), "type_name_index");
testResult.checkEquals(classFile.constant_pool.getUTF8Info(ev.const_name_index).value,
constName, "const_name_index");
}
@Override
public String toString() {
return typeName + "." + constName;
}
}
public static class TestClassElementValue extends TestElementValue {
private final String className;
private final static Map<String, String> mappedClassName;
static {
mappedClassName = new HashMap<>();
mappedClassName.put("void", "V");
mappedClassName.put("char", "C");
mappedClassName.put("byte", "B");
mappedClassName.put("short", "S");
mappedClassName.put("int", "I");
mappedClassName.put("long", "J");
mappedClassName.put("float", "F");
mappedClassName.put("double", "D");
}
public TestClassElementValue(String className) {
super('c');
this.className = className;
}
@Override
public void testElementValue(
TestResult testResult,
ClassFile classFile,
Annotation.element_value element_value)
throws ConstantPoolException {
testTag(testResult, element_value.tag);
Annotation.Class_element_value ev = (Annotation.Class_element_value) element_value;
String expectedClassName = className.replace(".class", "");
expectedClassName = mappedClassName.getOrDefault(expectedClassName,
String.format("Ljava/lang/%s;", expectedClassName));
testResult.checkEquals(
classFile.constant_pool.getUTF8Info(ev.class_info_index).value,
expectedClassName, "class_info_index : " + expectedClassName);
}
@Override
public String toString() {
return className;
}
}
public static class TestArrayElementValue extends TestElementValue {
public final List<TestElementValue> values;
public TestArrayElementValue(TestElementValue...values) {
super('[');
this.values = new ArrayList<>(Arrays.asList(values));
}
@Override
public void testElementValue(
TestResult testResult,
ClassFile classFile,
Annotation.element_value element_value)
throws ConstantPoolException {
testTag(testResult, element_value.tag);
Annotation.Array_element_value ev = (Annotation.Array_element_value) element_value;
for (int i = 0; i < values.size(); ++i) {
values.get(i).testElementValue(testResult, classFile, ev.values[i]);
}
}
@Override
public String toString() {
return values.stream()
.map(TestElementValue::toString)
.collect(Collectors.joining(", ", "{", "}"));
}
}
public static class TestAnnotationElementValue extends TestElementValue {
private final String annotationName;
private final TestAnnotationInfo annotation;
public TestAnnotationElementValue(String className, TestAnnotationInfo annotation) {
super('@');
this.annotationName = className;
this.annotation = annotation;
}
@Override
public void testElementValue(
TestResult testResult,
ClassFile classFile,
Annotation.element_value element_value)
throws ConstantPoolException {
testTag(testResult, element_value.tag);
Annotation ev = ((Annotation.Annotation_element_value) element_value).annotation_value;
testResult.checkEquals(
classFile.constant_pool.getUTF8Info(ev.type_index).value,
String.format("L%s;", annotationName),
"type_index");
for (int i = 0; i < ev.num_element_value_pairs; ++i) {
Annotation.element_value_pair pair = ev.element_value_pairs[i];
Pair expectedPair = annotation.elementValues.get(i);
expectedPair.elementValue.testElementValue(testResult, classFile, pair.value);
testResult.checkEquals(
classFile.constant_pool.getUTF8Info(pair.element_name_index).value,
expectedPair.elementName,
"element_name_index");
}
}
@Override
public String toString() {
return annotation.toString();
}
}
}

View File

@ -0,0 +1,459 @@
/*
* Copyright (c) 2015, 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 java.lang.annotation.RetentionPolicy;
import java.util.*;
import java.util.stream.Collectors;
public class TestCase {
/**
* The top-level classes of the test case.
*/
public final Map<String, TestClassInfo> classes = new LinkedHashMap<>();
/**
* Constructs a test class info with {@code classType} as top-level class,
* with {@code outerClassName} as name and {@code mods} as modifiers.
*
* @param classType a class type
* @param outerClassName a name
* @param mods an array of modifiers
*/
public TestClassInfo addClassInfo(ClassType classType, String outerClassName, String...mods) {
return addClassInfo(null, classType, outerClassName, mods);
}
/**
* Constructs a test class info with {@code classType} as top-level class,
* with {@code outerClassName} as name, {@code parent} class name
* as parent class and {@code mods} as modifiers.
*
* @param classType a class type
* @param outerClassName a name
* @param mods an array of modifiers
*/
public TestClassInfo addClassInfo(String parent, ClassType classType, String outerClassName, String...mods) {
TestClassInfo clazz = new TestClassInfo(classType, outerClassName, parent, mods);
if (classes.put(outerClassName, clazz) != null) {
throw new IllegalArgumentException("Duplicate class name: " + outerClassName);
}
return clazz;
}
public String generateSource() {
return classes.values().stream()
.map(TestMemberInfo::generateSource)
.collect(Collectors.joining("\n"));
}
/**
* Returns {@code TestClassInfo} by class signature.
* Example, {@code getTestClassInfo(&quot;Test$1Local&quot;)}
* returns local inner class of class {@code Test}.
*
* @param classSignature a class signature
* @return {@code TestClassInfo} by class signature
*/
public TestClassInfo getTestClassInfo(String classSignature) {
String[] cs = classSignature.split("\\$");
if (cs.length > 0 && classes.containsKey(cs[0])) {
// check signature corresponds to top level class
if (cs.length == 1) {
return classes.get(cs[0]);
}
} else {
throw new IllegalArgumentException("Cannot find class : " + classSignature);
}
TestClassInfo current = classes.get(cs[0]);
// find class info in the inner classes
for (int i = 1; i < cs.length; ++i) {
Map<String, TestClassInfo> innerClasses = current.innerClasses;
Map<String, TestMethodInfo> methods = current.methods;
current = innerClasses.get(cs[i]);
// if current is null then class info does not exist or the class is local
if (current == null) {
if (!cs[i].isEmpty()) {
// the class is local, remove leading digit
String className = cs[i].substring(1);
Optional<TestClassInfo> opt = methods.values().stream()
.flatMap(c -> c.localClasses.values().stream())
.filter(c -> c.name.equals(className)).findAny();
if (opt.isPresent()) {
current = opt.get();
// continue analysis of local class
continue;
}
}
throw new IllegalArgumentException("Cannot find class : " + classSignature);
}
}
return current;
}
/**
* Class represents a program member.
*/
public static abstract class TestMemberInfo {
// next two fields are used for formatting
protected final int indention;
protected final ClassType containerType;
public final List<String> mods;
public final String name;
public final Map<String, TestAnnotationInfo> annotations;
TestMemberInfo(int indention, ClassType containerType, String name, String... mods) {
this.indention = indention;
this.containerType = containerType;
this.mods = Arrays.asList(mods);
this.name = name;
this.annotations = new HashMap<>();
}
public abstract String generateSource();
public boolean isAnnotated(RetentionPolicy policy) {
return annotations.values().stream()
.filter(a -> a.policy == policy)
.findAny().isPresent();
}
public Set<String> getRuntimeVisibleAnnotations() {
return getRuntimeAnnotations(RetentionPolicy.RUNTIME);
}
public Set<String> getRuntimeInvisibleAnnotations() {
return getRuntimeAnnotations(RetentionPolicy.CLASS);
}
private Set<String> getRuntimeAnnotations(RetentionPolicy policy) {
return annotations.values().stream()
.filter(e -> e.policy == policy)
.map(a -> a.annotationName)
.distinct()
.collect(Collectors.toSet());
}
/**
* Generates source for annotations.
*
* @param prefix a leading text
* @param suffix a trailing text
* @param joining a text between annotations
* @return source for annotations
*/
protected String generateSourceForAnnotations(String prefix, String suffix, String joining) {
StringBuilder sb = new StringBuilder();
for (TestAnnotationInfo annotation : annotations.values()) {
sb.append(prefix);
if (annotation.isContainer) {
// the annotation is repeatable
// container consists of an array of annotations
TestAnnotationInfo.TestArrayElementValue containerElementValue =
(TestAnnotationInfo.TestArrayElementValue) annotation.elementValues.get(0).elementValue;
// concatenate sources of repeatable annotations
sb.append(containerElementValue.values.stream()
.map(TestAnnotationInfo.TestElementValue::toString)
.collect(Collectors.joining(joining)));
} else {
sb.append(annotation);
}
sb.append(suffix);
}
String src = sb.toString();
return src.trim().isEmpty() ? "" : src;
}
/**
* Generates source for annotations.
*
* @return source for annotations
*/
public String generateSourceForAnnotations() {
return generateSourceForAnnotations(indention(), "\n", "\n" + indention());
}
/**
* Adds annotation info to the member.
*
* @param anno an annotation info
*/
public void addAnnotation(TestAnnotationInfo anno) {
String containerName = anno.annotationName + "Container";
TestAnnotationInfo annotation = annotations.get(anno.annotationName);
TestAnnotationInfo containerAnnotation = annotations.get(containerName);
if (annotation == null) {
// if annotation is null then either it is first adding of the annotation to the member
// or there is the container of the annotation.
if (containerAnnotation == null) {
// first adding to the member
annotations.put(anno.annotationName, anno);
} else {
// add annotation to container
TestAnnotationInfo.TestArrayElementValue containerElementValue =
((TestAnnotationInfo.TestArrayElementValue) containerAnnotation.elementValues.get(0).elementValue);
containerElementValue.values.add(new TestAnnotationInfo.TestAnnotationElementValue(anno.annotationName, anno));
}
} else {
// remove previously added annotation and add new container of repeatable annotation
// which contains previously added and new annotation
annotations.remove(anno.annotationName);
containerAnnotation = new TestAnnotationInfo(
containerName,
anno.policy,
true,
new TestAnnotationInfo.Pair("value",
new TestAnnotationInfo.TestArrayElementValue(
new TestAnnotationInfo.TestAnnotationElementValue(anno.annotationName, annotation),
new TestAnnotationInfo.TestAnnotationElementValue(anno.annotationName, anno))));
annotations.put(containerName, containerAnnotation);
}
}
public String indention() {
char[] a = new char[4 * indention];
Arrays.fill(a, ' ');
return new String(a);
}
public String getName() {
return name;
}
}
/**
* The class represents a class.
*/
public static class TestClassInfo extends TestMemberInfo {
public final ClassType classType;
public final String parent;
public final Map<String, TestClassInfo> innerClasses;
public final Map<String, TestMethodInfo> methods;
public final Map<String, TestFieldInfo> fields;
TestClassInfo(int indention, ClassType classType, String className, String... mods) {
this(indention, classType, className, null, mods);
}
TestClassInfo(ClassType classType, String className, String parent, String... mods) {
this(0, classType, className, parent, mods);
}
TestClassInfo(int indention, ClassType classType, String className, String parent, String... mods) {
super(indention, null, className, mods);
this.classType = classType;
this.parent = parent;
innerClasses = new LinkedHashMap<>();
methods = new LinkedHashMap<>();
fields = new LinkedHashMap<>();
}
/**
* Generates source which represents the class.
*
* @return source which represents the class
*/
@Override
public String generateSource() {
String sourceForAnnotations = generateSourceForAnnotations();
String classModifiers = mods.stream().collect(Collectors.joining(" "));
return sourceForAnnotations
+ String.format("%s%s %s %s %s {%n",
indention(),
classModifiers,
classType.getDescription(),
name,
parent == null ? "" : "extends " + parent)
+ classType.collectFields(fields.values())
+ classType.collectMethods(methods.values())
+ classType.collectInnerClasses(innerClasses.values())
+ indention() + "}";
}
/**
* Adds a new inner class to the class.
*
* @param classType a class type
* @param className a class name
* @param mods modifiers
* @return a new added inner class to the class
*/
public TestClassInfo addInnerClassInfo(ClassType classType, String className, String... mods) {
TestClassInfo testClass = new TestClassInfo(indention + 1, classType, className, mods);
if (innerClasses.put(className, testClass) != null) {
throw new IllegalArgumentException("Duplicated class : " + className);
}
return testClass;
}
/**
* Adds a new method to the class.
*
* @param methodName a method name
* @param mods modifiers
* @return a new inner class to the class
*/
public TestMethodInfo addMethodInfo(String methodName, String... mods) {
return addMethodInfo(methodName, false, mods);
}
/**
* Adds a new method to the class.
*
* @param methodName a method name
* @param isSynthetic if {@code true} the method is synthetic
* @param mods modifiers
* @return a new method added to the class
*/
public TestMethodInfo addMethodInfo(String methodName, boolean isSynthetic, String... mods) {
boolean isConstructor = methodName.contains("<init>");
if (isConstructor) {
methodName = methodName.replace("<init>", name);
}
TestMethodInfo testMethod = new TestMethodInfo(indention + 1, classType, methodName, isConstructor, isSynthetic, mods);
if (methods.put(methodName, testMethod) != null) {
throw new IllegalArgumentException("Duplicated method : " + methodName);
}
return testMethod;
}
/**
* Adds a new field to the class.
*
* @param fieldName a method name
* @param mods modifiers
* @return a new field added to the class
*/
public TestFieldInfo addFieldInfo(String fieldName, String... mods) {
TestFieldInfo field = new TestFieldInfo(indention + 1, classType, fieldName, mods);
if (fields.put(fieldName, field) != null) {
throw new IllegalArgumentException("Duplicated field : " + fieldName);
}
return field;
}
public TestMethodInfo getTestMethodInfo(String methodName) {
return methods.get(methodName);
}
public TestFieldInfo getTestFieldInfo(String fieldName) {
return fields.get(fieldName);
}
}
public static class TestMethodInfo extends TestMemberInfo {
public final boolean isConstructor;
public final boolean isSynthetic;
public final Map<String, TestClassInfo> localClasses;
public final List<TestParameterInfo> parameters;
TestMethodInfo(int indention, ClassType containerType, String methodName,
boolean isConstructor, boolean isSynthetic, String... mods) {
super(indention, containerType, methodName, mods);
this.isSynthetic = isSynthetic;
this.localClasses = new LinkedHashMap<>();
this.parameters = new ArrayList<>();
this.isConstructor = isConstructor;
}
public boolean isParameterAnnotated(RetentionPolicy policy) {
return parameters.stream()
.filter(p -> p.isAnnotated(policy))
.findFirst().isPresent();
}
public TestParameterInfo addParameter(String type, String name) {
TestParameterInfo testParameter = new TestParameterInfo(type, name);
parameters.add(testParameter);
return testParameter;
}
/**
* Adds a local class to the method.
*
* @param className a class name
* @param mods modifiers
* @return a local class added to the method
*/
public TestClassInfo addLocalClassInfo(String className, String... mods) {
TestClassInfo testClass = new TestClassInfo(indention + 1, ClassType.CLASS, className, mods);
if (localClasses.put(className, testClass) != null) {
throw new IllegalArgumentException("Duplicated class : " + className);
}
return testClass;
}
@Override
public String generateSource() {
if (isSynthetic) {
return "";
}
return generateSourceForAnnotations() +
containerType.methodToString(this);
}
@Override
public String getName() {
return name.replaceAll("\\(.*\\)", "");
}
}
/**
* The class represents a method parameter.
*/
public static class TestParameterInfo extends TestMemberInfo {
public final String type;
TestParameterInfo(String type, String name) {
super(0, null, name);
this.type = type;
}
@Override
public String generateSource() {
return generateSourceForAnnotations() + type + " " + name;
}
public String generateSourceForAnnotations() {
return generateSourceForAnnotations("", " ", " ");
}
}
/**
* The class represents a field.
*/
public static class TestFieldInfo extends TestMemberInfo {
TestFieldInfo(int indention, ClassType containerType, String fieldName, String... mods) {
super(indention, containerType, fieldName, mods);
}
@Override
public String generateSource() {
return generateSourceForAnnotations() +
containerType.fieldToString(this);
}
}
}

View File

@ -0,0 +1,135 @@
/*
* Copyright (c) 2015, 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 java.lang.annotation.*;
@Retention(RetentionPolicy.CLASS)
@Repeatable(RuntimeInvisibleRepeatableContainer.class)
@interface RuntimeInvisibleRepeatable {
boolean booleanValue() default false;
byte byteValue() default 0;
char charValue() default 0;
short shortValue() default 0;
int intValue() default 0;
long longValue() default 0;
float floatValue() default 0;
double doubleValue() default 0;
String stringValue() default "";
int[] arrayValue1() default {};
String[] arrayValue2() default {};
Class<?> classValue1() default void.class;
Class<?> classValue2() default void.class;
EnumValue enumValue() default EnumValue.VALUE1;
AnnotationValue annoValue() default @AnnotationValue(stringValue = "StringValue");
AnnotationValue[] annoArrayValue() default
{@AnnotationValue(stringValue = "StringValue1"),
@AnnotationValue(stringValue = "StringValue2"),
@AnnotationValue(stringValue = "StringValue3")};
}
@Retention(RetentionPolicy.CLASS)
@interface RuntimeInvisibleRepeatableContainer {
RuntimeInvisibleRepeatable[] value();
}
@interface RuntimeInvisibleNotRepeatable {
boolean booleanValue() default false;
byte byteValue() default 0;
char charValue() default 0;
short shortValue() default 0;
int intValue() default 0;
long longValue() default 0;
float floatValue() default 0;
double doubleValue() default 0;
String stringValue() default "";
int[] arrayValue1() default {};
String[] arrayValue2() default {};
Class<?> classValue1() default void.class;
Class<?> classValue2() default void.class;
EnumValue enumValue() default EnumValue.VALUE1;
AnnotationValue annoValue() default @AnnotationValue(stringValue = "StringValue");
AnnotationValue[] annoArrayValue() default
{@AnnotationValue(stringValue = "StringValue1"),
@AnnotationValue(stringValue = "StringValue2"),
@AnnotationValue(stringValue = "StringValue3")};
}
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(RuntimeVisibleRepeatableContainer.class)
@interface RuntimeVisibleRepeatable {
boolean booleanValue() default false;
byte byteValue() default 0;
char charValue() default 0;
short shortValue() default 0;
int intValue() default 0;
long longValue() default 0;
float floatValue() default 0;
double doubleValue() default 0;
String stringValue() default "";
int[] arrayValue1() default {};
String[] arrayValue2() default {};
Class<?> classValue1() default void.class;
Class<?> classValue2() default void.class;
EnumValue enumValue() default EnumValue.VALUE1;
AnnotationValue annoValue() default @AnnotationValue(stringValue = "StringValue");
AnnotationValue[] annoArrayValue() default
{@AnnotationValue(stringValue = "StringValue1"),
@AnnotationValue(stringValue = "StringValue2"),
@AnnotationValue(stringValue = "StringValue3")};
}
@Retention(RetentionPolicy.RUNTIME)
@interface RuntimeVisibleRepeatableContainer {
RuntimeVisibleRepeatable[] value();
}
@Retention(RetentionPolicy.RUNTIME)
@interface RuntimeVisibleNotRepeatable {
boolean booleanValue() default false;
byte byteValue() default 0;
char charValue() default 0;
short shortValue() default 0;
int intValue() default 0;
long longValue() default 0;
float floatValue() default 0;
double doubleValue() default 0;
String stringValue() default "";
int[] arrayValue1() default {};
String[] arrayValue2() default {};
Class<?> classValue1() default void.class;
Class<?> classValue2() default void.class;
EnumValue enumValue() default EnumValue.VALUE1;
AnnotationValue annoValue() default @AnnotationValue(stringValue = "StringValue");
AnnotationValue[] annoArrayValue() default
{@AnnotationValue(stringValue = "StringValue1"),
@AnnotationValue(stringValue = "StringValue2"),
@AnnotationValue(stringValue = "StringValue3")};
}
enum EnumValue {
VALUE1, VALUE2, VALUE3
}
@interface AnnotationValue {
String stringValue() default "";
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2015, 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
@ -21,10 +21,9 @@
* questions.
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -210,6 +209,12 @@ public class TestBase {
assertTrue(found.containsAll(expected), message + " : " + copy);
}
public void writeToFile(Path path, String source) throws IOException {
try (BufferedWriter writer = Files.newBufferedWriter(path)) {
writer.write(source);
}
}
public File getSourceDir() {
return new File(System.getProperty("test.src", "."));
}

View File

@ -24,18 +24,16 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.*;
import java.util.stream.Collectors;
/**
* This class accumulates test results. Test results can be checked with method @{code checkStatus}.
*/
public class TestResult extends TestBase {
private final List<Info> testCases;
private final List<Info> testCasesInfo;
public TestResult() {
testCases = new ArrayList<>();
testCases.add(new Info("Global test info"));
testCasesInfo = new ArrayList<>();
}
/**
@ -44,21 +42,16 @@ public class TestResult extends TestBase {
* @param info the information about test case
*/
public void addTestCase(String info) {
testCases.add(new Info(info));
}
private String errorMessage() {
return testCases.stream().filter(Info::isFailed)
.map(tc -> String.format("Failure in test case:\n%s\n%s", tc.info(), tc.getMessage()))
.collect(Collectors.joining("\n"));
System.err.println("Test case: " + info);
testCasesInfo.add(new Info(info));
}
public boolean checkEquals(Object actual, Object expected, String message) {
echo("Testing : " + message);
if (!Objects.equals(actual, expected)) {
getLastTestCase().addAssert(String.format("%s\n" +
"Expected: %s,\n" +
" Got: %s", message, expected, actual));
"Expected: %s,\n" +
" Got: %s", message, expected, actual));
return false;
}
return true;
@ -96,14 +89,17 @@ public class TestResult extends TestBase {
}
public void addFailure(Throwable th) {
testCases.get(testCases.size() - 1).addFailure(th);
if (testCasesInfo.isEmpty()) {
testCasesInfo.add(new Info("Dummy info"));
}
getLastTestCase().addFailure(th);
}
private Info getLastTestCase() {
if (testCases.size() == 1) {
if (testCasesInfo.isEmpty()) {
throw new IllegalStateException("Test case should be created");
}
return testCases.get(testCases.size() - 1);
return testCasesInfo.get(testCasesInfo.size() - 1);
}
/**
@ -114,22 +110,41 @@ public class TestResult extends TestBase {
* or an exception occurs
*/
public void checkStatus() throws TestFailedException {
if (testCases.stream().anyMatch(Info::isFailed)) {
echo(errorMessage());
int passed = 0;
int failed = 0;
for (Info testCaseInfo : testCasesInfo) {
if (testCaseInfo.isFailed()) {
String info = testCaseInfo.info().replace("\n", LINE_SEPARATOR);
String errorMessage = testCaseInfo.getMessage().replace("\n", LINE_SEPARATOR);
System.err.printf("Failure in test case:%n%s%n%s%n", info, errorMessage);
++failed;
} else {
++passed;
}
}
System.err.printf("Test cases: passed: %d, failed: %d, total: %d.%n", passed, failed, passed + failed);
if (failed > 0) {
throw new TestFailedException("Test failed");
}
if (passed + failed == 0) {
throw new TestFailedException("Test cases were not found");
}
}
private class Info {
@Override
public void printf(String template, Object... args) {
getLastTestCase().printf(template, args);
}
private static class Info {
private final String info;
private final List<String> asserts;
private final List<Throwable> errors;
private final StringWriter writer;
private boolean isFailed;
private Info(String info) {
this.info = info;
asserts = new ArrayList<>();
errors = new ArrayList<>();
writer = new StringWriter();
}
public String info() {
@ -137,34 +152,25 @@ public class TestResult extends TestBase {
}
public boolean isFailed() {
return !asserts.isEmpty() || !errors.isEmpty();
return isFailed;
}
public void printf(String template, Object... args) {
writer.write(String.format(template, args));
}
public void addFailure(Throwable th) {
errors.add(th);
isFailed = true;
printf("[ERROR] : %s\n", getStackTrace(th));
}
public void addAssert(String e) {
asserts.add(e);
isFailed = true;
printf("[ASSERT] : %s\n", e);
}
public String getMessage() {
return (asserts.size() > 0 ? getAssertMessages(asserts) + "\n" : "")
+ getErrorMessages(errors);
}
public String getAssertMessages(List<String> list) {
return list.stream()
.map(message -> String.format("[ASSERT] : %s", message))
.collect(Collectors.joining("\n"));
}
public String getErrorMessages(List<? extends Throwable> list) {
return list.stream()
.map(throwable -> String.format("[ERROR] : %s", getStackTrace(throwable)))
.collect(Collectors.joining("\n"));
return writer.toString();
}
public String getStackTrace(Throwable throwable) {