458 lines
18 KiB
Java
458 lines
18 KiB
Java
/*
|
|
* Copyright 2010-2015 JetBrains s.r.o.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package org.jetbrains.kotlin.codegen;
|
|
|
|
import com.intellij.util.ArrayUtil;
|
|
import org.jetbrains.kotlin.test.ConfigurationKind;
|
|
|
|
import java.awt.*;
|
|
import java.lang.reflect.InvocationTargetException;
|
|
import java.lang.reflect.Method;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.List;
|
|
|
|
public class PackageGenTest extends CodegenTestCase {
|
|
|
|
@Override
|
|
protected void setUp() throws Exception {
|
|
super.setUp();
|
|
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY);
|
|
}
|
|
|
|
public void testPSVM() throws Exception {
|
|
loadText("fun main(args: Array<String>) { }");
|
|
Method main = generateFunction();
|
|
Object[] args = new Object[] {ArrayUtil.EMPTY_STRING_ARRAY};
|
|
main.invoke(null, args);
|
|
}
|
|
|
|
public void testReturnOne() throws Exception {
|
|
loadText("fun f() : Int { return 42; }");
|
|
Method main = generateFunction();
|
|
Object returnValue = main.invoke(null);
|
|
assertEquals(new Integer(42), returnValue);
|
|
}
|
|
|
|
public void testReturnA() throws Exception {
|
|
loadText("fun foo(a : Int) = a");
|
|
Method main = generateFunction();
|
|
Object returnValue = main.invoke(null, 50);
|
|
assertEquals(new Integer(50), returnValue);
|
|
}
|
|
|
|
public void testCurrentTime() throws Exception {
|
|
loadText("fun f() : Long { return System.currentTimeMillis(); }");
|
|
Method main = generateFunction();
|
|
long actual = (Long) main.invoke(null);
|
|
long expected = System.currentTimeMillis();
|
|
long diff = Math.abs(actual - expected);
|
|
assertTrue(
|
|
"Difference with current time: " + diff + " (this test is a bad one: it may fail even if the generated code is correct)",
|
|
diff <= 100
|
|
);
|
|
}
|
|
|
|
public void testIdentityHashCode() throws Exception {
|
|
loadText("fun f(o: Any) : Int { return System.identityHashCode(o); }");
|
|
Method main = generateFunction();
|
|
Object o = new Object();
|
|
int returnValue = (Integer) main.invoke(null, o);
|
|
assertEquals(returnValue, System.identityHashCode(o));
|
|
}
|
|
|
|
public void testSystemOut() throws Exception {
|
|
loadText("fun f() : Any? { return System.out; }");
|
|
Method main = generateFunction();
|
|
Object returnValue = main.invoke(null);
|
|
assertEquals(returnValue, System.out);
|
|
}
|
|
|
|
public void testBoxedInt() throws Exception {
|
|
loadText("fun foo(a: Int?) = if (a != null) a else 239");
|
|
Method main = generateFunction();
|
|
assertEquals(610, main.invoke(null, 610));
|
|
assertEquals(239, main.invoke(null, new Object[]{null}));
|
|
}
|
|
|
|
public void testIntBoxed() throws Exception {
|
|
loadText("fun foo(s: String): Int? = Integer.getInteger(s, 239)");
|
|
Method main = generateFunction();
|
|
assertEquals(239, main.invoke(null, "no.such.system.property"));
|
|
}
|
|
|
|
public void testBoxConstant() throws Exception {
|
|
loadText("fun foo(): Int? = 239");
|
|
Method main = generateFunction();
|
|
assertEquals(239, main.invoke(null));
|
|
}
|
|
|
|
public void testBoxVariable() throws Exception {
|
|
loadText("fun foo(): Int? { var x = 239; return x; }");
|
|
Method main = generateFunction();
|
|
assertEquals(239, main.invoke(null));
|
|
}
|
|
|
|
public void testAugAssign() throws Exception {
|
|
loadText("fun foo(a: Int): Int { var x = a; x += 5; return x; }");
|
|
Method main = generateFunction();
|
|
assertEquals(10, main.invoke(null, 5));
|
|
}
|
|
|
|
public void testBooleanNot() throws Exception {
|
|
loadText("fun foo(b: Boolean): Boolean = !b");
|
|
Method main = generateFunction();
|
|
assertEquals(true, main.invoke(null, false));
|
|
assertEquals(false, main.invoke(null, true));
|
|
}
|
|
|
|
public void testBooleanNotJump() throws Exception {
|
|
loadText("fun foo(a: Int) : Int = if (!(a < 5)) a else 0");
|
|
Method main = generateFunction();
|
|
assertEquals(6, main.invoke(null, 6));
|
|
assertEquals(0, main.invoke(null, 4));
|
|
}
|
|
|
|
public void testAnd() throws Exception {
|
|
loadText("fun foo(a : Int): Boolean = a > 0 && a/0 > 0");
|
|
Method main = generateFunction();
|
|
assertEquals(false, main.invoke(null, 0));
|
|
boolean hadException = false;
|
|
try {
|
|
main.invoke(null, 5);
|
|
} catch (InvocationTargetException e) {
|
|
if (e.getTargetException() instanceof ArithmeticException) {
|
|
hadException = true;
|
|
}
|
|
}
|
|
assertTrue(hadException);
|
|
}
|
|
|
|
public void testOr() throws Exception {
|
|
loadText("fun foo(a : Int): Boolean = a > 0 || a/0 > 0");
|
|
Method main = generateFunction();
|
|
assertEquals(true, main.invoke(null, 5));
|
|
boolean hadException = false;
|
|
try {
|
|
main.invoke(null, 0);
|
|
} catch (InvocationTargetException e) {
|
|
if (e.getTargetException() instanceof ArithmeticException) {
|
|
hadException = true;
|
|
}
|
|
}
|
|
assertTrue(hadException);
|
|
}
|
|
|
|
public void testJavaConstructor() throws Exception {
|
|
loadText("fun foo(): StringBuilder = StringBuilder()");
|
|
Method main = generateFunction();
|
|
Object result = main.invoke(null);
|
|
assertTrue(result instanceof StringBuilder);
|
|
}
|
|
|
|
public void testJavaConstructorWithParameters() throws Exception {
|
|
loadText("fun foo(): StringBuilder = StringBuilder(\"beer\")");
|
|
Method main = generateFunction();
|
|
StringBuilder result = (StringBuilder) main.invoke(null);
|
|
assertEquals("beer", result.toString());
|
|
}
|
|
|
|
@SuppressWarnings("StringOperationCanBeSimplified")
|
|
public void testJavaEquals() throws Exception {
|
|
loadText("fun foo(s1: String, s2: String) = s1 == s2");
|
|
Method main = generateFunction();
|
|
assertEquals(Boolean.TRUE, main.invoke(null, new String("kotlin"), new String("kotlin")));
|
|
assertEquals(Boolean.FALSE, main.invoke(null, new String("kotlin"), new String("ceylon")));
|
|
}
|
|
|
|
@SuppressWarnings("StringOperationCanBeSimplified")
|
|
public void testJavaNotEquals() throws Exception {
|
|
loadText("fun foo(s1: String, s2: String) = s1 != s2");
|
|
Method main = generateFunction();
|
|
assertEquals(Boolean.FALSE, main.invoke(null, new String("kotlin"), new String("kotlin")));
|
|
assertEquals(Boolean.TRUE, main.invoke(null, new String("kotlin"), new String("ceylon")));
|
|
}
|
|
|
|
public void testJavaEqualsNull() throws Exception {
|
|
loadText("fun foo(s1: String?, s2: String?) = s1 == s2");
|
|
Method main = generateFunction();
|
|
assertEquals(Boolean.TRUE, main.invoke(null, null, null));
|
|
assertEquals(Boolean.FALSE, main.invoke(null, "kotlin", null));
|
|
assertEquals(Boolean.FALSE, main.invoke(null, null, "kotlin"));
|
|
}
|
|
|
|
public void testEqualsNullLiteral() throws Exception {
|
|
loadText("fun foo(s: String?) = s == null");
|
|
Method main = generateFunction();
|
|
assertEquals(Boolean.TRUE, main.invoke(null, new Object[] { null }));
|
|
assertEquals(Boolean.FALSE, main.invoke(null, "kotlin"));
|
|
}
|
|
|
|
@SuppressWarnings("StringOperationCanBeSimplified")
|
|
public void testTripleEq() throws Exception {
|
|
loadText("fun foo(s1: String?, s2: String?) = s1 === s2");
|
|
Method main = generateFunction();
|
|
String s1 = new String("kotlin");
|
|
String s2 = new String("kotlin");
|
|
assertEquals(Boolean.TRUE, main.invoke(null, s1, s1));
|
|
assertEquals(Boolean.FALSE, main.invoke(null, s1, s2));
|
|
}
|
|
|
|
@SuppressWarnings("StringOperationCanBeSimplified")
|
|
public void testTripleNotEq() throws Exception {
|
|
loadText("fun foo(s1: String?, s2: String?) = s1 !== s2");
|
|
Method main = generateFunction();
|
|
String s1 = new String("kotlin");
|
|
String s2 = new String("kotlin");
|
|
assertEquals(Boolean.FALSE, main.invoke(null, s1, s1));
|
|
assertEquals(Boolean.TRUE, main.invoke(null, s1, s2));
|
|
}
|
|
|
|
public void testStringPlus() throws Exception {
|
|
loadText("fun foo(s1: String, s2: String) = s1 + s2");
|
|
Method main = generateFunction();
|
|
assertEquals("kotlinLang", main.invoke(null, "kotlin", "Lang"));
|
|
}
|
|
|
|
public void testStringPlusChained() throws Exception {
|
|
loadText("fun foo(s1: String, s2: String, s3: String) = s1 + s2 + s3");
|
|
String text = generateToText();
|
|
int firstStringBuilderCreation = text.indexOf("NEW java/lang/StringBuilder");
|
|
assertEquals(-1, text.indexOf("NEW java/lang/StringBuilder", firstStringBuilderCreation + 1));
|
|
Method main = generateFunction();
|
|
assertEquals("kotlin Lang", main.invoke(null, "kotlin", " ", "Lang"));
|
|
}
|
|
|
|
public void testStringPlusEq() throws Exception {
|
|
loadText("fun foo(s: String) : String { var result = s; result += s; return result; } ");
|
|
Method main = generateFunction();
|
|
assertEquals("JarJar", main.invoke(null, "Jar"));
|
|
}
|
|
|
|
public void testStringCompare() throws Exception {
|
|
loadText("fun foo(s1: String, s2: String) = s1 < s2");
|
|
Method main = generateFunction();
|
|
assertEquals(Boolean.TRUE, main.invoke(null, "Ceylon", "Java"));
|
|
assertEquals(Boolean.FALSE, main.invoke(null, "Kotlin", "Java"));
|
|
}
|
|
|
|
public void testElvis() throws Exception {
|
|
loadText("fun foo(s: String?) = s ?: \"null\"");
|
|
Method main = generateFunction();
|
|
assertEquals("kotlin", main.invoke(null, "kotlin"));
|
|
assertEquals("null", main.invoke(null, new Object[] { null }));
|
|
}
|
|
|
|
public void testElvisInt() throws Exception {
|
|
loadText("fun foo(a: Int?): Int = a ?: 239");
|
|
Method main = generateFunction();
|
|
assertEquals(610, main.invoke(null, 610));
|
|
assertEquals(239, main.invoke(null, new Object[]{null}));
|
|
}
|
|
|
|
public void testVarargs() throws Exception {
|
|
loadText("fun foo() = java.util.Arrays.asList(\"IntelliJ\", \"IDEA\")");
|
|
Method main = generateFunction();
|
|
List<?> list = (List<?>) main.invoke(null);
|
|
assertEquals(Arrays.asList("IntelliJ", "IDEA"), list);
|
|
}
|
|
|
|
public void testFieldRead() throws Exception {
|
|
loadText("import java.awt.*; fun foo(c: GridBagConstraints) = c.gridx");
|
|
Method main = generateFunction();
|
|
GridBagConstraints c = new GridBagConstraints();
|
|
c.gridx = 239;
|
|
assertEquals(239, main.invoke(null, c));
|
|
}
|
|
|
|
public void testFieldWrite() throws Exception {
|
|
loadText("import java.awt.*; fun foo(c: GridBagConstraints) { c.gridx = 239 }");
|
|
Method main = generateFunction();
|
|
GridBagConstraints c = new GridBagConstraints();
|
|
main.invoke(null, c);
|
|
assertEquals(239, c.gridx);
|
|
}
|
|
|
|
public void testFieldIncrement() throws Exception {
|
|
loadText("import java.awt.*; fun foo(c: GridBagConstraints) { c.gridx++; return; }");
|
|
Method main = generateFunction();
|
|
GridBagConstraints c = new GridBagConstraints();
|
|
c.gridx = 609;
|
|
main.invoke(null, c);
|
|
assertEquals(610, c.gridx);
|
|
}
|
|
|
|
public void testFieldAugAssign() throws Exception {
|
|
loadText("import java.awt.*; fun foo(c: GridBagConstraints) { c.gridx *= 2; return; }");
|
|
Method main = generateFunction();
|
|
GridBagConstraints c = new GridBagConstraints();
|
|
c.gridx = 305;
|
|
main.invoke(null, c);
|
|
assertEquals(610, c.gridx);
|
|
}
|
|
|
|
public void testIncrementAsLastOperation() {
|
|
loadText("fun foo() { var a = 0; a++; }");
|
|
generateFunction(); // make sure we're not falling off end of code
|
|
}
|
|
|
|
public void testArrayRead() throws Exception {
|
|
loadText("fun foo(c: Array<String>) = c[0]");
|
|
Method main = generateFunction();
|
|
assertEquals("main", main.invoke(null, new Object[]{new String[]{"main"}}));
|
|
}
|
|
|
|
public void testArrayWrite() throws Exception {
|
|
loadText("fun foo(c: Array<String>) { c[0] = \"kotlin\"; }");
|
|
Method main = generateFunction();
|
|
String[] array = new String[] { null };
|
|
main.invoke(null, new Object[] { array });
|
|
assertEquals("kotlin", array[0]);
|
|
}
|
|
|
|
public void testArrayAugAssign() throws Exception {
|
|
loadText("fun foo(c: Array<Int>) { c[0] *= 2 }");
|
|
Method main = generateFunction();
|
|
Integer[] data = new Integer[] { 5 };
|
|
main.invoke(null, new Object[] { data });
|
|
assertEquals(10, data[0].intValue());
|
|
}
|
|
|
|
public void testArrayAugAssignLong() throws Exception {
|
|
loadText("fun foo(c: LongArray) { c[0] *= 2.toLong() }");
|
|
Method main = generateFunction();
|
|
long[] data = new long[] { 5 };
|
|
main.invoke(null, new Object[] { data });
|
|
assertEquals(10L, data[0]);
|
|
}
|
|
|
|
public void testArrayNewNullable() throws Exception {
|
|
loadText("fun foo() = arrayOfNulls<Int>(4)");
|
|
Method main = generateFunction();
|
|
Integer[] result = (Integer[]) main.invoke(null);
|
|
assertEquals(4, result.length);
|
|
}
|
|
public void testFloatArrayNew() throws Exception {
|
|
loadText("fun foo() = FloatArray(4)");
|
|
Method main = generateFunction();
|
|
float[] result = (float[]) main.invoke(null);
|
|
assertEquals(4, result.length);
|
|
}
|
|
|
|
public void testArraySize() throws Exception {
|
|
loadText("fun foo(a: Array<Int>) = a.size");
|
|
Method main = generateFunction();
|
|
Object[] args = new Object[] { new Integer[4] };
|
|
int result = (Integer) main.invoke(null, args);
|
|
assertEquals(4, result);
|
|
}
|
|
|
|
public void testIntArraySize() throws Exception {
|
|
loadText("fun foo(a: IntArray) = a.size");
|
|
Method main = generateFunction();
|
|
Object[] args = new Object[] { new int[4] };
|
|
int result = (Integer) main.invoke(null, args);
|
|
assertEquals(4, result);
|
|
}
|
|
|
|
public void testIntRange() throws Exception {
|
|
loadText("fun foo() = 1..10");
|
|
Method main = generateFunction();
|
|
Object result = main.invoke(null);
|
|
Method contains = result.getClass().getMethod("contains", Integer.TYPE);
|
|
assertTrue((Boolean) contains.invoke(result, 1));
|
|
assertTrue((Boolean) contains.invoke(result, 10));
|
|
assertFalse((Boolean) contains.invoke(result, 11));
|
|
}
|
|
|
|
public void testSubstituteJavaMethodTypeParameters() throws Exception {
|
|
loadText("import java.util.*; fun foo(l: ArrayList<Int>) { l.add(10) }");
|
|
Method main = generateFunction();
|
|
ArrayList<Integer> l = new ArrayList<>();
|
|
main.invoke(null, l);
|
|
assertEquals(10, l.get(0).intValue());
|
|
}
|
|
|
|
public void testCallMethodDeclaredInSuperclass() throws Exception {
|
|
loadText("fun foo(sb: StringBuilder) = sb.get(0)");
|
|
Method main = generateFunction();
|
|
StringBuilder sb = new StringBuilder("x");
|
|
assertEquals('x', ((Character) main.invoke(null, sb)).charValue());
|
|
}
|
|
|
|
public void testPutBooleanAsVoid() throws Exception {
|
|
loadText("class C(val x: Int) { init { x > 0 } } fun box() { val c = C(0) } ");
|
|
Method main = generateFunction();
|
|
main.invoke(null); // must not fail
|
|
}
|
|
|
|
public void testJavaInterfaceMethod() throws Exception {
|
|
loadText("import java.util.*; fun foo(l: ArrayList<String>) { l.add(\"foo\") }");
|
|
Method main = generateFunction();
|
|
ArrayList<String> list = new ArrayList<>();
|
|
main.invoke(null, list);
|
|
assertEquals("foo", list.get(0));
|
|
}
|
|
|
|
public void testArrayAccessForArrayList() throws Exception {
|
|
loadText("import java.util.*; fun foo(l: ArrayList<String>) { l[0] = \"Kotlin\" + l[0]; }");
|
|
Method main = generateFunction();
|
|
ArrayList<String> list = new ArrayList<>();
|
|
list.add("Language");
|
|
main.invoke(null, list);
|
|
assertEquals("KotlinLanguage", list.get(0));
|
|
}
|
|
|
|
public void testEscapeSequence() throws Exception {
|
|
loadText("fun foo() = \"a\\nb\\$\"");
|
|
Method main = generateFunction();
|
|
assertEquals("a\nb$", main.invoke(null));
|
|
}
|
|
|
|
public void testStringTemplate() throws Exception {
|
|
loadText("fun foo(a: String) = \"IntelliJ $a Rulezzz\"");
|
|
Method main = generateFunction();
|
|
assertEquals("IntelliJ IDEA Rulezzz", main.invoke(null, "IDEA"));
|
|
}
|
|
|
|
public void testExplicitCallOfBinaryOpIntrinsic() throws Exception {
|
|
loadText("fun foo(a: Int) = a.plus(1)");
|
|
Method main = generateFunction();
|
|
assertEquals(2, ((Integer) main.invoke(null, 1)).intValue());
|
|
}
|
|
|
|
public void testExplicitCallOfUnaryMinusIntrinsic() throws Exception {
|
|
loadText("fun foo(a: Int) = a.unaryMinus()");
|
|
Method main = generateFunction();
|
|
assertEquals(-1, ((Integer) main.invoke(null, 1)).intValue());
|
|
}
|
|
|
|
public void testExplicitCallOfBooleanNotIntrinsic() throws Exception {
|
|
loadText("fun foo(a: Boolean) = a.not()");
|
|
Method main = generateFunction();
|
|
assertFalse(((Boolean) main.invoke(null, true)).booleanValue());
|
|
}
|
|
|
|
public void testAppendArrayToString() throws Exception {
|
|
loadText("fun foo(a: String, b: Array<String>) = a + b");
|
|
Method main = generateFunction();
|
|
String[] args = new String[] { "foo", "bar" };
|
|
//noinspection ImplicitArrayToString
|
|
assertEquals("s" + args.toString(), main.invoke(null, "s", args));
|
|
}
|
|
}
|