1/* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24import java.io.File; 25import java.io.IOException; 26import java.nio.file.Files; 27import java.nio.file.Path; 28import java.util.*; 29import java.util.function.Function; 30import java.util.function.Supplier; 31import java.util.regex.*; 32import java.util.stream.Collectors; 33import java.util.stream.Stream; 34 35import com.sun.tools.classfile.*; 36 37/** 38 * The tests work as follows. Firstly, it looks through the test cases 39 * and extracts the appropriate compiled classes. Each test case contains 40 * a set of expected classes, methods and fields. Those class members must not have 41 * the Synthetic attribute, while other found classes, methods and fields must have 42 * the Synthetic attribute if they are not in the set of expected class members. 43 * 44 * Each test executes SyntheticTestDriver specifying the name of test cases and 45 * the number of expected synthetic classes. Each test class is annotated by 46 * annotations which contains non-synthetic class members. 47 * 48 * See the appropriate class for more information about a test case. 49 */ 50public class SyntheticTestDriver extends TestResult { 51 52 private static final String ACC_SYNTHETIC = "ACC_SYNTHETIC"; 53 54 private final String testCaseName; 55 private final Map<String, ClassFile> classes; 56 private final Map<String, ExpectedClass> expectedClasses; 57 58 public static void main(String[] args) 59 throws TestFailedException, ConstantPoolException, IOException, ClassNotFoundException { 60 if (args.length != 1 && args.length != 2) { 61 throw new IllegalArgumentException("Usage: SyntheticTestDriver <class-name> [<number-of-synthetic-classes>]"); 62 } 63 int numberOfSyntheticClasses = args.length == 1 ? 0 : Integer.parseInt(args[1]); 64 new SyntheticTestDriver(args[0]).test(numberOfSyntheticClasses); 65 } 66 67 public SyntheticTestDriver(String testCaseName) throws IOException, ConstantPoolException, ClassNotFoundException { 68 Class<?> clazz = Class.forName(testCaseName); 69 this.testCaseName = testCaseName; 70 this.expectedClasses = Stream.of(clazz.getAnnotationsByType(ExpectedClass.class)) 71 .collect(Collectors.toMap(ExpectedClass::className, Function.identity())); 72 this.classes = new HashMap<>(); 73 Path classDir = getClassDir().toPath(); 74 Pattern filePattern = Pattern.compile(Pattern.quote(testCaseName.replace('.', File.separatorChar)) + ".*\\.class"); 75 List<Path> paths = Files.walk(classDir) 76 .map(p -> classDir.relativize(p.toAbsolutePath())) 77 .filter(p -> filePattern.matcher(p.toString()).matches()) 78 .collect(Collectors.toList()); 79 for (Path path : paths) { 80 String className = path.toString().replace(".class", "").replace(File.separatorChar, '.'); 81 classes.put(className, readClassFile(classDir.resolve(path).toFile())); 82 } 83 if (classes.isEmpty()) { 84 throw new RuntimeException("Classes have not been found."); 85 } 86 boolean success = classes.entrySet().stream() 87 .allMatch(e -> e.getKey().startsWith(testCaseName)); 88 if (!success) { 89 classes.forEach((className, $) -> printf("Found class: %s\n", className)); 90 throw new RuntimeException("Found classes are not from the test case : " + testCaseName); 91 } 92 } 93 94 private String getMethodName(ClassFile classFile, Method method) 95 throws ConstantPoolException, Descriptor.InvalidDescriptor { 96 String methodName = method.getName(classFile.constant_pool); 97 String parameters = method.descriptor.getParameterTypes(classFile.constant_pool); 98 return methodName + parameters; 99 } 100 101 public void test(int expectedNumberOfSyntheticClasses) throws TestFailedException { 102 try { 103 addTestCase(testCaseName); 104 Set<String> foundClasses = new HashSet<>(); 105 106 int numberOfSyntheticClasses = 0; 107 for (Map.Entry<String, ClassFile> entry : classes.entrySet()) { 108 String className = entry.getKey(); 109 ClassFile classFile = entry.getValue(); 110 foundClasses.add(className); 111 if (testAttribute( 112 classFile, 113 () -> (Synthetic_attribute) classFile.getAttribute(Attribute.Synthetic), 114 classFile.access_flags::getClassFlags, 115 expectedClasses.keySet(), 116 className, 117 "Testing class " + className)) { 118 ++numberOfSyntheticClasses; 119 } 120 ExpectedClass expectedClass = expectedClasses.get(className); 121 Set<String> expectedMethods = expectedClass != null 122 ? toSet(expectedClass.expectedMethods()) 123 : new HashSet<>(); 124 int numberOfSyntheticMethods = 0; 125 Set<String> foundMethods = new HashSet<>(); 126 for (Method method : classFile.methods) { 127 String methodName = getMethodName(classFile, method); 128 foundMethods.add(methodName); 129 if (testAttribute( 130 classFile, 131 () -> (Synthetic_attribute) method.attributes.get(Attribute.Synthetic), 132 method.access_flags::getMethodFlags, 133 expectedMethods, 134 methodName, 135 "Testing method " + methodName + " in class " 136 + className)) { 137 ++numberOfSyntheticMethods; 138 } 139 } 140 checkContains(foundMethods, expectedMethods, 141 "Checking that all methods of class " + className 142 + " without Synthetic attribute have been found"); 143 checkEquals(numberOfSyntheticMethods, 144 expectedClass == null ? 0 : expectedClass.expectedNumberOfSyntheticMethods(), 145 "Checking number of synthetic methods in class: " + className); 146 147 Set<String> expectedFields = expectedClass != null 148 ? toSet(expectedClass.expectedFields()) 149 : new HashSet<>(); 150 int numberOfSyntheticFields = 0; 151 Set<String> foundFields = new HashSet<>(); 152 for (Field field : classFile.fields) { 153 String fieldName = field.getName(classFile.constant_pool); 154 foundFields.add(fieldName); 155 if (testAttribute( 156 classFile, 157 () -> (Synthetic_attribute) field.attributes.get(Attribute.Synthetic), 158 field.access_flags::getFieldFlags, 159 expectedFields, 160 fieldName, 161 "Testing field " + fieldName + " in class " 162 + className)) { 163 ++numberOfSyntheticFields; 164 } 165 } 166 checkContains(foundFields, expectedFields, 167 "Checking that all fields of class " + className 168 + " without Synthetic attribute have been found"); 169 checkEquals(numberOfSyntheticFields, 170 expectedClass == null ? 0 : expectedClass.expectedNumberOfSyntheticFields(), 171 "Checking number of synthetic fields in class: " + className); 172 } 173 checkContains(foundClasses, expectedClasses.keySet(), 174 "Checking that all classes have been found"); 175 checkEquals(numberOfSyntheticClasses, expectedNumberOfSyntheticClasses, 176 "Checking number of synthetic classes"); 177 } catch (Exception e) { 178 addFailure(e); 179 } finally { 180 checkStatus(); 181 } 182 } 183 184 private boolean testAttribute(ClassFile classFile, 185 Supplier<Synthetic_attribute> getSyntheticAttribute, 186 Supplier<Set<String>> getAccessFlags, 187 Set<String> expectedMembers, String memberName, 188 String info) throws ConstantPoolException { 189 echo(info); 190 String className = classFile.getName(); 191 Synthetic_attribute attr = getSyntheticAttribute.get(); 192 Set<String> flags = getAccessFlags.get(); 193 if (expectedMembers.contains(memberName)) { 194 checkNull(attr, "Member must not have synthetic attribute : " 195 + memberName); 196 checkFalse(flags.contains(ACC_SYNTHETIC), 197 "Member must not have synthetic flag : " + memberName 198 + " in class : " + className); 199 return false; 200 } else { 201 return checkNull(attr, "Synthetic attribute should not be generated") 202 && checkTrue(flags.contains(ACC_SYNTHETIC), "Member must have synthetic flag : " 203 + memberName + " in class : " + className); 204 } 205 } 206 207 private Set<String> toSet(String[] strings) { 208 HashSet<String> set = new HashSet<>(); 209 Collections.addAll(set, strings); 210 return set; 211 } 212} 213