/* * 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.gen; import com.google.devtools.j2objc.GenerationTest; import java.io.IOException; /** * Tests for {@link ObjectiveCSegmentedHeaderGenerator}. * * @author Keith Stanger */ public class ObjectiveCSegmentedHeaderGeneratorTest extends GenerationTest { // Segmented headers are on by default. public void testTypicalPreprocessorStatements() throws IOException { String translation = translateSourceFile( "class Test { static class Inner {} }", "Test", "Test.h"); assertTranslatedLines(translation, "#pragma push_macro(\"INCLUDE_ALL_Test\")", "#ifdef RESTRICT_Test", "#define INCLUDE_ALL_Test 0", "#else", "#define INCLUDE_ALL_Test 1", "#endif", "#undef RESTRICT_Test"); assertTranslation(translation, "#pragma pop_macro(\"INCLUDE_ALL_Test\")"); assertTranslatedLines(translation, "#if !defined (Test_) && (INCLUDE_ALL_Test || defined(INCLUDE_Test))", "#define Test_"); assertTranslatedLines(translation, "#if !defined (Test_Inner_) && " + "(INCLUDE_ALL_Test || defined(INCLUDE_Test_Inner))", "#define Test_Inner_"); } public void testIncludedType() throws IOException { String translation = translateSourceFile( "class Test implements Runnable { public void run() {} }", "Test", "Test.h"); assertTranslatedLines(translation, "#define RESTRICT_JavaLangRunnable 1", "#define INCLUDE_JavaLangRunnable 1", "#include \"java/lang/Runnable.h\""); } public void testLocalInclude() throws IOException { String translation = translateSourceFile( "class Test { static class Inner extends Test {} }", "Test", "Test.h"); assertTranslatedLines(translation, "#ifdef INCLUDE_Test_Inner", "#define INCLUDE_Test 1", "#endif"); } public void testLocalIncludeOfBaseClass() throws IOException { String translation = translateSourceFile( "class Test extends Foo { } class Foo {}", "Test", "Test.h"); assertTranslatedLines(translation, "#ifdef INCLUDE_Test", "#define INCLUDE_Foo 1", "#endif"); } // Verify that when a class is referenced in the same source file, a header // isn't included for it. public void testPackagePrivateBaseClass() throws IOException { String translation = translateSourceFile( "package bar; public class Test extends Foo {} " + "abstract class Foo {}", "Test", "bar/Test.h"); assertNotInTranslation(translation, "#include \"Foo.h\""); } public void testAddIgnoreDeprecationWarningsPragmaIfDeprecatedDeclarationsIsEnabled() throws IOException { options.enableDeprecatedDeclarations(); String translation = translateSourceFile("class Test {}", "Test", "Test.h"); assertTranslation(translation, "#pragma clang diagnostic push"); assertTranslation(translation, "#pragma GCC diagnostic ignored \"-Wdeprecated-declarations\""); assertTranslation(translation, "#pragma clang diagnostic pop"); } public void testForwardDeclarationForTypeInSameIncludeAsSuperclass() throws IOException { addSourceFile("class Foo { static class Bar { } }", "Foo.java"); String translation = translateSourceFile( "class Test extends Foo { Foo.Bar bar; }", "Test", "Test.h"); assertTranslatedLines(translation, "#define RESTRICT_Foo 1", "#define INCLUDE_Foo 1", "#include \"Foo.h\""); // Forward declaration for Foo_Bar is needed because the include of Foo.h // is restricted to only the Foo type. assertTranslation(translation, "@class Foo_Bar"); } public void testCombinedJarVariableNames() throws IOException { addJarFile("some/path/test.jar", "foo/Test.java", "package foo; import abc.Bar; class Test extends Bar {}"); addJarFile("other/path/test2.jar", "abc/Bar.java", "package abc; public class Bar {}"); options.getHeaderMap().setCombineJars(); runPipeline("some/path/test.jar", "other/path/test2.jar"); String translation = getTranslatedFile("some/path/test.h"); // Check that the RESTRICT and INCLUDE_ALL variables are prefixed with a // name derived from the jar file path. assertTranslatedLines(translation, "#pragma push_macro(\"INCLUDE_ALL_SomePathTest\")", "#ifdef RESTRICT_SomePathTest", "#define INCLUDE_ALL_SomePathTest 0", "#else", "#define INCLUDE_ALL_SomePathTest 1", "#endif", "#undef RESTRICT_SomePathTest"); // Check that the include of "Bar" uses the correct prefix on it's RESTRICT // variable. assertTranslatedLines(translation, "#define RESTRICT_OtherPathTest2 1", "#define INCLUDE_AbcBar 1", "#include \"other/path/test2.h\""); } // Verify INCLUDE, INCLUDE_ALL, and RESTRICT can still be used as static variables. public void testReservedNames() throws IOException { String translation = translateSourceFile( "class Test { " + "public static final int INCLUDE = 1; " + "public static final int INCLUDE_ALL = 2;" + "static class Inner { public static final int RESTRICT = 3; } }", "Test", "Test.h"); assertTranslatedLines(translation, "inline jint Test_get_INCLUDE();", "#define Test_INCLUDE 1", "J2OBJC_STATIC_FIELD_CONSTANT(Test, INCLUDE, jint)"); assertTranslatedLines(translation, "inline jint Test_get_INCLUDE_ALL();", "#define Test_INCLUDE_ALL 2", "J2OBJC_STATIC_FIELD_CONSTANT(Test, INCLUDE_ALL, jint)"); assertTranslatedLines(translation, "inline jint Test_Inner_get_RESTRICT();", "#define Test_Inner_RESTRICT 3", "J2OBJC_STATIC_FIELD_CONSTANT(Test_Inner, RESTRICT, jint)"); } }