JlsTest.java
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2019 Arno Unkrig. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// SUPPRESS CHECKSTYLE JavadocMethod|MethodName:9999
package org.codehaus.commons.compiler.tests;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.codehaus.commons.compiler.IClassBodyEvaluator;
import org.codehaus.commons.compiler.ICompilerFactory;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import util.CommonsCompilerTestSuite;
import util.TestUtil;
/**
* Tests against the <a href="http://docs.oracle.com/javase/specs/">Java Language Specification, Java SE 7 Edition</a>.
*/
@RunWith(Parameterized.class) public
class JlsTest extends CommonsCompilerTestSuite {
@Parameters(name = "CompilerFactory={0}") public static List<Object[]>
compilerFactories() throws Exception {
return TestUtil.getCompilerFactoriesForParameters();
}
public
JlsTest(ICompilerFactory compilerFactory) throws Exception {
super(compilerFactory);
}
@SuppressWarnings("static-method")
@Before public void
setUp() throws Exception {
// Optionally print class file disassemblies to the console.
if (Boolean.getBoolean("disasm")) {
Logger scl = Logger.getLogger("org.codehaus.janino.UnitCompiler");
for (Handler h : scl.getHandlers()) h.setLevel(Level.FINEST);
scl.setLevel(Level.FINEST);
}
}
@Test public void
test_3__Lexical_Structure() throws Exception {
// 3.1. Lexical Structure -- Unicode
this.assertExpressionEvaluatesTrue("'\\u00e4' == '\u00e4'");
// 3.2. Lexical Structure -- Translations
this.assertScriptUncookable("3--4");
// 3.3. Lexical Structure -- Unicode Escapes
this.assertExpressionUncookable("aaa\\u123gbbb");
this.assertExpressionEvaluatesTrue("\"\\u0041\".equals(\"A\")");
this.assertExpressionEvaluatesTrue("\"\\uu0041\".equals(\"A\")");
this.assertExpressionEvaluatesTrue("\"\\uuu0041\".equals(\"A\")");
this.assertExpressionEvaluatesTrue("\"\\\\u0041\".equals(\"\\\\\" + \"u0041\")");
this.assertExpressionEvaluatesTrue("\"\\\\\\u0041\".equals(\"\\\\\" + \"A\")");
// 3.3. Lexical Structure -- Line Terminators
this.assertExpressionEvaluatesTrue("1//\r+//\r\n2//\n==//\n\r3");
// 3.6. Lexical Structure -- White Space
this.assertExpressionEvaluatesTrue("3\t\r \n==3");
// 3.7. Lexical Structure -- Comments
this.assertExpressionEvaluatesTrue("7/* */==7");
this.assertExpressionEvaluatesTrue("7/**/==7");
this.assertExpressionEvaluatesTrue("7/***/==7");
this.assertExpressionUncookable("7/*/==7");
this.assertExpressionEvaluatesTrue("7/*\r*/==7");
this.assertExpressionEvaluatesTrue("7//\r==7");
this.assertExpressionEvaluatesTrue("7//\n==7");
this.assertExpressionEvaluatesTrue("7//\r\n==7");
this.assertExpressionEvaluatesTrue("7//\n\r==7");
this.assertScriptUncookable("7// /*\n\rXXX*/==7");
// 3.8. Lexical Structure -- Identifiers
this.assertScriptExecutable("int a;");
this.assertScriptExecutable("int \u00e4\u00e4\u00e4;");
this.assertScriptExecutable("int \\u0391;"); // Greek alpha
this.assertScriptExecutable("int _aaa;");
this.assertScriptExecutable("int $aaa;");
this.assertScriptUncookable("int 9aaa;");
this.assertScriptUncookable("int const;");
}
@Test public void
test_3_10_1__Integer_Literals_decimal() throws Exception {
this.assertExpressionEvaluatesTrue("17 == 17L");
}
@Test public void
test_3_10_1__Integer_Literals_hex() throws Exception {
this.assertExpressionEvaluatesTrue("255 == 0xFFl");
}
@Test public void
test_3_10_1__Integer_Literals_octal() throws Exception {
this.assertExpressionEvaluatesTrue("17 == 021L");
this.assertExpressionUncookable(
"17 == 029",
"Digit '9' not allowed in octal literal|compiler.err.int.number.too.large|';' expected"
);
}
@Test public void
test_3_10_1__Integer_Literals_int_range() throws Exception {
this.assertExpressionEvaluatesTrue("2 * 2147483647 == -2");
this.assertExpressionEvaluatesTrue("2 * -2147483648 == 0");
this.assertExpressionUncookable("2147483648");
this.assertExpressionEvaluatable("-2147483648");
this.assertExpressionEvaluatesTrue("-1 == 0xffffffff");
this.assertExpressionEvaluatesTrue("1 == -0xffffffff");
this.assertExpressionEvaluatesTrue("-0xf == -15");
// https://github.com/janino-compiler/janino/issues/41 :
this.assertExpressionEvaluatesTrue("-(-2147483648) == -2147483648");
this.assertExpressionEvaluatesTrue("- -2147483648 == -2147483648");
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION >= 7) {
this.assertExpressionEvaluatesTrue("- -2147_483648 == -2147483648");
}
}
@Test public void
test_3_10_1__Integer_Literals_long_range() throws Exception {
this.assertExpressionEvaluatable("9223372036854775807L");
this.assertExpressionUncookable("9223372036854775808L");
this.assertExpressionUncookable("9223372036854775809L");
this.assertExpressionUncookable("99999999999999999999999999999L");
this.assertExpressionEvaluatable("-9223372036854775808L");
this.assertExpressionUncookable("-9223372036854775809L");
// https://github.com/janino-compiler/janino/issues/41 :
this.assertExpressionEvaluatesTrue("-(-9223372036854775808L) == -9223372036854775808L");
this.assertExpressionEvaluatesTrue("- -9223372036854775808L == -9223372036854775808L");
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION >= 7) {
this.assertExpressionEvaluatesTrue("- -922337_2036854775808L == -9223372036854775808L");
this.assertExpressionUncookable("- -9223372036854775808_L == -9223372036854775808L");
}
}
@Test public void
test_3_10_1__Integer_Literals_binary() throws Exception {
Assume.assumeFalse(this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 7);
this.assertExpressionEvaluatable("0b111");
this.assertExpressionEvaluatesTrue("0b111 == 7");
this.assertExpressionEvaluatesTrue("0b0000111 == 7");
this.assertExpressionEvaluatesTrue("0b00 == 0");
this.assertExpressionEvaluatesTrue("0b1111111111111111111111111111111 == 0x7fffffff");
this.assertExpressionEvaluatesTrue("0b10000000000000000000000000000000 == 0x80000000");
this.assertExpressionEvaluatesTrue("0b11111111111111111111111111111111 == 0xffffffff");
this.assertExpressionUncookable("0b100000000000000000000000000000000");
this.assertExpressionEvaluatesTrue("-0b1111111111111111111111111111111 == 0x80000001");
this.assertExpressionEvaluatesTrue("-0b10000000000000000000000000000000 == 0x80000000");
this.assertExpressionEvaluatesTrue("-0b11111111111111111111111111111111 == 1");
this.assertExpressionUncookable("-0b100000000000000000000000000000000");
this.assertExpressionEvaluatable("0b111111111111111111111111111111111111111111111111111111111111111L");
this.assertExpressionEvaluatable("0b1000000000000000000000000000000000000000000000000000000000000000L");
this.assertExpressionEvaluatable("0b1111111111111111111111111111111111111111111111111111111111111111L");
this.assertExpressionUncookable("0b10000000000000000000000000000000000000000000000000000000000000000L");
}
@Test public void
test_3_10_1__Integer_Literals_underscores() throws Exception {
Assume.assumeFalse(this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 7);
this.assertExpressionEvaluatesTrue("1_23 == 12_3");
this.assertExpressionEvaluatesTrue("1__3 == 13");
this.assertExpressionUncookable("_13 == 13"); // Leading underscor not allowed
this.assertExpressionUncookable("13_ == 13"); // Trailing underscore not allowed
this.assertExpressionEvaluatesTrue("1_23L == 12_3L");
this.assertExpressionEvaluatesTrue("1__3L == 13L");
this.assertExpressionUncookable("_13L == 13L"); // Leading underscor not allowed
this.assertExpressionUncookable("13_L == 13L"); // Trailing underscore not allowed
}
@Test public void
test_3_10_2__Floating_Point_Literals_float() throws Exception {
this.assertExpressionEvaluatesTrue("1e1f == 10f");
this.assertExpressionEvaluatesTrue("1E1F == 10f");
this.assertExpressionEvaluatesTrue(".3f == 0.3f");
this.assertExpressionEvaluatesTrue("0f == (float) 0");
this.assertExpressionEvaluatable("3.14f");
this.assertExpressionEvaluatable("3.40282347e+38f");
this.assertExpressionUncookable("3.40282357e+38f");
this.assertExpressionEvaluatable("1.40239846e-45f");
this.assertExpressionUncookable("7.0e-46f");
}
@Test public void
test_3_10_2__Floating_Point_Literals_double() throws Exception {
this.assertExpressionEvaluatable("1.79769313486231570e+308D");
this.assertExpressionUncookable("1.79769313486231581e+308d");
this.assertExpressionEvaluatable("4.94065645841246544e-324D");
this.assertExpressionUncookable("2e-324D");
}
/**
* Hex float literals, JLS8 3.10.2
*/
@Test public void
test_3_10_2__Floating_Point_Literals_hexadecimal() throws Exception {
this.assertExpressionEvaluatesTrue("0x1D == 29"); // "D" is NOT a float type suffix, but a hex digit!
this.assertExpressionEvaluatesTrue("0x1p0D == 1");
this.assertExpressionEvaluatesTrue("0x.8p0 == 0.5");
this.assertExpressionEvaluatesTrue("0x1p0 == 1");
this.assertExpressionEvaluatesTrue("0xfp1 == 30");
this.assertExpressionEvaluatesTrue("0xfp+1 == 30");
this.assertExpressionEvaluatesTrue("0xfp-1 == 7.5");
this.assertExpressionEvaluatesTrue("0x1.0004p0F == 0x1.0004p0");
this.assertExpressionEvaluatesTrue("0x1.0000004p0F != 0x1.0000004p0");
}
@Test public void
test_3_10_2__Floating_Point_Literals_underscores() throws Exception {
Assume.assumeFalse(this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 7);
this.assertExpressionEvaluatesTrue("1___0.1___0 == 10.1");
}
@Test public void
test_3_10_3__Boolean_Literals() throws Exception {
this.assertExpressionEvaluatesTrue("true");
this.assertExpressionEvaluatesTrue("! false");
}
@Test public void
test_3_10_4__Character_Literals() throws Exception {
this.assertExpressionEvaluatesTrue("'a' == 97");
this.assertExpressionUncookable("'''");
this.assertExpressionUncookable("'\\'");
this.assertExpressionUncookable("'\n'");
this.assertExpressionUncookable("'ax'");
this.assertExpressionUncookable("'a\n'");
this.assertExpressionEvaluatesTrue("'\"' == 34"); // Unescaped double quote is allowed!
}
@Test public void
test_3_10_5__String_Literals() throws Exception {
this.assertExpressionEvaluatesTrue("\"'\".charAt(0) == 39"); // Unescaped single quote is allowed!
// Escape sequences already tested above for character literals.
this.assertExpressionEvaluatesTrue("\"\\b\".charAt(0) == 8");
this.assertExpressionUncookable("\"aaa\nbbb\"");
this.assertExpressionUncookable("\"aaa\rbbb\"");
this.assertExpressionEvaluatesTrue("\"aaa\" == \"aaa\"");
this.assertExpressionEvaluatesTrue("\"aaa\" != \"bbb\"");
}
@Test public void
test_3_10_6__Text_Blocks_1() throws Exception {
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 15) return;
this.assertExpressionUncookable("\"\"\" a"); // No non-space allowed between leading """ and line break;
}
@Test public void
test_3_10_6__Text_Blocks_2() throws Exception {
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 15) return;
Assert.assertEquals("abc", this.evaluateExpression("\"\"\" \r abc \"\"\""));
}
@Test public void
test_3_10_6__Text_Blocks_3() throws Exception {
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 15) return;
Assert.assertEquals(
"Zeile 1\nZeile 2\nZeile 3\n",
this.evaluateExpression(
""
+ " \"\"\" \n"
+ " Zeile 1 \r" // <= Three leading spaces
+ "\t\t\tZeile 2 \n" // <= Three leading TABs
+ " \t Zeile 3\r\n" // <= Leading Space-TAB-Space
+ "\t \t \"\"\" " // <= Leading TAB-Space-TAB
)
);
}
@Test public void
test_3_10_6__Text_Blocks_4() throws Exception {
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 15) return;
Assert.assertEquals(
" Zeile 1\n\tZeile 2\n \t \tZeile 3\n",
this.evaluateExpression(
""
+ "\"\"\" \r\n"
+ " Zeile 1 \r" // <= 12 leading SPACEs
+ "\t\t\tZeile 2 \n" // <= 3 leading TABs
+ " \t \t \tZeile 3\r\n" // <= Combination of 9 leading TABs and SPACEs
+ " \"\"\" " // Two leading SPACEs
)
);
}
@Test public void
test_3_10_7__Escape_sequences_for_character_and_string_literals() throws Exception {
this.assertExpressionUncookable("'\\u000a'"); // 0x000a is LF
this.assertExpressionEvaluatesTrue("'\\b' == 8");
this.assertExpressionEvaluatesTrue("'\\t' == 9");
this.assertExpressionEvaluatesTrue("'\\n' == 10");
this.assertExpressionEvaluatesTrue("'\\f' == 12");
this.assertExpressionEvaluatesTrue("'\\r' == 13");
this.assertExpressionEvaluatesTrue("'\\\"' == 34");
this.assertExpressionEvaluatesTrue("'\\'' == 39");
this.assertExpressionEvaluatesTrue("'\\\\' == 92");
this.assertExpressionEvaluatesTrue("'\\0' == 0");
this.assertExpressionEvaluatesTrue("'\\07' == 7");
this.assertExpressionEvaluatesTrue("'\\377' == 255");
this.assertExpressionUncookable("'\\400'");
this.assertExpressionUncookable("'\\1234'");
}
@Test public void
test_3_10_8__The_null_literal() throws Exception {
this.assertExpressionEvaluatable("null");
}
@Test public void
test_3_11__Separators() throws Exception {
this.assertScriptExecutable(";");
}
@Test public void
test_3_12__Operators() throws Exception {
this.assertScriptReturnsTrue("int a = -11; a >>>= 2; return a == 1073741821;");
}
@Ignore @Test public void
test_4_5__Parameterized_Types() throws Exception {
this.assertScriptReturnsTrue("import java.util.*; Map<String, String> s = /*Collections.emptyMap()*/null; String x = s.get(\"foo\"); return x ==null;");
}
@Test public void
test_4_5_1__Type_arguments_and_wildcards() throws Exception {
this.assertScriptReturnsTrue(
""
+ "import java.util.*;\n"
+ "final List<String> l = new ArrayList();\n"
+ "l.add(\"x\");\n"
+ "final Iterator<String> it = l.iterator();\n"
+ "return it.hasNext() && \"x\".equals(it.next()) && !it.hasNext();"
);
}
@Test public void
test_5_1_7__Boxing_conversion() throws Exception {
this.assertScriptReturnsTrue("Boolean b = true; return b.booleanValue();");
this.assertScriptReturnsTrue("Boolean b = false; return !b.booleanValue();");
this.assertScriptReturnsTrue("Byte b = (byte) 7; return b.equals(new Byte((byte) 7));");
this.assertScriptReturnsTrue("Character c = 'X'; return c.equals(new Character('X'));");
this.assertScriptReturnsTrue("Short s = (short) 322; return s.equals(new Short((short) 322));");
this.assertScriptReturnsTrue("Integer i = 99; return i.equals(new Integer(99));");
this.assertScriptReturnsTrue("Long l = 733L; return l.equals(new Long(733L));");
this.assertScriptReturnsTrue("Float f = 12.5F; return f.equals(new Float(12.5F));");
this.assertScriptReturnsTrue("Double d = 14.3D; return d.equals(new Double(14.3D));");
}
@Test public void
test_5_1_8__Unboxing_conversion() throws Exception {
this.assertExpressionEvaluatesTrue("Boolean.TRUE");
this.assertExpressionEvaluatesTrue("!Boolean.FALSE");
this.assertExpressionEvaluatesTrue("new Byte((byte) 9) == (byte) 9");
this.assertExpressionEvaluatesTrue("new Character('Y') == 'Y'");
this.assertExpressionEvaluatesTrue("new Short((short) 33) == (short) 33");
this.assertExpressionEvaluatesTrue("new Integer(-444) == -444");
this.assertExpressionEvaluatesTrue("new Long(987654321L) == 987654321L");
this.assertExpressionEvaluatesTrue("new Float(33.3F) == 33.3F");
this.assertExpressionEvaluatesTrue("new Double(939.939D) == 939.939D");
}
@Test public void
test_5_2__Assignment_conversion() throws Exception {
this.assertScriptReturnsTrue("int i = 7; return i == 7;");
this.assertScriptReturnsTrue("String s = \"S\"; return s.equals(\"S\");");
this.assertScriptReturnsTrue("long l = 7; return l == 7L;");
this.assertScriptReturnsTrue("Object o = \"A\"; return o.equals(\"A\");");
this.assertScriptReturnsTrue("Integer i = 7; return i.intValue() == 7;");
this.assertScriptReturnsTrue("Object o = 7; return o.equals(new Integer(7));");
this.assertScriptReturnsTrue("int i = new Integer(7); return i == 7;");
this.assertScriptReturnsTrue("long l = new Integer(7); return l == 7L;");
this.assertScriptExecutable("byte b = -128;");
this.assertScriptUncookable("byte b = 128;");
this.assertScriptExecutable("short s = -32768;");
this.assertScriptUncookable("short s = 32768;");
this.assertScriptUncookable("char c = -1;");
this.assertScriptExecutable("char c = 0;");
this.assertScriptExecutable("char c = 65535;");
this.assertScriptUncookable("char c = 65536;");
this.assertScriptExecutable("Byte b = -128;");
this.assertScriptUncookable("Byte b = 128;");
this.assertScriptExecutable("Short s = -32768;");
this.assertScriptUncookable("Short s = 32768;");
this.assertScriptUncookable("Character c = -1;");
this.assertScriptExecutable("Character c = 0;");
this.assertScriptExecutable("Character c = 65535;");
this.assertScriptUncookable("Character c = 65536;");
}
@Test public void
test_5_5__Casting_conversion() throws Exception {
this.assertExpressionEvaluatesTrue("7 == (int) 7");
this.assertExpressionEvaluatesTrue("(int) 'a' == 97");
this.assertExpressionEvaluatesTrue("(int) 10000000000L == 1410065408");
this.assertExpressionEvaluatesTrue("((Object) \"SS\").equals(\"SS\")");
this.assertScriptReturnsTrue("Object o = \"SS\"; return ((String) o).length() == 2;");
this.assertExpressionEvaluatesTrue("((Integer) 7).intValue() == 7");
this.assertExpressionEvaluatesTrue("(int) new Integer(7) == 7");
// Boxing conversion followed by widening reference conversion - not described in JLS7, but supported by
// JAVAC. See JLS7 5.1.7, and JANINO-153.
this.assertExpressionEvaluatesTrue("null != (Comparable) 5.0");
// Unboxing conversion followed by widening primitive conversion - not described in JLS7, but supported by
// JAVAC. See JLS7 5.1.7, and JANINO-153.
this.assertExpressionEvaluatesTrue("0L != (long) new Integer(8)");
}
@Test public void
test_5_6__Number_promotions() throws Exception {
// 5.6.1 Unary Numeric Promotion
this.assertExpressionEvaluatesTrue("-new Byte((byte) 7) == -7");
this.assertExpressionEvaluatesTrue("-new Double(10.0D) == -10.0D");
this.assertScriptReturnsTrue("char c = 'a'; return -c == -97;");
// 5.6.2 Binary Numeric Promotion
this.assertExpressionEvaluatesTrue("2.5D * new Integer(4) == 10D");
this.assertExpressionEvaluatesTrue("7 % new Float(2.5F) == 2F");
this.assertExpressionEvaluatesTrue("2000000000 + 2000000000L == 4000000000L");
this.assertExpressionEvaluatesTrue("(short) 32767 + (byte) 100 == 32867");
}
@Test public void
test_6_6_1__Determining_Accessibility_member_access() throws Exception {
// SUPPRESS CHECKSTYLE Whitespace:4
this.assertExpressionEvaluatesTrue("for_sandbox_tests.ClassWithFields.publicField == 1");
this.assertExpressionUncookable ("for_sandbox_tests.ClassWithFields.protectedField == 2", "Protected member cannot be accessed|compiler.err.report.access");
this.assertExpressionUncookable ("for_sandbox_tests.ClassWithFields.packageAccessField == 3", "Member with \"package\" access cannot be accessed|compiler.err.not.def.public.cant.access");
this.assertExpressionUncookable ("for_sandbox_tests.ClassWithFields.privateField == 4", "Private member cannot be accessed|compiler.err.report.access");
}
@Test public void
test_7_5__Import_declarations() throws Exception {
// Default imports
this.assertExpressionEvaluatesTrue(
"import java.util.*; new ArrayList().getClass().getName().equals(\"java.util.ArrayList\")"
);
this.assertScriptUncookable("import java.util#;");
this.assertScriptUncookable("import java.util.9;");
this.assertScriptCookable("import java.util.*;");
this.assertClassBodyMainReturnsTrue(
"import java.util.*; public static boolean main() { return new ArrayList() instanceof List; }"
);
this.assertExpressionUncookable("import java.io.*; new ArrayList()");
// 7.5.1 Import Declarations -- Single-Type-Import
this.assertExpressionEvaluatable("import java.util.ArrayList; new ArrayList()");
this.assertExpressionEvaluatable("import java.util.ArrayList; import java.util.ArrayList; new ArrayList()");
this.assertScriptUncookable("import java.util.List; import java.awt.List;");
// 7.5.2 Import Declarations -- Import-on-Demand
this.assertExpressionEvaluatable("import java.util.*; new ArrayList()");
this.assertExpressionEvaluatable("import java.util.*; import java.util.*; new ArrayList()");
// 7.5.3 Import Declarations -- Single Static Import
this.assertExpressionEvaluatesTrue(
"import static java.util.Collections.EMPTY_SET; EMPTY_SET instanceof java.util.Set"
);
this.assertExpressionEvaluatesTrue(
"import static java.util.Collections.EMPTY_SET;"
+ "import static java.util.Collections.EMPTY_SET;"
+ "EMPTY_SET instanceof java.util.Set"
);
this.assertScriptExecutable("import static java.util.Map.Entry; Entry e;");
this.assertScriptExecutable(
"import static java.util.Map.Entry;"
+ "import static java.util.Map.Entry;"
+ "Entry e;"
);
this.assertScriptUncookable(
"import static java.util.Map.Entry;"
+ "import static java.security.KeyStore.Entry;"
+ "Entry e;"
);
this.assertExpressionEvaluatesTrue(
"import static java.util.Arrays.asList;"
+ "asList(new String[] { \"HELLO\", \"WORLD\" }).size() == 2"
);
this.assertExpressionEvaluatesTrue(
"import static java.util.Arrays.asList;"
+ "import static java.util.Arrays.asList;"
+ "asList(new String[] { \"HELLO\", \"WORLD\" }).size() == 2"
);
this.assertScriptUncookable(
"import static java.lang.Integer.decode;"
+ "import static java.lang.Long.decode;"
+ "decode(\"4000000000\");"
);
// 7.5.4 Import Declarations -- Static-Import-on-Demand
this.assertExpressionEvaluatesTrue("import static java.util.Collections.*; EMPTY_SET instanceof java.util.Set");
this.assertScriptExecutable("import static java.util.Map.*; Entry e;");
this.assertExpressionEvaluatesTrue(
"import static java.util.Arrays.*;"
+ "asList(new String[] { \"HELLO\", \"WORLD\" }).size() == 2"
);
}
@Test public void
test_8_1_1__Class_Modifiers() throws Exception {
// Modifiers for package member class:
this.assertCompilationUnitCookable("@SuppressWarnings(\"foo\") class Foo {}");
this.assertCompilationUnitCookable("abstract class Foo {}");
this.assertCompilationUnitCookable("final class Foo {}");
this.assertCompilationUnitCookable("public class Foo {}");
this.assertCompilationUnitCookable("strictfp class Foo {}");
this.assertCompilationUnitUncookable("default class Foo {}", "default not allowed|expected");
this.assertCompilationUnitUncookable("native class Foo {}", "native not allowed");
this.assertCompilationUnitUncookable("private class Foo {}", "private not allowed");
this.assertCompilationUnitUncookable("protected class Foo {}", "protected not allowed");
this.assertCompilationUnitUncookable("static class Foo {}", "static not allowed");
this.assertCompilationUnitUncookable("synchronized class Foo {}", "synchronized not allowed");
this.assertCompilationUnitUncookable("transient class Foo {}", "transient not allowed");
this.assertCompilationUnitUncookable("volatile class Foo {}", "volatile not allowed");
this.assertCompilationUnitUncookable("@SuppressWarnings(\"foo\") @SuppressWarnings(\"bar\") class Foo {}", "(?i)duplicate annotation|is not .* repeatable");
this.assertCompilationUnitUncookable("public protected class Foo {}", "allowed");
this.assertCompilationUnitUncookable("protected private class Foo {}", "allowed");
this.assertCompilationUnitUncookable("private public class Foo {}", "allowed");
this.assertCompilationUnitUncookable("abstract final class Foo {}", "Only one of abstract final is allowed|illegal combination");
}
@Test public void
test_8_1_2__Generic_Classes_and_Type_Parameters() throws Exception {
this.assertCompilationUnitMainReturnsTrue((
""
+ "public class Bag<T> {\n"
+ "\n"
+ " private T contents;\n"
+ "\n"
+ " void put(T element) { this.contents = element; }\n"
+ "\n"
+ " T get() { return this.contents; }\n"
+ "\n"
+ " public static boolean main() {\n"
+ " Bag<String> b = new Bag<String>();\n"
+ " b.put(\"FOO\");\n"
+ " String s = (String) b.get();\n"
+ " return \"FOO\".equals(s);\n"
+ " }\n"
+ "}\n"
), "Bag");
}
@Test public void
test_8_1_3__Inner_Classes_and_Enclosing_Instances() throws Exception {
this.assertCompilationUnitMainReturnsTrue((
""
+ "import org.junit.Assert;\n"
+ "\n"
+ "public class Main {\n"
+ " public static boolean\n"
+ " main() {\n"
+ " meth(1, new int[][] { { 2 } }, \"c\", new String[][] { { \"d\" } });\n"
+ " return true;\n"
+ " }\n"
+ "\n"
+ " public static boolean\n"
+ " meth(final int a, final int[] b[], final String c, final String[] d[]) {\n"
+ " final int e = 5;\n"
+ " final int[] f[] = { { 6 } };\n"
+ " final String g = \"g\";\n"
+ " final String[] h[] = { { \"h\" } };\n"
+ " new Runnable() {\n"
+ " public void run() {\n"
+ " Assert.assertEquals(1, a);\n"
+ " Assert.assertEquals(2, b[0][0]);\n"
+ " Assert.assertEquals(\"c\", c);\n"
+ " Assert.assertEquals(\"d\", d[0][0]);\n"
+ " Assert.assertEquals(5, e);\n"
+ " Assert.assertEquals(6, f[0][0]);\n"
+ " Assert.assertEquals(\"g\", g);\n"
+ " Assert.assertEquals(\"h\", h[0][0]);\n"
+ " }\n"
+ " }.run();\n"
+ " return true;\n"
+ " }\n"
+ "}\n"
), "Main");
}
@Test public void
test_8_4_8_3__Requirements_in_Overriding_and_Hiding() throws Exception {
this.assertClassBodyExecutable(
""
+ "public static interface FirstCloneable extends Cloneable {\n"
+ " public Object clone() throws CloneNotSupportedException;\n"
+ "}\n"
+ "\n"
+ "public static interface SecondCloneable extends Cloneable {\n"
+ " public SecondCloneable clone() throws CloneNotSupportedException;\n"
+ "}\n"
+ "\n"
+ "public static abstract class BaseClone implements FirstCloneable, SecondCloneable {\n"
+ " @Override public BaseClone clone() throws CloneNotSupportedException {\n"
+ " return (BaseClone)super.clone();\n"
+ " }\n"
+ "}\n"
+ "\n"
+ "public static class KidClone extends BaseClone {}\n"
+ "\n"
+ "public static void main() throws Exception {\n"
+ " new KidClone().clone();\n"
+ "}\n"
);
this.assertExpressionUncookable("new Object() { public void toString() {}}.toString()", "incompatible");
}
@Test public void
test_8_6__Instance_Initializers() throws Exception {
this.assertClassBodyMainReturnsTrue((
""
+ "public static boolean main() { return new " + IClassBodyEvaluator.DEFAULT_CLASS_NAME + "().inited; }\n"
+ "boolean inited;\n"
+ "{ this.inited = true; }\n"
));
// Inistance initializer with local variable.
// See issue #89.
this.assertClassBodyMainReturnsTrue((
""
+ "public static boolean main() { return new " + IClassBodyEvaluator.DEFAULT_CLASS_NAME + "().inited; }\n"
+ "boolean inited;\n"
+ "{ boolean b = true; this.inited = b; }\n"
));
}
@Test public void
test_8_7__Static_Initializers() throws Exception {
this.assertClassBodyMainReturnsTrue((
""
+ "public static boolean main() { return " + IClassBodyEvaluator.DEFAULT_CLASS_NAME + ".inited; }\n"
+ "static boolean inited;\n"
+ "static { " + IClassBodyEvaluator.DEFAULT_CLASS_NAME + ".inited = true; }\n"
));
// Static initializer with local variable.
this.assertClassBodyMainReturnsTrue((
""
+ "public static boolean main() { return " + IClassBodyEvaluator.DEFAULT_CLASS_NAME + ".inited; }\n"
+ "static boolean inited;\n"
+ "static { boolean b = true; " + IClassBodyEvaluator.DEFAULT_CLASS_NAME + ".inited = b; }\n"
));
}
@Test public void
test_8_9__Enums__1() throws Exception {
this.assertCompilationUnitMainReturnsTrue((
""
+ "public\n"
+ "enum Color { RED, GREEN, BLACK }\n"
+ "\n"
+ "public\n"
+ "class Main {\n"
+ "\n"
+ " public static Object\n"
+ " main() {\n"
+ " if (Color.RED.ordinal() != 0) return 1;\n"
+ " if (Color.GREEN.ordinal() != 1) return 2;\n"
+ " if (Color.BLACK.ordinal() != 2) return 3;\n"
+ " if (!\"RED\".equals(Color.RED.toString())) return Color.RED.toString();\n"
+ " if (!\"GREEN\".equals(Color.GREEN.toString())) return 5;\n"
+ " if (!\"BLACK\".equals(Color.BLACK.toString())) return 6;\n"
+ " return true;\n"
+ " }\n"
+ "}"
), "Main");
}
@Test public void
test_8_9__Enums__2() throws Exception {
this.assertCompilationUnitMainReturnsTrue((
""
+ "public\n"
+ "enum Shape {\n"
+ "\n"
+ " SQUARE(1, 2),\n"
+ " CIRCLE(3),\n"
+ " ;\n"
+ "\n"
+ " private final int length;\n"
+ " private final int width;\n"
+ "\n"
+ " Shape(int length, int width) {\n"
+ " this.length = length;\n"
+ " this.width = width;\n"
+ " }\n"
+ "\n"
+ " Shape(int size) {\n"
+ " this.length = this.width = size;\n"
+ " }\n"
+ " public int length() { return this.length; }\n"
+ " public int width() { return this.width; }\n"
+ "}\n"
+ "\n"
+ "public\n"
+ "class Main {\n"
+ "\n"
+ " public static Object\n"
+ " main() {\n"
+ " if (Shape.SQUARE.ordinal() != 0) return 100 + Shape.SQUARE.ordinal();\n"
+ " if (Shape.CIRCLE.ordinal() != 1) return 200 + Shape.CIRCLE.ordinal();\n"
+ "\n"
+ " if (!\"SQUARE\".equals(Shape.SQUARE.toString())) return 3;\n"
+ " if (!\"CIRCLE\".equals(Shape.CIRCLE.toString())) return 4;\n"
+ "\n"
+ " if (Shape.SQUARE.length() != 1) return 5;\n"
+ " if (Shape.SQUARE.width() != 2) return 6;\n"
+ " if (Shape.CIRCLE.length() != 3) return 7;\n"
+ " if (Shape.CIRCLE.width() != 3) return 8;\n"
+ "\n"
+ " return true;\n"
+ " }\n"
+ "}"
), "Main");
}
@Test public void
test_8_9__Enums__valueOf() throws Exception {
this.assertCompilationUnitMainReturnsTrue((
""
+ "public\n"
+ "enum Shape {\n"
+ "\n"
+ " SQUARE,\n"
+ " CIRCLE,\n"
+ "}\n"
+ "\n"
+ "public\n"
+ "class Main {\n"
+ "\n"
+ " public static Object\n"
+ " main() {\n"
+ " if (Shape.valueOf(\"SQUARE\") != Shape.SQUARE) return \"100\" + Shape.valueOf(\"SQUARE\");\n"
+ " if (Shape.valueOf(\"CIRCLE\") != Shape.CIRCLE) return \"200\" + Shape.valueOf(\"CIRCLE\");\n"
+ " try {\n"
+ " Shape.valueOf(\"SQUARE \");\n"
+ " return 500;\n"
+ " } catch (IllegalArgumentException iae) {\n"
+ " ;\n"
+ " }\n"
+ "\n"
+ " return true;\n"
+ " }\n"
+ "}"
), "Main");
}
@Test public void
test_8_9__Enums__values() throws Exception {
this.assertCompilationUnitMainReturnsTrue((
""
+ "public\n"
+ "enum Shape {\n"
+ "\n"
+ " SQUARE,\n"
+ " CIRCLE,\n"
+ "}\n"
+ "\n"
+ "public\n"
+ "class Main {\n"
+ "\n"
+ " public static Object\n"
+ " main() {\n"
+ " Shape[] ss = Shape.values();\n"
+ " if (ss == null) return 100;\n"
+ " if (ss.length != 2) return 200 + ss.length;\n"
+ " if (ss[0] == null) return 300;\n"
+ " if (ss[0] != Shape.SQUARE) return 400 + ss[0].toString();\n"
+ " if (ss[1] == null) return 500;\n"
+ " if (ss[1] != Shape.CIRCLE) return 600 + ss[0].toString();\n"
+ "\n"
+ " return true;\n"
+ " }\n"
+ "}"
), "Main");
}
@Test public void
test_9_3_1__Initialization_of_Fields_in_Interfaces__1() throws Exception {
this.assertClassBodyCookable("public final static double x = 0;");
this.assertClassBodyCookable("public final static double x = 0F;");
this.assertClassBodyCookable("public final static double x = 0D;");
}
@Test public void
test_9_3_1__Initialization_of_Fields_in_Interfaces__2() throws Exception {
this.assertClassBodyCookable("public final static float x = 0;");
this.assertClassBodyCookable("public final static float x = 0F;");
this.assertClassBodyUncookable("public final static float x = 0D;");
}
@Test public void
test_9_3_1__Initialization_of_Fields_in_Interfaces__3() throws Exception {
this.assertClassBodyCookable("public final static int x = 0;");
}
@Test public void
test_9_3_1__Initialization_of_Fields_in_Interfaces__4() throws Exception {
this.assertClassBodyCookable("public final static byte x = 0;");
this.assertClassBodyCookable("public final static byte x = 127;");
this.assertClassBodyUncookable("public final static byte x = 128;");
}
@Test public void
test_9_3_1__Initialization_of_Fields_in_Interfaces__5() throws Exception {
this.assertClassBodyCookable("public final static java.util.Map x = null;");
}
@Test public void
test_9_3_1__Initialization_of_Fields_in_Interfaces__6() throws Exception {
this.assertClassBodyCookable("public final static String x = null;");
this.assertClassBodyCookable("public final static String x = \"ABC\";");
this.assertClassBodyCookable("public final static String x = \"ABC\" + \"DEF\";");
}
@Test public void
test_9_4__Method_Declarations__1() throws Exception {
this.assertCompilationUnitCookable((
""
+ "public interface A {\n"
+ " A meth1();\n"
+ "}\n"
));
}
@Test public void
test_9_4__Method_Declarations__2() throws Exception {
// Static interface methods MUST declare a body.
this.assertCompilationUnitUncookable((
""
+ "public interface A {\n"
+ " static A meth1();\n"
+ "}\n"
));
}
@Test public void
test_9_4__Method_Declarations__3() throws Exception {
String cu = (
""
+ "public interface A {\n"
+ " static A meth1() { return null; }\n"
+ "}\n"
+ "\n"
+ "public\n"
+ "class Main {\n"
+ "\n"
+ " public static Object\n"
+ " main() {\n"
+ " return A.meth1() == null;\n"
+ " }\n"
+ "}\n"
);
this.assertCompilationUnitCookable(cu, "only available for target version 8\\+|compiler\\.err\\.mod\\.not\\.allowed\\.here");
}
@Test public void
test_9_4__Method_Declarations__4() throws Exception {
// Default interface methods - a Java 8 feature.
String cu = (
""
+ "public interface A { default boolean isTrue() { return true; } }\n"
+ "public class B implements A {}\n"
+ "public class Foo { public static boolean main() { return new B().isTrue(); } }\n"
);
{
SimpleCompilerTest sct = new SimpleCompilerTest(cu, "Foo");
sct.setSourceVersion(7);
sct.assertUncookable((
""
+ "Default interface methods only available for source version 8+"
+ "|"
+ "default methods are not supported in -source (1\\.)?7"
+ "|"
+ "compiler\\.err\\.illegal\\.start\\.of\\.type"
));
}
if (CommonsCompilerTestSuite.JVM_VERSION <= 7 && this.isJdk) return;
{
SimpleCompilerTest sct = new SimpleCompilerTest(cu, "Foo");
sct.setSourceVersion(8);
sct.setTargetVersion(8);
if (CommonsCompilerTestSuite.JVM_VERSION < 8) {
sct.assertCookable();
} else {
sct.assertResultTrue();
}
}
}
@Test public void
test_9_4__Method_Declarations__5() throws Exception {
// Modifiers for interface method:
this.assertCompilationUnitCookable("interface Foo { @SuppressWarnings(\"foo\") void meth(); }");
this.assertCompilationUnitCookable("interface Foo { abstract void meth(); }");
this.assertCompilationUnitCookable("interface Foo { public void meth(); }");
this.assertCompilationUnitCookable("interface Foo { static void meth() {} }", "only available for target version 8\\+|modifier static not allowed");
this.assertCompilationUnitUncookable("interface Foo { final void meth(); }", "final not allowed|illegal combination");
this.assertCompilationUnitUncookable("interface Foo { native void meth(); }", "native not allowed");
this.assertCompilationUnitUncookable("interface Foo { protected void meth(); }", "protected not allowed");
this.assertCompilationUnitUncookable("interface Foo { strictfp void meth(); }", "strictfp (not|only) allowed");
this.assertCompilationUnitUncookable("interface Foo { synchronized void meth(); }", "synchronized not allowed");
this.assertCompilationUnitUncookable("interface Foo { transient void meth(); }", "transient not allowed");
this.assertCompilationUnitUncookable("interface Foo { volatile void meth(); }", "volatile not allowed");
this.assertCompilationUnitUncookable("interface Foo { @SuppressWarnings(\"foo\") @SuppressWarnings(\"bar\") void meth(); }", "(?i)duplicate.*annotation");
this.assertCompilationUnitUncookable("interface Foo { public protected void meth(); }", "allowed");
this.assertCompilationUnitUncookable("interface Foo { protected private void meth(); }", "allowed");
this.assertCompilationUnitUncookable("interface Foo { private public void meth(); }", "allowed|(?i)illegal\\.combination");
this.assertCompilationUnitUncookable("interface Foo { abstract final void meth(); }", "Only one of abstract final is allowed|illegal combination|not allowed");
}
@Test public void
test_9_4__Method_Declarations__Default_methods() throws Exception {
// Default methods (a Java 8 feature).
String cu = (
""
+ "public interface MyInterface { default boolean isTrue() { return true; } }\n"
+ "public class Foo { public static boolean main() { return new MyInterface() {}.isTrue(); } }\n"
);
{
SimpleCompilerTest sct = new SimpleCompilerTest(cu, "Foo");
sct.setSourceVersion(7);
sct.assertUncookable("Default interface methods only available for source version 8+|default methods are not supported in -source (1\\.)?7|compiler\\.err\\.illegal\\.start\\.of\\.type");
}
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 8) return;
{
SimpleCompilerTest sct = new SimpleCompilerTest(cu, "Foo");
sct.setSourceVersion(8);
sct.setTargetVersion(8);
if (CommonsCompilerTestSuite.JVM_VERSION < 8) {
sct.assertCookable();
} else {
sct.assertResultTrue();
}
}
}
@Test public void
test_9_4__Method_Declarations__Static_interface_methods() throws Exception {
// Static interface methods (a Java 8 feature).
String cu = (
""
+ "public interface MyInterface { static boolean isTrue() { return true; } }\n"
+ "public class Foo { public static boolean main() { return MyInterface.isTrue(); } }\n"
);
{
SimpleCompilerTest sct = new SimpleCompilerTest(cu, "Foo");
sct.setSourceVersion(7);
sct.assertUncookable(
""
+ "Static interface methods only available for source version 8+"
+ "|"
+ "static interface methods are not supported in -source (1\\.)?7"
+ "|"
+ "modifier static not allowed here"
);
}
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 8) return;
{
SimpleCompilerTest sct = new SimpleCompilerTest(cu, "Foo");
sct.setSourceVersion(8);
sct.setTargetVersion(8);
if (CommonsCompilerTestSuite.JVM_VERSION < 8) {
sct.assertCookable();
} else {
sct.assertResultTrue();
}
}
}
@Test public void
test_9_4__Method_Declarations__Private_interface_methods() throws Exception {
// Static interface methods (a Java 8 feature).
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 9) return; // Default methods=Java 8+, private interface mathod=Java 9+
String cu = (
""
+ "public interface MyInterface {\n"
+ " private boolean isTrue2() { return true; }\n"
+ " default boolean isTrue() { return isTrue2(); }\n"
+ "}\n"
+ "public class Foo { public static boolean main() { return new MyInterface() {}.isTrue(); } }\n"
);
{
SimpleCompilerTest sct = new SimpleCompilerTest(cu, "Foo");
sct.setSourceVersion(8);
sct.assertUncookable(
"Private interface methods only available for target version 9\\+"
+ "|private interface methods are not supported in -source 8"
+ "|modifier private not allowed here"
);
}
{
SimpleCompilerTest sct = new SimpleCompilerTest(cu, "Foo");
sct.setSourceVersion(9);
sct.setTargetVersion(9);
if (CommonsCompilerTestSuite.JVM_VERSION < 9) {
if (this.isJanino) sct.assertCookable();
} else {
sct.assertResultTrue();
}
}
}
@Test public void
test_9_6__Annotation_Types() throws Exception {
this.assertCompilationUnitMainReturnsTrue((
""
+ "public\n"
+ "@interface MyAnno {\n"
+ "}\n"
+ "\n"
+ "public\n"
+ "class Main {\n"
+ "\n"
+ " public static boolean\n"
+ " main() throws Exception {\n"
+ " Class c = Main.class.getClassLoader().loadClass(\"MyAnno\");\n"
+ "// System.out.println(c.getModifiers());\n"
+ " return c.getModifiers() == 0x2601;\n" // 2000=ANNOTATION, 400=ABSTRACT, 200=INTERFACE, 1=PUBLIC
+ " }\n"
+ "}"
), "Main");
}
@Test public void
test_9_6_2__Defaults_for_annotation_type_elements() throws Exception {
this.assertCompilationUnitMainReturnsTrue((
""
+ "import java.lang.annotation.Retention;\n"
+ "import java.lang.annotation.RetentionPolicy;\n"
+ "\n"
+ "@Retention(RetentionPolicy.RUNTIME) public\n"
+ "@interface MyAnno { boolean value() default true; }\n"
+ "\n"
+ "@MyAnno public\n"
+ "class Main {\n"
+ "\n"
+ " public static boolean\n"
+ " main() throws Exception {\n"
+ " Class mc = Main.class;\n"
+ "// System.out.printf(\"mc=%s%n\", mc.toString());\n"
+ " Class ac = MyAnno.class;\n"
+ "// System.out.printf(\"ac=%s%n\", ac.toString());\n"
+ " Object a = mc.getAnnotation(ac);\n"
+ "// System.out.printf(\"a=%s%n\", a);\n"
+ " return ((MyAnno) a).value();\n"
+ " }\n"
+ "}"
), "Main");
}
@Test public void
test_9_7_2__Marker_Annotations() throws Exception {
this.assertCompilationUnitMainReturnsTrue((
""
+ "import org.codehaus.commons.compiler.tests.annotation.RuntimeRetainedAnnotation1;\n"
+ "\n"
+ "@RuntimeRetainedAnnotation1\n"
+ "public\n"
+ "class Main {\n"
+ "\n"
+ " public static boolean\n"
+ " main() {\n"
+ " RuntimeRetainedAnnotation1 anno = (\n"
+ " (RuntimeRetainedAnnotation1) Main.class.getAnnotation(RuntimeRetainedAnnotation1.class)\n"
+ " );\n"
+ " return anno != null;\n"
+ " }\n"
+ "}"
), "Main");
}
@Test public void
test_9_7_3__Single_Element_Annotations() throws Exception {
this.assertCompilationUnitMainReturnsTrue((
""
+ "import org.codehaus.commons.compiler.tests.annotation.RuntimeRetainedAnnotation2;\n"
+ "\n"
+ "@RuntimeRetainedAnnotation2(\"Foo\")\n"
+ "public\n"
+ "class Main {\n"
+ "\n"
+ " public static boolean\n"
+ " main() {\n"
+ " RuntimeRetainedAnnotation2 anno = (\n"
+ " (RuntimeRetainedAnnotation2) Main.class.getAnnotation(RuntimeRetainedAnnotation2.class)\n"
+ " );\n"
+ " if (anno == null) throw new AssertionError(1);\n"
+ " if (!anno.value().equals(\"Foo\")) throw new AssertionError(2);\n"
+ " return true;\n"
+ " }\n"
+ "}"
), "Main");
}
@Test public void
test_9_7_1__Normal_Annotations1() throws Exception {
this.assertCompilationUnitMainReturnsTrue((
""
+ "import org.codehaus.commons.compiler.tests.annotation.RuntimeRetainedAnnotation2;\n"
+ "\n"
+ "@RuntimeRetainedAnnotation2(value = \"Bar\")\n"
+ "public\n"
+ "class Main {\n"
+ "\n"
+ " public static boolean\n"
+ " main() {\n"
+ " RuntimeRetainedAnnotation2 anno = (\n"
+ " (RuntimeRetainedAnnotation2) Main.class.getAnnotation(RuntimeRetainedAnnotation2.class)\n"
+ " );\n"
+ " if (anno == null) throw new AssertionError(1);\n"
+ " if (!anno.value().equals(\"Bar\")) throw new AssertionError(2);\n"
+ " return true;\n"
+ " }\n"
+ "}"
), "Main");
}
@Test public void
test_9_7_1__Normal_Annotations2() throws Exception {
this.assertCompilationUnitMainReturnsTrue((
""
+ "import java.util.Arrays;\n"
+ "import org.codehaus.commons.compiler.tests.annotation.RuntimeRetainedAnnotation3;\n"
+ "\n"
+ "@RuntimeRetainedAnnotation3(\n"
+ " booleanValue = true,\n"
+ " byteValue = (byte) 127,\n"
+ " shortValue = (short) 32767,\n"
+ " intValue = 99999,\n"
+ " longValue = 9999999999L,\n"
+ " floatValue = 123.5F,\n"
+ " doubleValue = 3.1415927,\n"
+ " charValue = 'X',\n"
+ " stringValue = \"Foo\",\n"
+ " classValue = String.class,\n"
+ " annotationValue = @Override,\n"
+ " stringArrayValue = { \"Foo\", \"Bar\" },\n"
+ " intArrayValue = { 1, 2, 3 }\n"
+ ")\n"
+ "public\n"
+ "class Main {\n"
+ "\n"
+ " public static boolean\n"
+ " main() {\n"
+ " RuntimeRetainedAnnotation3 anno = (\n"
+ " (RuntimeRetainedAnnotation3) Main.class.getAnnotation(RuntimeRetainedAnnotation3.class)\n"
+ " );\n"
+ " if (anno == null) throw new AssertionError(1);\n"
+ "\n"
+ " if (!anno.booleanValue()) throw new AssertionError(2);\n"
+ " if (anno.byteValue() != 127) throw new AssertionError(3);\n"
+ " if (anno.shortValue() != 32767) throw new AssertionError(4);\n"
+ " if (anno.intValue() != 99999) throw new AssertionError(5);\n"
+ " if (anno.longValue() != 9999999999L) throw new AssertionError(6);\n"
+ " if (anno.floatValue() != 123.5F) throw new AssertionError(7);\n"
+ " if (anno.doubleValue() != 3.1415927) throw new AssertionError(8);\n"
+ " if (anno.charValue() != 'X') throw new AssertionError(9);\n"
+ " if (!anno.stringValue().equals(\"Foo\")) throw new AssertionError(10);\n"
+ " if (anno.classValue() != String.class) throw new AssertionError(11);\n"
+ " if (!(anno.annotationValue() instanceof Override)) throw new AssertionError(12);\n"
+ " if (!Arrays.equals(anno.stringArrayValue(), new String[] { \"Foo\", \"Bar\" })) throw new AssertionError(13);\n"
+ " if (!Arrays.equals(anno.intArrayValue(), new int[] { 1, 2, 3 })) throw new AssertionError(14);\n"
+ " return true;\n"
+ " }\n"
+ "}"
), "Main");
}
@Test public void
test_9_7_1__Normal_Annotations3() throws Exception {
this.assertCompilationUnitMainReturnsTrue((
""
+ "import java.util.Arrays;\n"
+ "import org.codehaus.commons.compiler.tests.annotation.RuntimeRetainedAnnotation5;\n"
+ "\n"
+ "@RuntimeRetainedAnnotation5(String.class)\n"
+ "public\n"
+ "class Main {\n"
+ "\n"
+ " public static boolean\n"
+ " main() {\n"
+ " RuntimeRetainedAnnotation5 anno = (\n"
+ " (RuntimeRetainedAnnotation5) Main.class.getAnnotation(RuntimeRetainedAnnotation5.class)\n"
+ " );\n"
+ " if (anno == null) throw new AssertionError(1);\n"
+ "\n"
+ " if (!(anno.value() instanceof Class[])) throw new AssertionError(2);\n"
+ " if (!(anno.value()[0] == String.class)) throw new AssertionError(3);\n"
+ " return true;\n"
+ " }\n"
+ "}"
), "Main");
}
@Test public void
test_9_7_4__Where_Annotations_May_Appear_field() throws Exception {
this.assertCompilationUnitMainReturnsTrue((
""
+ "import org.codehaus.commons.compiler.tests.annotation.RuntimeRetainedAnnotation2;\n"
+ "\n"
+ "public\n"
+ "class Main {\n"
+ "\n"
+ " @RuntimeRetainedAnnotation2(\"Foo\") public int field;\n"
+ "\n"
+ " public static boolean\n"
+ " main() throws Exception {\n"
+ " RuntimeRetainedAnnotation2 anno = ((RuntimeRetainedAnnotation2) Main.class.getField(\n"
+ " \"field\"\n"
+ " ).getAnnotation(RuntimeRetainedAnnotation2.class));\n"
+ " if (anno == null) throw new AssertionError(1);\n"
+ " if (!anno.value().equals(\"Foo\")) throw new AssertionError(2);\n"
+ " return true;\n"
+ " }\n"
+ "}"
), "Main");
}
@Test public void
test_9_7_4__Where_Annotations_May_Appear_method() throws Exception {
this.assertCompilationUnitMainReturnsTrue((
""
+ "import org.codehaus.commons.compiler.tests.annotation.RuntimeRetainedAnnotation2;\n"
+ "\n"
+ "public\n"
+ "class Main {\n"
+ "\n"
+ " @RuntimeRetainedAnnotation2(\"Foo\") public void method() {}\n"
+ "\n"
+ " public static boolean\n"
+ " main() throws Exception {\n"
+ " RuntimeRetainedAnnotation2 anno = ((RuntimeRetainedAnnotation2) Main.class.getMethod(\n"
+ " \"method\"\n"
+ " ).getAnnotation(RuntimeRetainedAnnotation2.class));\n"
+ " if (anno == null) throw new AssertionError(1);\n"
+ " if (!anno.value().equals(\"Foo\")) throw new AssertionError(2);\n"
+ " return true;\n"
+ " }\n"
+ "}"
), "Main");
}
@Test public void
test_10_6__Array_Initializers() throws Exception {
this.assertCompilationUnitCookable(
""
+ "class Foo {\n"
+ " String[] sa = { \"a\", \"b\" };\n"
+ " String sa2[] = { \"a\", \"b\" };\n"
+ " void meth() {\n"
+ " Number[] na = { 1, 2, 3.3 };\n"
+ " Number na2[] = { 1, 2, 3.3 };\n"
+ " }\n"
+ "}\n"
);
}
@Test public void
test_14_3__Local_class_declarations() throws Exception {
this.assertScriptReturnsTrue(
"class S2 extends SC { public int foo() { return 37; } }; return new S2().foo() == 37;"
);
}
@Test public void
test_14_4__Local_Variable_Declaration_Statements() throws Exception {
this.assertScriptReturnsTrue(
"class S2 extends SC { public int foo() { return 37; } }; return new S2().foo() == 37;"
);
String script = "var f = java.util.function.Function.<String>identity();\n";
if (this.isJanino) this.assertScriptUncookable(script, "NYI");
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION >= 10) this.assertScriptExecutable(script);
}
@Test public void
test_14_8__Expression_statements() throws Exception {
this.assertScriptReturnsTrue("int a; a = 8; ++a; a++; if (a != 10) return false; --a; a--; return a == 8;");
this.assertScriptExecutable("System.currentTimeMillis();");
this.assertScriptExecutable("new Object();");
this.assertScriptUncookable("new Object[3];", "not a statement|not allowed as an expression statement");
this.assertScriptUncookable("int a; a;", "not a statement|not allowed as an expression statement");
}
@Test public void
test_14_10__The_assert_statement() throws Exception {
this.assertScriptExecutable("assert true;");
this.assertScriptReturnsTrue("try { assert false; } catch (AssertionError ae) { return true; } return false;");
this.assertScriptReturnsTrue("try { assert false : \"x\"; } catch (AssertionError ae) { return \"x\".equals(ae.getMessage()); } return false;");
this.assertScriptReturnsTrue("try { assert false : 3; } catch (AssertionError ae) { return \"3\".equals(ae.getMessage()); } return false;");
this.assertScriptReturnsTrue("try { assert false : new Integer(8); } catch (AssertionError ae) { return \"8\".equals(ae.getMessage()); } return false;");
}
@Test public void
test_14_11__The_switch_statement() throws Exception {
this.assertScriptReturnsTrue("int x = 37; switch (x) {} return x == 37;");
this.assertScriptReturnsTrue("int x = 37; switch (x) { default: ++x; break; } return x == 38;");
this.assertScriptReturnsTrue(
"int x = 37; switch (x) { case 36: case 37: case 38: x += x; break; } return x == 74;"
);
this.assertScriptReturnsTrue(
"int x = 37; switch (x) { case 36: case 37: case 1000: x += x; break; } return x == 74;"
);
this.assertScriptReturnsTrue(
"int x = 37; switch (x) { case -10000: break; case 10000: break; } return x == 37;"
);
this.assertScriptReturnsTrue(
"int x = 37; switch (x) { case -2000000000: break; case 2000000000: break; } return x == 37;"
);
}
@Test public void
test_14_11__The_switch_statement_enum() throws Exception {
this.assertScriptReturnsTrue(
""
+ "import java.lang.annotation.ElementType;\n"
+ "\n"
+ "ElementType x = ElementType.FIELD;\n"
+ "switch (x) {\n"
+ "case ANNOTATION_TYPE:\n"
+ " return false;\n"
+ "case FIELD:\n"
+ " return true;\n"
+ "default:\n"
+ " break;\n"
+ "}\n"
+ "return false;"
);
}
@Test public void
test_14_11__The_switch_statement_String1() throws Exception {
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 7) return;
this.assertScriptReturnsTrue(
""
+ "String s = \"a\";\n"
+ "\n"
+ "switch (s) {\n"
+ "case \"a\": case \"b\": case \"c\":\n"
+ " return true;\n"
+ "case \"d\": case \"e\": case \"f\":\n"
+ " return false;\n"
+ "default:\n"
+ " return false;"
+ "}\n"
);
}
@Test public void
test_14_11__The_switch_statement_String2() throws Exception {
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 7) return;
this.assertScriptReturnsTrue(
""
+ "String s = \"f\";\n"
+ "\n"
+ "switch (s) {\n"
+ "case \"a\": case \"b\": case \"c\":\n"
+ " return false;\n"
+ "case \"d\": case \"e\": case \"f\":\n"
+ " return true;\n"
+ "default:\n"
+ " return false;"
+ "}\n"
);
}
@Test public void
test_14_11__The_switch_statement_String3() throws Exception {
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 7) return;
this.assertScriptReturnsTrue(
""
+ "String s = \"g\";\n"
+ "\n"
+ "switch (s) {\n"
+ "case \"a\": case \"b\": case \"c\":\n"
+ " return false;\n"
+ "case \"d\": case \"e\": case \"f\":\n"
+ " return false;\n"
+ "default:\n"
+ " return true;"
+ "}\n"
);
}
@Test public void
test_14_11__The_switch_statement_String4() throws Exception {
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 7) return;
this.assertScriptReturnsTrue(
""
+ "String s = \"g\";\n"
+ "\n"
+ "switch (s) {\n"
+ "case \"a\": case \"b\": case \"c\":\n"
+ " return false;\n"
+ "case \"d\": case \"e\": case \"f\":\n"
+ " return false;\n"
+ "}\n"
+ "return true;"
);
}
@Test public void
test_14_11__The_switch_statement_String5() throws Exception {
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 7) return;
String s1 = "AaAaAa", s2 = "AaAaBB";
Assert.assertEquals(s1.hashCode(), s2.hashCode());
this.assertScriptReturnsTrue(
""
+ "switch (\"" + s1 + "\") {\n"
+ "case \"" + s1 + "\":\n"
+ " return true;\n"
+ "}\n"
+ "return false;"
);
this.assertScriptReturnsTrue(
""
+ "switch (\"" + s1 + "\") {\n"
+ "case \"" + s1 + "\":\n"
+ "case \"" + s2 + "\":\n"
+ " return true;\n"
+ "}\n"
+ "return false;"
);
this.assertScriptReturnsTrue(
""
+ "switch (\"" + s1 + "\") {\n"
+ "case \"" + s1 + "\":\n"
+ " return true;\n"
+ "case \"" + s2 + "\":\n"
+ " return false;\n"
+ "}\n"
+ "return false;"
);
this.assertScriptReturnsTrue(
""
+ "switch (\"" + s1 + "\") {\n"
+ "case \"" + s2 + "\":\n"
+ " return false;\n"
+ "}\n"
+ "return true;"
);
}
@Test public void
test_14_11__The_switch_statement_String_DuplicateCaseValue() throws Exception {
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 7) return;
this.assertScriptUncookable((
""
+ "String s = \"c\";\n"
+ "\n"
+ "switch (s) {\n"
+ "case \"a\": case \"b\": case \"c\":\n"
+ " return;\n"
+ "case \"c\": case \"d\": case \"e\":\n"
+ " return;\n"
+ "default:\n"
+ " return;"
+ "}\n"
), "(?i)Duplicate case label");
}
@Test public void
test_14_11__The_switch_statement_DefiniteAssignment() throws Exception {
this.assertScriptReturnsTrue(
""
+ "int a = 2;\n"
+ "int b; // = -99;\n" // <= Do not initialize "b" here.
+ "// This will compile into a TABLESWITCH because the case labels are so contiguous:\n"
+ "switch (a) {\n"
+ "case 0:\n"
+ " b = 0;\n"
+ " break;\n"
+ "case 1:\n"
+ " b = 11;\n"
+ " break;\n"
+ "case 2:\n"
+ " b = 22;\n"
+ " break;\n"
+ "default:\n"
+ " throw new AssertionError();\n"
+ "}\n"
+ "return b == 22;\n" // <= Is "b" initialized at this point?
);
}
@Test public void
test_14_14_2_1__The_enhanced_for_statement_Iterable1() throws Exception {
this.assertScriptReturnsTrue(
"String x = \"A\";\n"
+ "for (Object y : java.util.Arrays.asList(new String[] { \"B\", \"C\" })) x += y;\n"
+ "return x.equals(\"ABC\");"
);
}
@Test public void
test_14_14_2_1__The_enhanced_for_statement_Iterable2() throws Exception {
this.assertScriptReturnsTrue(
"String x = \"A\";\n"
+ "for (String y : java.util.Arrays.asList(new String[] { \"B\", \"C\" })) x += y.length();\n"
+ "return x.equals(\"A11\");"
);
}
@Test public void
test_14_14_2_1__The_enhanced_for_statement_Iterable3() throws Exception {
String script = (
""
+ "String x = \"A\";\n"
+ "for (var y : java.util.Arrays.asList(new String[] { \"B\", \"C\" })) x += y.length();\n"
+ "return x.equals(\"A11\");"
);
if (this.isJanino) this.assertScriptUncookable(script, "NYI");
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION >= 10) this.assertScriptReturnsTrue(script);
}
@Test public void
test_14_14_2_1__The_enhanced_for_statement_Iterable4() throws Exception {
this.assertScriptReturnsTrue(
"java.util.List<Integer> l = new java.util.ArrayList<Integer>();\n"
+ "l.add(1);\n"
+ "l.add(2);\n"
+ "l.add(3);\n"
+ "for (int i : l) {\n"
+ " if (i != 1 && i != 2 && i != 3) return false;\n"
+ "}\n"
+ "return true;\n"
);
}
@Test public void
test_14_14_2_2__The_enhanced_for_statement_Array() throws Exception {
// Primitive array.
this.assertScriptReturnsTrue(
"int x = 1; for (int y : new int[] { 1, 2, 3 }) x += x * y; return x == 24;"
);
this.assertScriptReturnsTrue(
"int x = 1; for (int y : new short[] { 1, 2, 3 }) x += x * y; return x == 24;"
);
this.assertScriptUncookable(
"int x = 1; for (short y : new int[] { 1, 2, 3 }) x += x * y;",
"conversion not possible|possible loss of precision|possible lossy conversion"
);
// Object array.
this.assertScriptReturnsTrue(
"String x = \"A\"; for (String y : new String[] { \"B\", \"C\" }) x += y; return x.equals(\"ABC\");"
);
this.assertScriptReturnsTrue(
"String x = \"A\"; for (Object y : new String[] { \"B\", \"C\" }) x += y; return x.equals(\"ABC\");"
);
this.assertScriptUncookable(
"String x = \"A\"; for (Number y : new String[] { \"B\", \"C\" }) x += y; return x.equals(\"ABC\");",
"conversion not possible|incompatible types"
);
this.assertScriptReturnsTrue(
"String x = \"A\"; String[] sa = { \"B\",\"C\" }; for (String y : sa) x += y; return x.equals(\"ABC\");"
);
this.assertScriptReturnsTrue(
""
+ "final StringBuilder sb = new StringBuilder();\n"
+ "for (final String y : new String[] { \"A\", \"B\", \"C\" }) {\n"
+ " new Runnable() {\n"
+ " public void run() { sb.append(y); }\n"
+ " }.run();\n"
+ "}\n"
+ "return sb.toString().equals(\"ABC\");"
);
}
@Test public void
test_14_15__The_break_Statement() throws Exception {
this.assertScriptReturnsTrue(
""
+ "int result = 0;\n"
+ "for (int i = 0; i < 10; i++) {\n"
+ " LABEL: {\n"
+ " if (i == 3) break LABEL;\n"
+ " if (i == 5) break;\n" // <= Breaks the FOR loop, not the labeled BREAK!
+ " result++;\n"
+ " }\n"
+ "}\n"
+ "return result == 4;\n"
);
}
@Test public void
test_14_20_1__Execution_of_try_catch__1() throws Exception {
this.assertClassBodyMainReturnsTrue(
""
+ "static void meth() throws Throwable {\n"
+ "}\n"
+ "\n"
+ "public static boolean main() { \n"
+ " try {\n"
+ " meth();\n"
+ " } catch (java.io.FileNotFoundException fnfe) {\n"
+ " return false;\n"
+ " } catch (java.io.IOException ioe) {\n"
+ " return false;\n"
+ " } catch (Exception e) {\n"
+ " return false;\n"
+ " } catch (Throwable t) {\n"
+ " return false;\n"
+ " }\n"
+ " return true;\n"
+ "}\n"
);
}
@Test public void
test_14_20_1__Execution_of_try_catch__2() throws Exception {
this.assertClassBodyUncookable(
""
+ "static void meth() throws Throwable {\n"
+ "}\n"
+ "\n"
+ "public static boolean main() { \n"
+ " try {\n"
+ " meth();\n"
+ " } catch (java.io.FileNotFoundException fnfe) {\n"
+ " return false;\n"
+ " } catch (Exception e) {\n"
+ " return false;\n"
+ " } catch (java.io.IOException ioe) {\n" // <= Hidden by preceding "catch (Exception)"
+ " return false;\n"
+ " } catch (Throwable t) {\n"
+ " return false;\n"
+ " }\n"
+ " return true;\n"
+ "}\n"
);
}
@Test public void
test_14_20_1__Execution_of_try_catch__3() throws Exception {
this.assertClassBodyMainReturnsTrue(
""
+ "static void meth() throws java.io.IOException {\n"
+ "}\n"
+ "\n"
+ "public static boolean main() { \n"
+ " try {\n"
+ " meth();\n"
+ " } catch (java.io.FileNotFoundException fnfe) {\n"
+ " return false;\n"
+ " } catch (java.io.IOException ioe) {\n"
+ " return false;\n"
+ " } catch (Exception e) {\n"
+ " return false;\n"
+ " } catch (Throwable t) {\n"
+ " return false;\n"
+ " }\n"
+ " return true;\n"
+ "}\n"
);
}
@Test public void
test_14_20_1__Execution_of_try_catch__4() throws Exception {
// JAVAC does not detect this condition although, I believe, it should, according to the
// JLS.
Assume.assumeFalse(this.isJdk);
this.assertClassBodyUncookable(
""
+ "static void meth() throws java.io.FileNotFoundException {\n"
+ "}\n"
+ "\n"
+ "public static boolean main() { \n"
+ " try {\n"
+ " meth();\n"
+ " } catch (java.io.FileNotFoundException fnfe) {\n"
+ " return false;\n"
+ " } catch (java.io.IOException ioe) {\n" // <= Not thrown by 'meth()', but JDKs 6...8 don't detect that
+ " return false;\n"
+ " } catch (Exception e) {\n"
+ " return false;\n"
+ " } catch (Throwable t) {\n"
+ " return false;\n"
+ " }\n"
+ " return true;\n"
+ "}\n"
);
}
@Test public void
test_14_20_1__Execution_of_try_catch__5() throws Exception {
this.assertClassBodyMainReturnsTrue(
""
+ "public static boolean main() { \n"
+ " try {\n"
+ " if (true) throw new java.io.IOException();\n"
+ " } catch (java.io.FileNotFoundException fnfe) {\n" // <= Not thrown by TRY block, but neither JDK 6
+ " return false;\n" // nor JANINO detect that
+ " } catch (java.io.IOException ioe) {\n"
+ " return true;\n"
+ " } catch (Exception e) {\n"
+ " return false;\n"
+ " } catch (Throwable t) {\n"
+ " return false;\n"
+ " }\n"
+ " return false;\n"
+ "}\n"
);
}
@Test public void
test_14_20_1__Execution_of_try_catch__6() throws Exception {
this.assertCompilationUnitCookable(
""
+ "public class TestIt {\n"
+ " public static class MyException extends Exception implements Runnable {\n"
+ " public MyException(String st) {\n"
+ " super(st);\n"
+ " }\n"
+ "\n"
+ " public void run() {\n"
+ " }\n"
+ " }\n"
+ "\n"
+ " public void foo() throws MyException {\n"
+ " if (true) {\n"
+ " try {\n"
+ " if (false != false) {\n"
+ " throw new MyException(\"my exc\");\n"
+ " }\n"
+ " System.out.println(\"abc\");\n"
+ " System.out.println(\"xyz\");\n"
+ "\n"
+ " } catch (MyException e) {\n"
+ " throw new java.lang.RuntimeException(e);\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "\n"
+ " public static boolean main() {\n"
+ " try {\n"
+ " new TestIt().foo();\n"
+ " } catch (MyException e) {\n"
+ " System.out.println(\"caught\");\n"
+ " }\n"
+ " return true;\n"
+ " }\n"
+ "}\n"
);
}
@Test public void
test_14_20_2__Execution_of_try_finally_and_try_catch_finally__1() throws Exception {
this.assertScriptReturnsNull(
""
+ "int x = 7;\n"
+ "//System.out.println(\"A\" + x);\n"
+ "try {\n"
+ " //System.out.println(\"B\" + x);\n"
+ " if (x != 7) return x;\n"
+ " //System.out.println(\"C\" + x);\n"
+ " x++;\n"
+ " //System.out.println(\"D\" + x);\n"
+ "} finally {\n"
+ " //System.out.println(\"E\" + x);\n"
+ " if (x != 8) return x;\n"
+ " //System.out.println(\"F\" + x);\n"
+ " x++;\n"
+ " //System.out.println(\"G\" + x);\n"
+ "}\n"
+ "//System.out.println(\"H\" + x);\n"
+ "if (x != 9) return x;\n"
+ "return null;\n"
);
}
@Test public void
test_14_20_2__Execution_of_try_finally_and_try_catch_finally__2() throws Exception {
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 7) return;
this.assertScriptExecutable(
""
+ "try {\n"
+ " int a = 7;\n"
+ "} finally {\n"
+ " ;\n"
+ "}\n"
);
}
@Test public void
test_14_20_3__try_with_resources__1() throws Exception {
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 7) return;
this.assertScriptReturnsNull(
""
+ "final int[] closed = new int[1];\n"
+ "class MyCloseable implements java.io.Closeable {\n"
+ " public void close() { closed[0]++; }\n"
+ "}\n"
+ "\n"
+ "try (MyCloseable mc = new MyCloseable()) {\n"
+ " if (closed[0] != 0) return closed[0];\n"
+ " System.currentTimeMillis();\n"
+ "}\n"
+ "if (closed[0] != 1) return closed[0];\n"
+ "return null;\n"
);
}
@Test public void
test_14_20_3__try_with_resources__2() throws Exception {
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 7) return;
this.assertScriptReturnsTrue(
""
+ "final int[] closed = new int[1];\n"
+ "class MyCloseable implements java.io.Closeable {\n"
+ " public void close() { closed[0]++; }\n"
+ "}\n"
+ "\n"
+ "try (\n"
+ " MyCloseable mc1 = new MyCloseable();\n"
+ " MyCloseable mc2 = new MyCloseable();\n"
+ " MyCloseable mc3 = new MyCloseable()\n"
+ ") {\n"
+ " if (closed[0] != 0) return false;\n"
+ " System.currentTimeMillis();\n"
+ "}\n"
+ "if (closed[0] != 3) return false;\n"
+ "return true;\n"
);
}
@Test public void
test_14_20_3__try_with_resources__2a() throws Exception {
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 7) return;
this.assertScriptExecutable(
""
+ "class MyCloseable implements java.io.Closeable {\n"
+ " public void close() {}\n"
+ "}\n"
+ "\n"
+ "try (\n"
+ " MyCloseable mc1 = new MyCloseable();\n"
+ " MyCloseable mc2 = new MyCloseable()\n"
+ ") {\n"
+ " System.currentTimeMillis();\n"
+ "}\n"
);
}
@Test public void
test_14_20_3__try_with_resources__3() throws Exception {
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 7) return;
this.assertScriptReturnsTrue(
""
+ "final int[] closed = new int[1];\n"
+ "class MyCloseable implements java.io.Closeable {\n"
+ " public void close() { closed[0]++; }\n"
+ "}\n"
+ "\n"
+ "try (\n"
+ " MyCloseable mc1 = new MyCloseable();\n"
+ " MyCloseable mc2 = null;\n"
+ " MyCloseable mc3 = new MyCloseable()\n"
+ ") {\n"
+ " if (closed[0] != 0) return false;\n"
+ " System.currentTimeMillis();\n"
+ "}\n"
+ "if (closed[0] != 2) return false;\n"
+ "return true;\n"
);
}
/**
* Tests the "enhanced try-with-resources statement" that was introduced with Java 9 with a "local variable
* declarator resource" with a local variable access.
*/
@Test public void
test_14_20_3__try_with_resources__10a() throws Exception {
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 9) return;
this.assertScriptExecutable(
""
+ "import java.io.Closeable;\n"
+ "import java.io.IOException;\n"
+ "try {\n"
+ " final int[] x = new int[1];\n"
+ " Closeable lv = new Closeable() {\n"
+ " public void close() { if (++x[0] != 2) throw new AssertionError(); }\n"
+ " };\n"
+ " \n"
+ " try (lv) {\n"
+ " if (++x[0] != 1) throw new AssertionError();\n"
+ " }\n"
+ " if (++x[0] != 3) throw new AssertionError();\n"
+ "} catch (IOException ioe) {\n"
+ " throw new AssertionError(ioe);\n"
+ "}\n"
);
}
/**
* Tests the "enhanced try-with-resources statement" that was introduced with Java 9 with a "variable access
* resource" with a static field access.
*/
@Test public void
test_14_20_3__try_with_resources__10b() throws Exception {
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 9) return;
this.assertClassBodyExecutable(
""
+ "import java.io.Closeable;\n"
+ "import java.io.IOException;\n"
+ "\n"
+ "public static final Closeable sf = new Closeable() {\n"
+ " public void close() { if (++x[0] != 2) throw new AssertionError(); }\n"
+ "};\n"
+ "public static final int[] x = new int[1];\n"
+ "\n"
+ "public static void main() {\n"
+ " try {\n"
+ " \n"
+ " try (SC.sf) {\n"
+ " if (++x[0] != 1) throw new AssertionError();\n"
+ " }\n"
+ " if (++x[0] != 3) throw new AssertionError();\n"
+ " } catch (IOException ioe) {\n"
+ " throw new AssertionError(ioe.toString());\n"
+ " }\n"
+ "}\n"
);
}
/**
* Tests the "enhanced try-with-resources statement" that was introduced with Java 9 with a "variable access
* resource" with a non-static field access.
*/
@Test public void
test_14_20_3__try_with_resources__10c() throws Exception {
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 9) return;
this.assertClassBodyExecutable(
""
+ "import java.io.Closeable;\n"
+ "import java.io.IOException;\n"
+ "\n"
+ "public final Closeable sf = new Closeable() {\n"
+ " public void close() { if (++SC.this.x[0] != 2) throw new AssertionError(); }\n"
+ "};\n"
+ "public final int[] x = new int[1];\n"
+ "\n"
+ "public void main() {\n"
+ " try {\n"
+ " \n"
+ " try (this.sf) {\n"
+ " if (++this.x[0] != 1) throw new AssertionError();\n"
+ " }\n"
+ " if (++this.x[0] != 3) throw new AssertionError();\n"
+ " } catch (IOException ioe) {\n"
+ " throw new AssertionError(ioe.toString());\n"
+ " }\n"
+ "}\n"
);
}
/**
* Tests the "enhanced try-with-resources statement" that was introduced with Java 9 with a "local variable
* declarator resource" with an invalid variable access.
*/
@Test public void
test_14_20_3__try_with_resources__10d() throws Exception {
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION < 9) return;
this.assertScriptUncookable(
(
""
+ "import java.io.Closeable;\n"
+ "import java.io.IOException;\n"
+ "import org.junit.Assert;\n"
+ "try {\n"
+ " try (new Closeable() { public void close() {} }) {\n"
+ " }\n"
+ "} catch (Exception ioe) {\n"
+ " Assert.fail(ioe.toString());\n"
+ "}\n"
),
(
"compiler.err.try.with.resources.expr.needs.var"
+ "|"
+ "NewAnonymousClassInstance rvalue not allowed as a resource"
)
);
}
@Test public void
test_14_21__Unreachable_statements() throws Exception {
this.assertClassBodyUncookable(
""
+ "public void test() throws Exception {}\n"
+ "public void test2() {\n"
+ " try {\n"
+ " test();\n"
+ " } catch (Exception e) {\n"
+ " ;\n"
+ " } catch (java.io.IOException e) {\n"
+ " // This CATCH clause is unreachable.\n"
+ " }\n"
+ "}\n"
);
this.assertClassBodyCookable(
""
+ "public void test2() {\n"
+ " try {\n"
+ " throw new java.io.IOException();\n"
+ " } catch (java.io.IOException e) {\n"
+ " ;\n"
+ " } catch (NullPointerException e) {\n"
+ " ;\n"
+ " } catch (RuntimeException e) {\n"
+ " ;\n"
+ " } catch (Exception e) {\n"
+ " ;\n"
+ " } catch (NoClassDefFoundError e) {\n"
+ " ;\n"
+ " } catch (Throwable e) {\n"
+ " ;\n"
+ " }\n"
+ "}\n"
);
}
@Test public void
test_15_2_2_5__Choosing_the_most_specific_vararg_method_1() throws Exception {
this.assertClassBodyMainReturnsTrue(
""
+ "public static boolean main() {\n"
+ " return meth(new int[][] { { 3 } }) == 1;\n"
+ "}\n"
+ "\n"
+ "static int meth(int[][]...a) {\n"
+ " return 0;\n"
+ "}\n"
+ "\n"
+ "static int meth(int[]... b) {\n"
+ " return 1;\n"
+ "}\n"
);
}
@Test public void
test_15_9_1__Determining_the_class_being_Instantiated() throws Exception {
this.assertExpressionEvaluatesTrue("new Object() instanceof Object");
this.assertExpressionUncookable("new java.util.List()");
this.assertExpressionUncookable("new other_package.PackageClass()");
this.assertExpressionUncookable("new java.util.AbstractList()");
this.assertExpressionEvaluatesTrue(
"new other_package.Foo(3).new PublicMemberClass() instanceof other_package.Foo.PublicMemberClass"
);
this.assertExpressionUncookable("new other_package.Foo(3).new Foo.PublicMemberClass()");
this.assertExpressionUncookable("new other_package.Foo(3).new other_package.Foo.PublicMemberClass()");
this.assertExpressionUncookable("new other_package.Foo(3).new PackageMemberClass()");
this.assertExpressionUncookable("new other_package.Foo(3).new PublicAbstractMemberClass()");
this.assertExpressionUncookable("new other_package.Foo(3).new PublicStaticMemberClass()");
this.assertExpressionUncookable("new other_package.Foo(3).new PublicMemberInterface()");
this.assertExpressionUncookable("new java.util.ArrayList().new PublicMemberClass()");
// The following one is tricky: A Java 6 JRE declares
// public int File.compareTo(File)
// public abstract int Comparable.compareTo(Object)
// , and yet "File" is not abstract!
this.assertCompilationUnitMainReturnsTrue((
"class MyFile extends java.io.File {\n"
+ " public MyFile() { super(\"/my/file\"); }\n"
+ "}\n"
+ "public class Main {\n"
+ " public static boolean main() {\n"
+ " return 0 == new MyFile().compareTo(new MyFile());\n"
+ " }\n"
+ "}"
), "Main");
// "Type interference for generic instance creation" (a.k.a. the "diamond operator"); a Java 7 feature.
if (this.isJdk && CommonsCompilerTestSuite.JVM_VERSION >= 7) {
this.assertScriptReturnsTrue(
"java.util.Map<String, Integer> map = new java.util.HashMap<>(); return !map.containsKey(\"\");"
);
}
}
@Test public void
test_15_9_3a__Choosing_the_Constructor_and_its_Arguments() throws Exception {
this.assertExpressionEvaluatable("new Integer(3)");
this.assertExpressionEvaluatable("new Integer(new Integer(3))");
this.assertExpressionEvaluatable("new Integer(new Byte((byte) 3))");
this.assertExpressionUncookable("new Integer(new Object())");
}
@Test public void
test_15_9_3b__Choosing_the_Constructor_and_its_Arguments() throws Exception {
// "Diamond operator".
this.assertScriptExecutable(
""
+ "import java.util.*;\n"
+ "List<String> l = new ArrayList<>();\n"
);
}
@Test public void
test_15_9_5a__Anonymous_Class_Declarations() throws Exception {
this.assertCompilationUnitMainExecutable((
""
+ "public class Foo {\n"
+ " public static void main() { new Foo().meth(); }\n"
+ " private Object meth() {\n"
+ " return new Object() {};\n"
+ " }\n"
+ "}\n"
), "Foo");
}
@Test public void
test_15_9_5b__Anonymous_Class_Declarations() throws Exception {
this.assertCompilationUnitMainExecutable((
""
+ "public class A {\n"
+ " public static void main() { new A(); }\n"
+ " public A(Object o) {}\n"
+ " public A() {\n"
+ " this(new Object() {});\n"
+ " }\n"
+ "}\n"
), "A");
}
/**
* Notice: In JLS2 and JLS7, this section had number "15.3" (which, since JLS8, is the number for section "Method
* Reference Expressions"). Since JLS8 it has number "15.10.3".
*/
@Test public void
test_15_10_3__Array_Access_Expressions() throws Exception {
this.assertExpressionCookable("(new int[3])[(byte) 0]");
this.assertExpressionCookable("(new int[3])[(char) 0]");
this.assertExpressionCookable("(new int[3])[(short) 0]");
this.assertExpressionCookable("(new int[3])[0]");
this.assertExpressionUncookable("(new int[3])[0L]");
}
@Test public void
test_15_11_2__Accessing_Superclass_Members_using_super() throws Exception {
this.assertCompilationUnitMainReturnsTrue((
""
+ "public class T1 { int x = 1; }\n"
+ "public class T2 extends T1 { int x = 2; }\n"
+ "public class T3 extends T2 {\n"
+ " int x = 3;\n"
+ " public static boolean main() {\n"
+ " return new T3().test2();\n"
+ " }\n"
+ " public boolean test2() {\n"
+ " return (\n"
+ " x == 3\n"
+ " && super.x == 2\n"
+ " && T3.super.x == 2\n"
+ "// && T2.super.x == 1\n" // <= Does not work with the SUN JDK 1.6 compiler
+ " && ((T2) this).x == 2\n"
+ " && ((T1) this).x == 1\n"
+ " );\n"
+ " }\n"
+ "}\n"
), "T3");
}
@Test public void
test_15_12_2_4__Phase3Identify_applicable_variable_arity_methods__1() throws Exception {
this.assertExpressionEvaluatesTrue("\"two one\".equals(String.format(\"%2$s %1$s\", \"one\", \"two\"))");
}
@Test public void
test_15_12_2_4__Phase3Identify_applicable_variable_arity_methods__2() throws Exception {
this.assertClassBodyMainReturnsTrue(
""
+ "public static boolean\n"
+ "main() {\n"
+ " return (\n"
+ " meth(6, 1, 2, 3)\n"
+ " && meth(10, 1, 2, 3, 4)\n"
+ " && meth(15, 1, 2, 3, 4, 5)\n"
+ " && meth(21, 1, 2, 3, 4, 5, 6)\n"
+ " );\n"
+ "}\n"
+ "\n"
+ "static boolean\n"
+ "meth(int expected, int... operands) {\n"
+ " int sum = 0;\n"
+ " for (int i = 0; i < operands.length; i++) sum += operands[i];\n"
+ " return sum == expected;\n"
+ "}\n"
);
}
@Test public void
test_15_12_2_4__Phase3Identify_applicable_variable_arity_methods__3() throws Exception {
this.assertClassBodyMainReturnsTrue(
""
+ "public static boolean main() {\n"
+ " if (meth(1, 2, 3) != 5) return false;\n"
+ " if (meth(1) != 0) return false;\n"
+ " if (meth(1, null) != 99) return false;\n"
+ " return true;\n"
+ "}\n"
+ "\n"
+ "static double meth(int x, double... va) {\n"
+ " if (va == null) return 99;\n"
+ "\n"
+ " double sum = 0;\n"
+ " for (int i = 0; i < va.length; i++) sum += va[i];\n"
+ " return sum;\n"
+ "}\n"
);
}
@Test public void
test_15_12_2_4__Phase3Identify_applicable_variable_arity_methods__4() throws Exception {
this.assertScriptReturnsTrue(
""
+ "class LocalClass {\n"
+ " int x;\n"
+ "\n"
+ " LocalClass(String s, Object... oa) {\n"
+ " x = oa.length;\n"
+ " }\n"
+ "}\n"
+ "\n"
+ "if (new LocalClass(\"\").x != 0) return false;\n"
+ "if (new LocalClass(\"\", 1, 2).x != 2) return false;\n"
+ "return true;\n"
);
}
@Test public void
test_15_12_2_5__Choose_the_Most_Specific_Method() throws Exception {
this.assertCompilationUnitUncookable(
""
+ "public class Main { public static boolean test() { return new A().meth(\"x\", \"y\"); } }\n"
+ "public class A {\n"
+ " public boolean meth(String s, Object o) { return true; }\n"
+ " public boolean meth(Object o, String s) { return false; }\n"
+ "}\n"
);
// The following case is tricky: JLS7 says that the invocation is AMBIGUOUS, but only JAVAC 1.2 issues an
// error; JAVAC 1.4.1, 1.5.0 and 1.6.0 obviously ignore the declaring type and invoke "A.meth(String)".
// JLS7 is not clear about this. For compatibility with JAVA 1.4.1, 1.5.0 and 1.6.0, JANINO also ignores the
// declaring type.
//
// See also JANINO-79 and "IClass.IInvocable.isMoreSpecificThan()".
this.assertCompilationUnitMainReturnsTrue((
""
+ "public class Main { public static boolean main() { return new B().meth(\"x\"); } }\n"
+ "public class A { public boolean meth(String s) { return true; } }\n"
+ "public class B extends A { public boolean meth(Object o) { return false; } }\n"
), "Main");
}
@Test public void
test_15_12_2_6__Identify_applicable_variable_arity_methods__4() throws Exception {
this.assertClassBodyMainReturnsTrue(
""
+ "public static boolean main() {\n"
+ " return meth((byte)1, (byte)2) == 1;\n"
+ "}\n"
+ "\n"
+ "static int meth(byte...a) {\n"
+ " return 0;\n"
+ "}\n"
+ "\n"
+ "static int meth(int a, int b){\n"
+ " return 1;\n"
+ "}\n"
+ "\n"
+ "static int meth(int a, double b){\n"
+ " return 2;\n"
+ "}\n"
);
}
@Test public void
test_15_12_2_7__Identify_applicable_variable_arity_methods__4() throws Exception {
// The resolution phases should go like this:
// - all three methods are *applicable*, but fixed-arity ones have higher priority
// (meaning the chosen one, if any, must be a fixed-arity)
// - now we are left with (int, int) and (byte, double)
// - neither of these is more specific than the other,
// therefore it is an ambiguous case
// Ref: http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2.1
//
// (Note: Some versions of javac choose the variable-arity method ("return 0"). Their reasoning seems to be
// that there is ambiguity amongst fixed-arity applicables, so picking a vararg is acceptable if that means
// there is no ambiguity. I have not been able to find any piece of documentation about this in the docs.)
// JDK 1.7.0_17 and _21 do _not_ issue an error, although they should!?
Assume.assumeFalse(this.isJdk && CommonsCompilerTestSuite.JVM_VERSION == 7);
this.assertClassBodyUncookable((
""
+ "public static Object main() {\n"
+ " return meth((byte) 1, (byte) 2);\n"
+ "}\n"
+ "\n"
+ "static int meth(byte...a) {\n"
+ " return 0;\n"
+ "}\n"
+ "\n"
+ "static int meth(int a, int b){\n"
+ " return 1;\n"
+ "}\n"
+ "\n"
+ "static int meth(byte a, double b){\n"
+ " return 2;\n"
+ "}\n"
), "Invocation of.*method.*is ambiguous|compiler\\.err\\.ref\\.ambiguous");
}
@Test public void
test_15_13__Method_reference_expressions() throws Exception {
if (CommonsCompilerTestSuite.JVM_VERSION < 9) return;
// ExpressionName '::' [ TypeArguments ] Identifier (ExpressionName = a{.b})
this.assertScriptExecutable(
"Runnable r = new Runnable() { @Override public void run() { } }; Runnable s = r::run;"
);
// Primary '::' [ TypeArguments ] Identifier
this.assertScriptExecutable(
"Runnable r = new Runnable() { @Override public void run() { } }; Runnable s = (r)::run;"
);
// ReferenceType '::' [ TypeArguments ] Identifier
this.assertScriptExecutable(
""
+ "Runnable r = new Runnable() { @Override public void run() { } };\n"
+ "Runnable t = java.util.Collections::emptySet;\n"
);
// 'super' '::' [ TypeArguments ] Identifier
// TODO
// TypeName '.' 'super' '::' [ TypeArguments ] Identifier
// TODO
// ClassType '::' [ TypeArguments ] 'new'
this.assertScriptExecutable("Runnable r4 = java.util.HashMap::new;");
// ArrayType '::' 'new'
this.assertScriptExecutable("java.util.function.Consumer<Integer> c1 = int[]::new;");
}
@Test public void
test_15_14_2__Postfix_Increment_Operator() throws Exception {
this.assertScriptReturnsTrue("int i = 7; i++; return i == 8;");
this.assertScriptReturnsTrue("Integer i = new Integer(7); i++; return i.intValue() == 8;");
this.assertScriptReturnsTrue("int i = 7; return i == 7 && i++ == 7 && i == 8;");
this.assertScriptReturnsTrue(
"Integer i = new Integer(7);"
+ "return i.intValue() == 7 && (i++).intValue() == 7 && i.intValue() == 8;"
);
// byte
this.assertScriptReturnsTrue("byte b = -1; b++; return b == 0;");
this.assertScriptReturnsTrue("byte b = 0; b++; return b == 1;");
this.assertScriptReturnsTrue("byte b = 127; b++; return b == -128;");
this.assertScriptReturnsTrue("byte b = 0; return b++ == 0;");
this.assertScriptReturnsTrue("byte b = 127; return b++ == 127;");
this.assertScriptReturnsTrue("byte b = -128; return b++ == -128;");
// short
this.assertScriptReturnsTrue("short s = -1; s++; return s == 0;");
this.assertScriptReturnsTrue("short s = 0; s++; return s == 1;");
this.assertScriptReturnsTrue("short s = 127; s++; return s == 128;");
this.assertScriptReturnsTrue("short s = 32767; s++; return s == -32768;");
this.assertScriptReturnsTrue("short s = 0; return s++ == 0;");
this.assertScriptReturnsTrue("short s = 32767; return s++ == 32767;");
this.assertScriptReturnsTrue("short s = -32768; return s++ == -32768;");
// int
this.assertScriptReturnsTrue("int i = -1; i++; return i == 0;");
this.assertScriptReturnsTrue("int i = 0; i++; return i == 1;");
this.assertScriptReturnsTrue("int i = 127; i++; return i == 128;");
this.assertScriptReturnsTrue("int i = 32767; i++; return i == 32768;");
this.assertScriptReturnsTrue("int i = Integer.MAX_VALUE; i++; return i == Integer.MIN_VALUE;");
this.assertScriptReturnsTrue("int i = 0; return i++ == 0;");
this.assertScriptReturnsTrue("int i = 32767; return i++ == 32767;");
this.assertScriptReturnsTrue("int i = -32768; return i++ == -32768;");
this.assertScriptReturnsTrue("int i = Integer.MIN_VALUE; return i++ == Integer.MIN_VALUE;");
this.assertScriptReturnsTrue("int i = Integer.MAX_VALUE; return i++ == Integer.MAX_VALUE;");
// long
this.assertScriptReturnsTrue("long i = -1; i++; return i == 0;");
this.assertScriptReturnsTrue("long i = 0; i++; return i == 1;");
this.assertScriptReturnsTrue("long i = 127; i++; return i == 128;");
this.assertScriptReturnsTrue("long i = 32767; i++; return i == 32768;");
this.assertScriptReturnsTrue("long i = Integer.MAX_VALUE; i++; return i == Integer.MAX_VALUE + 1L;");
this.assertScriptReturnsTrue("long i = Long.MAX_VALUE; i++; return i == Long.MIN_VALUE;");
this.assertScriptReturnsTrue("long i = 0; return i++ == 0;");
this.assertScriptReturnsTrue("long i = 32767; return i++ == 32767;");
this.assertScriptReturnsTrue("long i = -32768; return i++ == -32768;");
this.assertScriptReturnsTrue("long i = Integer.MIN_VALUE; return i++ == Integer.MIN_VALUE;");
this.assertScriptReturnsTrue("long i = Long.MIN_VALUE; return i++ == Long.MIN_VALUE;");
this.assertScriptReturnsTrue("long i = Long.MAX_VALUE; return i++ == Long.MAX_VALUE;");
// char
this.assertScriptReturnsTrue("char c = 0; c++; return c == 1;");
this.assertScriptReturnsTrue("char c = 127; c++; return c == 128;");
this.assertScriptReturnsTrue("char c = 255; c++; return c == 256;");
this.assertScriptReturnsTrue("char c = 32767; c++; return c == 32768;");
this.assertScriptReturnsTrue("char c = 65535; c++; return c == 0;");
this.assertScriptReturnsTrue("char c = 0; return c++ == 0;");
this.assertScriptReturnsTrue("char c = 127; return c++ == 127;");
this.assertScriptReturnsTrue("char c = 128; return c++ == 128;");
this.assertScriptReturnsTrue("char c = 255; return c++ == 255;");
this.assertScriptReturnsTrue("char c = 256; return c++ == 256;");
this.assertScriptReturnsTrue("char c = 32767; return c++ == 32767;");
this.assertScriptReturnsTrue("char c = 32768; return c++ == 32768;");
this.assertScriptReturnsTrue("char c = 65535; return c++ == 65535;");
// float
this.assertScriptReturnsTrue("float f = 3.0F; f++; return f == 4.0F;");
// double
this.assertScriptReturnsTrue("double d = 17.9; d++; return d == 18.9;");
// boolean
this.assertScriptUncookable("boolean b = true; b++;");
}
@Test public void
test_15_14_3__Postfix_Decrement_Operator() throws Exception {
this.assertScriptReturnsTrue("int i = 7; i--; return i == 6;");
this.assertScriptReturnsTrue("Integer i = new Integer(7); i--; return i.intValue() == 6;");
this.assertScriptReturnsTrue("int i = 7; return i == 7 && i-- == 7 && i == 6;");
this.assertScriptReturnsTrue(
"Integer i = new Integer(7);"
+ "return i.intValue() == 7 && (i--).intValue() == 7 && i.intValue() == 6;"
);
// byte
this.assertScriptReturnsTrue("byte b = 0; b--; return b == -1;");
this.assertScriptReturnsTrue("byte b = 1; b--; return b == 0;");
this.assertScriptReturnsTrue("byte b = -128; b--; return b == 127;");
this.assertScriptReturnsTrue("byte b = 0; return b-- == 0;");
this.assertScriptReturnsTrue("byte b = 127; return b-- == 127;");
this.assertScriptReturnsTrue("byte b = -128; return b-- == -128;");
// short
this.assertScriptReturnsTrue("short s = 0; s--; return s == -1;");
this.assertScriptReturnsTrue("short s = 1; s--; return s == 0;");
this.assertScriptReturnsTrue("short s = 128; s--; return s == 127;");
this.assertScriptReturnsTrue("short s = -32768; s--; return s == 32767;");
this.assertScriptReturnsTrue("short s = 0; return s-- == 0;");
this.assertScriptReturnsTrue("short s = 32767; return s-- == 32767;");
this.assertScriptReturnsTrue("short s = -32768; return s-- == -32768;");
// int
this.assertScriptReturnsTrue("int i = 0; i--; return i == -1;");
this.assertScriptReturnsTrue("int i = 1; i--; return i == 0;");
this.assertScriptReturnsTrue("int i = 128; i--; return i == 127;");
this.assertScriptReturnsTrue("int i = 32768; i--; return i == 32767;");
this.assertScriptReturnsTrue("int i = Integer.MIN_VALUE; i--; return i == Integer.MAX_VALUE;");
this.assertScriptReturnsTrue("int i = 0; return i-- == 0;");
this.assertScriptReturnsTrue("int i = 32767; return i-- == 32767;");
this.assertScriptReturnsTrue("int i = -32768; return i-- == -32768;");
this.assertScriptReturnsTrue("int i = Integer.MIN_VALUE; return i-- == Integer.MIN_VALUE;");
this.assertScriptReturnsTrue("int i = Integer.MAX_VALUE; return i-- == Integer.MAX_VALUE;");
// long
this.assertScriptReturnsTrue("long i = 0; i--; return i == -1;");
this.assertScriptReturnsTrue("long i = 1; i--; return i == 0;");
this.assertScriptReturnsTrue("long i = 128; i--; return i == 127;");
this.assertScriptReturnsTrue("long i = 32768; i--; return i == 32767;");
this.assertScriptReturnsTrue("long i = Integer.MAX_VALUE + 1L; i--; return i == Integer.MAX_VALUE;");
this.assertScriptReturnsTrue("long i = Long.MIN_VALUE ; i--; return i == Long.MAX_VALUE;");
this.assertScriptReturnsTrue("long i = 0; return i-- == 0;");
this.assertScriptReturnsTrue("long i = 32767; return i-- == 32767;");
this.assertScriptReturnsTrue("long i = -32768; return i-- == -32768;");
this.assertScriptReturnsTrue("long i = Integer.MIN_VALUE; return i-- == Integer.MIN_VALUE;");
this.assertScriptReturnsTrue("long i = Long.MIN_VALUE; return i-- == Long.MIN_VALUE;");
this.assertScriptReturnsTrue("long i = Long.MAX_VALUE; return i-- == Long.MAX_VALUE;");
// char
this.assertScriptReturnsTrue("char c = 1; c--; return c == 0;");
this.assertScriptReturnsTrue("char c = 128; c--; return c == 127;");
this.assertScriptReturnsTrue("char c = 256; c--; return c == 255;");
this.assertScriptReturnsTrue("char c = 32768; c--; return c == 32767;");
this.assertScriptReturnsTrue("char c = 0; c--; return c == 65535;");
this.assertScriptReturnsTrue("char c = 0; return c-- == 0;");
this.assertScriptReturnsTrue("char c = 127; return c-- == 127;");
this.assertScriptReturnsTrue("char c = 128; return c-- == 128;");
this.assertScriptReturnsTrue("char c = 255; return c-- == 255;");
this.assertScriptReturnsTrue("char c = 256; return c-- == 256;");
this.assertScriptReturnsTrue("char c = 32767; return c-- == 32767;");
this.assertScriptReturnsTrue("char c = 32768; return c-- == 32768;");
this.assertScriptReturnsTrue("char c = 65535; return c-- == 65535;");
// float
this.assertScriptReturnsTrue("float f = 4.0F; f--; return f == 3.0F;");
// double
this.assertScriptReturnsTrue("double d = 18.9; d--; return d == 17.9;");
// boolean
this.assertScriptUncookable("boolean b = true; b--;");
}
@Test public void
test_15_15_1__Prefix_Increment_Operator() throws Exception {
this.assertScriptReturnsTrue("int i = 7; ++i; return i == 8;");
this.assertScriptReturnsTrue("Integer i = new Integer(7); ++i; return i.intValue() == 8;");
this.assertScriptReturnsTrue("int i = 7; return i == 7 && ++i == 8 && i == 8;");
this.assertScriptReturnsTrue(
"Integer i = new Integer(7);"
+ "return i.intValue() == 7 && (++i).intValue() == 8 && i.intValue() == 8;"
);
// byte
this.assertScriptReturnsTrue("byte b = -1; ++b; return b == 0;");
this.assertScriptReturnsTrue("byte b = 0; ++b; return b == 1;");
this.assertScriptReturnsTrue("byte b = 127; ++b; return b == -128;");
this.assertScriptReturnsTrue("byte b = 0; return ++b == 1;");
this.assertScriptReturnsTrue("byte b = 127; return ++b == -128;");
this.assertScriptReturnsTrue("byte b = -128; return ++b == -127;");
// short
this.assertScriptReturnsTrue("short s = -1; ++s; return s == 0;");
this.assertScriptReturnsTrue("short s = 0; ++s; return s == 1;");
this.assertScriptReturnsTrue("short s = 127; ++s; return s == 128;");
this.assertScriptReturnsTrue("short s = 32767; ++s; return s == -32768;");
this.assertScriptReturnsTrue("short s = 0; return ++s == 1;");
this.assertScriptReturnsTrue("short s = 32767; return ++s == -32768;");
this.assertScriptReturnsTrue("short s = -32768; return ++s == -32767;");
// int
this.assertScriptReturnsTrue("int i = -1; ++i; return i == 0;");
this.assertScriptReturnsTrue("int i = 0; ++i; return i == 1;");
this.assertScriptReturnsTrue("int i = 127; ++i; return i == 128;");
this.assertScriptReturnsTrue("int i = 32767; ++i; return i == 32768;");
this.assertScriptReturnsTrue("int i = Integer.MAX_VALUE; ++i; return i == Integer.MIN_VALUE;");
this.assertScriptReturnsTrue("int i = 0; return ++i == 1;");
this.assertScriptReturnsTrue("int i = 32767; return ++i == 32768;");
this.assertScriptReturnsTrue("int i = -32769; return ++i == -32768;");
this.assertScriptReturnsTrue("int i = Integer.MIN_VALUE; return ++i == Integer.MIN_VALUE + 1;");
this.assertScriptReturnsTrue("int i = Integer.MAX_VALUE; return ++i == Integer.MIN_VALUE;");
// long
this.assertScriptReturnsTrue("long i = -1; ++i; return i == 0;");
this.assertScriptReturnsTrue("long i = 0; ++i; return i == 1;");
this.assertScriptReturnsTrue("long i = 127; ++i; return i == 128;");
this.assertScriptReturnsTrue("long i = 32767; ++i; return i == 32768;");
this.assertScriptReturnsTrue("long i = Integer.MAX_VALUE; ++i; return i == Integer.MAX_VALUE + 1L;");
this.assertScriptReturnsTrue("long i = Long.MAX_VALUE; ++i; return i == Long.MIN_VALUE;");
this.assertScriptReturnsTrue("long i = 0; return ++i == 1;");
this.assertScriptReturnsTrue("long i = 32767; return ++i == 32768;");
this.assertScriptReturnsTrue("long i = -32769; return ++i == -32768;");
this.assertScriptReturnsTrue("long i = Integer.MIN_VALUE - 1L; return ++i == Integer.MIN_VALUE;");
this.assertScriptReturnsTrue("long i = Long.MIN_VALUE; return ++i == Long.MIN_VALUE + 1;");
this.assertScriptReturnsTrue("long i = Long.MAX_VALUE; return ++i == Long.MIN_VALUE;");
// char
this.assertScriptReturnsTrue("char c = 0; ++c; return c == 1;");
this.assertScriptReturnsTrue("char c = 127; ++c; return c == 128;");
this.assertScriptReturnsTrue("char c = 255; ++c; return c == 256;");
this.assertScriptReturnsTrue("char c = 32767; ++c; return c == 32768;");
this.assertScriptReturnsTrue("char c = 65535; ++c; return c == 0;");
this.assertScriptReturnsTrue("char c = 0; return ++c == 1;");
this.assertScriptReturnsTrue("char c = 127; return ++c == 128;");
this.assertScriptReturnsTrue("char c = 128; return ++c == 129;");
this.assertScriptReturnsTrue("char c = 255; return ++c == 256;");
this.assertScriptReturnsTrue("char c = 256; return ++c == 257;");
this.assertScriptReturnsTrue("char c = 32767; return ++c == 32768;");
this.assertScriptReturnsTrue("char c = 32768; return ++c == 32769;");
this.assertScriptReturnsTrue("char c = 65535; return ++c == 0;");
// float
this.assertScriptReturnsTrue("float f = 3.0F; ++f; return f == 4.0F;");
// double
this.assertScriptReturnsTrue("double d = 17.9; ++d; return d == 18.9;");
// boolean
this.assertScriptUncookable("boolean b = true; ++b;");
}
@Test public void
test_15_15_2__Prefix_Decrement_Operator() throws Exception {
this.assertScriptReturnsTrue("int i = 7; --i; return i == 6;");
this.assertScriptReturnsTrue("Integer i = new Integer(7); --i; return i.intValue() == 6;");
this.assertScriptReturnsTrue("int i = 7; return i == 7 && --i == 6 && i == 6;");
this.assertScriptReturnsTrue(
"Integer i = new Integer(7);"
+ "return i.intValue() == 7 && (--i).intValue() == 6 && i.intValue() == 6;"
);
// byte
this.assertScriptReturnsTrue("byte b = 0; --b; return b == -1;");
this.assertScriptReturnsTrue("byte b = 1; --b; return b == 0;");
this.assertScriptReturnsTrue("byte b = -128; --b; return b == 127;");
this.assertScriptReturnsTrue("byte b = 0; return --b == -1;");
this.assertScriptReturnsTrue("byte b = 127; return --b == 126;");
this.assertScriptReturnsTrue("byte b = -128; return --b == 127;");
// short
this.assertScriptReturnsTrue("short s = 0; --s; return s == -1;");
this.assertScriptReturnsTrue("short s = 1; --s; return s == 0;");
this.assertScriptReturnsTrue("short s = 128; --s; return s == 127;");
this.assertScriptReturnsTrue("short s = -32768; --s; return s == 32767;");
this.assertScriptReturnsTrue("short s = 0; return --s == -1;");
this.assertScriptReturnsTrue("short s = 32767; return --s == 32766;");
this.assertScriptReturnsTrue("short s = -32768; return --s == 32767;");
// int
this.assertScriptReturnsTrue("int i = 0; --i; return i == -1;");
this.assertScriptReturnsTrue("int i = 1; --i; return i == 0;");
this.assertScriptReturnsTrue("int i = 128; --i; return i == 127;");
this.assertScriptReturnsTrue("int i = 32768; --i; return i == 32767;");
this.assertScriptReturnsTrue("int i = Integer.MIN_VALUE; --i; return i == Integer.MAX_VALUE;");
this.assertScriptReturnsTrue("int i = 0; return --i == -1;");
this.assertScriptReturnsTrue("int i = 127; return --i == 126;");
this.assertScriptReturnsTrue("int i = 128; return --i == 127;");
this.assertScriptReturnsTrue("int i = -128; return --i == -129;");
this.assertScriptReturnsTrue("int i = 32767; return --i == 32766;");
this.assertScriptReturnsTrue("int i = -32768; return --i == -32769;");
this.assertScriptReturnsTrue("int i = Integer.MIN_VALUE; return --i == Integer.MAX_VALUE;");
this.assertScriptReturnsTrue("int i = Integer.MAX_VALUE; return --i == Integer.MAX_VALUE - 1;");
// long
this.assertScriptReturnsTrue("long i = 0; --i; return i == -1;");
this.assertScriptReturnsTrue("long i = 1; --i; return i == 0;");
this.assertScriptReturnsTrue("long i = 128; --i; return i == 127;");
this.assertScriptReturnsTrue("long i = 32768; --i; return i == 32767;");
this.assertScriptReturnsTrue("long i = Integer.MAX_VALUE + 1L; --i; return i == Integer.MAX_VALUE;");
this.assertScriptReturnsTrue("long i = Long.MIN_VALUE; --i; return i == Long.MAX_VALUE;");
this.assertScriptReturnsTrue("long i = 0; return --i == -1;");
this.assertScriptReturnsTrue("long i = 32767; return --i == 32766;");
this.assertScriptReturnsTrue("long i = -32768; return --i == -32769;");
this.assertScriptReturnsTrue("long i = Integer.MIN_VALUE; return --i == Integer.MIN_VALUE - 1L;");
this.assertScriptReturnsTrue("long i = Long.MIN_VALUE; return --i == Long.MAX_VALUE;");
this.assertScriptReturnsTrue("long i = Long.MAX_VALUE; return --i == Long.MAX_VALUE - 1;");
// char
this.assertScriptReturnsTrue("char c = 1; --c; return c == 0;");
this.assertScriptReturnsTrue("char c = 128; --c; return c == 127;");
this.assertScriptReturnsTrue("char c = 256; --c; return c == 255;");
this.assertScriptReturnsTrue("char c = 32768; --c; return c == 32767;");
this.assertScriptReturnsTrue("char c = 0; --c; return c == 65535;");
this.assertScriptReturnsTrue("char c = 0; return --c == 65535;");
this.assertScriptReturnsTrue("char c = 127; return --c == 126;");
this.assertScriptReturnsTrue("char c = 128; return --c == 127;");
this.assertScriptReturnsTrue("char c = 255; return --c == 254;");
this.assertScriptReturnsTrue("char c = 256; return --c == 255;");
this.assertScriptReturnsTrue("char c = 32767; return --c == 32766;");
this.assertScriptReturnsTrue("char c = 32768; return --c == 32767;");
this.assertScriptReturnsTrue("char c = 65535; return --c == 65534;");
// float
this.assertScriptReturnsTrue("float f = 4.0F; --f; return f == 3.0F;");
// double
this.assertScriptReturnsTrue("double d = 18.9; --d; return d == 17.9;");
// boolean
this.assertScriptUncookable("boolean b = true; --b;");
}
@Test public void
test_15_15_3__Unary_Plus_Operator() throws Exception {
this.assertExpressionEvaluatesTrue("new Integer(+new Integer(7)).intValue() == 7");
}
@Test public void
test_15_15_4__Unary_Minus_Operator() throws Exception {
this.assertExpressionEvaluatesTrue("new Integer(-new Integer(7)).intValue() == -7");
}
@Test public void
test_15_17__Multiplicative_operators() throws Exception {
this.assertExpressionEvaluatesTrue("new Integer(new Byte((byte) 2) * new Short((short) 3)).intValue() == 6");
}
@Test public void
test_15_18_1__String_Concatenation_Operator_plus() throws Exception {
this.assertScriptExecutable(
""
// + " final IClassLoader\n"
+ " final Object\n"
// + " iClassLoader = new CompilerIClassLoader(this.sourceFinder, this.classFileFinder, this.getIClassLoader());\n"
+ " iClassLoader = new Object();\n"
+ "\n"
+ " // Initialize compile time fields.\n"
// + " this.parsedCompilationUnits.clear();\n"
+ " Object.class.hashCode();\n"
+ "\n"
+ " // Parse all source files.\n"
+ " for (Object sourceResource : new Object[1]) {\n"
// + "// for (int ii = 0; ii < sourceResources.length; ii++) {\n"
// + "// Resource sourceResource = sourceResources[ii];\n"
+ "\n"
// + " Compiler.LOGGER.log(Level.FINE, \"Compiling \\\"{0}\\\"\", sourceResource);\n"
+ " Object.class.hashCode();\n"
+ "\n"
+ " Object uc = new Object();\n"
// + " UnitCompiler uc = new UnitCompiler(\n"
// + " this.parseAbstractCompilationUnit(\n"
// + " sourceResource.getFileName(), // fileName\n"
// + " new BufferedInputStream(sourceResource.open()), // inputStream\n"
// + " this.sourceCharset // charset\n"
// + " ),\n"
// + " iClassLoader\n"
// + " );\n"
// + " uc.setTargetVersion(this.targetVersion);\n"
// + " uc.setCompileErrorHandler(this.compileErrorHandler);\n"
// + " uc.setWarningHandler(this.warningHandler);\n"
// + " uc.options(this.options);\n"
+ " uc.hashCode();\n"
// + "\n"
// + " this.parsedCompilationUnits.add(uc);\n"
+ " }\n"
+ "\n"
+ " // Compile all parsed compilation units. The vector of parsed CUs may grow while they are being compiled,\n"
+ " // but eventually all CUs will be compiled.\n"
+ " for (int i = 0; i < 3; ++i) {\n"
// + " UnitCompiler unitCompiler = (UnitCompiler) this.parsedCompilationUnits.get(i);\n"
+ " Object unitCompiler = (Object) \"\";\n"
// + "\n"
// + " File sourceFile;\n"
+ " Object sourceFile;\n"
+ " {\n"
// + " Java.AbstractCompilationUnit acu = unitCompiler.getAbstractCompilationUnit();\n"
// + " if (acu.fileName == null) throw new InternalCompilerException();\n"
// + " sourceFile = new File(acu.fileName);\n"
+ " sourceFile = new Object();\n"
+ " }\n"
// + "\n"
// + " unitCompiler.setTargetVersion(this.targetVersion);\n"
// + " unitCompiler.setCompileErrorHandler(this.compileErrorHandler);\n"
// + " unitCompiler.setWarningHandler(this.warningHandler);\n"
// + "\n"
// + " this.benchmark.beginReporting(\"Compiling compilation unit \\\"\" + sourceFile + \"\\\"\");\n"
// + " ClassFile[] classFiles;\n"
+ " Object[] classFiles;\n"
+ "\n"
+ " // Compile the compilation unit.\n"
// + " classFiles = unitCompiler.compileUnit(this.debugSource, this.debugLines, this.debugVars);\n"
+ " classFiles = new Object[] { \"\" };\n"
// + "\n"
+ " // Store the compiled classes and interfaces into class files.\n"
+ " new String(\n"
+ " \"Storing \"\n"
// + " + classFiles.length\n"
+ " + 7\n"
+ " + \" class file(s) resulting from compilation unit \\\"\"\n"
// + " + sourceFile\n"
+ " + new Object()\n"
+ "// + \"\\\"\"\n"
+ " );\n"
// + " for (ClassFile classFile : classFiles) this.storeClassFile(classFile, sourceFile);\n"
// + " for (Object classFile : new Object[1]) System.out.printf(\"%s%s\", classFile, sourceFile);\n"
+ " }\n"
);
}
@Test public void
test_15_18__Additive_operators() throws Exception {
// 15.18 Additive Operators -- Numeric
this.assertExpressionEvaluatesTrue("(new Byte((byte) 7) - new Double(1.5D) + \"x\").equals(\"5.5x\")");
// 15.18.1.3 Additive Operators -- String Concatentation
this.assertExpressionEvaluatesTrue(
"(\"The square root of 6.25 is \" + Math.sqrt(6.25)).equals(\"The square root of 6.25 is 2.5\")"
);
this.assertExpressionEvaluatesTrue("1 + 2 + \" fiddlers\" == \"3 fiddlers\"");
this.assertExpressionEvaluatesTrue("\"fiddlers \" + 1 + 2 == \"fiddlers 12\"");
// JAVAC does not supports "super-long string literals".
Assume.assumeFalse(this.isJdk);
for (int i = 65530; i <= 65537; ++i) {
char[] ca = new char[i];
Arrays.fill(ca, 'x');
String s1 = new String(ca);
this.assertExpressionEvaluatesTrue("\"" + s1 + "\".length() == " + i);
this.assertExpressionEvaluatesTrue("(\"" + s1 + "\" + \"XXX\").length() == " + (i + 3));
}
}
@Test public void
test_15_20__Relation_operators() throws Exception {
// 15.20.1 Numerical Comparison Operators <, <=, > and >=
this.assertExpressionEvaluatesTrue("new Integer(7) > new Byte((byte) 5)");
}
@Test public void
test_15_21__Equality_operators() throws Exception {
// 15.21.1 Numerical Equality Operators == and !=
this.assertExpressionUncookable("new Integer(7) != new Byte((byte) 5)");
this.assertExpressionEvaluatesTrue("new Integer(7) == 7");
this.assertExpressionEvaluatesTrue("new Byte((byte) -7) == -7");
this.assertExpressionEvaluatesTrue("5 == new Byte((byte) 5)");
// 15.21.2 Boolean Equality Operators == and !=
this.assertExpressionEvaluatesTrue("new Boolean(true) != new Boolean(true)");
this.assertExpressionEvaluatesTrue("new Boolean(true) == true");
this.assertExpressionEvaluatesTrue("false == new Boolean(false)");
this.assertExpressionEvaluatesTrue("false != true");
// 15.21.3 Reference Equality Operators == and !=
this.assertExpressionEvaluatesTrue("new Object() != new Object()");
this.assertExpressionEvaluatesTrue("new Object() != null");
this.assertExpressionEvaluatesTrue("new Object() != \"foo\"");
this.assertExpressionUncookable("new Integer(3) == \"foo\"");
}
@Test public void
test_15_22__Bitwise_and_logical_operators() throws Exception {
// 15.22.1 Integer Bitwise Operators &, ^, and |
this.assertExpressionEvaluatesTrue("(7 & 12) == 4");
this.assertExpressionEvaluatesTrue("(7L & 12) == 4");
this.assertExpressionUncookable("(7.0 & 12) == 4");
this.assertExpressionEvaluatesTrue("(new Long(7L) & 12) == 4");
this.assertExpressionEvaluatesTrue("(Long.valueOf(7) & Byte.valueOf((byte) 12)) == Short.valueOf((short) 4)");
this.assertExpressionUncookable("(7 & Boolean.TRUE) == 4");
// 15.22.2 Boolean Logical Operators &, ^, and |
this.assertExpressionEvaluatesTrue("new Boolean(true) & new Boolean(true)");
this.assertExpressionEvaluatesTrue("new Boolean(true) ^ false");
this.assertExpressionEvaluatesTrue("false | new Boolean(true)");
}
@Test public void
test_15_23__Conditional_and_operator() throws Exception {
// 15.23 Conditional-And Operator &&
this.assertExpressionEvaluatesTrue("new Boolean(true) && new Boolean(true)");
this.assertExpressionEvaluatesTrue("new Boolean(true) && true");
this.assertExpressionEvaluatesTrue("true && new Boolean(true)");
}
@Test public void
test_15_24__Conditional_or_operator() throws Exception {
// 15.24 Conditional-Or Operator ||
this.assertExpressionEvaluatesTrue("new Boolean(true) || new Boolean(false)");
this.assertExpressionEvaluatesTrue("new Boolean(false) || true");
this.assertExpressionEvaluatesTrue("true || new Boolean(true)");
}
/**
* 15.25 Conditional Operator ? :
*/
@Test public void
test_15_25__Conditional_operator__1() throws Exception {
this.assertExpressionEvaluatesTrue("99 == (true ? 99 : -1)");
this.assertExpressionEvaluatesTrue("-1 == (false ? 99 : -1)");
this.assertExpressionEvaluatesTrue("99 == (true ? 99 : null)");
this.assertExpressionEvaluatesTrue("null == (false ? 99 : null)");
this.assertExpressionEvaluatesTrue("null == (true ? null : 99)");
this.assertExpressionEvaluatesTrue("99 == (false ? null : 99)");
// Related to "#85 Ternary expression resolves to strange supertype":
this.assertScriptCookable(
""
+ "import java.util.*;\n"
+ "List list = true ? new ArrayList() : Arrays.asList(new String [] {});"
);
this.assertExpressionEvaluatesTrue("7 == (true ? 7 : 9)");
this.assertExpressionEvaluatesTrue("9 == (Boolean.FALSE ? 7 : 9)");
this.assertExpressionUncookable("1 ? 2 : 3)");
this.assertExpressionUncookable("true ? 2 : System.currentTimeMillis())");
// List 1, bullet 1
this.assertExpressionEvaluatesTrue("(true ? 2 : 3) == 2");
this.assertExpressionEvaluatesTrue("(true ? null : null) == null");
// List 1, bullet 2
this.assertExpressionEvaluatesTrue("(true ? 'a' : Character.valueOf('b')) == 'a'");
// List 1, bullet 3
this.assertExpressionEvaluatesTrue("(true ? \"\" : null).getClass() == String.class");
// List 1, bullet 4, bullet 1
this.assertScriptExecutable("short s = true ? (byte) 1 : (short) 2;");
// List 1, bullet 4, bullet 2
this.assertScriptUncookable("byte b = false ? (byte) 1 : -129;");
this.assertScriptExecutable("byte b = false ? (byte) 1 : -128;");
this.assertScriptExecutable("byte b = false ? (byte) 1 : 127;");
this.assertScriptUncookable("byte b = false ? (byte) 1 : 128;");
this.assertScriptUncookable("short s = false ? (short) 1 : -32769;");
this.assertScriptExecutable("short s = false ? (short) 1 : -32768;");
this.assertScriptExecutable("short s = false ? (short) 1 : 32767;");
this.assertScriptUncookable("short s = false ? (short) 1 : 32768;");
this.assertScriptUncookable("char c = false ? 'A' : -1;");
this.assertScriptExecutable("char c = false ? 'A' : 0;");
this.assertScriptExecutable("char c = false ? 'A' : 65535;");
this.assertScriptUncookable("char c = false ? 'A' : 65536;");
// List 1, bullet 4, bullet 3
this.assertScriptUncookable("byte b = false ? Byte.valueOf((byte) 1) : -129;");
this.assertScriptExecutable("byte b = false ? Byte.valueOf((byte) 1) : -128;");
this.assertScriptExecutable("byte b = false ? Byte.valueOf((byte) 1) : 127;");
this.assertScriptUncookable("byte b = false ? Byte.valueOf((byte) 1) : 128;");
this.assertScriptUncookable("short s = false ? Short.valueOf((short) 1) : -32769;");
this.assertScriptExecutable("short s = false ? Short.valueOf((short) 1) : -32768;");
this.assertScriptExecutable("short s = false ? Short.valueOf((short) 1) : 32767;");
this.assertScriptUncookable("short s = false ? Short.valueOf((short) 1) : 32768;");
this.assertScriptUncookable("char c = false ? Character.valueOf('A') : -1;");
this.assertScriptExecutable("char c = false ? Character.valueOf('A') : 0;");
this.assertScriptExecutable("char c = false ? Character.valueOf('A') : 65535;");
this.assertScriptUncookable("char c = false ? Character.valueOf('A') : 65536;");
// List 1, bullet 4, bullet 4
this.assertScriptExecutable("long l = false ? 1 : 1L;");
this.assertScriptUncookable("int i = false ? 1 : 1L;");
// List 1, bullet 5
this.assertExpressionEvaluatesTrue("(true ? new Object() : \"\") != null");
this.assertExpressionEvaluatesTrue("(true ? new Object() : 7).getClass().getName().equals(\"java.lang.Object\")");
this.assertExpressionEvaluatesTrue("(true ? new Object() : Integer.valueOf(7)).getClass().getName().equals(\"java.lang.Object\")");
this.assertExpressionEvaluatesTrue("(true ? Integer.valueOf(9) : Integer.valueOf(7)).getClass().getName().equals(\"java.lang.Integer\")");
this.assertExpressionEvaluatesTrue("(true ? Integer.valueOf(9) : Long.valueOf(7)) == 9L");
this.assertScriptCookable("import org.codehaus.commons.compiler.tests.JlsTest; (true ? new JlsTest.D1() : new JlsTest.D2()).c1();");
this.assertScriptCookable("import org.codehaus.commons.compiler.tests.JlsTest; (true ? new JlsTest.D3() : new JlsTest.D4()).c1();");
// Why, for god's sake, can JAVAC compile these assignments?? Some kind of type inference must happen here...
if (this.isJdk) {
this.assertScriptCookable("import org.codehaus.commons.compiler.tests.JlsTest; JlsTest.I1 i1 = (\"\".equals(\"\") ? new JlsTest.D3() : new JlsTest.D4());");
this.assertScriptCookable("import org.codehaus.commons.compiler.tests.JlsTest; JlsTest.I2 i2 = (true ? new JlsTest.D3() : new JlsTest.D4());");
}
this.assertScriptUncookable("import org.codehaus.commons.compiler.tests.JlsTest; JlsTest.I3 i3 = (true ? new JlsTest.D3() : new JlsTest.D4());");
// List 2, bullet 1
this.assertScriptReturnsTrue("int a = 3; return (a == 0 ? ++a : a + a) == 6;");
// List 2, bullet 2
this.assertScriptReturnsTrue("int a = 3; return (a != 0 ? ++a : a + a) == 4;");
}
public static class C1 { public void c1() {} } // SUPPRESS CHECKSTYLE Javadoc|Align:7
public static class D1 extends C1 {}
public static class D2 extends C1 {}
public interface I1 { void i1(); }
public interface I2 { void i2(); }
public interface I3 { void i3(); }
public static class D3 extends C1 implements I1, I2 { @Override public void i1() {} @Override public void i2() {} }
public static class D4 extends C1 implements I1, I2 { @Override public void i1() {} @Override public void i2() {} }
@Test public void
test_15_25__Conditional_operator__2() throws Exception {
// IScriptEvaluator eval = new ScriptEvaluator();
// eval.setReturnType(Object[].class);
String script = (
""
+ "class A {\n"
+ " private Integer val;\n"
+ " public A(Integer v) {\n"
+ " val = v;\n"
+ " }\n"
+ " public boolean isNull() {\n"
+ " return val == null;\n"
+ " }\n"
+ " public int getInt() {\n"
+ " return val;\n"
+ " }\n"
+ "}\n"
+ "A a = new A(3);\n"
+ "Object[] c = new Object[] {\n"
+ " !a.isNull() ? (Object) a.getInt() : null,\n" // auto boxing & casting in LHS
+ " !a.isNull() ? a.getInt() : null,\n" // auto boxing & no explicit casting in LHS
+ " a.isNull() ? null : (Object) a.getInt(),\n" // auto boxing & casting in RHS
+ " a.isNull() ? null : a.getInt(),\n" // auto boxing & no explicit casting in RHS
+ " (Object) \"hello\",\n" // simple casting
+ "};\n"
+ "return c;"
);
final Object[] result = (Object[]) this.assertScriptExecutable(script, Object[].class);
Assert.assertArrayEquals(new Object[] {
3,
3,
3,
3,
"hello",
}, result);
}
/**
* 15.26 Assignment Operators
*/
@Test public void
test_15_26__Assignment_operators() throws Exception {
// 15.26.2 Compound Assignment Operators
this.assertScriptReturnsTrue("int a = 7; a += 3; return a == 10;");
this.assertScriptReturnsTrue("int a = 7; a %= 3; return a == 1;");
this.assertScriptUncookable("Object a = \"foo\"; a += 3;");
this.assertScriptUncookable("int a = 7; a += \"foo\";");
this.assertScriptReturnsTrue("String a = \"foo\"; a += 3; return a.equals(\"foo3\");");
this.assertScriptReturnsTrue("String a = \"foo\"; a += 'o'; return a.equals(\"fooo\");");
this.assertScriptReturnsTrue("String a = \"foo\"; a += 1.0; return a.equals(\"foo1.0\");");
this.assertScriptReturnsTrue("String[] a = { \"foo\" }; a[0] += 1.0; return a[0].equals(\"foo1.0\");");
this.assertScriptReturnsTrue("Integer a = 7; a += 3; return a == 10;");
this.assertScriptReturnsTrue("int a = 7; a += new Integer(3); return a == 10;");
// JANINO-155: Compound assignment does not implement boxing conversion
this.assertScriptReturnsTrue("Double[] a = { 1.0, 2.0 }; a[0] += 1.0; return a[0] == 2.0;");
}
@Test public void
test_15_27_1__Lambda_parameters() throws Exception {
// "java.util.Function" only since Java 10.
if (CommonsCompilerTestSuite.JVM_VERSION < 10) return;
this.assertScriptExecutable("java.util.function.Function<String, Integer> f = (var s) -> s.length();\n");
}
@Test public void
test_16_2_13__break_yield_continue_return_and_throw_Statements() throws Exception {
this.assertClassBodyMainReturnsTrue(
""
+ "public static boolean\n"
+ "main() {\n"
+ " String s;\n"
+ " if (System.currentTimeMillis() == 7) {\n"
+ " s = \"seven\";\n"
+ " } else\n"
+ " if (System.currentTimeMillis() != 8) {\n"
+ " s = \"not eight\";\n"
+ " } else\n"
+ " {\n"
+ " throw new RuntimeException();\n"
+ " }\n"
+ "\n"
+ " return s.equals(\"not eight\");\n"
+ "}\n"
);
}
}