/*
* 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 com.google.devtools.j2objc.translate;
import com.google.devtools.j2objc.GenerationTest;
import java.io.IOException;
/**
* Unit tests for {@link VarargsRewriter} class.
*
* @author Tom Ball, Keith Stanger
*/
public class VarargsRewriterTest extends GenerationTest {
// Issue 360: a null argument for a varargs parameter should not be rewritten
// as an array.
public void testNilVarargs() throws IOException {
String source =
"public class Test { "
+ " void foo(char... chars) {}"
+ " void test() { foo(null); }}";
String translation = translateSourceFile(source, "Test", "Test.m");
assertTranslation(translation, "[self fooWithCharArray:nil];");
assertNotInTranslation(translation,
"[self fooWithCharArray:[IOSCharArray arrayWithChars:(unichar[]){ nil } count:1]];");
}
public void testVarargsOfVariousNodeTypes() throws IOException {
String translation = translateSourceFile(
"interface Foo { void foo(int i); }"
+ "enum E { VALUE1(1); E(int... i) {} }"
+ "class A { A(int... i) {} A() { this(2); } void foo(int... i) {} }"
+ "class Test extends A { Test() { super(3); } void foo(int... i) {}"
+ "void test() { A a = new A(4); foo(5); super.foo(6); Foo f = this::foo; } }",
"Test", "Test.m");
// EnumConstantDeclaration
assertTranslation(translation,
"E_initWithIntArray_withNSString_withInt_(e, [IOSIntArray arrayWithInts:"
+ "(jint[]){ 1 } count:1], @\"VALUE1\", 0);");
// ConstructorInvocation
assertTranslatedLines(translation,
"void A_init(A *self) {",
" A_initWithIntArray_(self, [IOSIntArray arrayWithInts:(jint[]){ 2 } count:1]);",
"}");
// SuperConstructorInvocation
assertTranslatedLines(translation,
"void Test_init(Test *self) {",
" A_initWithIntArray_(self, [IOSIntArray arrayWithInts:(jint[]){ 3 } count:1]);",
"}");
assertTranslatedLines(translation,
// ClassInstanceCreation
"A *a = create_A_initWithIntArray_([IOSIntArray arrayWithInts:(jint[]){ 4 } count:1]);",
// MethodInvocation
"[self fooWithIntArray:[IOSIntArray arrayWithInts:(jint[]){ 5 } count:1]];",
// SuperMethodInvocation
"[super fooWithIntArray:[IOSIntArray arrayWithInts:(jint[]){ 6 } count:1]];");
// MethodReference
assertTranslatedLines(translation,
"- (void)fooWithInt:(jint)a {",
" [target$_ fooWithIntArray:[IOSIntArray arrayWithInts:(jint[]){ a } count:1]];",
"}");
}
// Verify that a single object array argument to an object varargs method is passed unchanged.
// Covers all kinds of invocation.
public void testObjectArrayVarargs() throws IOException {
String translation = translateSourceFile(
"import java.util.Arrays;"
+ "interface Baz { void baz(Object[] o); } class Foo<T> { Foo(T... t) {} } class Bar {"
+ "<T> Bar(T... t) {} Bar(int i, Object[] array) { this(array); } <T> void bar(T... t) {} }"
+ "enum E { A(new Object[] { }); <T> E(T... t) {} }"
+ "class Test extends Bar { Test(Object[] array) { super(array); }"
+ "void test(Object[] array) { "
+ "Arrays.asList(array); super.bar(array); new Foo(array); Baz b = Arrays::asList;}}",
"Test", "Test.m");
assertTranslation(translation,
"E_initWithNSObjectArray_withNSString_withInt_(e, [IOSObjectArray arrayWithObjects:"
+ "(id[]){ } count:0 type:NSObject_class_()], @\"A\", 0);");
assertTranslatedLines(translation,
"void Bar_initWithInt_withNSObjectArray_(Bar *self, jint i, IOSObjectArray *array) {",
" Bar_initWithNSObjectArray_(self, array);",
"}");
assertTranslatedLines(translation,
"void Test_initWithNSObjectArray_(Test *self, IOSObjectArray *array) {",
" Bar_initWithNSObjectArray_(self, array);",
"}");
assertTranslatedLines(translation,
"JavaUtilArrays_asListWithNSObjectArray_(array);",
"[super barWithNSObjectArray:array];",
"create_Foo_initWithNSObjectArray_(array);");
// Lambda implementation for Arrays::asList.
assertTranslatedLines(translation,
"- (void)bazWithNSObjectArray:(IOSObjectArray *)a {",
" JavaUtilArrays_asListWithNSObjectArray_(a);",
"}");
}
// Verify that a single primitive array argument to a primitive varargs method is
// passed unchanged.
public void testPrimitiveArrayVarargs() throws IOException {
String translation = translateSourceFile(
"class Test { void doVarargs(int... ints) {}"
+ "void test(int[] array) { doVarargs(array); }}",
"Test", "Test.m");
assertTranslation(translation, "[self doVarargsWithIntArray:array];");
}
// Verify that a single primitive array argument to an object varargs method is just treated
// like any other object.
public void testPrimitiveArrayToObjectVarargs() throws IOException {
String translation = translateSourceFile(
"class Test { void test(float[] array) { java.util.Arrays.asList(array); }}",
"Test", "Test.m");
assertTranslation(translation, "JavaUtilArrays_asListWithNSObjectArray_("
+ "[IOSObjectArray arrayWithObjects:(id[]){ array } count:1 "
+ "type:IOSClass_floatArray(1)]);");
}
public void testMultiDimPrimitiveArrayPassedToTypeVariableVarargs() throws IOException {
String translation = translateSourceFile(
"class Test { void test(int[][] array) { java.util.Arrays.asList(array); } }",
"Test", "Test.m");
// Array should be passed as it is.
assertTranslation(translation, "JavaUtilArrays_asListWithNSObjectArray_(array);");
}
public void testTwoDimObjectArrayPassedToObjectVarargs() throws IOException {
String translation = translateSourceFile(
"class Test { void foo(Object... args) {} void test(Object[][] array) { foo(array); } }",
"Test", "Test.m");
// Array should be passed as it is.
assertTranslation(translation, "[self fooWithNSObjectArray:array];");
}
// Verify cloning a single array argument doesn't cause it to get boxed in another array.
public void testArrayCloneArgument() throws IOException {
String translation = translateSourceFile(
"class A { void varargs(String s, Object... objects) {}"
+ "void test() { Object[] objs = new Object[] { \"\", \"\" };"
+ "varargs(\"objects\", objs.clone()); }}", "A", "A.m");
assertTranslation(translation,
"[self varargsWithNSString:@\"objects\" withNSObjectArray:[objs java_clone]];");
}
public void testGenericSuperMethodInvocation() throws IOException {
String translation = translateSourceFile(
"class Test { class A<E> { void test(E... objs) {} } class B<E> extends A<E> { "
+ "void test(E... objs) { super.test(objs); } } }", "Test", "Test.m");
// Must pass the objs parameter as a direct argument, not wrap in a varargs array.
assertTranslation(translation, "[super testWithNSObjectArray:objs];");
}
public void testGenericVarargsInvocation() throws IOException {
String translation = translateSourceFile(
"class Test<T extends Runnable> { void foo(T... t) {} void test(T t) { foo(t); } }",
"Test", "Test.m");
assertTranslation(translation,
"[self fooWithJavaLangRunnableArray:[IOSObjectArray arrayWithObjects:(id[]){ t } "
+ "count:1 type:JavaLangRunnable_class_()]];");
}
}