SimpleCompilationTest.java revision fd8342a51a96282df315cd27055ba539e89a8c9e
1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.databinding.compilationTest;
18
19
20import org.apache.commons.lang3.StringUtils;
21import org.junit.Test;
22
23import android.databinding.tool.processing.ErrorMessages;
24import android.databinding.tool.processing.ScopedErrorReport;
25import android.databinding.tool.processing.ScopedException;
26import android.databinding.tool.store.Location;
27
28import java.io.File;
29import java.io.IOException;
30import java.net.URISyntaxException;
31import java.util.List;
32
33import static org.junit.Assert.assertEquals;
34import static org.junit.Assert.assertNotEquals;
35import static org.junit.Assert.assertNotNull;
36import static org.junit.Assert.assertTrue;
37import static org.junit.Assert.fail;
38
39@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
40public class SimpleCompilationTest extends BaseCompilationTest {
41
42    @Test
43    public void listTasks() throws IOException, URISyntaxException, InterruptedException {
44        prepareProject();
45        CompilationResult result = runGradle("tasks");
46        assertEquals(0, result.resultCode);
47        assertTrue("there should not be any errors", StringUtils.isEmpty(result.error));
48        assertTrue("Test sanity, empty project tasks",
49                result.resultContainsText("All tasks runnable from root project"));
50    }
51
52    @Test
53    public void testEmptyCompilation() throws IOException, URISyntaxException, InterruptedException {
54        prepareProject();
55        CompilationResult result = runGradle("assembleDebug");
56        assertEquals(result.error, 0, result.resultCode);
57        assertTrue("there should not be any errors " + result.error, StringUtils.isEmpty(result.error));
58        assertTrue("Test sanity, should compile fine",
59                result.resultContainsText("BUILD SUCCESSFUL"));
60    }
61
62    private ScopedException singleFileErrorTest(String resource, String targetFile,
63            String expectedExtract, String errorMessage)
64            throws IOException, URISyntaxException, InterruptedException {
65        prepareProject();
66        copyResourceTo(resource, targetFile);
67        CompilationResult result = runGradle("assembleDebug");
68        assertNotEquals(0, result.resultCode);
69        ScopedException scopedException = result.getBindingException();
70        assertNotNull(result.error, scopedException);
71        ScopedErrorReport report = scopedException.getScopedErrorReport();
72        assertNotNull(report);
73        assertEquals(1, report.getLocations().size());
74        Location loc = report.getLocations().get(0);
75        if (expectedExtract != null) {
76            String extract = extract(targetFile, loc);
77            assertEquals(expectedExtract, extract);
78        }
79        final File errorFile = new File(report.getFilePath());
80        assertTrue(errorFile.exists());
81        assertEquals(new File(testFolder, targetFile).getCanonicalFile(),
82                errorFile.getCanonicalFile());
83        if (errorMessage != null) {
84            assertEquals(errorMessage, scopedException.getBareMessage());
85        }
86        return scopedException;
87    }
88
89    @Test
90    public void testMultipleExceptionsInDifferentFiles()
91            throws IOException, URISyntaxException, InterruptedException {
92        prepareProject();
93        copyResourceTo("/layout/undefined_variable_binding.xml",
94                "/app/src/main/res/layout/broken.xml");
95        copyResourceTo("/layout/invalid_setter_binding.xml",
96                "/app/src/main/res/layout/invalid_setter.xml");
97        CompilationResult result = runGradle("assembleDebug");
98        assertNotEquals(result.output, 0, result.resultCode);
99        List<ScopedException> bindingExceptions = result.getBindingExceptions();
100        assertEquals(result.error, 2, bindingExceptions.size());
101        File broken = new File(testFolder, "/app/src/main/res/layout/broken.xml");
102        File invalidSetter = new File(testFolder, "/app/src/main/res/layout/invalid_setter.xml");
103        for (ScopedException exception : bindingExceptions) {
104            ScopedErrorReport report = exception.getScopedErrorReport();
105            final File errorFile = new File(report.getFilePath());
106            String message = null;
107            String expectedErrorFile = null;
108            if (errorFile.getCanonicalPath().equals(broken.getCanonicalPath())) {
109                message = String.format(ErrorMessages.UNDEFINED_VARIABLE, "myVariable");
110                expectedErrorFile = "/app/src/main/res/layout/broken.xml";
111            } else if (errorFile.getCanonicalPath().equals(invalidSetter.getCanonicalPath())) {
112                message = String.format(ErrorMessages.CANNOT_FIND_SETTER_CALL, "android:textx",
113                        String.class.getCanonicalName());
114                expectedErrorFile = "/app/src/main/res/layout/invalid_setter.xml";
115            } else {
116                fail("unexpected exception " + exception.getBareMessage());
117            }
118            assertEquals(1, report.getLocations().size());
119            Location loc = report.getLocations().get(0);
120            String extract = extract(expectedErrorFile, loc);
121            assertEquals("myVariable", extract);
122            assertEquals(message, exception.getBareMessage());
123        }
124    }
125
126    @Test
127    public void testBadSyntax() throws IOException, URISyntaxException, InterruptedException {
128        singleFileErrorTest("/layout/layout_with_bad_syntax.xml",
129                "/app/src/main/res/layout/broken.xml",
130                "myVar.length())",
131                String.format(ErrorMessages.SYNTAX_ERROR,
132                        "extraneous input ')' expecting {<EOF>, ',', '.', '[', '+', '-', '*', '/', "
133                                + "'%', '<<', '>>>', '>>', '<=', '>=', '>', '<', 'instanceof', "
134                                + "'==', '!=', '&', '^', '|', '&&', '||', '?', '??'}"));
135    }
136
137    @Test
138    public void testBrokenSyntax() throws IOException, URISyntaxException, InterruptedException {
139        singleFileErrorTest("/layout/layout_with_completely_broken_syntax.xml",
140                "/app/src/main/res/layout/broken.xml",
141                "new String()",
142                String.format(ErrorMessages.SYNTAX_ERROR,
143                        "mismatched input 'String' expecting {<EOF>, ',', '.', '[', '+', '-', '*', "
144                                + "'/', '%', '<<', '>>>', '>>', '<=', '>=', '>', '<', 'instanceof',"
145                                + " '==', '!=', '&', '^', '|', '&&', '||', '?', '??'}"));
146    }
147
148    @Test
149    public void testUndefinedVariable() throws IOException, URISyntaxException,
150            InterruptedException {
151        ScopedException ex = singleFileErrorTest("/layout/undefined_variable_binding.xml",
152                "/app/src/main/res/layout/broken.xml", "myVariable",
153                String.format(ErrorMessages.UNDEFINED_VARIABLE, "myVariable"));
154    }
155
156    @Test
157    public void testInvalidSetterBinding() throws IOException, URISyntaxException,
158            InterruptedException {
159        prepareProject();
160        ScopedException ex = singleFileErrorTest("/layout/invalid_setter_binding.xml",
161                "/app/src/main/res/layout/invalid_setter.xml", "myVariable",
162                String.format(ErrorMessages.CANNOT_FIND_SETTER_CALL, "android:textx",
163                        String.class.getCanonicalName()));
164    }
165
166    @Test
167    public void testRootTag() throws IOException, URISyntaxException,
168            InterruptedException {
169        prepareProject();
170        copyResourceTo("/layout/root_tag.xml", "/app/src/main/res/layout/root_tag.xml");
171        CompilationResult result = runGradle("assembleDebug");
172        assertNotEquals(0, result.resultCode);
173        assertNotNull(result.error);
174        final String expected = String.format(ErrorMessages.ROOT_TAG_NOT_SUPPORTED, "hello");
175        assertTrue(result.error.contains(expected));
176    }
177
178    @Test
179    public void testInvalidVariableType() throws IOException, URISyntaxException,
180            InterruptedException {
181        prepareProject();
182        ScopedException ex = singleFileErrorTest("/layout/invalid_variable_type.xml",
183                "/app/src/main/res/layout/invalid_variable.xml", "myVariable",
184                String.format(ErrorMessages.CANNOT_RESOLVE_TYPE, "myVariable~"));
185    }
186
187    @Test
188    public void testSingleModule() throws IOException, URISyntaxException, InterruptedException {
189        prepareApp(toMap(KEY_DEPENDENCIES, "compile project(':module1')",
190                KEY_SETTINGS_INCLUDES, "include ':app'\ninclude ':module1'"));
191        prepareModule("module1", "com.example.module1", toMap());
192        copyResourceTo("/layout/basic_layout.xml", "/module1/src/main/res/layout/module_layout.xml");
193        copyResourceTo("/layout/basic_layout.xml", "/app/src/main/res/layout/app_layout.xml");
194        CompilationResult result = runGradle("assembleDebug");
195        assertEquals(result.error, 0, result.resultCode);
196    }
197
198    @Test
199    public void testTwoLevelDependency() throws IOException, URISyntaxException, InterruptedException {
200        prepareApp(toMap(KEY_DEPENDENCIES, "compile project(':module1')",
201                KEY_SETTINGS_INCLUDES, "include ':app'\ninclude ':module1'\n"
202                        + "include ':module2'"));
203        prepareModule("module1", "com.example.module1", toMap(KEY_DEPENDENCIES,
204                "compile project(':module2')"));
205        prepareModule("module2", "com.example.module2", toMap());
206        copyResourceTo("/layout/basic_layout.xml",
207                "/module2/src/main/res/layout/module2_layout.xml");
208        copyResourceTo("/layout/basic_layout.xml", "/module1/src/main/res/layout/module1_layout.xml");
209        copyResourceTo("/layout/basic_layout.xml", "/app/src/main/res/layout/app_layout.xml");
210        CompilationResult result = runGradle("assembleDebug");
211        assertEquals(result.error, 0, result.resultCode);
212    }
213
214    @Test
215    public void testIncludeInMerge() throws Throwable {
216        prepareProject();
217        copyResourceTo("/layout/merge_include.xml", "/app/src/main/res/layout/merge_include.xml");
218        CompilationResult result = runGradle("assembleDebug");
219        assertNotEquals(0, result.resultCode);
220        List<ScopedException> errors = ScopedException.extractErrors(result.error);
221        assertEquals(result.error, 1, errors.size());
222        final ScopedException ex = errors.get(0);
223        final ScopedErrorReport report = ex.getScopedErrorReport();
224        final File errorFile = new File(report.getFilePath());
225        assertTrue(errorFile.exists());
226        assertEquals(
227                new File(testFolder, "/app/src/main/res/layout/merge_include.xml")
228                        .getCanonicalFile(),
229                errorFile.getCanonicalFile());
230        assertEquals("Merge shouldn't support includes as root. Error message was '" + result.error,
231                ErrorMessages.INCLUDE_INSIDE_MERGE, ex.getBareMessage());
232    }
233}
234