summaryrefslogtreecommitdiff
path: root/compilationTests
diff options
context:
space:
mode:
authorYigit Boyar <yboyar@google.com>2015-06-25 10:50:24 -0700
committerYigit Boyar <yboyar@google.com>2015-06-30 10:19:08 -0700
commit731b74f7f44e67312a1fc4161c4e0aae221b2417 (patch)
tree62ff3308d8e30d00568db694469c54caacff90d1 /compilationTests
parent4df4ba38a62b791bbbc25e923efe8d9c2f9a52e9 (diff)
downloaddata-binding-731b74f7f44e67312a1fc4161c4e0aae221b2417.tar.gz
Introduce Scopes to track logical stack traces
This CL introduces a static class called Scope, which is used the logical processing stack for data binding. These scopes are used to generate meaningful error messages when an error is detected. Bug: 21953001 Change-Id: I5470a8c4ad94401d34a140762baae9d53c5a0402
Diffstat (limited to 'compilationTests')
-rw-r--r--compilationTests/build.gradle1
-rw-r--r--compilationTests/src/test/java/android/databinding/compilationTest/BaseCompilationTest.java51
-rw-r--r--compilationTests/src/test/java/android/databinding/compilationTest/CompilationResult.java20
-rw-r--r--compilationTests/src/test/java/android/databinding/compilationTest/SimpleCompilationTest.java111
4 files changed, 171 insertions, 12 deletions
diff --git a/compilationTests/build.gradle b/compilationTests/build.gradle
index abe046ac..e8b56dd9 100644
--- a/compilationTests/build.gradle
+++ b/compilationTests/build.gradle
@@ -12,4 +12,5 @@ dependencies {
testCompile 'org.apache.commons:commons-lang3:3.3.2'
testCompile 'commons-io:commons-io:2.4'
testCompile 'commons-codec:commons-codec:1.10'
+ testCompile project(':compilerCommon')
} \ No newline at end of file
diff --git a/compilationTests/src/test/java/android/databinding/compilationTest/BaseCompilationTest.java b/compilationTests/src/test/java/android/databinding/compilationTest/BaseCompilationTest.java
index c390edcc..51925d58 100644
--- a/compilationTests/src/test/java/android/databinding/compilationTest/BaseCompilationTest.java
+++ b/compilationTests/src/test/java/android/databinding/compilationTest/BaseCompilationTest.java
@@ -19,6 +19,10 @@ package android.databinding.compilationTest;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.TestName;
+
+import android.databinding.tool.store.Location;
import java.io.File;
import java.io.FileOutputStream;
@@ -29,8 +33,11 @@ import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.attribute.PosixFilePermission;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
@@ -42,6 +49,8 @@ import static org.junit.Assert.assertTrue;
public class BaseCompilationTest {
+ @Rule
+ public TestName name = new TestName();
static Pattern VARIABLES = Pattern.compile("!@\\{([A-Za-z0-9_-]*)}");
public static final String KEY_MANIFEST_PACKAGE = "PACKAGE";
@@ -49,7 +58,7 @@ public class BaseCompilationTest {
public static final String KEY_SETTINGS_INCLUDES = "SETTINGS_INCLUDES";
public static final String DEFAULT_APP_PACKAGE = "com.android.databinding.compilationTest.test";
- File testFolder = new File("./build/build-test");
+ protected final File testFolder = new File("./build/build-test");
protected void copyResourceTo(String name, String path) throws IOException {
copyResourceTo(name, new File(testFolder, path));
@@ -81,6 +90,36 @@ public class BaseCompilationTest {
}
}
+ /**
+ * Extracts the text in the given location from the the at the given application path.
+ * @param pathInApp The path, relative to the root of the application under test
+ * @param location The location to extract
+ * @return The string that is contained in the given location
+ * @throws IOException If file is invalid.
+ */
+ protected String extract(String pathInApp, Location location) throws IOException {
+ File file = new File(testFolder, pathInApp);
+ assertTrue(file.exists());
+ StringBuilder result = new StringBuilder();
+ List<String> lines = FileUtils.readLines(file);
+ for (int i = location.startLine; i <= location.endLine; i ++) {
+ if (i > location.startLine) {
+ result.append("\n");
+ }
+ String line = lines.get(i);
+ int start = 0;
+ if (i == location.startLine) {
+ start = location.startOffset;
+ }
+ int end = line.length() - 1; // inclusive
+ if (i == location.endLine) {
+ end = location.endOffset;
+ }
+ result.append(line.substring(start, end + 1));
+ }
+ return result.toString();
+ }
+
protected void copyResourceTo(String name, File targetFile) throws IOException {
File directory = targetFile.getParentFile();
FileUtils.forceMkdir(directory);
@@ -179,13 +218,17 @@ public class BaseCompilationTest {
copyResourceTo("/module_build.gradle", new File(moduleFolder, "build.gradle"), replacements);
}
- protected CompilationResult runGradle(String params) throws IOException, InterruptedException {
+ protected CompilationResult runGradle(String... params) throws IOException, InterruptedException {
setExecutable();
File pathToExecutable = new File(testFolder, "gradlew");
- ProcessBuilder builder = new ProcessBuilder(pathToExecutable.getAbsolutePath(), params);
+ List<String> args = new ArrayList<>();
+ args.add(pathToExecutable.getAbsolutePath());
+ args.add("--project-cache-dir");
+ args.add(new File("../.caches/", name.getMethodName()).getAbsolutePath());
+ Collections.addAll(args, params);
+ ProcessBuilder builder = new ProcessBuilder(args);
builder.environment().putAll(System.getenv());
builder.directory(testFolder);
- //builder.redirectErrorStream(true); // merges error and input streams
Process process = builder.start();
String output = IOUtils.toString(process.getInputStream());
String error = IOUtils.toString(process.getErrorStream());
diff --git a/compilationTests/src/test/java/android/databinding/compilationTest/CompilationResult.java b/compilationTests/src/test/java/android/databinding/compilationTest/CompilationResult.java
index 496550ba..f50755bd 100644
--- a/compilationTests/src/test/java/android/databinding/compilationTest/CompilationResult.java
+++ b/compilationTests/src/test/java/android/databinding/compilationTest/CompilationResult.java
@@ -16,6 +16,13 @@
package android.databinding.compilationTest;
+import android.databinding.tool.processing.ScopedErrorReport;
+import android.databinding.tool.processing.ScopedException;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
public class CompilationResult {
public final int resultCode;
public final String output;
@@ -34,4 +41,17 @@ public class CompilationResult {
public boolean errorContainsText(String text) {
return resultCode != 0 && error.indexOf(text) > 0;
}
+
+ public ScopedException getBindingException() {
+ List<ScopedException> errors = ScopedException.extractErrors(error);
+ if (errors.isEmpty()) {
+ return null;
+ }
+ assertEquals(1, errors.size());
+ return errors.get(0);
+ }
+
+ public List<ScopedException> getBindingExceptions() {
+ return ScopedException.extractErrors(error);
+ }
}
diff --git a/compilationTests/src/test/java/android/databinding/compilationTest/SimpleCompilationTest.java b/compilationTests/src/test/java/android/databinding/compilationTest/SimpleCompilationTest.java
index 6540e67d..877fe80a 100644
--- a/compilationTests/src/test/java/android/databinding/compilationTest/SimpleCompilationTest.java
+++ b/compilationTests/src/test/java/android/databinding/compilationTest/SimpleCompilationTest.java
@@ -20,13 +20,21 @@ package android.databinding.compilationTest;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
+import android.databinding.tool.processing.ErrorMessages;
+import android.databinding.tool.processing.ScopedErrorReport;
+import android.databinding.tool.processing.ScopedException;
+import android.databinding.tool.store.Location;
+
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
+import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
public class SimpleCompilationTest extends BaseCompilationTest {
@@ -50,17 +58,95 @@ public class SimpleCompilationTest extends BaseCompilationTest {
result.resultContainsText("BUILD SUCCESSFUL"));
}
+ private ScopedException singleFileErrorTest(String resource, String targetFile,
+ String expectedExtract, String errorMessage)
+ throws IOException, URISyntaxException, InterruptedException {
+ prepareProject();
+ copyResourceTo(resource, targetFile);
+ CompilationResult result = runGradle("assembleDebug");
+ assertNotEquals(0, result.resultCode);
+ ScopedException scopedException = result.getBindingException();
+ assertNotNull(scopedException);
+ ScopedErrorReport report = scopedException.getScopedErrorReport();
+ assertNotNull(report);
+ assertEquals(1, report.getLocations().size());
+ Location loc = report.getLocations().get(0);
+ if (expectedExtract != null) {
+ String extract = extract(targetFile, loc);
+ assertEquals(expectedExtract, extract);
+ }
+ final File errorFile = new File(report.getFilePath());
+ assertTrue(errorFile.exists());
+ assertEquals(new File(testFolder, targetFile).getCanonicalFile(),
+ errorFile.getCanonicalFile());
+ if (errorMessage != null) {
+ assertEquals(errorMessage, scopedException.getBareMessage());
+ }
+ return scopedException;
+ }
+
@Test
- public void testUndefinedVariable() throws IOException, URISyntaxException,
- InterruptedException {
+ public void testMultipleExceptionsInDifferentFiles()
+ throws IOException, URISyntaxException, InterruptedException {
prepareProject();
copyResourceTo("/layout/undefined_variable_binding.xml",
"/app/src/main/res/layout/broken.xml");
+ copyResourceTo("/layout/invalid_setter_binding.xml",
+ "/app/src/main/res/layout/invalid_setter.xml");
CompilationResult result = runGradle("assembleDebug");
assertNotEquals(0, result.resultCode);
- assertTrue("Undefined variable",
- result.errorContainsText(
- "Identifiers must have user defined types from the XML file. myVariable is missing it"));
+ List<ScopedException> bindingExceptions = result.getBindingExceptions();
+ assertEquals(2, bindingExceptions.size());
+ File broken = new File(testFolder, "/app/src/main/res/layout/broken.xml");
+ File invalidSetter = new File(testFolder, "/app/src/main/res/layout/invalid_setter.xml");
+ for (ScopedException exception : bindingExceptions) {
+ ScopedErrorReport report = exception.getScopedErrorReport();
+ final File errorFile = new File(report.getFilePath());
+ String message = null;
+ String expectedErrorFile = null;
+ if (errorFile.getCanonicalPath().equals(broken.getCanonicalPath())) {
+ message = String.format(ErrorMessages.UNDEFINED_VARIABLE, "myVariable");
+ expectedErrorFile = "/app/src/main/res/layout/broken.xml";
+ } else if (errorFile.getCanonicalPath().equals(invalidSetter.getCanonicalPath())) {
+ message = String.format(ErrorMessages.CANNOT_FIND_SETTER_CALL, "android:textx",
+ String.class.getCanonicalName());
+ expectedErrorFile = "/app/src/main/res/layout/invalid_setter.xml";
+ } else {
+ fail("unexpected exception " + exception.getBareMessage());
+ }
+ assertEquals(1, report.getLocations().size());
+ Location loc = report.getLocations().get(0);
+ String extract = extract(expectedErrorFile, loc);
+ assertEquals("myVariable", extract);
+ assertEquals(message, exception.getBareMessage());
+ }
+ }
+
+ @Test
+ public void testUndefinedVariable() throws IOException, URISyntaxException,
+ InterruptedException {
+ ScopedException ex = singleFileErrorTest("/layout/undefined_variable_binding.xml",
+ "/app/src/main/res/layout/broken.xml", "myVariable",
+ String.format(ErrorMessages.UNDEFINED_VARIABLE, "myVariable"));
+ }
+
+ @Test
+ public void testInvalidSetterBinding() throws IOException, URISyntaxException,
+ InterruptedException {
+ prepareProject();
+ ScopedException ex = singleFileErrorTest("/layout/invalid_setter_binding.xml",
+ "/app/src/main/res/layout/invalid_setter.xml", "myVariable",
+ String.format(ErrorMessages.CANNOT_FIND_SETTER_CALL, "android:textx",
+ String.class.getCanonicalName()));
+ }
+
+ @Test
+ public void testInvalidVariableType() throws IOException, URISyntaxException,
+ InterruptedException {
+ prepareProject();
+ ScopedException ex = singleFileErrorTest("/layout/invalid_variable_type.xml",
+ "/app/src/main/res/layout/invalid_variable.xml", "myVariable",
+ String.format(ErrorMessages.CANNOT_RESOLVE_TYPE, "myVariable~"));
}
@Test
@@ -96,8 +182,17 @@ public class SimpleCompilationTest extends BaseCompilationTest {
copyResourceTo("/layout/merge_include.xml", "/app/src/main/res/layout/merge_include.xml");
CompilationResult result = runGradle("assembleDebug");
assertNotEquals(0, result.resultCode);
- assertTrue("Merge shouldn't support includes as root. Error message was '" + result.error + "'",
- result.errorContainsText(
- "Data binding does not support include elements as direct children of a merge element"));
+ List<ScopedException> errors = ScopedException.extractErrors(result.error);
+ assertEquals(result.error, 1, errors.size());
+ final ScopedException ex = errors.get(0);
+ final ScopedErrorReport report = ex.getScopedErrorReport();
+ final File errorFile = new File(report.getFilePath());
+ assertTrue(errorFile.exists());
+ assertEquals(
+ new File(testFolder, "/app/src/main/res/layout/merge_include.xml")
+ .getCanonicalFile(),
+ errorFile.getCanonicalFile());
+ assertEquals("Merge shouldn't support includes as root. Error message was '" + result.error,
+ ErrorMessages.INCLUDE_INSIDE_MERGE, ex.getBareMessage());
}
}