mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
8357739: [jittester] disable the hashCode method
Reviewed-by: lmesnik
This commit is contained in:
parent
66836d40b8
commit
a2315ddd2a
@ -31,3 +31,6 @@ java/lang/System::nanoTime()
|
||||
java/lang/annotation/IncompleteAnnotationException::IncompleteAnnotationException(Ljava/lang/Class;Ljava/lang/String;)
|
||||
java/util/AbstractSet::toString()
|
||||
java/util/HashSet::toString()
|
||||
|
||||
#Unstable methods
|
||||
*::hashCode
|
||||
|
||||
@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright (c) 2025, 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.
|
||||
*/
|
||||
|
||||
package jdk.test.lib.jittester;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Executable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
import static java.util.function.Predicate.not;
|
||||
|
||||
|
||||
/**
|
||||
* A wrapper for string method templates, similar to the CompileCommand patterns.
|
||||
*/
|
||||
public final class MethodTemplate {
|
||||
|
||||
/**
|
||||
* String that can have wildcard symbols on its ends, allowing it to match a family of strings.
|
||||
* For example, "abc*" matches "abc123", and so on.
|
||||
*/
|
||||
public static class WildcardString {
|
||||
private final String pattern;
|
||||
private final boolean frontWildcarded;
|
||||
private final boolean tailWildcarded;
|
||||
|
||||
/**
|
||||
* Creates a WildcardString from given string.
|
||||
* @param pattern string pattern, like "some*"
|
||||
*/
|
||||
public WildcardString(String pattern) {
|
||||
// check for the leading '*'
|
||||
frontWildcarded = pattern.charAt(0) == '*';
|
||||
pattern = frontWildcarded ? pattern.substring(1) : pattern;
|
||||
|
||||
// check for the trailing '*'
|
||||
tailWildcarded = pattern.length() > 0 && pattern.charAt(pattern.length() - 1) == '*';
|
||||
pattern = tailWildcarded ? pattern.substring(0, pattern.length() - 1) : pattern;
|
||||
|
||||
this.pattern = pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true it this WildcardString matches given other string.
|
||||
* @param other the string that this WildcardString should be matched against
|
||||
* @return true in case of a match.
|
||||
*/
|
||||
public boolean matches(String other) {
|
||||
boolean result = pattern.equals(other);
|
||||
result |= frontWildcarded ? other.endsWith(pattern) : result;
|
||||
result |= tailWildcarded ? other.startsWith(pattern) : result;
|
||||
result |= tailWildcarded && frontWildcarded ? other.contains(pattern) : result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Pattern METHOD_PATTERN = Pattern.compile(generateMethodPattern());
|
||||
|
||||
private final WildcardString klassName;
|
||||
private final WildcardString methodName;
|
||||
private final Optional<List<Class<?>>> signature;
|
||||
|
||||
private MethodTemplate(String klassName, String methodName, Optional<List<Class<?>>> signature) {
|
||||
this.klassName = new WildcardString(klassName);
|
||||
this.methodName = new WildcardString(methodName);
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
private static String generateMethodPattern() {
|
||||
// Sample valid template(s): java/lang/String::indexOf(Ljava/lang/String;I)
|
||||
// java/lang/::*(Ljava/lang/String;I)
|
||||
// *String::indexOf(*)
|
||||
// java/lang/*::indexOf
|
||||
|
||||
String primitiveType = "[ZBSCIJFD]"; // Simply a letter, like 'I'
|
||||
String referenceType = "L[\\w/$]+;"; // Like 'Ljava/lang/String;'
|
||||
String primOrRefType =
|
||||
"\\[?" + primitiveType + // Bracket is optional: '[Z', or 'Z'
|
||||
"|" +
|
||||
"\\[?" + referenceType; // Bracket is optional: '[LSomeObject;' or 'LSomeObject;'
|
||||
String argTypesOrWildcard = "(" + // Method argument(s) Ljava/lang/String;Z...
|
||||
"(" + primOrRefType + ")*" +
|
||||
")|\\*"; // .. or a wildcard:
|
||||
|
||||
return
|
||||
"(?<klassName>[\\w/$]*\\*?)" + // Class name, like 'java/lang/String'
|
||||
"::" + // Simply '::'
|
||||
"(?<methodName>\\*?[\\w$]+\\*?)" + // method name, 'indexOf''
|
||||
"(\\((?<argTypes>" + // Method argument(s) in brackets:
|
||||
argTypesOrWildcard + // (Ljava/lang/String;Z) or '*' or nothing
|
||||
")\\))?";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true iff none of the given MethodTemplates matches the given Executable.
|
||||
*
|
||||
* @param templates the collection of templates to check
|
||||
* @param method the executable to match the colletions templates
|
||||
* @return true if none of the given templates matches the method, false otherwise
|
||||
*/
|
||||
public static boolean noneMatches(Collection<MethodTemplate> templates, Executable method) {
|
||||
for (MethodTemplate template : templates) {
|
||||
if (template.matches(method)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this MethodTemplate matches the given Executable.
|
||||
*
|
||||
* @param other the Executable to try to match to
|
||||
* @return whether the other matches this MethodTemplate
|
||||
*/
|
||||
public boolean matches(Executable other) {
|
||||
boolean result = klassName.matches(other.getDeclaringClass().getName());
|
||||
|
||||
result &= (other instanceof Constructor)
|
||||
? result
|
||||
: methodName.matches(other.getName());
|
||||
|
||||
return result &&
|
||||
signature.map(Arrays.asList(other.getParameterTypes())::equals)
|
||||
.orElse(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given string and returs a MethodTemplate.
|
||||
*
|
||||
* @param methodStr the string to parse
|
||||
* @return created MethodTemplate
|
||||
*/
|
||||
public static MethodTemplate parse(String methodStr) {
|
||||
Matcher matcher = METHOD_PATTERN.matcher(methodStr);
|
||||
String msg = String.format("Format of the methods exclude input file is incorrect,"
|
||||
+ " methodStr \"%s\" has wrong format", methodStr);
|
||||
Asserts.assertTrue(matcher.matches(), msg);
|
||||
|
||||
String klassName = matcher.group("klassName").replaceAll("/", "\\.");
|
||||
String methodName = matcher.group("methodName");
|
||||
Optional<List<Class<?>>> signature = Optional.ofNullable(matcher.group("argTypes"))
|
||||
.filter(not("*"::equals))
|
||||
.map(MethodTemplate::parseSignature);
|
||||
return new MethodTemplate(klassName, methodName, signature);
|
||||
}
|
||||
|
||||
private static List<Class<?>> parseSignature(String signature) {
|
||||
List<Class<?>> sigClasses = new ArrayList<>();
|
||||
char typeChar;
|
||||
boolean isArray;
|
||||
String klassName;
|
||||
StringBuilder sb;
|
||||
StringBuilder arrayDim;
|
||||
try (StringReader str = new StringReader(signature)) {
|
||||
int symbol = str.read();
|
||||
while (symbol != -1) {
|
||||
typeChar = (char) symbol;
|
||||
arrayDim = new StringBuilder();
|
||||
Class<?> primArrayClass = null;
|
||||
if (typeChar == '[') {
|
||||
isArray = true;
|
||||
arrayDim.append('[');
|
||||
symbol = str.read();
|
||||
while (symbol == '[') {
|
||||
arrayDim.append('[');
|
||||
symbol = str.read();
|
||||
}
|
||||
typeChar = (char) symbol;
|
||||
if (typeChar != 'L') {
|
||||
primArrayClass = Class.forName(arrayDim.toString() + typeChar);
|
||||
}
|
||||
} else {
|
||||
isArray = false;
|
||||
}
|
||||
switch (typeChar) {
|
||||
case 'Z':
|
||||
sigClasses.add(isArray ? primArrayClass : boolean.class);
|
||||
break;
|
||||
case 'I':
|
||||
sigClasses.add(isArray ? primArrayClass : int.class);
|
||||
break;
|
||||
case 'J':
|
||||
sigClasses.add(isArray ? primArrayClass : long.class);
|
||||
break;
|
||||
case 'F':
|
||||
sigClasses.add(isArray ? primArrayClass : float.class);
|
||||
break;
|
||||
case 'D':
|
||||
sigClasses.add(isArray ? primArrayClass : double.class);
|
||||
break;
|
||||
case 'B':
|
||||
sigClasses.add(isArray ? primArrayClass : byte.class);
|
||||
break;
|
||||
case 'S':
|
||||
sigClasses.add(isArray ? primArrayClass : short.class);
|
||||
break;
|
||||
case 'C':
|
||||
sigClasses.add(isArray ? primArrayClass : char.class);
|
||||
break;
|
||||
case 'L':
|
||||
sb = new StringBuilder();
|
||||
symbol = str.read();
|
||||
while (symbol != ';') {
|
||||
sb.append((char) symbol);
|
||||
symbol = str.read();
|
||||
}
|
||||
klassName = sb.toString().replaceAll("/", "\\.");
|
||||
if (isArray) {
|
||||
klassName = arrayDim.toString() + "L" + klassName + ";";
|
||||
}
|
||||
Class<?> klass = Class.forName(klassName);
|
||||
sigClasses.add(klass);
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unknown type " + typeChar);
|
||||
}
|
||||
symbol = str.read();
|
||||
}
|
||||
} catch (IOException | ClassNotFoundException ex) {
|
||||
throw new Error("Unexpected exception while parsing exclude methods file", ex);
|
||||
}
|
||||
return sigClasses;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2025, 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
|
||||
@ -23,9 +23,7 @@
|
||||
|
||||
package jdk.test.lib.jittester;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.lang.reflect.Executable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
@ -35,22 +33,31 @@ import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
import jdk.test.lib.jittester.functions.FunctionInfo;
|
||||
import jdk.test.lib.jittester.types.TypeArray;
|
||||
import jdk.test.lib.jittester.types.TypeKlass;
|
||||
|
||||
import static java.util.function.Predicate.not;
|
||||
|
||||
/**
|
||||
* Class used for parsing included classes file and excluded methods file
|
||||
*/
|
||||
public class TypesParser {
|
||||
|
||||
private List<MethodTemplate> methodsToExclude;
|
||||
|
||||
private static final HashMap<Class<?>, Type> TYPE_CACHE = new HashMap<>();
|
||||
|
||||
private static String trimComment(String source) {
|
||||
int commentStart = source.indexOf('#');
|
||||
return commentStart == -1 ? source : source.substring(0, commentStart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses included classes file and excluded methods file to TypeList and SymbolTable.
|
||||
* This routine takes all classes named in the classes file and puts them to the TypeList,
|
||||
@ -62,27 +69,21 @@ public class TypesParser {
|
||||
public static void parseTypesAndMethods(String klassesFileName, String exMethodsFileName) {
|
||||
Asserts.assertNotNull(klassesFileName, "Classes input file name is null");
|
||||
Asserts.assertFalse(klassesFileName.isEmpty(), "Classes input file name is empty");
|
||||
List<Class<?>> klasses = parseKlasses(klassesFileName);
|
||||
Set<Executable> methodsToExclude;
|
||||
if (exMethodsFileName != null && !exMethodsFileName.isEmpty()) {
|
||||
methodsToExclude = parseMethods(exMethodsFileName);
|
||||
} else {
|
||||
methodsToExclude = new HashSet<>();
|
||||
}
|
||||
klasses.stream().forEach(klass -> {
|
||||
TypeKlass typeKlass = (TypeKlass) getType(klass);
|
||||
if (TypeList.isReferenceType(typeKlass)) {
|
||||
return;
|
||||
}
|
||||
TypeList.add(typeKlass);
|
||||
Set<Executable> methods = new HashSet<>();
|
||||
methods.addAll(Arrays.asList(klass.getMethods()));
|
||||
methods.addAll(Arrays.asList(klass.getConstructors()));
|
||||
methods.removeAll(methodsToExclude);
|
||||
methods.stream().forEach(method -> {
|
||||
if (method.isSynthetic()) {
|
||||
return;
|
||||
}
|
||||
TypesParser theParser = new TypesParser();
|
||||
theParser.initMethodsToExclude(exMethodsFileName);
|
||||
parseKlasses(klassesFileName)
|
||||
.stream()
|
||||
.filter(klass -> !TypeList.isReferenceType(getTypeKlass(klass)))
|
||||
.forEach(theParser::processKlass);
|
||||
}
|
||||
|
||||
private void processKlass(Class<?> klass) {
|
||||
TypeKlass typeKlass = getTypeKlass(klass);
|
||||
TypeList.add(typeKlass);
|
||||
Stream.concat(Arrays.stream(klass.getMethods()), Arrays.stream(klass.getConstructors()))
|
||||
.filter(not(Executable::isSynthetic))
|
||||
.filter(method -> MethodTemplate.noneMatches(methodsToExclude, method))
|
||||
.forEach(method -> {
|
||||
String name = method.getName();
|
||||
boolean isConstructor = false;
|
||||
Type returnType;
|
||||
@ -106,10 +107,8 @@ public class TypesParser {
|
||||
paramList.add(new VariableInfo("arg" + argNum, typeKlass, paramType,
|
||||
VariableInfo.LOCAL | VariableInfo.INITIALIZED));
|
||||
}
|
||||
typeKlass.addSymbol(new FunctionInfo(name, typeKlass, returnType, 1, flags,
|
||||
paramList));
|
||||
typeKlass.addSymbol(new FunctionInfo(name, typeKlass, returnType, 1, flags, paramList));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private static Type getType(Class<?> klass) {
|
||||
@ -155,6 +154,10 @@ public class TypesParser {
|
||||
return type;
|
||||
}
|
||||
|
||||
private static TypeKlass getTypeKlass(Class<?> klass) {
|
||||
return (TypeKlass) getType(klass);
|
||||
}
|
||||
|
||||
private static int getArrayClassDimension(Class<?> klass) {
|
||||
if (!klass.isArray()) {
|
||||
return 0;
|
||||
@ -234,133 +237,24 @@ public class TypesParser {
|
||||
return klassesList;
|
||||
}
|
||||
|
||||
private static Set<Executable> parseMethods(String methodsFileName) {
|
||||
Asserts.assertNotNull(methodsFileName, "Methods exclude input file name is null");
|
||||
Asserts.assertFalse(methodsFileName.isEmpty(), "Methods exclude input file name is empty");
|
||||
LinkedList<String> methodNamesList = new LinkedList<>();
|
||||
Path klassesFilePath = Paths.get(methodsFileName);
|
||||
try {
|
||||
Files.lines(klassesFilePath).forEach(line -> {
|
||||
line = line.trim();
|
||||
if (line.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
String msg = String.format("Format of the methods exclude input file \"%s\" is incorrect,"
|
||||
+ " line \"%s\" has wrong format", methodsFileName, line);
|
||||
Asserts.assertTrue(line.matches("\\w[\\w/$]*::[\\w$]+\\((\\[?[ZBSCIJFD]|\\[?L[\\w/$]+;)*\\)"), msg);
|
||||
methodNamesList.add(line.substring(0, line.length() - 1));
|
||||
});
|
||||
} catch (IOException ex) {
|
||||
throw new Error("Error reading exclude method file", ex);
|
||||
}
|
||||
Set<Executable> methodsList = new HashSet<>();
|
||||
methodNamesList.forEach(methodName -> {
|
||||
String[] klassAndNameAndSig = methodName.split("::");
|
||||
String klassName = klassAndNameAndSig[0].replaceAll("/", "\\.");
|
||||
String[] nameAndSig = klassAndNameAndSig[1].split("[\\(\\)]");
|
||||
String name = nameAndSig[0];
|
||||
String signature = "";
|
||||
if (nameAndSig.length > 1) {
|
||||
signature = nameAndSig[1];
|
||||
}
|
||||
Class<?> klass = null;
|
||||
List<Class<?>> signatureTypes = null;
|
||||
private void initMethodsToExclude(String methodsFileName) {
|
||||
if (methodsFileName != null && !methodsFileName.isEmpty()) {
|
||||
Path methodsFilePath = Paths.get(methodsFileName);
|
||||
try {
|
||||
klass = Class.forName(klassName);
|
||||
signatureTypes = parseSignature(signature);
|
||||
} catch (ClassNotFoundException ex) {
|
||||
throw new Error("Unexpected exception while parsing exclude methods file", ex);
|
||||
}
|
||||
try {
|
||||
Executable method;
|
||||
if (name.equals(klass.getSimpleName())) {
|
||||
method = klass.getConstructor(signatureTypes.toArray(new Class<?>[0]));
|
||||
} else {
|
||||
method = klass.getMethod(name, signatureTypes.toArray(new Class<?>[0]));
|
||||
}
|
||||
methodsList.add(method);
|
||||
} catch (NoSuchMethodException | SecurityException ex) {
|
||||
throw new Error("Unexpected exception while parsing exclude methods file", ex);
|
||||
}
|
||||
});
|
||||
return methodsList;
|
||||
}
|
||||
methodsToExclude = Files.lines(methodsFilePath)
|
||||
// Cleaning nonimportant parts
|
||||
.map(TypesParser::trimComment)
|
||||
.map(String::trim)
|
||||
.filter(not(String::isEmpty))
|
||||
|
||||
private static List<Class<?>> parseSignature(String signature) throws ClassNotFoundException {
|
||||
LinkedList<Class<?>> sigClasses = new LinkedList<>();
|
||||
char typeChar;
|
||||
boolean isArray;
|
||||
String klassName;
|
||||
StringBuilder sb;
|
||||
StringBuilder arrayDim;
|
||||
try (StringReader str = new StringReader(signature)) {
|
||||
int symbol = str.read();
|
||||
while (symbol != -1){
|
||||
typeChar = (char) symbol;
|
||||
arrayDim = new StringBuilder();
|
||||
Class<?> primArrayClass = null;
|
||||
if (typeChar == '[') {
|
||||
isArray = true;
|
||||
arrayDim.append('[');
|
||||
symbol = str.read();
|
||||
while (symbol == '['){
|
||||
arrayDim.append('[');
|
||||
symbol = str.read();
|
||||
}
|
||||
typeChar = (char) symbol;
|
||||
if (typeChar != 'L') {
|
||||
primArrayClass = Class.forName(arrayDim.toString() + typeChar);
|
||||
}
|
||||
} else {
|
||||
isArray = false;
|
||||
}
|
||||
switch (typeChar) {
|
||||
case 'Z':
|
||||
sigClasses.add(isArray ? primArrayClass : boolean.class);
|
||||
break;
|
||||
case 'I':
|
||||
sigClasses.add(isArray ? primArrayClass : int.class);
|
||||
break;
|
||||
case 'J':
|
||||
sigClasses.add(isArray ? primArrayClass : long.class);
|
||||
break;
|
||||
case 'F':
|
||||
sigClasses.add(isArray ? primArrayClass : float.class);
|
||||
break;
|
||||
case 'D':
|
||||
sigClasses.add(isArray ? primArrayClass : double.class);
|
||||
break;
|
||||
case 'B':
|
||||
sigClasses.add(isArray ? primArrayClass : byte.class);
|
||||
break;
|
||||
case 'S':
|
||||
sigClasses.add(isArray ? primArrayClass : short.class);
|
||||
break;
|
||||
case 'C':
|
||||
sigClasses.add(isArray ? primArrayClass : char.class);
|
||||
break;
|
||||
case 'L':
|
||||
sb = new StringBuilder();
|
||||
symbol = str.read();
|
||||
while (symbol != ';') {
|
||||
sb.append((char) symbol);
|
||||
symbol = str.read();
|
||||
}
|
||||
klassName = sb.toString().replaceAll("/", "\\.");
|
||||
if (isArray) {
|
||||
klassName = arrayDim.toString() + "L" + klassName + ";";
|
||||
}
|
||||
Class<?> klass = Class.forName(klassName);
|
||||
sigClasses.add(klass);
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unknown type " + typeChar);
|
||||
}
|
||||
symbol = str.read();
|
||||
// Actual parsing
|
||||
.map(MethodTemplate::parse)
|
||||
.collect(Collectors.toList());
|
||||
} catch (IOException ex) {
|
||||
throw new Error("Error reading exclude method file", ex);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new Error("Unexpected exception while parsing exclude methods file", ex);
|
||||
} else {
|
||||
methodsToExclude = new ArrayList<>();
|
||||
}
|
||||
return sigClasses;
|
||||
}
|
||||
}
|
||||
|
||||
128
test/lib-test/jdk/test/lib/jittester/MethodTemplateTest.java
Normal file
128
test/lib-test/jdk/test/lib/jittester/MethodTemplateTest.java
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2025, 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.
|
||||
*/
|
||||
|
||||
package jdk.test.lib.jittester;
|
||||
|
||||
import java.lang.reflect.Executable;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary Unit tests for JITTester string method templates
|
||||
*
|
||||
* @library /test/lib
|
||||
* /test/hotspot/jtreg/testlibrary/jittester/src
|
||||
*
|
||||
* @run testng jdk.test.lib.jittester.MethodTemplateTest
|
||||
*/
|
||||
public class MethodTemplateTest {
|
||||
|
||||
@Test
|
||||
public void testMatchingPatterns() throws NoSuchMethodException {
|
||||
Tester.forMethod(System.class, "getenv", String.class)
|
||||
.assertMatches("java/lang/System::getenv(Ljava/lang/String;)")
|
||||
.assertMatches("*::getenv(Ljava/lang/String;)")
|
||||
.assertMatches("java/lang/*::getenv(Ljava/lang/String;)")
|
||||
.assertMatches("java/lang/System::*env*(Ljava/lang/String;)")
|
||||
.assertMatches("java/lang/System::getenv")
|
||||
.assertMatches("java/lang/System::getenv(*)");
|
||||
|
||||
Tester.forCtor(RuntimeException.class, Throwable.class)
|
||||
.assertMatches("java/lang/RuntimeException::RuntimeException(Ljava/lang/Throwable;)");
|
||||
|
||||
Tester.forMethod(String.class, "regionMatches", int.class, String.class, int.class, int.class)
|
||||
.assertMatches("java/lang/String::regionMatches(ILjava/lang/String;II)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonMatchingPatterns() throws NoSuchMethodException {
|
||||
Tester.forMethod(String.class, "regionMatches", int.class, String.class, int.class, int.class)
|
||||
.assertDoesNotMatch("java/lang/String::regionMatches(IIILjava/lang/String;)");
|
||||
|
||||
Tester.forMethod(String.class, "endsWith", String.class)
|
||||
.assertDoesNotMatch("java/lang/String::startsWith(Ljava/lang/String;)");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWildcardStrings() {
|
||||
assertTrue(new MethodTemplate.WildcardString("Torment")
|
||||
.matches("Torment"));
|
||||
|
||||
assertTrue(new MethodTemplate.WildcardString("Torm*")
|
||||
.matches("Torment"));
|
||||
|
||||
assertTrue(new MethodTemplate.WildcardString("*ent")
|
||||
.matches("Torment"));
|
||||
|
||||
assertTrue(new MethodTemplate.WildcardString("*")
|
||||
.matches("Something"));
|
||||
|
||||
assertTrue(new MethodTemplate.WildcardString("**")
|
||||
.matches("Something"));
|
||||
|
||||
assertTrue(new MethodTemplate.WildcardString("*Middle*")
|
||||
.matches("OnlyMiddleMatches"));
|
||||
|
||||
assertFalse(new MethodTemplate.WildcardString("Wrong")
|
||||
.matches("Correct"));
|
||||
assertFalse(new MethodTemplate.WildcardString("Joy")
|
||||
.matches("Joyfull"));
|
||||
assertFalse(new MethodTemplate.WildcardString("*Torm*")
|
||||
.matches("Sorrow"));
|
||||
}
|
||||
|
||||
static final class Tester {
|
||||
private final Executable executable;
|
||||
|
||||
private Tester(Executable executable) {
|
||||
this.executable = executable;
|
||||
}
|
||||
|
||||
public Tester assertMatches(String stringTemplate) {
|
||||
MethodTemplate template = MethodTemplate.parse(stringTemplate);
|
||||
assertTrue(template.matches(executable),
|
||||
"Method '" + executable + "' does not match template '" + stringTemplate + "'");
|
||||
return this;
|
||||
}
|
||||
|
||||
public Tester assertDoesNotMatch(String stringTemplate) {
|
||||
MethodTemplate template = MethodTemplate.parse(stringTemplate);
|
||||
assertFalse(template.matches(executable),
|
||||
"Method '" + executable + "' erroneously matches template '" + stringTemplate + "'");
|
||||
return this;
|
||||
}
|
||||
|
||||
public static Tester forMethod(Class klass, String name, Class<?>... arguments)
|
||||
throws NoSuchMethodException {
|
||||
return new Tester(klass.getDeclaredMethod(name, arguments));
|
||||
}
|
||||
|
||||
public static Tester forCtor(Class klass, Class<?>... arguments)
|
||||
throws NoSuchMethodException {
|
||||
return new Tester(klass.getConstructor(arguments));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user