/*
* Copyright 2011 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.gen;
import com.google.devtools.j2objc.GenerationTest;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Unit tests for CPP line directive generation, used to support debugging.
*
* @author Tom Ball
*/
public class LineDirectivesTest extends GenerationTest {
@Override
protected void setUp() throws IOException {
super.setUp();
options.setEmitLineDirectives(true);
}
public void testNoHeaderNumbering() throws IOException {
String translation = translateSourceFile(
"import java.util.*;\n\n public class A {\n\n"
+ " // Method one\n"
+ " void one() {}\n\n"
+ " // Method two\n"
+ " void two() {}\n}\n",
"A", "A.h");
assertFalse(translation.contains("#line"));
}
public void testMethodNumbering() throws IOException {
String translation = translateSourceFile(
"import java.util.*;\n\n public class A {\n\n"
+ " // Method one\n"
+ " void one() {}\n\n"
+ " // Method two\n"
+ " void two() {}\n"
+ " void three() {}}\n",
"A", "A.m");
assertTranslation(translation, "#line 1 \"A.java\"");
assertTranslation(translation, "#line 3\n@implementation A");
assertTranslation(translation, "#line 6\n- (void)one");
// Lines match up between one() and two() so no need for the directive.
assertNotInTranslation(translation, "#line 9\n- (void)two");
assertTranslation(translation, "#line 10\n- (void)three");
}
public void testStatementNumbering() throws IOException {
String translation = translateSourceFile(
"public class A {\n"
+ " String test() {\n"
+ " // some comment\n"
+ " int i = 0;\n\n"
+ " // another comment\n"
+ " return Integer.toString(i);\n"
+ " }}\n",
"A", "A.m");
assertTranslation(translation, "#line 1 \"A.java\"");
assertTranslation(translation, "#line 2\n- (NSString *)test");
assertTranslation(translation, "#line 4\n jint i = 0;");
assertTranslation(translation, "#line 7\n return JavaLangInteger_toStringWithInt_(i);");
}
public void testForIfWhileStatementsWithoutBlocks() throws IOException {
String translation = translateSourceFile(
"public class Test {\n"
+ " void test(int n) {\n"
+ " for (int i = 0; i < 10; i++)\n"
+ " if ((n % 2) == 0)\n"
+ " n += i;\n"
+ " \n"
+ " for (int j = 0; j < 100; j++)\n"
+ " for (int k = 0; k < 1000; k++)\n"
+ " n += j + k;\n"
+ " \n"
+ " while (n > 0)\n"
+ " n--;"
+ " }}",
"Test", "Test.m");
assertTranslatedLines(translation,
"for (jint i = 0; i < 10; i++)",
"#line 4",
"if ((n % 2) == 0)",
"#line 5",
"n += i;",
"",
"#line 7",
"for (jint j = 0; j < 100; j++)",
"#line 8",
"for (jint k = 0; k < 1000; k++)",
"#line 9",
"n += j + k;",
"",
"#line 11",
"while (n > 0)",
"#line 12",
"n--;");
}
public void testCombinedFileLineDirectives() throws IOException {
// An example where some types will be reordered
addSourceFile(
"package unit;\n"
+ "public class Test {\n"
+ " public String Dummy(int i) {\n"
+ " System.out.println(\"Hello world!\");\n"
+ " return Integer.toString(i);\n"
+ " }\n"
+ "}\n"
+ "\n"
+ "class NotReordered {"
+ " public String DummyTwo(int i) {\n"
+ " int j = i + 1;\n"
+ " return Integer.toString(j);\n"
+ " }"
+ "}\n",
"unit/Test.java");
addSourceFile(
"package unit;\n"
+ "public class TestDependent {\n"
+ " public Test Dummy() {\n"
+ " return new Test();\n"
+ " }\n"
+ " public AnotherTest AnotherDummy() {\n"
+ " return new AnotherTest();\n"
+ " }\n"
+ "}\n",
"unit/TestDependent.java");
addSourceFile(
"package unit;\n"
+ "public class AnotherTest extends Test {\n"
+ " public void AnotherDummy() {\n"
+ " }\n"
+ "}\n"
+ "\n"
+ "class AlsoNotReordered {"
+ " public void DummyTwo() {\n"
+ " }"
+ "}\n",
"unit/AnotherTest.java");
String translation = translateCombinedFiles(
"unit/Foo", ".m",
"unit/TestDependent.java", "unit/AnotherTest.java", "unit/Test.java");
assertDirectivePreceedsLine(
translation, "TestDependent.java", "@implementation UnitTestDependent");
assertDirectivePreceedsLine(
translation, "Test.java", "@implementation UnitTest");
assertDirectivePreceedsLine(
translation, "AnotherTest.java", "@implementation UnitAnotherTest");
assertDirectivePreceedsLine(
translation, "AnotherTest.java", "@implementation UnitAlsoNotReordered");
assertDirectivePreceedsLine(
translation, "Test.java", "@implementation UnitNotReordered");
// make sure lines get re-synced when files are interwoven
assertTranslatedLines(translation,
"#line 3",
"- (NSString *)DummyWithInt:(jint)i {");
assertTranslatedLines(translation,
"#line 9",
"- (NSString *)DummyTwoWithInt:(jint)i {");
}
private static final Pattern LINE_DIRECTIVE_PATTERN = Pattern.compile(
"\\n#line \\d+ \"(\\S*)\"\\n");
/**
* Asserts that the directive "#line some_line "some_prefix/$filename""
* most immediately preceding the given line matches the given filename;
* that is, the line directives should say we are on the given filename
* and not some other filename.
*/
private void assertDirectivePreceedsLine(String translation, String filename, String line) {
int lineIndex = translation.indexOf(line + "\n");
assertTrue(lineIndex > 0);
// Find the last instance of a #line directive before lineIndex
Matcher m = LINE_DIRECTIVE_PATTERN.matcher(translation.substring(0, lineIndex));
String foundLineDirectiveFilename = "";
while (m.find()) {
foundLineDirectiveFilename = m.group(1);
}
assertTrue(foundLineDirectiveFilename.endsWith(filename));
}
}