--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/vmTestbase/vm/runtime/defmeth/shared/DefMethTest.java Wed May 23 17:09:49 2018 -0700
@@ -0,0 +1,366 @@
+/*
+1;2c * Copyright (c) 2013, 2018, 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 vm.runtime.defmeth.shared;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.TreeSet;
+import java.util.regex.Pattern;
+import nsk.share.TestFailure;
+import nsk.share.log.Log;
+import nsk.share.test.TestBase;
+import vm.runtime.defmeth.AccessibilityFlagsTest;
+import vm.runtime.defmeth.BasicTest;
+import vm.runtime.defmeth.ConflictingDefaultsTest;
+import vm.runtime.defmeth.DefaultVsAbstractTest;
+import vm.runtime.defmeth.MethodResolutionTest;
+import vm.runtime.defmeth.ObjectMethodOverridesTest;
+import vm.runtime.defmeth.PrivateMethodsTest;
+import vm.runtime.defmeth.StaticMethodsTest;
+import vm.runtime.defmeth.SuperCallTest;
+import vm.runtime.defmeth.shared.annotation.Crash;
+import vm.runtime.defmeth.shared.annotation.KnownFailure;
+import vm.runtime.defmeth.shared.annotation.NotApplicableFor;
+import vm.runtime.defmeth.shared.builder.TestBuilderFactory;
+import vm.share.options.Option;
+import vm.share.options.OptionSupport;
+import vm.share.options.Options;
+import static java.lang.String.format;
+import java.util.Collections;
+import vm.runtime.defmeth.RedefineTest;
+import vm.runtime.defmeth.shared.annotation.NotTest;
+
+/**
+ * Parent class for all default method tests.
+ *
+ * Contains common settings and code to run individual tests.
+ *
+ * Provides command-line interface to run arbitrary subset of
+ * tests on default methods with some customizations.
+ */
+public abstract class DefMethTest extends TestBase {
+ /** Classes that contain tests on default methods */
+ static private final List<Class<? extends DefMethTest>> classes;
+
+ // the number of tests has failed
+ // note that if more than one sub-test has failed within a test,
+ // it will be counted as 1 failure for that test
+ private int numFailures;
+
+ static {
+ List<Class<? extends DefMethTest>> intlList = new ArrayList<>();
+
+ intlList.add(AccessibilityFlagsTest.class);
+ intlList.add(BasicTest.class);
+ intlList.add(ConflictingDefaultsTest.class);
+ intlList.add(DefaultVsAbstractTest.class);
+ intlList.add(MethodResolutionTest.class);
+ intlList.add(ObjectMethodOverridesTest.class);
+ intlList.add(SuperCallTest.class);
+ intlList.add(PrivateMethodsTest.class);
+ intlList.add(StaticMethodsTest.class);
+ intlList.add(RedefineTest.class);
+
+ classes = Collections.unmodifiableList(intlList);
+ }
+
+ public static List<Class<? extends DefMethTest>> getTests() {
+ return classes;
+ }
+
+ @Option(name="list", default_value="false", description="list tests w/o executing them")
+ boolean listTests;
+
+ @Option(name="filter", default_value="", description="filter executed tests")
+ String filterString;
+
+ @Option(name="ignoreKnownFailures", default_value="false", description="ignore tests with known failures")
+ boolean ignoreKnownFailures;
+
+ @Option(name="runOnlyFailingTests", default_value="false", description="run only failing tests")
+ boolean runOnlyFailingTests;
+
+ @Option(name="ignoreCrashes", default_value="false", description="don't run tests with crash VM")
+ boolean ignoreCrashes;
+
+ @Option(name="silent", default_value="false", description="silent mode - don't print anything")
+ boolean isSilent;
+
+ @Option(name="failfast", default_value="false", description="fail the whole set of test on first failure")
+ boolean failFast;
+
+ @Option(name="testAllModes", default_value="false", description="run each test in all possible modes")
+ boolean testAllModes;
+
+ @Option(name="mode", description="invocation mode (direct, reflect, invoke)", default_value="direct")
+ private String mode;
+
+ private Pattern filter; // Precompiled pattern for filterString
+
+ /**
+ * Used from individual tests to get TestBuilder instances,
+ * which is aware of current testing configuration
+ */
+ @Options
+ protected TestBuilderFactory factory = new TestBuilderFactory(this);
+
+ private void init() {
+ if (isSilent) {
+ getLog().setInfoEnabled(false);
+ getLog().setWarnEnabled(false);
+ getLog().setDebugEnabled(false);
+ }
+
+ if (filterString != null && !"".equals(filterString)) {
+ filter = Pattern.compile(".*" + filterString + ".*");
+ } else {
+ filter = Pattern.compile(".*"); // match everything
+ }
+
+ // Test-specific config
+ configure();
+ }
+
+ @Override
+ public final void run() {
+ init();
+
+ boolean success = runTest();
+ if (!success) {
+ getLog().info("TEST FAILED");
+ setFailed(true);
+ } else {
+ getLog().info("TEST PASSED");
+ }
+ }
+
+ protected void configure() {
+ // Is overriden by specific tests to do test-specific setup
+ }
+
+ public Log getLog() {
+ return log;
+ }
+
+ @Override
+ public String toString() {
+ return format("%s%s",
+ getClass().getSimpleName(), factory);
+ }
+
+ /** Enumerate invocation modes to be tested */
+ private ExecutionMode[] getInvocationModes() {
+ if (factory.getExecutionMode() != null) {
+ return new ExecutionMode[] { ExecutionMode.valueOf(factory.getExecutionMode()) };
+ }
+
+ if (testAllModes) {
+ return ExecutionMode.values();
+ }
+
+ switch(mode) {
+ case "direct": return new ExecutionMode[] { ExecutionMode.DIRECT };
+ case "reflect": return new ExecutionMode[] { ExecutionMode.REFLECTION };
+ case "invoke_exact": return new ExecutionMode[] { ExecutionMode.INVOKE_EXACT };
+ case "invoke_generic": return new ExecutionMode[] { ExecutionMode.INVOKE_GENERIC };
+ case "indy": return new ExecutionMode[] { ExecutionMode.INDY };
+ case "invoke": return new ExecutionMode[] { ExecutionMode.INVOKE_WITH_ARGS,
+ ExecutionMode.INVOKE_EXACT,
+ ExecutionMode.INVOKE_GENERIC,
+ ExecutionMode.INDY };
+ case "redefinition":
+ throw new Error("redefinition is only a pseudo-mode");
+ default:
+ throw new Error("Unknown mode: " + mode);
+ }
+ }
+
+ // Check whether the test is applicable to selected execution mode
+ private boolean shouldExecute(Method m, ExecutionMode mode) {
+ Class<? extends DefMethTest> test = this.getClass();
+
+ int acc = m.getModifiers();
+ if (m.isAnnotationPresent(NotTest.class)
+ || (ignoreCrashes && m.isAnnotationPresent(Crash.class))
+ || !Modifier.isPublic(acc) || Modifier.isStatic(acc)
+ //|| m.getReturnType() != Void.class
+ || m.getParameterTypes().length != 0)
+ {
+ return false; // not a test
+ }
+
+ String testName = format("%s.%s", test.getName(), m.getName());
+ if (!filter.matcher(testName).matches()) {
+ return false; // test is filtered out
+ }
+
+ if (m.isAnnotationPresent(NotApplicableFor.class)) {
+ for (ExecutionMode excludeFromMode : m.getAnnotation(NotApplicableFor.class).modes()) {
+ if (mode == excludeFromMode) {
+ return false; // not applicable to current execution mode
+ } else if (excludeFromMode == ExecutionMode.REDEFINITION &&
+ (factory.isRedefineClasses() || factory.isRetransformClasses())) {
+ return false; // Can't redefine some tests.
+ }
+
+ }
+ }
+
+ if (ignoreKnownFailures &&
+ m.isAnnotationPresent(KnownFailure.class)) {
+ ExecutionMode[] modes = m.getAnnotation(KnownFailure.class).modes();
+
+ if (modes.length == 0) return false; // by default, matches all modes
+
+ for (ExecutionMode knownFailingMode : modes) {
+ if (mode == knownFailingMode) {
+ return false; // known failure in current mode
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /** Information about the test being executed */
+ public String shortTestName;
+
+ public static class ComparableMethod implements Comparable<ComparableMethod> {
+ final java.lang.reflect.Method m;
+ ComparableMethod(java.lang.reflect.Method m) { this.m = m; }
+ public int compareTo(ComparableMethod mo) {
+ String name = m.getName();
+ String mo_name = mo.m.getName();
+ return name.compareTo(mo_name);
+ }
+ }
+
+ /** helper method for subclass to report the number of test failures.
+ * It is more important for the reflection case as an exception thrown
+ * deep in the call stack may not be propagated to this level.
+ *
+ * @param failures
+ */
+ public void addFailureCount(int failures) {
+ numFailures += failures;
+ }
+
+ /**
+ * Execute all tests from current class and report status.
+ *
+ * The following execution customization is supported:
+ * - filter tests by name using regex
+ * - ignore tests marked as @KnownFailure
+ * - ignore tests marked as @Crash
+ * - only run tests marked as @KnownFailure
+ *
+ * @return any failures occurred?
+ */
+ public final boolean runTest() {
+ if (ignoreKnownFailures && runOnlyFailingTests) {
+ throw new IllegalArgumentException("conflicting parameters");
+ }
+
+ ExecutionMode[] invocationModes = getInvocationModes();
+
+ try {
+ int totalTests = 0;
+ int passedTests = 0;
+
+ Class<? extends DefMethTest> test = this.getClass();
+
+ getLog().info(format("\n%s %s", test.getSimpleName(), factory.toString()));
+
+ TreeSet<ComparableMethod> ts = new TreeSet<ComparableMethod>();
+ for (java.lang.reflect.Method m : test.getDeclaredMethods()) {
+ ts.add(new ComparableMethod(m));
+ }
+
+ for (ComparableMethod cm : ts) {
+ java.lang.reflect.Method m = cm.m;
+ for (ExecutionMode mode : invocationModes) {
+ shortTestName = format("%s.%s", test.getSimpleName(), m.getName());
+
+ if (!shouldExecute(m, mode)) {
+ continue; // skip the test due to current configuration
+ }
+
+ totalTests++;
+
+ getLog().info(shortTestName);
+
+ if (listTests) {
+ continue; // just print test info
+ }
+
+ // Iterate over all test modes
+ try {
+ factory.setExecutionMode(mode.name());
+ getLog().info(format(" %s: ", mode));
+ m.invoke(this);
+ } catch (IllegalAccessException | IllegalArgumentException e) {
+ throw new TestFailure(e);
+ } catch (InvocationTargetException e) {
+ if (e.getCause() instanceof TestFailure) {
+ // Failure details were printed in GeneratedTest.run()/ReflectionTest.run()
+ } else {
+ if (Constants.PRINT_STACK_TRACE) {
+ e.printStackTrace();
+ }
+ }
+
+ if (failFast) {
+ throw new TestFailure(e.getCause());
+ }
+ }
+ }
+ }
+
+ passedTests = totalTests - numFailures;
+ getLog().info(format("%d test run: %d passed, %d failed", totalTests, passedTests, numFailures));
+ if (numFailures == 0) {
+ return true;
+ } else {
+ return false;
+ }
+ } catch (Exception | Error e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /** Command-line interface to initiate test run */
+ public static void main(String[] args) {
+ for (Class<? extends DefMethTest> clz : classes) {
+ try {
+ DefMethTest test = clz.newInstance();
+ OptionSupport.setupAndRun(test, args);
+ } catch (InstantiationException | IllegalAccessException e) {
+ throw new TestFailure(e);
+ }
+ }
+ }
+}