33081
|
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 |
}
|