langtools/test/tools/javac/classfiles/attributes/Synthetic/SyntheticTestDriver.java
changeset 30065 a3873788f1b4
child 30067 08fb37c9b670
equal deleted inserted replaced
30064:39493809b601 30065:a3873788f1b4
       
     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 
       
    24 import java.io.IOException;
       
    25 import java.nio.file.Files;
       
    26 import java.nio.file.Path;
       
    27 import java.util.*;
       
    28 import java.util.function.Function;
       
    29 import java.util.function.Supplier;
       
    30 import java.util.stream.Collectors;
       
    31 import java.util.stream.Stream;
       
    32 
       
    33 import com.sun.tools.classfile.*;
       
    34 
       
    35 /**
       
    36  * The tests work as follows. Firstly, it looks through the test cases
       
    37  * and extracts the appropriate compiled classes. Each test case contains
       
    38  * a set of expected classes, methods and fields. Those class members must not have
       
    39  * the Synthetic attribute, while other found classes, methods and fields must have
       
    40  * the Synthetic attribute if they are not in the set of expected class members.
       
    41  *
       
    42  * Each test executes SyntheticTestDriver specifying the name of test cases and
       
    43  * the number of expected synthetic classes. Each test class is annotated by
       
    44  * annotations which contains non-synthetic class members.
       
    45  *
       
    46  * See the appropriate class for more information about a test case.
       
    47  */
       
    48 public class SyntheticTestDriver extends TestResult {
       
    49 
       
    50     private static final String ACC_SYNTHETIC = "ACC_SYNTHETIC";
       
    51 
       
    52     private final String testCaseName;
       
    53     private final Map<String, ClassFile> classes;
       
    54     private final Map<String, ExpectedClass> expectedClasses;
       
    55 
       
    56     public static void main(String[] args)
       
    57             throws TestFailedException, ConstantPoolException, IOException, ClassNotFoundException {
       
    58         if (args.length != 1 && args.length != 2) {
       
    59             throw new IllegalArgumentException("Usage: SyntheticTestDriver <class-name> [<number-of-synthetic-classes>]");
       
    60         }
       
    61         int numberOfSyntheticClasses = args.length == 1 ? 0 : Integer.parseInt(args[1]);
       
    62         new SyntheticTestDriver(args[0]).test(numberOfSyntheticClasses);
       
    63     }
       
    64 
       
    65     public SyntheticTestDriver(String testCaseName) throws IOException, ConstantPoolException, ClassNotFoundException {
       
    66         Class<?> clazz = Class.forName(testCaseName);
       
    67         this.testCaseName = testCaseName;
       
    68         this.expectedClasses = Stream.of(clazz.getAnnotationsByType(ExpectedClass.class))
       
    69                 .collect(Collectors.toMap(ExpectedClass::className, Function.identity()));
       
    70         this.classes = new HashMap<>();
       
    71         Path classDir = getClassDir().toPath();
       
    72         String sourceFileName = testCaseName.replace('.', '/');
       
    73         List<Path> paths = Files.walk(classDir)
       
    74                 .map(p -> classDir.relativize(p.toAbsolutePath()))
       
    75                 .filter(p -> p.toString().matches(sourceFileName + ".*\\.class"))
       
    76                 .collect(Collectors.toList());
       
    77         for (Path path : paths) {
       
    78             String className = path.toString().replace(".class", "").replace('/', '.');
       
    79             classes.put(className, readClassFile(classDir.resolve(path).toFile()));
       
    80         }
       
    81         if (classes.isEmpty()) {
       
    82             throw new RuntimeException("Classes have not been found.");
       
    83         }
       
    84         boolean success = classes.entrySet().stream()
       
    85                 .allMatch(e -> e.getKey().startsWith(testCaseName));
       
    86         if (!success) {
       
    87             classes.forEach((className, $) -> printf("Found class: %s\n", className));
       
    88             throw new RuntimeException("Found classes are not from the test case : " + testCaseName);
       
    89         }
       
    90     }
       
    91 
       
    92     private String getMethodName(ClassFile classFile, Method method)
       
    93             throws ConstantPoolException, Descriptor.InvalidDescriptor {
       
    94         String methodName = method.getName(classFile.constant_pool);
       
    95         String parameters = method.descriptor.getParameterTypes(classFile.constant_pool);
       
    96         return methodName + parameters;
       
    97     }
       
    98 
       
    99     public void test(int expectedNumberOfSyntheticClasses) throws TestFailedException {
       
   100         try {
       
   101             addTestCase(testCaseName);
       
   102             Set<String> foundClasses = new HashSet<>();
       
   103 
       
   104             int numberOfSyntheticClasses = 0;
       
   105             for (Map.Entry<String, ClassFile> entry : classes.entrySet()) {
       
   106                 String className = entry.getKey();
       
   107                 ClassFile classFile = entry.getValue();
       
   108                 foundClasses.add(className);
       
   109                 if (testAttribute(
       
   110                         classFile,
       
   111                         () -> (Synthetic_attribute) classFile.getAttribute(Attribute.Synthetic),
       
   112                         classFile.access_flags::getClassFlags,
       
   113                         expectedClasses.keySet(),
       
   114                         className,
       
   115                         "Testing class " + className)) {
       
   116                     ++numberOfSyntheticClasses;
       
   117                 }
       
   118                 ExpectedClass expectedClass = expectedClasses.get(className);
       
   119                 Set<String> expectedMethods = expectedClass != null
       
   120                         ? toSet(expectedClass.expectedMethods())
       
   121                         : new HashSet<>();
       
   122                 int numberOfSyntheticMethods = 0;
       
   123                 Set<String> foundMethods = new HashSet<>();
       
   124                 for (Method method : classFile.methods) {
       
   125                     String methodName = getMethodName(classFile, method);
       
   126                     foundMethods.add(methodName);
       
   127                     if (testAttribute(
       
   128                             classFile,
       
   129                             () -> (Synthetic_attribute) method.attributes.get(Attribute.Synthetic),
       
   130                             method.access_flags::getMethodFlags,
       
   131                             expectedMethods,
       
   132                             methodName,
       
   133                             "Testing method " + methodName + " in class "
       
   134                                     + className)) {
       
   135                         ++numberOfSyntheticMethods;
       
   136                     }
       
   137                 }
       
   138                 checkContains(foundMethods, expectedMethods,
       
   139                         "Checking that all methods of class " + className
       
   140                                 + " without Synthetic attribute have been found");
       
   141                 checkEquals(numberOfSyntheticMethods,
       
   142                         expectedClass == null ? 0 : expectedClass.expectedNumberOfSyntheticMethods(),
       
   143                         "Checking number of synthetic methods in class: " + className);
       
   144 
       
   145                 Set<String> expectedFields = expectedClass != null
       
   146                         ? toSet(expectedClass.expectedFields())
       
   147                         : new HashSet<>();
       
   148                 int numberOfSyntheticFields = 0;
       
   149                 Set<String> foundFields = new HashSet<>();
       
   150                 for (Field field : classFile.fields) {
       
   151                     String fieldName = field.getName(classFile.constant_pool);
       
   152                     foundFields.add(fieldName);
       
   153                     if (testAttribute(
       
   154                             classFile,
       
   155                             () -> (Synthetic_attribute) field.attributes.get(Attribute.Synthetic),
       
   156                             field.access_flags::getFieldFlags,
       
   157                             expectedFields,
       
   158                             fieldName,
       
   159                             "Testing field " + fieldName + " in class "
       
   160                                     + className)) {
       
   161                         ++numberOfSyntheticFields;
       
   162                     }
       
   163                 }
       
   164                 checkContains(foundFields, expectedFields,
       
   165                         "Checking that all fields of class " + className
       
   166                                 + " without Synthetic attribute have been found");
       
   167                 checkEquals(numberOfSyntheticFields,
       
   168                         expectedClass == null ? 0 : expectedClass.expectedNumberOfSyntheticFields(),
       
   169                         "Checking number of synthetic fields in class: " + className);
       
   170             }
       
   171             checkContains(foundClasses, expectedClasses.keySet(),
       
   172                     "Checking that all classes have been found");
       
   173             checkEquals(numberOfSyntheticClasses, expectedNumberOfSyntheticClasses,
       
   174                     "Checking number of synthetic classes");
       
   175         } catch (Exception e) {
       
   176             addFailure(e);
       
   177         } finally {
       
   178             checkStatus();
       
   179         }
       
   180     }
       
   181 
       
   182     private boolean testAttribute(ClassFile classFile,
       
   183                                Supplier<Synthetic_attribute> getSyntheticAttribute,
       
   184                                Supplier<Set<String>> getAccessFlags,
       
   185                                Set<String> expectedMembers, String memberName,
       
   186                                String info) throws ConstantPoolException {
       
   187         echo(info);
       
   188         String className = classFile.getName();
       
   189         Synthetic_attribute attr = getSyntheticAttribute.get();
       
   190         Set<String> flags = getAccessFlags.get();
       
   191         if (expectedMembers.contains(memberName)) {
       
   192             checkNull(attr, "Member must not have synthetic attribute : "
       
   193                     + memberName);
       
   194             checkFalse(flags.contains(ACC_SYNTHETIC),
       
   195                     "Member must not have synthetic flag : " + memberName
       
   196                             + " in class : " + className);
       
   197             return false;
       
   198         } else {
       
   199             return checkNull(attr, "Synthetic attribute should not be generated")
       
   200                     && checkTrue(flags.contains(ACC_SYNTHETIC), "Member must have synthetic flag : "
       
   201                                 + memberName + " in class : " + className);
       
   202         }
       
   203     }
       
   204 
       
   205     private Set<String> toSet(String[] strings) {
       
   206         HashSet<String> set = new HashSet<>();
       
   207         Collections.addAll(set, strings);
       
   208         return set;
       
   209     }
       
   210 }