6b45a75b88
Open sourced default method tests Reviewed-by: ccheung, iignatyev, erikj
527 lines
16 KiB
Java
527 lines
16 KiB
Java
/*
|
|
* 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;
|
|
|
|
import nsk.share.test.TestBase;
|
|
import vm.runtime.defmeth.shared.DefMethTest;
|
|
import vm.runtime.defmeth.shared.annotation.KnownFailure;
|
|
import vm.runtime.defmeth.shared.data.*;
|
|
import vm.runtime.defmeth.shared.data.method.param.NewInstanceParam;
|
|
import vm.runtime.defmeth.shared.builder.TestBuilder;
|
|
import static vm.runtime.defmeth.shared.ExecutionMode.*;
|
|
import static vm.runtime.defmeth.shared.data.method.body.CallMethod.Invoke.*;
|
|
import static vm.runtime.defmeth.shared.data.method.body.CallMethod.IndexbyteOp.*;
|
|
|
|
/**
|
|
* Tests on interaction of default methods with abstract methods
|
|
*
|
|
* The rule: "the superclass always wins."
|
|
*
|
|
* In searching the superclass hierarchy, a declaration in a superclass is
|
|
* preferred to a default in an interface. This preference includes abstract
|
|
* methods in superclasses as well; the defaults are only considered when
|
|
* the entire implementation hierarchy is silent on the status of the method
|
|
* in question.
|
|
*/
|
|
public class DefaultVsAbstractTest extends DefMethTest {
|
|
|
|
public static void main(String[] args) {
|
|
TestBase.runTest(new DefaultVsAbstractTest(), args);
|
|
}
|
|
|
|
/*
|
|
* interface I { public int m() default { return 1; } }
|
|
* class C implements I { public abstract int m(); }
|
|
*
|
|
* TEST: new C() throws InstantiationError
|
|
*/
|
|
public void test0() {
|
|
TestBuilder b = factory.getBuilder();
|
|
|
|
Interface I = b.intf("I")
|
|
.defaultMethod("m", "()I").returns(1).build()
|
|
.build();
|
|
|
|
ConcreteClass C = b.clazz("C").implement(I)
|
|
.abstractMethod("m", "()I").build()
|
|
.build();
|
|
|
|
b.test()
|
|
.callSite(I, C, "m", "()I")
|
|
.throws_(InstantiationError.class)
|
|
.done()
|
|
.run();
|
|
}
|
|
|
|
/*
|
|
* interface I {
|
|
* public int m() default { return 1; }
|
|
* }
|
|
* class C implements I {
|
|
* public abstract int m();
|
|
* }
|
|
* class D extends C {}
|
|
*
|
|
* TEST: I i = new D(); i.m() ==> AME
|
|
* TEST: C c = new D(); c.m() ==> AME
|
|
* TEST: D d = new D(); d.m() ==> AME
|
|
*/
|
|
@KnownFailure(modes = {INVOKE_EXACT, INVOKE_GENERIC, INVOKE_WITH_ARGS, INDY }) // Test1_I_D_m: NPE instead of AME
|
|
// Test3_D_D_m: AME => IAE => ICCE instead of AME
|
|
public void test1() {
|
|
TestBuilder b = factory.getBuilder();
|
|
|
|
Interface I = b.intf("I")
|
|
.defaultMethod("m", "()I").returns(1).build()
|
|
.build();
|
|
|
|
ConcreteClass C = b.clazz("C").implement(I)
|
|
.abstractMethod("m", "()I").build()
|
|
.build();
|
|
|
|
ConcreteClass D = b.clazz("D").extend(C).build();
|
|
|
|
b.test()
|
|
.callSite(I, D, "m", "()I")
|
|
.throws_(AbstractMethodError.class)
|
|
.done()
|
|
.test()
|
|
.callSite(C, D, "m", "()I")
|
|
.throws_(AbstractMethodError.class)
|
|
.done()
|
|
.test()
|
|
.callSite(D, D, "m", "()I")
|
|
.throws_(AbstractMethodError.class)
|
|
.done()
|
|
.run();
|
|
}
|
|
|
|
/*
|
|
* interface I {
|
|
* default public int m() { return 1; }
|
|
* }
|
|
* class C {
|
|
* abstract public int m();
|
|
* }
|
|
* class D extends C implements I {}
|
|
*
|
|
* TEST: I o = new D(); o.m()I throws AME
|
|
* TEST: C o = new D(); o.m()I throws AME
|
|
* TEST: D o = new D(); o.m()I throws AME
|
|
*/
|
|
@KnownFailure(modes = { INVOKE_EXACT, INVOKE_GENERIC, INVOKE_WITH_ARGS, INDY }) // Test1_I_D_m: NPE instead of AME
|
|
// Test3_D_D_m: AME => IAE => ICCE instead of AME
|
|
public void test2() {
|
|
TestBuilder b = factory.getBuilder();
|
|
|
|
Interface I = b.intf("I")
|
|
.defaultMethod("m", "()I").returns(1).build()
|
|
.build();
|
|
|
|
ConcreteClass C = b.clazz("C")
|
|
.abstractMethod("m", "()I").build()
|
|
.build();
|
|
|
|
ConcreteClass D = b.clazz("D").extend(C).implement(I).build();
|
|
|
|
b.test()
|
|
.callSite(I, D, "m", "()I")
|
|
.throws_(AbstractMethodError.class)
|
|
.done()
|
|
.test()
|
|
.callSite(C, D, "m", "()I")
|
|
.throws_(AbstractMethodError.class)
|
|
.done()
|
|
.test()
|
|
.callSite(D, D, "m", "()I")
|
|
.throws_(AbstractMethodError.class)
|
|
.done()
|
|
.run();
|
|
}
|
|
|
|
/*
|
|
* interface I {
|
|
* default public int m() { return 1; }
|
|
* }
|
|
* class C {
|
|
* abstract public int m();
|
|
* }
|
|
* class D extends C implements I {
|
|
* public int m() { return 2; }
|
|
* }
|
|
*
|
|
* TEST: I o = new D(); o.m()I == 2
|
|
* TEST: C o = new D(); o.m()I == 2
|
|
* TEST: D o = new D(); o.m()I == 2
|
|
*/
|
|
public void test3() {
|
|
TestBuilder b = factory.getBuilder();
|
|
|
|
Interface I = b.intf("I")
|
|
.defaultMethod("m", "()I").returns(1).build()
|
|
.build();
|
|
|
|
ConcreteClass C = b.clazz("C")
|
|
.abstractMethod("m", "()I").build()
|
|
.build();
|
|
|
|
ConcreteClass D = b.clazz("D").extend(C).implement(I)
|
|
.concreteMethod("m", "()I").returns(2)
|
|
.build()
|
|
.build();
|
|
|
|
b.test() // I i = new D(); ...
|
|
.callSite(I, D, "m", "()I").returns(2)
|
|
.done()
|
|
.test() // C c = new D(); ...
|
|
.callSite(C, D, "m", "()I").returns(2)
|
|
.done()
|
|
.test() // D d = new C(); ...
|
|
.callSite(D, D, "m", "()I").returns(2)
|
|
.done()
|
|
.run();
|
|
}
|
|
|
|
/*
|
|
* interface I {
|
|
* default public int m() { return 1; }
|
|
* }
|
|
* class E {
|
|
* abstract public int m();
|
|
* }
|
|
* class D extends E {}
|
|
* class C extends D implements I {}
|
|
*
|
|
* TEST: I o = new C(); o.m()I throws AME
|
|
* TEST: E o = new C(); o.m()I throws AME
|
|
* TEST: D o = new C(); o.m()I throws AME
|
|
* TEST: C o = new C(); o.m()I throws AME
|
|
*/
|
|
@KnownFailure(modes = {
|
|
INVOKE_EXACT, INVOKE_GENERIC, INVOKE_WITH_ARGS, INDY // Test1_I_C_m: NPE instead of AME
|
|
// Test3_D_C_m: AME => IAE => ICCE instead of AME
|
|
// Test4_C_C_m: AME => IAE => ICCE instead of AME
|
|
})
|
|
public void test4() {
|
|
TestBuilder b = factory.getBuilder();
|
|
|
|
Interface I = b.intf("I")
|
|
.defaultMethod("m", "()I").returns(1).build()
|
|
.build();
|
|
|
|
ConcreteClass E = b.clazz("E")
|
|
.abstractMethod("m", "()I").build()
|
|
.build();
|
|
|
|
ConcreteClass D = b.clazz("D").extend(E).build();
|
|
|
|
ConcreteClass C = b.clazz("C").extend(D).implement(I).build();
|
|
|
|
b.test() // I i = new C(); ...
|
|
.callSite(I, C, "m", "()I")
|
|
.throws_(AbstractMethodError.class)
|
|
.done()
|
|
.test() // E e = new C(); ...
|
|
.callSite(E, C, "m", "()I")
|
|
.throws_(AbstractMethodError.class)
|
|
.done()
|
|
.test() // D d = new C(); ...
|
|
.callSite(D, C, "m", "()I")
|
|
.throws_(AbstractMethodError.class)
|
|
.done()
|
|
.test() // C c = new C(); ...
|
|
.callSite(C, C, "m", "()I")
|
|
.throws_(AbstractMethodError.class)
|
|
.done()
|
|
.run();
|
|
}
|
|
|
|
/*
|
|
* interface I {
|
|
* default public int m() { return 1; }
|
|
* }
|
|
* class E {
|
|
* abstract public int m();
|
|
* }
|
|
* class D extends E {
|
|
* public int m() { return 2; }
|
|
* }
|
|
* class C extends D implements I {}
|
|
*
|
|
* TEST: I o = new C(); o.m()I == 2
|
|
* TEST: I o = new C(); o.m()I == 2
|
|
* TEST: I o = new C(); o.m()I == 2
|
|
* TEST: I o = new C(); o.m()I == 2
|
|
*/
|
|
public void test5() {
|
|
TestBuilder b = factory.getBuilder();
|
|
|
|
Interface I = b.intf("I")
|
|
.defaultMethod("m", "()I").returns(1).build()
|
|
.build();
|
|
|
|
ConcreteClass E = b.clazz("E")
|
|
.abstractMethod("m", "()I").build()
|
|
.build();
|
|
|
|
ConcreteClass D = b.clazz("D").extend(E)
|
|
.concreteMethod("m", "()I").returns(2).build()
|
|
.build();
|
|
|
|
ConcreteClass C = b.clazz("C").extend(D).implement(I).build();
|
|
|
|
b.test() // I i = new C(); ...
|
|
.callSite(I, C, "m", "()I")
|
|
.returns(2)
|
|
.done()
|
|
.test() // E e = new C(); ...
|
|
.callSite(I, C, "m", "()I")
|
|
.returns(2)
|
|
.done()
|
|
.test() // D d = new C(); ...
|
|
.callSite(I, C, "m", "()I")
|
|
.returns(2)
|
|
.done()
|
|
.test() // C c = new C(); ...
|
|
.callSite(I, C, "m", "()I")
|
|
.returns(2)
|
|
.done()
|
|
.run();
|
|
}
|
|
|
|
/*
|
|
* interface I {
|
|
* default public int m() { return 1; }
|
|
* }
|
|
* interface J {
|
|
* default public int m() { return 2; }
|
|
* }
|
|
* class E {
|
|
* abstract public int m();
|
|
* }
|
|
* class D extends E {
|
|
* public int m() { return 3; }
|
|
* }
|
|
* class C extends D implements I, J {}
|
|
*
|
|
* TEST: I o = new C(); o.m()I == 3
|
|
* TEST: J o = new C(); o.m()I == 3
|
|
* TEST: E o = new C(); o.m()I == 3
|
|
* TEST: D o = new C(); o.m()I == 3
|
|
* TEST: J o = new C(); o.m()I == 3
|
|
*/
|
|
public void test6() {
|
|
TestBuilder b = factory.getBuilder();
|
|
|
|
Interface I = b.intf("I")
|
|
.defaultMethod("m", "()I").returns(1).build()
|
|
.build();
|
|
|
|
Interface J = b.intf("J")
|
|
.defaultMethod("m", "()I").returns(2).build()
|
|
.build();
|
|
|
|
ConcreteClass E = b.clazz("E")
|
|
.abstractMethod("m", "()I").build()
|
|
.build();
|
|
|
|
ConcreteClass D = b.clazz("D").extend(E)
|
|
.concreteMethod("m", "()I").returns(3).build()
|
|
.build();
|
|
|
|
ConcreteClass C = b.clazz("C").extend(D).implement(I, J).build();
|
|
|
|
|
|
b.test() // I i = new C(); ...
|
|
.callSite(I, C, "m", "()I").returns(3)
|
|
.done()
|
|
.test() // J j = new C(); ...
|
|
.callSite(J, C, "m", "()I").returns(3)
|
|
.done()
|
|
.test() // E e = new C(); ...
|
|
.callSite(E, C, "m", "()I").returns(3)
|
|
.done()
|
|
.test() // D d = new C(); ...
|
|
.callSite(D, C, "m", "()I").returns(3)
|
|
.done()
|
|
.test() // C c = new C(); ...
|
|
.callSite(J, C, "m", "()I").returns(3)
|
|
.done()
|
|
.run();
|
|
}
|
|
|
|
/*
|
|
* interface I {
|
|
* abstract public int m();
|
|
* }
|
|
*
|
|
* interface J {
|
|
* default public int m() { return 1; }
|
|
* }
|
|
*
|
|
* class A implements I;
|
|
*
|
|
* class B extends A implements J;
|
|
*
|
|
* TEST: A o = new B(); o.m()I
|
|
* returns 1 for REFLECTION and INVOKE_WITH_ARGS
|
|
* ICCE for other modes
|
|
*/
|
|
public void testInvokeInterfaceClassDefaultMethod() {
|
|
TestBuilder b = factory.getBuilder();
|
|
|
|
Interface I = b.intf("I")
|
|
.abstractMethod("m", "()I").build()
|
|
.build();
|
|
|
|
Interface J = b.intf("J")
|
|
.extend(I)
|
|
.defaultMethod("m", "()I").returns(1).build()
|
|
.build();
|
|
|
|
ConcreteClass A = b.clazz("A").implement(I).build();
|
|
|
|
ConcreteClass B = b.clazz("B").extend(A).implement(J).build();
|
|
|
|
String exeMode = factory.getExecutionMode();
|
|
|
|
// the test passes in the reflection mode because there's no way to
|
|
// express invokeinterface on a class using Reflection API
|
|
// In the test generator, vm.runtime.defmeth.shared.executor.ReflectionTest,
|
|
// the invokeinterface is switched to invokevirtual.
|
|
//
|
|
// the test passes in the INVOKE_WITH_ARGS mode due to the fix for
|
|
// JDK-8032010 to conform with the removal of the following check
|
|
// during method resolution in JVMS-5.4.3.3 Method Resolution
|
|
// "If method lookup succeeds and the method is abstract, but C is not
|
|
// abstract, method resolution throws an AbstractMethodError."
|
|
if (exeMode.equals("REFLECTION") ||
|
|
exeMode.equals("INVOKE_WITH_ARGS")) {
|
|
b.test().interfaceCallSite(A, B, "m", "()I")
|
|
.returns(1).done()
|
|
.run();
|
|
} else {
|
|
// ICCE in other modes due to
|
|
// JVMS-5.4.3.4. Interface Method Resolution
|
|
// When resolving an interface method reference:
|
|
// If C is not an interface, interface method resolution throws an IncompatibleClassChangeError.
|
|
b.test().interfaceCallSite(A, B, "m", "()I")
|
|
.throws_(IncompatibleClassChangeError.class).done()
|
|
.run();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* interface I {
|
|
* abstract public int m();
|
|
* }
|
|
*
|
|
* interface J {
|
|
* abstract public int m();
|
|
* }
|
|
*
|
|
* class A implements I;
|
|
*
|
|
* class B extends A implements J;
|
|
*
|
|
* TEST: A o = new B(); o.m()I
|
|
* ICCE for DIRECT mode
|
|
* AME for REFLECTION and INVOKE_WITH_ARGS modes
|
|
* IAE for other modes
|
|
*/
|
|
public void testInvokeInterfaceClassAbstractMethod() {
|
|
TestBuilder b = factory.getBuilder();
|
|
|
|
Interface I = b.intf("I")
|
|
.abstractMethod("m", "()I").build()
|
|
.build();
|
|
|
|
Interface J = b.intf("J")
|
|
.abstractMethod("m", "()I").build()
|
|
.build();
|
|
|
|
ConcreteClass A = b.clazz("A").implement(I).build();
|
|
|
|
ConcreteClass B = b.clazz("B").extend(A).implement(J).build();
|
|
|
|
String exeMode = factory.getExecutionMode();
|
|
|
|
// ICCE in direct mode due to
|
|
// JVMS-5.4.3.4. Interface Method Resolution
|
|
// When resolving an interface method reference:
|
|
// If C is not an interface, interface method resolution throws an IncompatibleClassChangeError.
|
|
Class expectedError = IncompatibleClassChangeError.class;;
|
|
|
|
b.test().interfaceCallSite(A, B, "m", "()I")
|
|
.throws_(expectedError).done()
|
|
.run();
|
|
|
|
}
|
|
|
|
/*
|
|
* interface I {
|
|
* public int m() default { return 1; }
|
|
* }
|
|
*
|
|
* interface J {
|
|
* public int m() default { return 1; }
|
|
* }
|
|
*
|
|
* class A implements I;
|
|
*
|
|
* class B extends A implements J;
|
|
*
|
|
* TEST: A o = new B(); o.m()I
|
|
* ICCE for all modes
|
|
*/
|
|
public void testInvokeInterfaceMultipleDefinedClassDefaultMethod() {
|
|
TestBuilder b = factory.getBuilder();
|
|
|
|
Interface I = b.intf("I")
|
|
.defaultMethod("m", "()I").returns(1).build()
|
|
.build();
|
|
|
|
Interface J = b.intf("J")
|
|
.defaultMethod("m", "()I").returns(1).build()
|
|
.build();
|
|
|
|
ConcreteClass A = b.clazz("A").implement(I).build();
|
|
|
|
ConcreteClass B = b.clazz("B").extend(A).implement(J).build();
|
|
|
|
String exeMode = factory.getExecutionMode();
|
|
|
|
// ICCE in direct mode due to
|
|
// JVMS-5.4.3.4. Interface Method Resolution
|
|
// When resolving an interface method reference:
|
|
// If C is not an interface, interface method resolution throws an IncompatibleClassChangeError.
|
|
Class expectedError = IncompatibleClassChangeError.class;
|
|
|
|
b.test().interfaceCallSite(A, B, "m", "()I")
|
|
.throws_(expectedError).done()
|
|
.run();
|
|
}
|
|
|
|
}
|