blob: 978be89ba620ce50fbc4e5b54d9fc435f2f41e15 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2010 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
/*
* Here we focus on various aspects of the runtime behavior of the generated
* code.
*/
package org.eclipse.jdt.core.tests.compiler.regression;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import junit.framework.Test;
@SuppressWarnings({ "rawtypes" })
public class RuntimeTests extends AbstractRegressionTest {
public RuntimeTests(String name) {
super(name);
}
// Static initializer to specify tests subset using TESTS_* static variables
// All specified tests which does not belong to the class are skipped...
// Only the highest compliance level is run; add the VM argument
// -Dcompliance=1.4 (for example) to lower it if needed
static {
// TESTS_NAMES = new String[] { "test0001" };
// TESTS_NUMBERS = new int[] { 1 };
// TESTS_RANGE = new int[] { 1, -1 };
}
public static Test suite() {
return buildAllCompliancesTestSuite(testClass());
}
public static Class testClass() {
return RuntimeTests.class;
}
// decided not to keep this active because of negative effects on the test
// series (the OOME potentially causing grief to others)
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=217078
// memory exhaustion - try to allocate too big an instance
public void _test0001_memory_exhaustion() {
runTest(
new String[] { /* testFiles */
"X.java",
"public class X {\n" +
" public static void main(String args[]) {\n" +
" try {" +
" Y y = new Y(Integer.MAX_VALUE);\n" +
" }" +
" catch (OutOfMemoryError e) {\n" +
" System.out.println(\"SUCCESS\");\n" +
" return;\n" +
" }\n" +
" System.out.println(\"FAILURE\");\n" +
" }\n" +
"}\n" +
"class Y {\n" +
" long storage[];\n" +
" Y(int itemsNb) {\n" +
" storage = new long[itemsNb];\n" +
" }\n" +
"}\n"},
false /* expectingCompilerErrors */,
"" /* expectedCompilerLog */,
"SUCCESS" /* expectedOutputString */,
null /* expectedErrorString - skip this because some JREs emit additional info to stderr in case of exception */,
false /* forceExecution */,
null /* classLib */,
true /* shouldFlushOutputDirectory */,
null /* vmArguments */,
null /* customOptions */,
null /* clientRequestor */,
true /* skipJavac */);
}
// synchronization - concurrent access to a resource with explicit and
// implicit locks
public void test0500_synchronization() {
this.runConformTest(
new String[] {
"X.java",
"public class X {\n" +
"static public void main (String args[]) {\n" +
" new Lock().implicitLock();\n" +
"}\n" +
"}\n" +
"class Lock extends Thread {\n" +
" byte step = 0;\n" +
" void logStep(String start) {\n" +
" System.out.println(start + \" \" + this.step); //$NON-NLS-1$\n" +
" }\n" +
" public void run() {\n" +
" for (int i = 1; i < 3; i++) {\n" +
" logStep(\"explicit lock\"); //$NON-NLS-1$\n" +
" synchronized (this) {\n" +
" this.step++;\n" +
" notify();\n" +
" while(this.step < 2 * i) {\n" +
" try {\n" +
" wait();\n" +
" } catch (InterruptedException e) {\n" +
" System.out.println(\"EXCEPTION\"); //$NON-NLS-1$\n" +
" }\n" +
" }\n" +
" }\n" +
" }\n" +
" }\n" +
" synchronized void implicitLock() {\n" +
" this.start();\n" +
" for (int i = 0; i < 2; i++) {\n" +
" while (this.step < 1 + i * 2) {\n" +
" try {\n" +
" wait();\n" +
" } catch (InterruptedException e) {\n" +
" System.out.println(\"EXCEPTION\"); //$NON-NLS-1$\n" +
" }\n" +
" }\n" +
" logStep(\"implicit lock\"); //$NON-NLS-1$\n" +
" this.step++;\n" +
" notify();\n" +
" }\n" +
" return;\n" +
" }\n" +
"}\n"},
"explicit lock 0\n" +
"implicit lock 1\n" +
"explicit lock 2\n" +
"implicit lock 3"
);
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=126712
// reflection - access to a public method of a package visible
// class through a public extending class
public void test0600_reflection() {
runConformTest(
true,
new String[] {
"X.java",
"import java.lang.reflect.*;\n" +
"import p.*;\n" +
"public class X {\n" +
"static public void main (String args[]) {\n" +
" Y y = new Y();\n" +
" try {\n" +
" Method foo = Y.class.getMethod(\"foo\", (Class []) null);\n" +
" y.foo();\n" +
" foo.invoke(y, (Object []) null);\n" +
" } catch (NoSuchMethodException e) {\n" +
" //ignore\n" +
" } catch (InvocationTargetException e) {\n" +
" //ignore\n" +
" } catch (IllegalAccessException e) {\n" +
" System.out.print(\"FAILURE: IllegalAccessException\");\n" +
" }\n" +
"}\n" +
"}",
"p/Y.java",
"package p;\n" +
"public class Y extends Z {\n" +
" /* empty */\n" +
"}\n",
"p/Z.java",
"package p;\n" +
"class Z {\n" +
" public void foo() {\n" +
" System.out.println(\"SUCCESS\"); //$NON-NLS-1$\n" +
" }\n" +
"}\n"},
"",
this.complianceLevel <= ClassFileConstants.JDK1_5 ? "SUCCESS\n" + "FAILURE: IllegalAccessException" : "SUCCESS\n" + "SUCCESS",
"",
JavacTestOptions.EclipseJustification.EclipseBug126712
);
}
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=126712
// reflection - access to a public field of a package visible
// class through a public extending class
public void test0601_reflection() {
this.runConformTest(
new String[] {
"X.java",
"import java.lang.reflect.*;\n" +
"import p.*;\n" +
"public class X {\n" +
"static public void main (String args[]) {\n" +
" Y y = new Y();\n" +
" try {\n" +
" Field f = Y.class.getField(\"m\");\n" +
" System.out.println(y.m);\n" +
" System.out.println(f.get(y));\n" +
" } catch (NoSuchFieldException e) {\n" +
" //ignore\n" +
" } catch (IllegalAccessException e) {\n" +
" System.out.print(\"FAILURE: IllegalAccessException\");\n" +
" }\n" +
"}\n" +
"}",
"p/Y.java",
"package p;\n" +
"public class Y extends Z {\n" +
" /* empty */\n" +
"}\n",
"p/Z.java",
"package p;\n" +
"class Z {\n" +
" public String m = \"SUCCESS\";\n" +
"}\n"},
"SUCCESS\n" +
"FAILURE: IllegalAccessException"
);
}
// partial rebuild - method signature changed (return type)
public void test1000_partial_rebuild() {
this.runConformTest(
new String[] {
"X.java",
"public class X {\n" +
"static public void main(String args[]) {\n" +
" Z.go();\n" +
"}\n" +
"}\n",
"Z.java",
"public class Z {\n" +
"static public void go() {\n" +
" int flag = 0;\n" +
" try {\n" +
" new Y().random();\n" +
" flag = 1;\n" +
" }\n" +
" catch (NoSuchMethodError e) {\n" +
" flag = 2;\n" +
" }\n" +
" catch (Throwable t) {\n" +
" flag = 3;\n" +
" }\n" +
" System.out.println(flag);\n" +
"}\n" +
"}\n",
"Y.java",
"public class Y {\n" +
"java.util.Random generator = new java.util.Random();" +
"public byte random() {\n" +
" return (byte) (generator.nextInt() % Byte.MAX_VALUE);\n" +
"}\n" +
"}\n",
},
"1");
this.runConformTest(
new String[] {
"X.java",
"public class X {\n" +
"static public void main(String args[]) {\n" +
" Z.go();\n" +
"}\n" +
"}\n",
"Y.java",
"public class Y {\n" +
"java.util.Random generator = new java.util.Random();" +
"public int random() {\n" + // random now returns an int
" return generator.nextInt();\n" +
"}\n" +
"}\n",
},
"2",
null,
false, // do not purge output directory - pick old version of Z.class
null);
}
// partial rebuild - method signature changed (parameter type)
public void test1001_partial_rebuild() {
this.runConformTest(
new String[] {
"X.java",
"public class X {\n" +
"static public void main(String args[]) {\n" +
" Z.go();\n" +
"}\n" +
"}\n",
"Z.java",
"public class Z {\n" +
"static public void go() {\n" +
" byte flag = 0;\n" +
" try {\n" +
" new Y().random(flag);\n" +
" flag = 1;\n" +
" }\n" +
" catch (NoSuchMethodError e) {\n" +
" flag = 2;\n" +
" }\n" +
" catch (Throwable t) {\n" +
" flag = 3;\n" +
" }\n" +
" System.out.println(flag);\n" +
"}\n" +
"}\n",
"Y.java",
"public class Y {\n" +
"public int random(byte seed) {\n" +
" return seed++;\n" +
"}\n" +
"}\n",
},
"1");
this.runConformTest(
new String[] {
"X.java",
"public class X {\n" +
"static public void main(String args[]) {\n" +
" Z.go();\n" +
"}\n" +
"}\n",
"Y.java",
"public class Y {\n" +
"public int random(int seed) {\n" + // seed now of type int
" return seed++;\n" +
"}\n" +
"}\n",
},
"2",
null,
false, // do not purge output directory - pick old version of Z.class
null);
}
// partial rebuild - method signature changed (visibility)
public void test1002_partial_rebuild() {
this.runConformTest(
new String[] {
"X.java",
"public class X {\n" +
"static public void main(String args[]) {\n" +
" new Z().go();\n" +
"}\n" +
"}\n",
"Z.java",
"public class Z extends p.Y {\n" +
" class ZInner extends YInner {\n" +
" // empty\n" +
" }\n" +
"public void go() {\n" +
" byte flag = 0;\n" +
" try {\n" +
" new ZInner().foo();\n" +
" flag = 1;\n" +
" }\n" +
" catch (IllegalAccessError e) {\n" +
" flag = 2;\n" +
" }\n" +
" catch (Throwable t) {\n" +
" flag = 3;\n" +
" }\n" +
" System.out.println(flag);\n" +
"}\n" +
"}\n",
"p/Y.java",
"package p;\n" +
"public class Y {\n" +
" public class YInner {\n" +
" public void foo() {\n" +
" return;\n" +
" }\n" +
" }\n" +
"}\n",
},
"1");
this.runConformTest(
false,
new String[] {
"X.java",
"public class X {\n" +
"static public void main(String args[]) {\n" +
" new Z().go();\n" +
"}\n" +
"}\n",
"p/Y.java",
"package p;\n" +
"public class Y {\n" +
" public class YInner {\n" +
" void foo() {\n" + // now foo no more visible (package only)
" return;\n" +
" }\n" +
" }\n" +
"}\n",
},
"",
"2",
"",
JavacTestOptions.JavacHasABug.JavacBugFixed_6_10);
}
// partial rebuild - method signature changed (visibility)
public void test1003_partial_rebuild() {
this.runConformTest(
new String[] {
"X.java",
"public class X {\n" +
"static public void main(String args[]) {\n" +
" new Z().go();\n" +
"}\n" +
"}\n",
"Z.java",
"public class Z extends p.Y {\n" +
" class ZInner extends YInner {\n" +
" // empty\n" +
" }\n" +
"public void go() {\n" +
" byte flag = 0;\n" +
" try {\n" +
" new ZInner().foo();\n" +
" flag = 1;\n" +
" }\n" +
" catch (IllegalAccessError e) {\n" +
" flag = 2;\n" +
" }\n" +
" catch (Throwable t) {\n" +
" flag = 3;\n" +
" }\n" +
" System.out.println(flag);\n" +
"}\n" +
"}\n",
"p/Y.java",
"package p;\n" +
"public class Y {\n" +
" public class YInner {\n" +
" public void foo() {\n" +
" return;\n" +
" }\n" +
" }\n" +
"}\n",
},
"1");
this.runConformTest(
false, // do not purge output directory - pick old version of Z.class
new String[] {
"X.java",
"public class X {\n" +
"static public void main(String args[]) {\n" +
" new Z().go();\n" +
"}\n" +
"}\n",
"p/Y.java",
"package p;\n" +
"public class Y {\n" +
" public class YInner {\n" +
" protected void foo() {\n" +
// now foo no more visible (package + inheriting classes only)
" return;\n" +
" }\n" +
" }\n" +
"}\n",
},
"",
"2",
"",
JavacTestOptions.JavacHasABug.JavacBugFixed_6_10);
}
// partial rebuild - extending class now redefines extended class fields and
// methods
// was Compliance_1_x#test009
public void test1004_partial_rebuild() {
this.runConformTest(
new String[] {
"p1/Z.java",
"package p1; \n"+
"public class Z { \n" +
" public static void main(String[] arguments) { \n"+
" Y y = new Y(); \n" +
" System.out.print(y.field); \n" +
" System.out.print(y.staticField); \n" +
" System.out.print(y.method()); \n" +
" System.out.println(y.staticMethod()); \n" +
" } \n"+
"} \n",
"p1/X.java",
"package p1; \n"+
"public class X { \n"+
" public String field = \"X.field-\"; \n" +
" public static String staticField = \"X.staticField-\"; \n" +
" public String method(){ return \"X.method()-\"; } \n" +
" public static String staticMethod(){ return \"X.staticMethod()-\"; } \n" +
"} \n",
"p1/Y.java",
"package p1; \n"+
"public class Y extends X { \n"+
"} \n"
},
"X.field-X.staticField-X.method()-X.staticMethod()-");
String expectedOutput =
this.complianceLevel == ClassFileConstants.JDK1_3 ?
"X.field-X.staticField-Y.method()-X.staticMethod()-" :
"Y.field-Y.staticField-Y.method()-Y.staticMethod()-";
this.runConformTest(
new String[] {
"p1/Y.java",
"package p1; \n"+
"public class Y extends X { \n"+
" public static void main(String[] arguments) { \n"+
" Z.main(arguments); \n" +
" } \n" +
" public String field = \"Y.field-\"; \n" +
" public static String staticField = \"Y.staticField-\"; \n" +
" public String method(){ return \"Y.method()-\"; } \n" +
" public static String staticMethod(){ return \"Y.staticMethod()-\"; } \n" +
"} \n"
},
expectedOutput, // expected output
null, // use default class-path
false, // do not flush previous output dir content
null); // no special vm args
}
}