/*
* Copyright 2012 Google Inc. All Rights Reserved.
*
* 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.types;
import com.google.devtools.j2objc.GenerationTest;
import com.google.devtools.j2objc.util.HeaderMap;
import java.io.IOException;
/**
* Unit tests for the {@link ImplementationImportCollector} class.
*
* @author Tom Ball
*/
public class ImplementationImportCollectorTest extends GenerationTest {
// Verify that invoked method's return value has associated header.
public void testMethodReturnHasHeader() throws IOException {
addSourceFile("class FooException extends Exception { AssertionError asAssertion() { "
+ "return new AssertionError(this); }}", "FooException.java");
addSourceFile(
"class FooMaker { static FooException makeException() { return new FooException(); }}",
"FooMaker.java");
String translation = translateSourceFile(
"class A { void test() { "
+ "throw FooMaker.makeException().asAssertion(); }}", "A", "A.m");
assertTranslation(translation, "#include \"FooException.h\"");
}
// http://b/7073329
public void testVarargsMethodNoActualArguments() throws IOException {
translateSourceFile(
"class Test { Test(String ... values) { } Test test = new Test(); }",
"Test", "Test.m");
// Nothing to do; Successful translation is the test.
}
public void testOneArgumentAndVarargs() throws IOException {
translateSourceFile(
"class Test { Test(int count, int ... values) { } Test test = new Test(2, 42, 63); }",
"Test", "Test.m");
// Nothing to do; Successful translation is the test.
}
// http://b/7106570
public void testVarargsMethodManyArguments() throws IOException {
translateSourceFile(
"class Test { Test(int... values) { } Test test = new Test(1,2,3); }",
"Test", "Test.m");
// Nothing to do; Successful translation is the test.
}
public void testBooleanArrayImport() throws IOException {
addSourceFile("class A { boolean[] b; }", "A.java");
String translation = translateSourceFile(
"class B { int test() { return new A().b.length; }}", "B", "B.m");
assertTranslation(translation, "#include \"IOSPrimitiveArray.h\"");
}
public void testPrimitiveArrayAsParameterImport() throws IOException {
addSourceFile(
"class B { protected char bits[]; public B(char[] bits_) { bits = bits_;} }", "B.java");
String translation = translateSourceFile(
"class A { public static final B test = new B(new char[]{'a', 'b'}); }", "A", "A.m");
assertTranslation(translation, "#include \"IOSPrimitiveArray.h\"");
}
public void testObjectArrayImport() throws IOException {
String translation = translateSourceFile(
"import java.util.BitSet; class A { public BitSet[] test = new BitSet[3]; }", "A", "A.m");
assertTranslation(translation, "#include \"IOSObjectArray.h\"");
assertTranslation(translation, "#include \"java/util/BitSet.h\"");
}
public void testEnhancedForMethodInvocation() throws IOException {
addSourceFile("import java.util.*; class A { "
+ "final Map<String,String> map = new HashMap<>(); }", "A.java");
String translation = translateSourceFile(
"import java.util.*; class B extends A { "
+ "void test() { for (String s : map.keySet()) {}}}", "B", "B.m");
assertTranslation(translation, "#include \"java/util/Map.h\"");
}
public void testReturnTypeOfSuperclassMethod() throws IOException {
addSourceFile("interface I {}", "I.java");
addSourceFile("class A implements I {}", "A.java");
addSourceFile("class B { A getAnA() { return new A(); } }", "B.java");
String translation = translateSourceFile(
"class C extends B { void test() { I i = getAnA(); } }", "C", "C.m");
assertTranslation(translation, "#include \"A.h\"");
}
// Verify that a primitive type literal has a wrapper class import.
public void testPrimitiveTypeLiteral() throws IOException {
// Use assignment to a @Weak object to ensure the IOSClass import isn't
// picked up by visiting a method or function invocation.
String translation = translateSourceFile(
"import com.google.j2objc.annotations.Weak; "
+ "class Test { @Weak Object o; void test() { o = double.class; } }",
"Test", "Test.m");
assertTranslation(translation, "#include \"IOSClass.h\"");
}
// Verify that an object array type literal imports IOSClass.
public void testArrayTypeLiteralImport() throws IOException {
String translation = translateSourceFile(
"class Test { Class arrayType() { return Object[].class; }}",
"Test", "Test.m");
assertTranslation(translation, "#include \"IOSClass.h\"");
}
// Verify that a multi-dimensional array declaration imports IOSObjectArray.
public void testMultiArrayTypeLiteralImport() throws IOException {
String translation = translateSourceFile(
"class Test { String[][] map = { { \"1\", \"one\" }, { \"2\", \"two\" } }; }",
"Test", "Test.m");
assertTranslation(translation, "#include \"IOSObjectArray.h\"");
}
// Verify that a multi-catch clause imports are all collected.
public void testMultiCatchClauses() throws IOException {
String translation = translateSourceFile(
"class Test { void test() {"
+ " try { System.out.println(); } catch (ArithmeticException | AssertionError | "
+ " ClassCastException | SecurityException e) {} }}",
"Test", "Test.m");
assertTranslation(translation, "#include \"java/lang/ArithmeticException.h\"");
assertTranslation(translation, "#include \"java/lang/AssertionError.h\"");
assertTranslation(translation, "#include \"java/lang/ClassCastException.h\"");
assertTranslation(translation, "#include \"java/lang/SecurityException.h\"");
}
// Verify that platform class packages aren't truncated with --no-package-directories.
public void testPlatformImports() throws IOException {
options.getHeaderMap().setOutputStyle(HeaderMap.OutputStyleOption.NONE);
String translation = translateSourceFile(
"package foo.bar; import org.xml.sax.*; import org.xml.sax.helpers.*; "
+ "class Test { XMLReader test() { "
+ " try { return XMLReaderFactory.createXMLReader(); } catch (SAXException e) {} "
+ " return null; }}",
"Test", "Test.m");
// Test file's import should not have package.
assertTranslation(translation, "#include \"Test.h\"");
// Platform file's imports should.
assertTranslation(translation, "#include \"org/xml/sax/SAXException.h\"");
assertTranslation(translation, "#include \"org/xml/sax/XMLReader.h\"");
assertTranslation(translation, "#include \"org/xml/sax/helpers/XMLReaderFactory.h\"");
}
// Verify that platform class packages aren't changed with --preserve-full-paths.
public void testPlatformImportsSourceDirs() throws IOException {
options.getHeaderMap().setOutputStyle(HeaderMap.OutputStyleOption.SOURCE);
String translation = translateSourceFile(
"package foo.bar; import org.xml.sax.*; import org.xml.sax.helpers.*; "
+ "class Test { XMLReader test() { "
+ " try { return XMLReaderFactory.createXMLReader(); } catch (SAXException e) {} "
+ " return null; }}",
"Test", "Test.m");
// Test file's import should not have package.
assertTranslation(translation, "#include \"Test.h\"");
// Platform file's imports should.
assertTranslation(translation, "#include \"org/xml/sax/SAXException.h\"");
assertTranslation(translation, "#include \"org/xml/sax/XMLReader.h\"");
assertTranslation(translation, "#include \"org/xml/sax/helpers/XMLReaderFactory.h\"");
}
public void testAddsHeaderForRenamedMainType() throws IOException {
String translation = translateSourceFile(
"package foo; import com.google.j2objc.annotations.ObjectiveCName;"
+ " @ObjectiveCName(\"Bar\") class Test {}", "foo.Test", "foo/Test.m");
assertTranslation(translation, "#include \"foo/Test.h\"");
}
public void testImportsNativeExpressionType() throws IOException {
addSourceFile("class Foo { "
+ " static java.util.List list = java.util.Collections.EMPTY_LIST; "
+ "}", "Foo.java");
String translation = translateSourceFile("class Test { void test() { "
+ "java.util.Collection c = null; c = Foo.list; }}", "Test", "Test.m");
assertTranslation(translation, "#include \"java/util/List.h\"");
}
public void testNoImportsForAbstractMethod() throws IOException {
String translation = translateSourceFile(
"interface Test { java.util.Map foo(java.util.List l); }", "Test", "Test.m");
assertNotInTranslation(translation, "Map.h");
assertNotInTranslation(translation, "List.h");
}
public void testReturnExpressionTypeIncluded() throws IOException {
addSourceFile("interface I {}", "I.java");
addSourceFile("class J implements I {}", "J.java");
addSourceFile("class A { J j; }", "A.java");
String translation = translateSourceFile(
"class B extends A { I foo() { return j; } }", "B", "B.m");
assertTranslation(translation, "#include \"J.h\"");
}
// Issue #802.
public void testEnhancedForStatementExpressionTypeIncluded() throws IOException {
addSourceFile("class A { public java.util.ArrayList<String> list; }", "A.java");
String translation = translateSourceFile(
"class B extends A { void foo() { if (list != null) { for (String elem : list) { "
+ "elem.hashCode(); } } } }", "B", "B.m");
assertTranslation(translation, "#include \"java/util/ArrayList.h\"");
}
}