ReportedBugsTest.java
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010 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.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.codehaus.commons.compiler.AbstractJavaSourceClassLoader;
import org.codehaus.commons.compiler.CompileException;
import org.codehaus.commons.compiler.IClassBodyEvaluator;
import org.codehaus.commons.compiler.ICompiler;
import org.codehaus.commons.compiler.ICompilerFactory;
import org.codehaus.commons.compiler.ICookable;
import org.codehaus.commons.compiler.IExpressionEvaluator;
import org.codehaus.commons.compiler.IScriptEvaluator;
import org.codehaus.commons.compiler.ISimpleCompiler;
import org.codehaus.commons.compiler.Location;
import org.codehaus.commons.compiler.tests.bug172.First;
import org.codehaus.commons.compiler.tests.bug180.UnaryDoubleFunction;
import org.codehaus.commons.compiler.tests.bug63.IPred;
import org.codehaus.commons.compiler.tests.bug63.Pred;
import org.codehaus.commons.compiler.util.reflect.ByteArrayClassLoader;
import org.codehaus.commons.compiler.util.resource.MapResourceCreator;
import org.codehaus.commons.compiler.util.resource.MapResourceFinder;
import org.codehaus.commons.compiler.util.resource.Resource;
import org.junit.Assert;
import org.junit.Before;
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;
/**
* Test cases for the bugs reported on CODEHAUS JIRA (which ceased to exist in 2015) and <a
* href="https://github.com/janino-compiler/janino/issues">issues</a> and <a
* href="https://github.com/janino-compiler/janino/pulls">pull requests</a> on GITHUB for project JANINO.
*/
@RunWith(Parameterized.class) public
class ReportedBugsTest extends CommonsCompilerTestSuite {
@Parameters(name = "CompilerFactory={0}") public static Collection<Object[]>
compilerFactories() throws Exception {
return TestUtil.getCompilerFactoriesForParameters();
}
public
ReportedBugsTest(ICompilerFactory compilerFactory) throws Exception {
super(compilerFactory);
}
@SuppressWarnings("static-method") // JUNIT does not like it when "setUp()" is STATIC.
@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);
}
}
/**
* StackOverflowError when using field annotations with enum members.
*
* @see <a href="https://github.com/janino-compiler/janino/pull/31">GITHUB pull request #31</a>
*/
@Test public void
testPullRequest31() throws Exception {
this.assertCompilationUnitCookable((
""
+ "package demo;\n"
+ "\n"
+ "import java.io.Serializable;\n"
+ "import org.codehaus.commons.compiler.tests.annotation.RuntimeRetainedAnnotation2;\n"
+ "import org.codehaus.commons.compiler.tests.annotation.RuntimeRetainedAnnotation4;\n"
+ "import static org.codehaus.commons.compiler.tests.annotation.RuntimeRetainedAnnotation4Enum.SECOND;\n"
+ "\n"
+ "public class JaninoTestComponent implements Serializable {\n"
+ "\n"
+ " public static final String CONST = \"HOWDY\";\n"
+ " private static final long serialVersionUID = 1L;\n"
+ "\n"
+ " @RuntimeRetainedAnnotation2(CONST)\n"
+ " protected java.util.Date lastModifiedDate;\n"
+ "\n"
+ " public JaninoTestComponent() {\n"
+ " // default constructor;\n"
+ " }\n"
+ "}\n"
));
}
@Test public void
testPullRequest46() throws Exception {
String params254 = (
""
+ "long arg000, long arg001, long arg002, long arg003, long arg004, long arg005, long arg006, long arg007, "
+ "long arg008, long arg009, long arg010, long arg011, long arg012, long arg013, long arg014, long arg015, "
+ "long arg016, long arg017, long arg018, long arg019, long arg020, long arg021, long arg022, long arg023, "
+ "long arg024, long arg025, long arg026, long arg027, long arg028, long arg029, long arg030, long arg031, "
+ "long arg032, long arg033, long arg034, long arg035, long arg036, long arg037, long arg038, long arg039, "
+ "long arg040, long arg041, long arg042, long arg043, long arg044, long arg045, long arg046, long arg047, "
+ "long arg048, long arg049, long arg050, long arg051, long arg052, long arg053, long arg054, long arg055, "
+ "long arg056, long arg057, long arg058, long arg059, long arg060, long arg061, long arg062, long arg063, "
+ "long arg064, long arg065, long arg066, long arg067, long arg068, long arg069, long arg070, long arg071, "
+ "long arg072, long arg073, long arg074, long arg075, long arg076, long arg077, long arg078, long arg079, "
+ "long arg080, long arg081, long arg082, long arg083, long arg084, long arg085, long arg086, long arg087, "
+ "long arg088, long arg089, long arg090, long arg091, long arg092, long arg093, long arg094, long arg095, "
+ "long arg096, long arg097, long arg098, long arg099, long arg100, long arg101, long arg102, long arg103, "
+ "long arg104, long arg105, long arg106, long arg107, long arg108, long arg109, long arg110, long arg111, "
+ "long arg112, long arg113, long arg114, long arg115, long arg116, long arg117, long arg118, long arg119, "
+ "long arg120, long arg121, long arg122, long arg123, long arg124, long arg125, long arg126"
);
this.assertClassBodyCookable("public void foo(" + params254 + ") {}");
this.assertClassBodyUncookable("public void foo(" + params254 + ", int a) {}");
this.assertClassBodyCookable("public static void foo(" + params254 + ", int a) {}");
this.assertClassBodyUncookable("public static void foo(" + params254 + ", long a) {}");
}
@Test public void
testBug48() throws Exception {
this.assertCompilationUnitMainExecutable((
""
+ "package demo;\n"
+ "public class Service {\n"
+ " public static boolean main() {\n"
+ " Broken[] dummy = new Broken[5];\n"
+ " return true;\n"
+ " }\n"
+ " class Broken {\n"
+ " }\n"
+ "}"
), "demo.Service");
this.assertCompilationUnitMainExecutable((
""
+ "package demo;\n"
+ "public class Service {\n"
+ " public static Broken[] main() {\n"
+ " return null;\n"
+ " }\n"
+ "}\n"
+ "class Broken {\n"
+ "}"
), "demo.Service");
}
@Test public void
testBug54a() throws Exception {
this.assertScriptReturnsTrue(
""
+ "String s = \"\";\n"
+ "try {\n"
+ " {\n"
+ " s += \"set1\";\n"
+ " }\n"
+ " {\n"
+ " boolean tmp4 = false;\n"
+ " if (tmp4) {\n"
+ " {\n"
+ " s += \"if true\";\n"
+ " if (true) return false;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " {\n"
+ " s += \"return\";\n"
+ " }\n"
+ "} catch (Exception e) {\n"
+ " s += \"exception\";\n"
+ "} finally {\n"
+ " s +=\"finally\";\n"
+ "}\n"
+ "return \"set1returnfinally\".equals(s);"
);
}
@Test public void
testBug54b() throws Exception {
this.assertClassBodyCookable(
""
+ "void foo() {\n"
+ " while (true) {\n"
+ " if (true) {\n"
+ " break;\n"
+ " }\n"
+ " return;\n"
+ " }\n"
+ "}\n"
+ "void bar() {\n"
+ " while (true) {\n"
+ " {\n"
+ " if (true) {\n"
+ " break;\n"
+ " }\n"
+ " }\n"
+ " return;\n"
+ " }\n"
+ "}\n"
);
}
@Test public void
testBug54c() throws Exception {
this.assertClassBodyCookable(
""
+ "void baz1() {\n"
+ " for (int i = 0; i < 100;) {\n"
+ " {\n"
+ " if (true) {\n"
+ " break;\n"
+ " }\n"
+ " }\n"
+ " i += 2;\n"
+ " }\n"
+ "}\n"
);
}
@Test public void
testBug54d() throws Exception {
this.assertClassBodyCookable(
""
+ "void baz2() {\n"
+ " for (int i = 0; i < 100; i++) {\n"
+ " {\n"
+ " if (true) {\n"
+ " break;\n"
+ " }\n"
+ " }\n"
+ " i += 2;\n"
+ " }\n"
+ "}\n"
);
}
@Test public void
testBug54e() throws Exception {
this.assertClassBodyCookable(
""
+ "public void foo() throws Exception {\n"
+ " for (int i = 0 ; true; i++) {\n"
+ " break;\n"
+ " }\n"
+ "}\n"
);
}
@Test public void
testBug54f() throws Exception {
this.assertClassBodyCookable(
""
+ "public void foo() throws Exception {\n"
+ " for (int i = 0 ; true; i++) {\n"
+ " if (true) { break; }\n"
+ " }\n"
+ "}\n"
);
}
@Test public void
testBug54g() throws Exception {
this.assertClassBodyCookable(
""
+ "public void foo() throws Exception {\n"
+ " {\n"
+ " try {\n"
+ " int i = 0;\n"
+ " for (; true;) {\n"
+ " try {\n"
+ " {\n"
+ " {\n" // Invoke: break
+ " if (true) { break; }\n"
+ " }\n" // End Invoke: break
+ " }\n"
+ " i++;\n"
+ " } finally {}\n"
+ " i++;\n"
+ " }\n"
+ " return;\n"
+ " } finally {}\n"
+ " }\n"
+ "}\n"
);
}
@Test public void
testBug54h() throws Exception {
this.assertScriptExecutable(
""
+ "int c = 5;\n"
+ "if (c == 5) {\n"
+ " if (true) return;\n"
+ "} else {\n"
+ " return;\n"
+ "}\n"
+ "int b = 3;\n" // Physically unreachable, but logically reachable, hence not a compile error.
);
}
@Test public void
testBug55() throws Exception {
this.assertCompilationUnitCookable(
""
+ "class Junk {" + "\n"
+ " double[][] x = { { 123.4 } };" + "\n"
+ "}"
);
}
@Test public void
testBug56() throws Exception {
this.assertScriptCookable(
""
+ "int dummy3 = 3;\n"
+ "try {\n"
+ " // 3 vars must be declared in try block\n"
+ " int dummy5 = 5;\n"
+ " int dummy4 = 4;\n"
+ " boolean b = true;\n"
+ "\n"
+ " while (b) {\n"
+ " try {\n"
+ " ++dummy5;\n" // Optional
+ " return;\n" // <= Required
+ " } catch (Exception ex) {\n"
+ " ++dummy5;\n"
+ " }\n"
+ " }\n"
+ "} finally {\n"
+ " ++dummy3;\n"
+ "}\n"
);
}
@Test public void
testBug63() throws Exception {
String cnIPred = IPred.class.getCanonicalName();
String cnPred = Pred.class.getCanonicalName();
this.assertClassBodyUncookable(
""
+ "public static boolean main() {\n"
+ " " + cnIPred + " p = new " + cnPred + "();\n"
+ " return !p.filter();\n" // Comile error, because 'IPred.filter()' throws 'Exception'
+ "}\n"
);
this.assertClassBodyMainReturnsTrue(
""
+ "public static boolean main() {\n"
+ " " + cnPred + " p = new " + cnPred + "();\n"
+ " return !p.filter();\n"
+ "}\n"
);
}
@Test public void
testBug69() throws Exception {
this.assertCompilationUnitMainExecutable((
""
+ "public class Test {\n"
+ " public static void main() {\n"
+ " Object foo = baz();\n"
+ "// System.out.println(\"hello\");\n"
+ " }\n"
+ " public static Object baz() {\n"
+ " final Test test = new Test();\n"
+ " return new Foo() {\n"
+ " private final void bar() {\n"
+ " try {\n"
+ " whee();\n"
+ " } catch (Throwable ex) {\n"
+ " throw test.choke();\n"
+ " }\n"
+ " }\n"
+ " private void whee() {\n"
+ " }\n"
+ " };\n"
+ " }\n"
+ " public RuntimeException choke() {\n"
+ " return new RuntimeException(\"ack\");\n"
+ " }\n"
+ " private static abstract class Foo {\n"
+ " }\n"
+ "}\n"
), "Test");
}
@Test public void
testBug70() throws Exception {
this.assertClassBodyCookable(
""
+ "public String result = \"allow\", email = null, anno = null, cnd = null, transactionID = null;\n"
+ "public String treeCode(String root) {\n"
+ " try {\n"
+ " return null;\n"
+ " } catch (Exception treeEx) {\n"
+ " treeEx.printStackTrace();\n"
+ " result = \"allow\";\n"
+ " }\n"
+ " return result;\n"
+ "}\n"
);
}
@Test public void
testBug71() throws Exception {
this.assertCompilationUnitMainReturnsTrue((
""
+ "public class ACI {\n"
+ " public static boolean main() {\n"
+ " Sub s = new ACI().new Sub(new int[] { 1, 2 });\n"
+ " return s.x == 1 && s.y == 2;\n"
+ " }\n"
+ " class Sub {\n"
+ " int x, y;\n"
+ " public Sub(int[] a) {\n"
+ " this(a[0], a[1]);\n"
+ " }\n"
+ " public Sub(int x, int y) {\n"
+ " this.x = x;\n"
+ " this.y = y;\n"
+ " }\n"
+ " }\n"
+ "}\n"
), "ACI");
this.assertCompilationUnitMainReturnsTrue((
""
+ "public class SCI {\n"
+ " public static boolean main() {\n"
+ " Sub s = new SCI().new Sub(1, 2);\n"
+ " return s.x == 1 && s.y == 2;\n"
+ " }\n"
+ " class Sub extends Foo.Subb {\n"
+ " public Sub(int x, int y) {\n"
+ " new Foo().super(x, y);\n"
+ " }\n"
+ " }\n"
+ "}\n"
+ "class Foo {\n"
+ " class Subb {\n"
+ " int x, y;\n"
+ " public Subb(int x, int y) {\n"
+ " this.x = x;\n"
+ " this.y = y;\n"
+ " }\n"
+ " }\n"
+ "}\n"
), "SCI");
}
@Test public void
testBug80() throws Exception {
// Expression compilation is said to throw StackOverflowError!?
this.assertExpressionUncookable("(10).total >= 100.0 ? 0.0 : 7.95");
}
@Test public void
testBug81() throws Exception {
// IncompatibleClassChangeError when invoking getClass() on interface references
this.assertScriptExecutable(
""
+ "import java.util.ArrayList;\n"
+ "import java.util.List;\n"
+ "\n"
+ "List list = new ArrayList();\n"
+ "/*System.out.println(*/list.getClass()/*)*/;\n"
);
}
@Test public void
testBug99() throws Exception {
// ConcurrentModificationException due to instance variable of Class type initialized using a class literal
this.assertCompilationUnitCookable("class Test{Class c = String.class;}");
}
@Test public void
testBug102() throws Exception {
// Static initializers are not executed
this.assertCompilationUnitMainReturnsTrue((
""
+ "public class Test{\n"
+ " static String x = \"\";\n"
+ " static { x += 0; }\n"
+ " static int a = 7;\n"
+ " static { x += a; }\n"
+ "// static { System.out.println(\"HELLO\"); }\n"
+ " public static boolean main() {\n"
+ "// System.out.println(\">>>\" + x + \"<<<\");\n"
+ " return x.equals(\"07\");\n"
+ " }\n"
+ "}"
), "Test");
ISimpleCompiler compiler = this.compilerFactory.newSimpleCompiler();
compiler.cook(new StringReader("public class Test{static{System.setProperty(\"foo\", \"bar\");}}"));
Class<?> testClass = compiler.getClassLoader().loadClass("Test"); // Only loads the class (JLS7 12.2).
Assert.assertNull(System.getProperty("foo"));
testClass.newInstance(); // Initializes the class (JLS7 12.4).
Assert.assertEquals("bar", System.getProperty("foo"));
System.getProperties().remove("foo");
Assert.assertNull(System.getProperty("foo"));
}
@Test public void
testBug105() throws Exception {
// Possible to call a method of an enclosing class as if it was a member of an inner class
this.assertClassBodyUncookable(
""
+ "class Price {\n"
+ " public int getPriceA() {\n"
+ " return 1;\n"
+ " }\n"
+ "\n"
+ " public int getPriceB() {\n"
+ " return 2;\n"
+ " }\n"
+ "}\n"
+ "\n"
+ "Price price;\n"
+ "\n"
+ "public int assign() {\n"
+ " return price.rate();\n" // This should not compile.
+ "}\n"
+ "\n"
+ "int rate() {\n"
+ " return 17;\n"
+ "}\n"
);
}
@Test public void
testBug106() throws Exception {
this.assertJavaSourceLoadable(new File("src/test/resources/Bug 106"), "b.C3");
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");
this.assertScriptReturnsTrue(
""
+ "StringBuffer sb = new StringBuffer();\n"
+ "sb.append('(');\n"
+ "return sb.length() == 1;\n"
);
}
@Test public void
testBug147() throws Exception {
this.assertCompilationUnitCookable(
""
+ "public class Foo {\n"
+ " public static void main(String[] args) {\n"
+ " new Object() {\n"
+ " Object bar = new Object() {\n"
+ " public Object getObject(int i8) {\n"
+ " switch (i8) { case 0: return \"sss\"; }\n"
+ " return null;\n"
+ " }\n"
+ " };\n"
+ " };\n"
+ " }\n"
+ "}"
);
}
@Test public void
testBug149() throws Exception {
// JLS7 3.10.6: "aaa\/bbb" contains an invalid escape sequence: "\/".
this.assertExpressionUncookable("\"aaa\\/bbb\"");
}
@SuppressWarnings("deprecation") @Test public void
testBug157() throws Exception {
this.compilerFactory.newExpressionEvaluator().setReturnType(Long.class);
}
@Test public void
testBug153_1() throws Exception {
this.assertScriptExecutable("Comparable x = 5.0;");
}
@Test public void
testBug153_2() throws Exception {
// JLS7 5.5 says about casting conversion:
//
// Casting contexts allow the use of:
// ...
// * a boxing conversion (���5.1.7)
//
// , but obviously (JAVAC) a boxing conversion followed by a widening reference conversion is also
// permitted (as for assignment conversion).
this.assertScriptExecutable("Comparable x = (Comparable) 5.0;");
}
@Test public void
testBug153_3() throws Exception {
this.assertScriptExecutable("long x = new Integer(8);");
}
@Test public void
testBug153_4() throws Exception {
// JLS7 5.5 says about casting conversion:
//
// Casting contexts allow the use of:
// ...
// * an unboxing conversion (���5.1.8)
//
// , but obviously (JAVAC) an unboxing conversion followed by a widening primitive conversion is also
// permitted (as for assignment conversion).
this.assertScriptExecutable("long x = (long) new Integer(8);");
}
@Test public void
testBug161_1() throws Exception {
this.assertCompilationUnitCookable(
""
+ "public class Test {\n"
+ " public static void test2(boolean x, boolean y) {\n"
+ " boolean v4 = x || null == null;\n"
+ " }\n"
+ "}\n"
);
}
@Test public void
testBug161_2() throws Exception {
this.assertCompilationUnitCookable(
""
+ "public class Test\n"
+ "{\n"
+ " boolean bar = false;\n"
+ " public void test() {\n"
+ " boolean v4 = bar || null == null;\n"
+ " }\n"
+ "\n"
+ " public static void main(String[] args) {\n"
+ " new Test().test();\n"
+ " }\n"
+ "}\n"
);
}
@Test public void
testBug162() throws Exception {
this.assertCompilationUnitCookable(
""
+ "public class BridgeTest {\n"
+ "\n"
+ " public static class Dad {\n"
+ " public Object foo() { return 1; } \n"
+ " }\n"
+ "\n"
+ " public static class Kid extends Dad {\n"
+ " @Override public Double foo() { return 2.3; }\n"
+ " }\n"
+ "\n"
+ "\n"
+ " public static void main() {\n"
+ " new Kid().foo();\n"
+ " }\n"
+ "}"
);
}
@Test public void
testBug163() throws Exception {
this.assertClassBodyCookable(
""
+ "import java.io.*;\n"
+ "\n"
+ "public void foo() throws IOException {\n"
+ " if (true) {\n"
+ " try {\n"
+ " if (false) {\n"
+ " throw new IOException(\"my exc\");\n"
+ " }\n"
+ " System.out.println(\"xyz\");\n" // <= At least one stmt.
+ "\n"
+ " } catch (IOException e) {\n" // <= "Catch clause is unreachable"
+ " throw new java.lang.RuntimeException(e);\n"
+ " }\n"
+ " }\n"
+ "}"
);
}
@Test public void
testBug169() throws Exception {
this.assertCompilationUnitCookable(
""
+ "import java.util.*;\n"
+ "\n"
+ "class Test2 {\n"
+ " final Object fld1 = \"\";\n"
+ " public void bind(final Object param2) {\n"
+ " fld1.hashCode();\n"
+ " final Object lvar3 = param2;\n"
+ " new Object() {\n"
+ " {\n"
+ " fld1.hashCode();\n"
+ " param2.hashCode();\n"
+ " }\n"
+ " final Object fld4 = fld1.hashCode() + param2.hashCode() + lvar3.hashCode();\n"
+ " public void meth(final Object parm5) {\n"
+ " fld1.hashCode();\n"
+ " param2.hashCode();\n"
+ " lvar3.hashCode();\n"
+ " fld4.hashCode();\n"
+ " parm5.hashCode();\n"
+ " final Object lvar5a = null;\n"
+ " final Object lvar6 = new Object() {\n"
+ " void meth() {\n"
+ " fld1.hashCode();\n"
+ " param2.hashCode();\n"
+ " lvar3.hashCode();\n"
+ " fld4.hashCode();\n"
+ " parm5.hashCode();\n"
+ " }\n"
+ " final Object fld7 = fld1.hashCode() + param2.hashCode() + lvar3.hashCode() + fld4.hashCode() + parm5.hashCode() + lvar5a.hashCode() /*+ SNO lvar6.hashCode()*/;\n"
+ " private void dummy() { throw new AssertionError(lvar5a); }\n"
+ " Object fld8 = new Object() {\n"
+ " final Object fld9 = fld1.hashCode() + /*param2.hashCode() + lvar3.hashCode() +*/ fld4.hashCode() + /*parm5.hashCode() + lvar5a.hashCode() + lvar6.hashCode()*/ + fld7.hashCode() + fld8.hashCode();\n"
+ " public void apply(final Object parm10) {\n"
+ " fld1.hashCode();\n"
+ " // Unknown var or type param2.hashCode();\n"
+ " // Unknown var or type lvar3.hashCode();\n"
+ " fld4.hashCode();\n"
+ " // Unknown var or type parm5.hashCode();\n"
+ " // Unknown var or type lvar5a.hashCode();\n"
+ " // Unknown var or type lvar6.hashCode();\n"
+ " fld7.hashCode();\n"
+ " fld8.hashCode();\n"
+ " fld9.hashCode();\n"
+ " parm10.hashCode();\n"
+ " final Object lvar11 = null;\n"
+ " final Object lvar12 = new Object() {\n"
+ " final Object fld13 = fld1.hashCode() + fld4.hashCode() + fld7.hashCode() + fld8.hashCode();\n"
+ " public void meth(final Object parm14) {\n"
+ " fld1.hashCode();\n"
+ " // Unknown var or type param2.hashCode();\n"
+ " // Unknown var or type lvar3.hashCode();\n"
+ " fld4.hashCode();\n"
+ " // Unknown var or type parm5.hashCode();\n"
+ " // Unknown var or type lvar6.hashCode();\n"
+ " fld7.hashCode();\n"
+ " fld8.hashCode();\n"
+ " fld9.hashCode();\n"
+ " parm10.hashCode();\n"
+ " lvar11.hashCode();\n"
+ " // SNO lvar12.hashCode();\n"
+ " fld13.hashCode();\n"
+ " parm14.hashCode();\n"
+ " final Object lvar15 = fld1.hashCode() + fld4.hashCode() + fld7.hashCode() + fld8.hashCode();\n"
+ " new Object() {\n"
+ " void meth() {\n"
+ " fld1.hashCode();\n"
+ " // Unknown var or type param2.hashCode();\n"
+ " // Unknown var or type lvar3.hashCode();\n"
+ " fld4.hashCode();\n"
+ " // Unknown var or type parm5.hashCode();\n"
+ " // Unknown var or type lvar6.hashCode();\n"
+ " fld7.hashCode();\n"
+ " fld8.hashCode();\n"
+ " fld9.hashCode();\n"
+ " parm10.hashCode();\n"
+ " lvar11.hashCode();\n"
+ " // SNO lvar12.hashCode();\n"
+ " fld13.hashCode();\n"
+ " parm14.hashCode();\n"
+ " lvar15.hashCode();\n"
+ " }\n"
+ " };\n"
+ " }\n"
+ " };\n"
+ " }\n"
+ " };\n"
+ " };\n"
+ " }\n"
+ " };\n"
+ " }\n"
+ "}\n"
);
}
@Test public void
testBug172() throws Exception {
String cnFirst = First.class.getCanonicalName();
this.assertCompilationUnitCookable(
""
+ "public class Base {\n"
+ "\n"
+ " public String foo = \"foo_field\";\n"
+ "\n"
+ " static Object obj = new " + cnFirst + "();\n"
+ " static int ref = ((" + cnFirst + ") obj).field1;\n"
+ "}\n"
);
}
@Test public void
testBug179() throws Exception {
IExpressionEvaluator ee = this.compilerFactory.newExpressionEvaluator();
ee.setExpressionType(Object[].class);
ee.cook("new Object[] { 1, \"foo\", 3, 4 }");
}
@Test public void
testBug180() throws Exception {
// System.out.println(System.getProperty("java.version"));
String interfaceName = UnaryDoubleFunction.class.getCanonicalName();
String script = (
""
+ "package test.compiled;\n"
+ "import static java.lang.Math.*;\n"
+ "public final class JaninoCompiledFastexpr1 implements " + interfaceName + " {\n"
+ " public double evaluate(double x) {\n"
+ " return (2 + (7-5) * 3.14159 * x + sin(0));\n"
+ " }\n"
+ "}"
);
ISimpleCompiler sc = this.compilerFactory.newSimpleCompiler();
sc.cook(script);
}
@Test public void
testBug182() throws Exception {
this.assertExpressionCookable("System.currentTimeMillis() == 7 ? Double.valueOf(1) : Float.valueOf(2)");
}
@Test public void
testBug184() throws Exception {
this.assertCompilationUnitCookable(
""
+ "public class Test {\n"
+ " public void foo() {\n"
// + " byte a = 1;\n"
// + " if (true) {\n"
+ " Label: {\n"
+ " if (false) {\n"
+ " break Label;\n"
+ " }\n"
+ " if (true) {\n"
+ " break Label;\n"
+ " }\n"
+ " }\n"
// + " }\n"
+ " }\n"
+ "}\n"
);
}
/**
* <a href="https://github.com/janino-compiler/janino/issues/6">Issue #6: Assertion error for public static final
* field declaration</a>
*/
@Test public void
testIssue6() throws Exception {
this.assertCompilationUnitCookable(
""
+ "public enum MyEnum {\n"
+ " A, B;\n"
+ " Object notAnEnumConstant = new Object();\n"
+ "}\n"
);
}
/**
* <a href="https://github.com/janino-compiler/janino/issues/53">Issue #53: Cannot compile enums</a>
* @throws Exception
*/
@Test public void
testIssue53() throws Exception {
AbstractJavaSourceClassLoader jscl = this.compilerFactory.newJavaSourceClassLoader();
jscl.setSourcePath(new File[] { new File("src/test/resources/issue53") });
String cfid = this.compilerFactory.getId();
String fieldName = (
cfid.startsWith("org.codehaus.janino") ? "ENUM$VALUES" :
"org.codehaus.commons.compiler.jdk".equals(cfid) ? "$VALUES" :
"???"
);
Assert.assertTrue(jscl.loadClass("pkg1.Enum1").getDeclaredField(fieldName).getType().isArray());
Assert.assertTrue(jscl.loadClass("pkg2.Enum1").getDeclaredField(fieldName).getType().isArray());
}
/**
* <a href="https://github.com/janino-compiler/janino/issues/65">Issue #65:Compilation Error Messages Generated by
* JDK</a>
*/
@Test public void
testIssue65() throws Exception {
ReportedBugsTest.assertUncookableLocation(
"File 'FILENAME', Line 5, Column 9",
this.compilerFactory.newSimpleCompiler(),
(
""
+ "public class Example {\n"
+ " public static void main(String[] unused) {\n"
+ "\n"
+ "\n"
+ " )\n"
+ "\n"
+ "\n"
+ " }\n"
+ "\n"
+ "\n"
+ "}\n"
)
);
}
@Test public void
testIssue65_tabWidth() throws Exception {
ReportedBugsTest.assertUncookableLocation(
"File 'FILENAME', Line 5, Column 25",
this.compilerFactory.newSimpleCompiler(),
(
""
+ "public class Example {\n"
+ " public static void main(String[] unused) {\n"
+ "\n"
+ "\n"
+ " \t\t\t)\n" // <= Three TABs expand to 3x8=24 columns
+ "\n"
+ "\n"
+ " }\n"
+ "\n"
+ "\n"
+ "}\n"
)
);
}
@Test public void
testIssue65_classBodyEvaluator() throws Exception {
ReportedBugsTest.assertUncookableLocation(
"File 'FILENAME', Line 4, Column 5",
this.compilerFactory.newClassBodyEvaluator(),
(
""
+ "public static void main(String[] unused) {\n"
+ "\n"
+ "\n"
+ " )\n"
+ "\n"
+ "\n"
+ "}\n"
)
);
}
@Test public void
testIssue65_scriptEvaluator() throws Exception {
ReportedBugsTest.assertUncookableLocation(
"File 'FILENAME', Line 1, Column 7",
this.compilerFactory.newScriptEvaluator(),
" ) \n"
);
}
@Test public void
testIssue65_scriptEvaluators() throws Exception {
ReportedBugsTest.assertUncookableLocation(
"File 'FILENAME2', Line 4, Column 7",
this.compilerFactory.newScriptEvaluator(),
";",
" ;",
" \r \n \r\n )" // <= FILENAME2
);
}
@Test public void
testIssue69_IncompatibleClassChangeError_when_evaluating_against_janino9plus() throws Exception {
if (CommonsCompilerTestSuite.JVM_VERSION < 8) return;
try {
IExpressionEvaluator ee = this.compilerFactory.newExpressionEvaluator();
// ee.setSourceVersion(8);
// ee.setTargetVersion(8);
ee.cook("java.util.stream.Stream.of(1, 2, 3).toArray()");
Assert.assertArrayEquals(new Object[] { 1, 2, 3 }, (Object[]) ee.evaluate());
} catch (CompileException ce) {
if (ce.getMessage().contains("only available for target version")) return;
throw ce;
}
}
// @Test public void
// testIssue69() throws Exception {
//
// if (CommonsCompilerTestSuite.JVM_VERSION < 8) return;
//
// IExpressionEvaluator ee = this.compilerFactory.newExpressionEvaluator();
// ee.cook("java.util.stream.Stream.of(1, 2, 3)");
// Assert.assertEquals("xxx", ee.evaluate());
// }
@Test public void
testIssue73_Operator_Ampersand_not_defined_on_types_java_lang_Integer_int() throws Exception {
this.assertExpressionCookable("new Integer(1)&2");
}
/**
* <a href="https://github.com/janino-compiler/janino/issues/47">Issue #47: UnitCompiler fails with
* CompileException when parent interface method is overridden in child interface with subtype return type</a>
*/
@Test public void
testIssue47() throws Exception {
ISimpleCompiler s = this.compilerFactory.newSimpleCompiler();
s.setDebuggingInformation(true, true, true);
s.cook(
""
+ "package pkg;\n"
+ "\n"
+ "import org.codehaus.commons.compiler.tests.ReportedBugsTest.B;\n"
+ "\n"
+ "public class D {\n"
+ " public Object one(B b) {\n"
+ " return b.theFirstMethod().theSecondMethod();\n"
+ " }\n"
+ "}\n"
);
s.getClassLoader().loadClass("pkg.D");
}
/**
* <a href="https://github.com/janino-compiler/janino/issues/90">Issue #90: "Incompatible expression types" or
* verification errors when using ternary expressions with null in one branch</a>
*/
@Test public void
testIssue90() throws Exception {
this.assertExpressionEvaluatesTrue("1 == (false ? null : 1)");
this.assertScriptExecutable("boolean cond = true; Integer result = cond ? null : 1;");
}
/**
* <a href="https://github.com/janino-compiler/janino/issues/102">Issue #102: "$" in class name can't be handled by
* janino</a>
*/
@Test public void
testIssue102__1() throws Exception {
this.assertExpressionEvaluatable("import java.util.Map; Map.class");
}
@Test public void
testIssue102__2() throws Exception {
this.assertExpressionEvaluatable("import java.util.Map; Map.Entry.class");
}
@Test public void
testIssue102__4() throws Exception {
this.assertCompilationUnitMainReturnsTrue((
""
+ "class A$B {}\n"
+ "public class Main {\n"
+ " public static boolean main() {\n"
+ " return A$B.class.getName().equals(\"A$B\");\n"
+ " }\n"
+ "}\n"
), "Main");
}
@Test public void
testIssue102__5() throws Exception {
this.assertCompilationUnitMainReturnsTrue((
""
+ "class A$$B {}\n"
+ "public class Main {\n"
+ " public static boolean main() {\n"
+ " new A$$B();\n"
+ " return A$$B.class.getName().equals(\"A$$B\");\n"
+ " }\n"
+ "}\n"
), "Main");
}
@Test public void
testIssue102__6() throws Exception {
this.assertCompilationUnitMainReturnsTrue((
""
+ "class A$B { class C$D {} }\n"
+ "public class Main {\n"
+ " public static boolean main() {\n"
+ " return A$B.C$D.class.getName().equals(\"A$B$C$D\");\n"
+ " }\n"
+ "}\n"
), "Main");
}
@Test public void
testIssue102__7() throws Exception {
this.assertCompilationUnitUncookable((
""
+ "class A$B { class C$D {} }\n"
+ "public class Main {\n"
+ " public static boolean main() {\n"
+ " return A$B$C$D.class.getName().equals(\"A$B$C$D\");\n"
+ " }\n"
+ "}\n"
));
}
@Test public void
testIssue102__8() throws Exception {
CompileUnit unit1 = new CompileUnit("demo.pkg1", "A$$1", (
""
+ "package demo.pkg1;\n"
+ "import demo.pkg2.*;\n"
+ "public class A$$1 {\n"
+ " public static String main() { return B$1.hello(); }\n"
+ " public static String hello() { return \"HELLO\"; }\n"
+ "}"
));
CompileUnit unit2 = new CompileUnit("demo.pkg2", "B$1", (
""
+ "package demo.pkg2;\n"
+ "import demo.pkg1.*;\n"
+ "public class B$1 {\n"
+ " public static String hello() { return \"HELLO\" /*A$$1.hello()*/; }\n"
+ "}"
));
ClassLoader
classLoader = this.compile(Thread.currentThread().getContextClassLoader(), unit1, unit2);
Assert.assertEquals(
"HELLO",
classLoader.loadClass("demo.pkg1.A$$1").getMethod("main").invoke(null)
);
}
@Test public void
testIssue126() throws Exception {
if (CommonsCompilerTestSuite.JVM_VERSION < 8) return;
ISimpleCompiler s = this.compilerFactory.newSimpleCompiler();
s.setSourceVersion(8);
s.setTargetVersion(8);
s.cook((
""
+ "package issue126;\n"
+ "\n"
+ "public interface BaseTestable {\n"
+ " public void test();\n"
+ "}\n"
+ "\n"
+ "public interface Testable extends BaseTestable {\n"
+ " @Override\n"
+ " default public void test() {\n"
+ " System.out.println(\"test\");\n"
+ " }\n"
+ "}\n"
+ "\n"
+ "public class Test implements Testable {\n"
+ " //blank implementation\n"
+ "}\n"
));
Assert.assertNotNull(s.getClassLoader().loadClass("issue126.Test").getConstructor().newInstance());
}
@Test public void
testIssue144() throws Exception {
this.assertScriptCookable("int a = 7, b = 5; Object o = new Object[] { a, b };");
this.assertScriptCookable("int a = 7, b = 5; Object o = new Object[] { a < b, b };");
this.assertScriptCookable("int a = 7, b = 5; Object o = new Object[] { a, b > a };");
this.assertScriptCookable("int a = 7, b = 5; Object o = new Object[] { a < b, b > a };");
this.assertScriptCookable("import java.util.Map; Map<Long, Long> a;");
}
@Test public void
testPullRequest146() throws Exception {
this.assertCompilationUnitCookable((
""
+ "public class JaninoTest {\n"
+ " public int func(int v) {\n"
+ " long local_var0 = 0;\n"
+ " switch (v) {\n"
+ " case 0:\n"
+ " long local_var1 = 1;\n"
+ " local_var0 = local_var1;\n"
+ " break;\n"
+ "\n"
+ " default:\n"
+ " long local_var2 = 2;\n"
+ " local_var0 = local_var2;\n"
+ " break;\n"
+ " }\n"
+ "\n"
+ " long local_var3 = 1;\n"
+ " if (v % 4 == 0) {\n"
+ " local_var3 += 2;\n"
+ " }\n"
+ " if ((local_var0 + local_var3) % 2 == 0) {\n"
+ " return 0;\n"
+ " } else {\n"
+ " return 1;\n"
+ " }\n"
+ " }\n"
+ "}\n"
));
}
@Test public void
testIssue151() throws Exception {
// The original code was reduced to this snippet:
this.assertScriptCookable((
""
+ "double a;\n" // <= Must be LONG or DOUBLE, and must not be initialized.
+ "boolean b;\n" // <= Must be declared *after* "a".
+ "b = true; a = 1;\n" // <= In *that* order.
+ "System.out.println(b);//if (b) {}\n"
));
}
public ClassLoader
compile(ClassLoader parentClassLoader, CompileUnit... compileUnits) {
MapResourceFinder sourceFinder = new MapResourceFinder();
for (CompileUnit unit : compileUnits) {
String stubFileName = unit.pkg.replace(".", "/") + "/" + unit.mainClassName + ".java";
sourceFinder.addResource(stubFileName, unit.getCode());
}
// Storage for generated bytecode
final Map<String, byte[]> classes = new HashMap<>();
// Set up the compiler.
ICompiler compiler = this.compilerFactory.newCompiler();
// compiler.setClassFileFinder(ClassLoaders.getsResourceAsStream(parentClassLoader));
compiler.setClassFileCreator(new MapResourceCreator(classes));
compiler.setClassFileFinder(new MapResourceFinder(classes));
// Compile all sources
try {
compiler.compile(sourceFinder.resources().toArray(new Resource[0]));
} catch (CompileException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
// Set up a class loader that finds and defined the generated classes.
return new ByteArrayClassLoader(classes, parentClassLoader);
}
interface Supplier<T> { T get(); }
public
class CompileUnit {
String pkg;
String mainClassName;
private final String code;
public
CompileUnit(String pkg, String mainClassName, String code) {
this.pkg = pkg;
this.mainClassName = mainClassName;
this.code = code;
}
public String
getCode() { return this.code; }
@Override public String
toString() { return "CompileUnit{ pkg=" + this.pkg + ", mainClassName='" + this.mainClassName + " }"; }
}
// SUPPRESS CHECKSTYLE Javadoc:2
public interface A { A theFirstMethod(); }
public interface B extends A { @Override B theFirstMethod(); Object theSecondMethod(); }
private static void
assertUncookableLocation(String expected, ICookable cookable, String text) {
try {
cookable.cook("FILENAME", text);
Assert.fail();
} catch (CompileException ce) {
Location loc = ce.getLocation();
Assert.assertEquals(ce.toString(), expected, String.valueOf(loc));
}
}
private static void
assertUncookableLocation(String expected, IScriptEvaluator cookable, String... text) {
try {
if (text.length == 1) {
cookable.cook("FILENAME", text[0]);
} else {
String[] fileNames = new String[text.length];
for (int i = 0; i < text.length; i++) fileNames[i] = "FILENAME" + i;
cookable.cook(fileNames, text);
}
Assert.fail();
} catch (CompileException ce) {
Location loc = ce.getLocation();
Assert.assertEquals(expected, String.valueOf(loc));
}
}
@Test public void
testIssue165() throws Exception {
Thread.currentThread().getContextClassLoader().loadClass("com.company.user.Country");
this.assertClassBodyMainReturnsTrue((
""
+ "public static boolean main() {\n"
+ " return com.company.user.Country.get() == 99;\n"
+ "}\n"
));
}
@Test public void
testIssue168() throws Exception {
ISimpleCompiler sc = this.compilerFactory.newSimpleCompiler();
// Reference a package in the *classpath* (not the bootclasspath!):
sc.cook("import de.unkrig.jdisasm.Disassembler;");
}
@Test public void
testIssue169() throws Exception {
this.assertCompilationUnitMainExecutable((
""
+ "public interface Actor {\n"
+ " Actor dashed(float... dashed);\n"
+ " Actor xx(int... test);\n"
+ "}\n"
+ "\n"
+ "public class ActorImpl implements Actor {\n"
+ " @Override public Actor dashed(float... dashed) { return this; }\n"
+ " @Override public Actor xx(int... test) { return this; }\n"
+ "}\n"
+ "\n"
+ "public class Main {\n"
+ " public static void main() {\n"
+ " new ActorImpl().dashed(1f, 10f).xx(1, 2, 3);\n"
+ "\n"
+ " ActorImpl a = new ActorImpl();\n"
+ " a.dashed(1f, 10f).xx(1, 2, 3);\n"
+ " }\n"
+ "}\n"
), "Main");
}
@Test public void
testIssue172__1() throws Exception {
this.assertCompilationUnitMainReturnsTrue((
""
+ "public class test {\n"
+ " public static boolean\n"
+ " main() {\n"
+ " String s;\n"
+ " if (Boolean.FALSE || (s = \"Hello World!\") == null) {\n"
+ " return false;\n"
+ " }\n"
+ " return true;\n"
+ " }\n"
+ "}\n"
), "test");
}
@Test public void
testIssue172__2() throws Exception {
this.assertCompilationUnitMainReturnsTrue((
""
+ "public class test {\n"
+ " public static boolean\n"
+ " main() {\n"
+ " String s;\n"
+ " if (f() || (s = \"Hello World!\") == null) {\n"
+ " return true;\n"
+ " }\n"
+ " return false;\n"
+ " }\n"
+ "\n"
+ " public static boolean\n"
+ " f() { return true; }\n"
+ "}\n"
), "test");
}
@Test public void
testIssue172__3() throws Exception {
this.assertCompilationUnitMainExecutable((
""
+ "public class test {\n"
+ " public static void\n"
+ " main() {\n"
+ " String[] args = { \"4\" };\n"
+ " boolean b = args.length > 0;\n"
+ " String s;\n"
+ " if (b || (s = \"Hello World!\") == null) {\n"
+ " return;\n"
+ " }\n"
+ " System.currentTimeMillis();\n"
+ " }\n"
+ "}\n"
), "test");
}
@Test
public void
testIssue174__SmallMethod() throws Exception {
String body = ReportedBugsTest.getClassBody(10);
this.createObject(body);
}
@Test
public void
testIssue174__BigMethod() throws Exception {
// Generate inefficient code with lots of assignments.
// Breaks JVMs >=16 when using more than 840 assignments:
// # Internal Error (metaspaceArena.cpp:88), pid=12308, tid=6659
// # guarantee(requested_word_size <= chunklevel::MAX_CHUNK_WORD_SIZE) failed: Requested size too large (756627) - max allowed size per allocation is 524288.
String body = ReportedBugsTest.getClassBody(1000);
this.createObject(body);
}
private Nukable
createObject(String body) throws Exception {
// Store source code in .java file for manual analysis.
// try (Writer w = new FileWriter("Nuke" + body.length() + ".java")) {
// w.write(body);
// }
// Instantiate an object from the generated class.
IClassBodyEvaluator cbe = this.compilerFactory.newClassBodyEvaluator();
cbe.setClassName("Nuke");
cbe.setImplementedInterfaces(new Class[] { Nukable.class });
cbe.setParentClassLoader(this.getClass().getClassLoader());
cbe.setDefaultImports("java.util.Arrays");
Nukable result = (Nukable) cbe.createInstance(new StringReader(body));
for (Entry<String, byte[]> e : cbe.getBytecodes().entrySet()) {
byte[] bytecode = e.getValue();
String className = e.getKey();
CommonsCompilerTestSuite.assertLessThan(className, 14000, bytecode.length);
// Store the bytecode in .class files for manual analysis.
// try (OutputStream os = new FileOutputStream("Nuke" + body.length() + ".class")) {
// byte[] buffer = new byte[4096];
// ByteArrayInputStream is = new ByteArrayInputStream(e.getValue());
// for (;;) {
// int n = is.read(buffer);
// if (n == -1) break;
// os.write(buffer, 0, n);
// }
// }
}
return result;
}
private static String
getClassBody(int numAssignments) {
String template = (
""
+ "public Object[] nuke() {%n"
+ " String bloat = \"some_bloat\";%n"
+ " // Lots of variables%n"
+ "%s"
+ " // Big array initialization%n"
+ " return new Object[] {%n"
+ "%s"
+ " };%n"
+ "}%n"
+ "%n"
+ "public static void main(String[] args) throws Exception {%n"
+ " System.out.println(Arrays.toString(new Nuke().nuke()));%n"
+ "}%n"
);
StringBuilder localVariableDeclarations = new StringBuilder();
StringBuilder arrayInitializerBody = new StringBuilder();
for (int i = 0; i < numAssignments; i++) {
localVariableDeclarations.append(String.format(" final String current%s = bloat;%n", i));
arrayInitializerBody.append(String.format(" current%s,%n", i));
}
return String.format(template, localVariableDeclarations, arrayInitializerBody);
}
public
interface Nukable {
Object[] nuke();
}
// -------------------------------
/**
* Supposed to reproduce https://github.com/janino-compiler/janino/issues/174#issuecomment-1243022653, but doesn't.
*/
@Test public void
testIssue174__JaninoCompilerTest() throws Exception {
// // public void compile_long_method(@TempDir Path tempDir) throws Exception {
String code = ReportedBugsTest.getClassCode(ReportedBugsTest.getClassBody2(1000));
// JaninoCompiler compiler = new JaninoCompiler();
// compiler.getArgs().setDestdir(tempDir.toFile().getAbsolutePath());
// compiler.getArgs().setSource(code, "Nuke.java");
// compiler.getArgs().setFullClassName("Nuke");
// compiler.compile();
// URL[] urls = new URL[]{tempDir.toUri().toURL()};
// ClassLoader cl = new URLClassLoader(urls);
// ClassLoader cl = sc.getClassLoader();
AbstractJavaSourceClassLoader cl = this.compilerFactory.newJavaSourceClassLoader();
cl.setSourceFinder(new MapResourceFinder(Collections.singletonMap("Nuke.java", code.getBytes("UTF-8"))));
Class<?> clazz = cl.loadClass("Nuke");
Object o = clazz.getDeclaredConstructor().newInstance();
System.out.println(o);
}
private static String
getClassCode(String body) {
return (
""
+ "import java.util.Arrays;\n\n"
+ "public class Nuke {"
+ body
+ "}"
);
}
private static String
getClassBody2(int numAssignments) {
String template = (
""
+ "public Object[] nuke() {\n"
+ "\tString bloat = \"some_bloat\";\n"
+ "\t//Lots of variables\n"
+ "%s"
+ "\t//Big array initialization\n"
+ "\treturn new Object[]\n"
+ "\t{\n"
+ "%s"
+ "\t};\n"
+ "}\n"
+ "\n"
+ ""
+ "public static void main(String[] args) throws Exception {"
+ "\tSystem.out.println(Arrays.toString(new Nuke().nuke()));"
+ "}"
);
StringBuilder assignments = new StringBuilder();
StringBuilder appends = new StringBuilder();
for (int i = 0; i < numAssignments; i++) {
assignments.append(String.format("\tfinal String current%s = bloat;\n", i));
appends.append(String.format("\t\tcurrent%s", i));
if (i < numAssignments - 1) {
appends.append(",");
}
appends.append("\n");
}
return String.format(template, assignments, appends);
}
// --------------------
@Test
public void
testIssue177() throws Exception {
this.assertCompilationUnitMainExecutable((
""
+ "public class\n"
+ "test2 {\n"
+ " public final static double x = 0;\n"
+ " public static void main() {}\n"
+ "}\n"
+ ""
), "test2");
}
// TODO: Doesn't reproduce the problem!
@Test
public void
testIssue181() throws Exception {
this.assertCompilationUnitCookable(
""
+ "public\n"
+ "interface Main {\n"
+ " class Member {\n"
+ " Object i = new Object();\n"
+ " }\n"
+ "}\n"
);
}
@Test public void
testIssue185() throws Exception {
this.assertScriptCookable(
""
+ "java.io.BufferedReader br = new java.io.BufferedReader(new java.io.InputStreamReader(System.in));\n"
+ "String line;\n"
+ "while ((line = br.readLine()) != null) {\n"
+ " System.out.println(line);\n"
+ "}\n"
);
}
@Test public void
testIssue187() throws Exception {
this.assertCompilationUnitMainReturnsTrue((
""
+ "public class MyClass {\n"
+ " public static boolean main() {\n"
+ " boolean b;\n"
+ " if (false) {\n"
+ " b = true;\n"
+ " } else {\n"
+ " b = false;\n"
+ " }\n"
+ " return !b;\n"
+ " }\n"
+ "}"
), "MyClass");
}
@Test public void
testIssue188() throws Exception {
this.assertScriptExecutable("Object o = true ? (String) null : \"\";");
this.assertScriptExecutable("Object o = true ? (Object) null : \"\";");
this.assertScriptExecutable("Object o = true ? null : \"\";"); // <= InternalCompilerException
this.assertScriptExecutable("String s1 = new StringBuilder().append(true ? (String) null : \"abc\").toString(); // ok\n");
this.assertScriptExecutable("String s2 = new StringBuilder().append(true ? null : \"abc\").toString(); // <= InternalCompilerException\n");
}
@Test public void
testIssue195() throws Exception {
this.assertCompilationUnitUncookable(
""
+ "public class Test {\n"
+ " public Test(int i) {}\n"
+ " public Test(int i) {}\n"
+ "}\n"
);
}
@Test public void
testIssue201() throws Exception {
// That should be enough to cause a stack overflow:
String expression = ReportedBugsTest._nestedDoc(20000, "( ", ") ", "t");
ExpressionTest et = new ExpressionTest(expression);
et.setParameters(new String[] { "t" }, new Class[] { int.class });
et.assertUncookable("nested|unknown reason");
}
public static String
_nestedDoc(int nesting, String open, String close, String content) {
StringBuilder sb = new StringBuilder(nesting * (open.length() + close.length()));
for (int i = 0; i < nesting; ++i) sb.append(open);
sb.append(content);
for (int i = 0; i < nesting; ++i) sb.append(close);
return sb.toString();
}
@Test public void
testIssue208UnconditionalForWithUpdateWithBodyThatCannotCompleteNormally() throws Exception {
String body = (
""
+ "public class MyClass {\n"
+ "\n"
+ " public static boolean\n"
+ " main() {\n"
+ "\n"
+ " for (int c = 7; true; c++) {\n"
+ " boolean a = false;\n" // Any type but "long" or "double"\n"
+ " long b = 33;\n" // "double" works as well.\n"
+ " break;\n" // Unconditional; "break" works as well.\n"
+ " }\n" // Doesn't matter if condition has constant value or not.\n"
+ " \n"
+ " int c = 9;\n" // Any type but "long" or "double"\n"
+ " boolean d = false;\n" // Any type but "long" or "double"\n"
+ " long e = -1;\n" // "double" works as well <== java.lang.ArrayIndexOutOfBoundsException: arraycopy: length -1 is negative\n"
+ " return true;\n"
+ " }\n"
+ "}\n"
);
this.assertCompilationUnitMainReturnsTrue(body, "MyClass");
}
@Test public void
testIssue208UnconditionalForWithoutUpdateWithBodyThatCannotCompleteNormally() throws Exception {
String body = (
""
+ "public class MyClass {\n"
+ "\n"
+ " public static boolean\n"
+ " main() {\n"
+ "\n"
+ " for (int c = 7; true;) {\n" // Doesn't matter if condition has constant value or not.
+ " boolean a = false;\n" // Any type but "long" or "double"
+ " long b = 33;\n" // "double" works as well.
+ " break;\n" // Unconditional
+ " }\n"
+ " \n"
+ " int c = 9;\n" // Any type but "long" or "double"
+ " boolean d = false;\n" // Any type but "long" or "double"
+ " long e = -1;\n" // "double" works as well <== java.lang.ArrayIndexOutOfBoundsException: arraycopy: length -1 is negative
+ " return true;\n"
+ " }\n"
+ "}\n"
);
this.assertCompilationUnitMainReturnsTrue(body, "MyClass");
}
@Test public void
testIssue208UnconditionalWhileWithBodyThatCannotCompleteNormally() throws Exception {
String body = (
""
+ "public class MyClass {\n"
+ "\n"
+ " public static boolean\n"
+ " main() {\n"
+ "\n"
+ " while (true) {\n" // Doesn't matter if condition has constant value or not.\n"
+ " boolean a = false;\n" // Any type but "long" or "double"\n"
+ " long b = 33;\n" // "double" works as well.\n"
+ " break;\n" // Unconditional
+ " }\n"
+ " \n"
+ " int c = 9;\n" // Any type but "long" or "double"\n"
+ " boolean d = false;\n" // Any type but "long" or "double"\n"
+ " long e = -1;\n" // "double" works as well <== java.lang.ArrayIndexOutOfBoundsException: arraycopy: length -1 is negative\n"
+ " return true;\n"
+ " }\n"
+ "}\n"
);
this.assertCompilationUnitMainReturnsTrue(body, "MyClass");
}
@Test public void
testIssue208WhileWithBodyThatCannotCompleteNormally() throws Exception {
String body = (
""
+ "public class MyClass {\n"
+ "\n"
+ " public static boolean\n"
+ " main() {\n"
+ "\n"
+ " while (System.currentTimeMillis() != 0) {\n" // Doesn't matter if condition has constant value or not.
+ " boolean a = false;\n" // Any type but "long" or "double"
+ " long b = 33;\n" // "double" works as well.
+ " break;\n" // Unconditional
+ " }\n"
+ " \n"
+ " int c = 9;\n" // Any type but "long" or "double"
+ " boolean d = false;\n" // Any type but "long" or "double"
+ " long e = -1;\n" // "double" works as well <== java.lang.ArrayIndexOutOfBoundsException: arraycopy: length -1 is negative
+ " return true;\n"
+ " }\n"
+ "}\n"
);
this.assertCompilationUnitMainReturnsTrue(body, "MyClass");
}
@Test public void
testIssue208DoWithBodyThatCannotCompleteNormally1() throws Exception {
String body = (
""
+ "public class MyClass {\n"
+ "\n"
+ " public static boolean\n"
+ " main() {\n"
+ "\n"
+ " do {\n"
+ " boolean a = false;\n" // Any type but "long" or "double"
+ " long b = 33;\n" // "double" works as well.
+ " continue;\n" // Unconditional
+ " } while (false);\n" // Doesn't matter if condition has constant value or not.
+ " \n"
+ " int c = 9;\n" // Any type but "long" or "double"
+ " boolean d = false;\n" // Any type but "long" or "double"
+ " long e = -1;\n" // "double" works as well <== java.lang.ArrayIndexOutOfBoundsException: arraycopy: length -1 is negative
+ " return true;\n"
+ " }\n"
+ "}\n"
);
this.assertCompilationUnitMainReturnsTrue(body, "MyClass");
}
@Test public void
testIssue208DoWithBodyThatCannotCompleteNormally2() throws Exception {
String body = (
""
+ "public class MyClass {\n"
+ "\n"
+ " public static boolean\n"
+ " main() {\n"
+ "\n"
+ " do {\n"
+ " boolean a = false;\n" // Any type but "long" or "double"
+ " long b = 33;\n" // "double" works as well.
+ " break;\n" // Unconditional
+ " } while (false);\n" // Doesn't matter if condition has constant value or not.
+ " \n"
+ " int c = 9;\n" // Any type but "long" or "double"
+ " boolean d = false;\n" // Any type but "long" or "double"
+ " long e = -1;\n" // "double" works as well <== java.lang.ArrayIndexOutOfBoundsException: arraycopy: length -1 is negative
+ " return true;\n"
+ " }\n"
+ "}\n"
);
this.assertCompilationUnitMainReturnsTrue(body, "MyClass");
}
@Test public void
testIssue208LabeledStatementWithBodyThatCannotCompleteNormally() throws Exception {
String body = (
""
+ "public class MyClass {\n"
+ "\n"
+ " public static boolean\n"
+ " main() {\n"
+ "\n"
+ " LABEL: {\n"
+ " boolean a = false;\n" // Any type but "long" or "double"
+ " long b = 33;\n" // "double" works as well.
+ " break LABEL;\n" // Unconditional
+ " }\n"
+ " \n"
+ " int c = 9;\n" // Any type but "long" or "double"
+ " boolean d = false;\n" // Any type but "long" or "double"
+ " long e = -1;\n" // "double" works as well <== java.lang.ArrayIndexOutOfBoundsException: arraycopy: length -1 is negative
+ " return true;\n"
+ " }\n"
+ "}\n"
);
this.assertCompilationUnitMainReturnsTrue(body, "MyClass");
}
@Test public void
testIssue210CompilerExceptionWithStaticInnerClasses() throws Exception {
String body = (
""
+ "public class Base1 {\n"
+ "\n"
+ " public static void setFirstName(String firstName) {}\n"
+ "\n"
+ " public static class Builder {\n"
+ " public Builder setFirstName(String firstName) { return this; }\n"
+ " }\n"
+ "}\n"
+ "\n"
+ "public class Base2 extends Base1 {\n"
+ "\n"
+ " public static void setLastName(String lastName) {}\n"
+ "\n"
+ " public static class Builder extends Base1.Builder {\n"
+ " public Builder setLastName(String lastName) { return this; }\n"
+ " }\n"
+ "}\n"
+ "\n"
+ "public class Derived {\n"
+ "\n"
+ " public static void setAge(int age) {}\n"
+ "\n"
+ " public static class Builder extends Base2.Builder {\n"
+ " public Builder setAge(int age) { return this; }\n"
+ " }\n"
+ "}\n"
+ "\n"
+ "public class MyClass {\n"
+ " public static boolean main() {\n"
+ " new Derived.Builder().setAge(17);\n"
+ " return true;\n"
+ " }\n"
+ "}\n"
);
this.assertCompilationUnitMainReturnsTrue(body, "MyClass");
}
@Test public void
testIssue212AssignmentConversionNotPossibleFromTypeInterfaceClassToTypeAbstractClass() throws Exception {
String body = (
""
+ "import org.codehaus.commons.compiler.tests.issue212.base.IBase;\n"
+ "import org.codehaus.commons.compiler.tests.issue212.base.BaseClass;\n"
+ "import org.codehaus.commons.compiler.tests.issue212.base.DerivedClass;\n"
+ "\n"
+ "public class MyClass {\n"
+ " public static String main() {\n"
+ " BaseClass o1 = new DerivedClass().path();\n" // <= Works
+ " IBase o2 = ((IBase) new DerivedClass()).path();\n" // <= Works
+ " BaseClass o3 = ((BaseClass) new DerivedClass()).path();\n" // <= "Ass. conv. not possible from IBase to BaseClass"
+ " return o3.toString();\n"
+ " }\n"
+ "}\n"
);
this.assertCompilationUnitMainEquals("BaseClass DerivedClass", body, "MyClass");
}
}