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 package compiler.compilercontrol.share.method;
  25 
  26 import compiler.compilercontrol.share.method.MethodDescriptor.PatternType;
  27 import compiler.compilercontrol.share.method.MethodDescriptor.Separator;
  28 import jdk.test.lib.Pair;
  29 import jdk.test.lib.Triple;
  30 import jdk.test.lib.Utils;
  31 import pool.PoolHelper;
  32 
  33 import java.lang.reflect.Executable;
  34 import java.util.ArrayList;
  35 import java.util.EnumSet;
  36 import java.util.List;
  37 import java.util.concurrent.Callable;
  38 import java.util.function.Function;
  39 
  40 /**
  41  * Generates combinations of method descriptors from the pool of methods
  42  */
  43 public class MethodGenerator {
  44     private static final List<Pair<Executable, Callable<?>>> METHODS =
  45             new PoolHelper().getAllMethods(PoolHelper.METHOD_FILTER);
  46     // Different combinations of patterns
  47     private static final List<Combination<PatternType>> PATTERNS_LIST;
  48     // Different combinations of separators
  49     private static final List<Combination<Separator>> SEPARATORS_LIST;
  50     // List of functions that modify elements
  51     private static final List<Function<String, String>> ELEMENT_MUTATORS;
  52 
  53     static {
  54         PATTERNS_LIST =
  55                 generate(EnumSet.allOf(PatternType.class),
  56                         EnumSet.allOf(PatternType.class),
  57                         EnumSet.of(PatternType.ANY, PatternType.EXACT));
  58         SEPARATORS_LIST =
  59                 generate(EnumSet.of(Separator.SLASH, Separator.DOT),
  60                         EnumSet.complementOf(EnumSet.of(Separator.NONE)),
  61                         EnumSet.of(Separator.COMMA, Separator.SPACE,
  62                                 Separator.NONE));
  63         ELEMENT_MUTATORS = generateMutators();
  64     }
  65 
  66     // Test method
  67     public static void main(String[] args) {
  68         MethodGenerator methodGenerator = new MethodGenerator();
  69         List<MethodDescriptor> tests = methodGenerator.getTests();
  70         tests.forEach(System.out::println);
  71     }
  72 
  73     /**
  74      * Generates random method descriptor
  75      *
  76      * @param executable executable used to generate descriptor
  77      * @return MethodDescriptor instance
  78      */
  79     public MethodDescriptor generateRandomDescriptor(Executable executable) {
  80         Combination<PatternType> patterns =
  81                 Utils.getRandomElement(PATTERNS_LIST);
  82         Combination<Separator> separators =
  83                 Utils.getRandomElement(SEPARATORS_LIST);
  84         // Create simple mutators for signature generation
  85         List<Function<String, String>> signMutators = new ArrayList<>();
  86         signMutators.add(input -> input);
  87         signMutators.add(input -> "");
  88         Combination<Function<String, String>> mutators = new Combination<>(
  89                 Utils.getRandomElement(ELEMENT_MUTATORS),
  90                 Utils.getRandomElement(ELEMENT_MUTATORS),
  91                 // use only this type of mutators
  92                 Utils.getRandomElement(signMutators));
  93         return makeMethodDescriptor(executable, patterns,
  94                 separators, mutators);
  95     }
  96 
  97     /**
  98      * Compile command signature that looks like java/lang/String.indexOf
  99      * http://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html#BABDDFII
 100      *
 101      * @param executable executable used to generate descriptor
 102      * @return MethodDescriptor instance
 103      */
 104     public static MethodDescriptor commandDescriptor(Executable executable) {
 105         MethodDescriptor md = new MethodDescriptor(executable);
 106         md.aClass.setSeparator(Separator.SLASH);
 107         md.aMethod.setSeparator(Separator.DOT);
 108         md.aSignature.setSeparator(Separator.NONE);
 109         return md;
 110     }
 111 
 112     /**
 113      * Compile command signature that looks like java.lang.String::indexOf
 114      *
 115      * @param executable executable used to generate descriptor
 116      * @return MethodDescriptor instance
 117      */
 118     public static MethodDescriptor logDescriptor(Executable executable) {
 119         MethodDescriptor md = new MethodDescriptor(executable);
 120         md.aClass.setSeparator(Separator.DOT);
 121         md.aMethod.setSeparator(Separator.DOUBLECOLON);
 122         md.aSignature.setSeparator(Separator.NONE);
 123         return md;
 124     }
 125 
 126     /**
 127      * Generates a list of method patterns from the pool of methods
 128      *
 129      * @return a list of test cases
 130      */
 131     public List<MethodDescriptor> getTests() {
 132         List<MethodDescriptor> list = new ArrayList<>();
 133         METHODS.forEach(pair -> list.addAll(getTests(pair.first)));
 134         return list;
 135     }
 136 
 137     /**
 138      * Generates all combinations of method descriptors for a given executable
 139      *
 140      * @param executable executable for which the different combination is built
 141      * @return list of method descriptors
 142      */
 143     public List<MethodDescriptor> getTests(Executable executable) {
 144         List<MethodDescriptor> list = new ArrayList<>();
 145         for (Combination<PatternType> patterns : PATTERNS_LIST) {
 146             for (Combination<Separator> separators : SEPARATORS_LIST) {
 147                 for (Function<String, String> classGen : ELEMENT_MUTATORS) {
 148                     for (Function<String, String> methodGen :
 149                             ELEMENT_MUTATORS) {
 150                         for (Function<String, String> signatureGen :
 151                                 ELEMENT_MUTATORS) {
 152                             list.add(makeMethodDescriptor(executable,
 153                                     patterns, separators,
 154                                     new Combination<>(classGen, methodGen,
 155                                         signatureGen)));
 156                         }
 157                     }
 158                 }
 159             }
 160         }
 161         return list;
 162     }
 163 
 164     /**
 165      * Creates method descriptor from the given executable,
 166      * patterns and separators for its elements
 167      */
 168     private MethodDescriptor makeMethodDescriptor(
 169             Executable executable,
 170             Combination<PatternType> patterns,
 171             Combination<Separator> separators,
 172             Combination<Function<String, String>> mutators) {
 173         MethodDescriptor methodDescriptor = new MethodDescriptor(executable);
 174         methodDescriptor.setSeparators(separators);
 175         methodDescriptor.applyMutates(mutators);
 176         methodDescriptor.setPatterns(patterns);
 177         return methodDescriptor;
 178     }
 179 
 180     /**
 181      * Creates a list of functions that change given string
 182      */
 183     private static List<Function<String, String>> generateMutators() {
 184         List<Function<String, String>> elements = new ArrayList<>();
 185         // Use the input itself
 186         elements.add(input -> input);
 187         // Use half of the input string
 188         elements.add(input -> input.substring(input.length() / 2));
 189         // Add nonexistent element
 190         elements.add(input -> "nonexistent");
 191         // Use left and right angle brackets
 192         elements.add(input -> "<" + input + ">");
 193         // Embed * inside
 194         elements.add(input -> embed(input, "*"));
 195         // ** as a whole element
 196         elements.add(input -> "**");
 197         // Embed JLS-invalid letters
 198         elements.add(input -> embed(input, "@%"));
 199         elements.add(input -> embed(input, "]"));
 200         // Use JLS-invalid letters
 201         elements.add(input -> "-");
 202         elements.add(input -> "+");
 203         elements.add(input -> ")" + input);
 204         elements.add(input -> "{" + input + "}");
 205         // Add valid Java identifier start char
 206         elements.add(input -> "_" + input);
 207         elements.add(input -> "$" + input);
 208         elements.add(input -> "0" + input);
 209         // Unicode characters
 210         elements.add(input -> embed(input, "\u0001"));
 211         elements.add(input -> embed(input, "\u007F"));
 212         // Combining character
 213         elements.add(input -> embed(input, "\u0300"));
 214         elements.add(input -> embed(input, "\u0306"));
 215         // Supplementary character
 216         elements.add(input -> new String(Character.toChars(0x1F64C)));
 217         return elements;
 218     }
 219 
 220     /**
 221      * Embeds one string inside another one
 222      *
 223      * @param target  target source string
 224      * @param element string to be embedded into target string
 225      * @return result string
 226      */
 227     private static String embed(String target, String element) {
 228         int mid = target.length() / 2;
 229         String begin = target.substring(0, mid);
 230         String end = target.substring(mid);
 231         return begin + element + end;
 232     }
 233 
 234     /**
 235      * Generates triples from the given enum sets
 236      * for each of the method elements
 237      *
 238      * @param classSet  set of allowed elements for class
 239      * @param methodSet set of allowed elements for method
 240      * @param signSet   set of allowed elements for signature
 241      * @param <E>       type of generated triples
 242      * @return list of triples
 243      */
 244     private static <E extends Enum<E>> List<Combination<E>> generate(
 245             EnumSet<E> classSet, EnumSet<E> methodSet, EnumSet<E> signSet) {
 246         List<Combination<E>> list = new ArrayList<>();
 247         classSet.forEach(clsElement ->
 248             methodSet.forEach(methodElement ->
 249                 signSet.forEach(signElement ->
 250                     list.add(new Combination<>(clsElement, methodElement,
 251                             signElement))
 252                 )
 253             )
 254         );
 255         return list;
 256     }
 257 
 258     private static class Combination<T> extends Triple<T, T, T> {
 259         public Combination(T first, T second, T third) {
 260             super(first, second, third);
 261         }
 262     }
 263 }