/* * Copyright (C) 2013 The Android Open Source Project * * 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.android.tools.idea.gradle.output.parser; import com.android.annotations.Nullable; import com.android.tools.idea.gradle.output.GradleMessage; import com.android.tools.idea.gradle.output.GradleProjectAwareMessage; import com.android.tools.idea.gradle.output.parser.aapt.AbstractAaptOutputParser; import com.google.common.base.Charsets; import com.google.common.io.Closeables; import com.google.common.io.Files; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.SystemProperties; import com.intellij.util.containers.ContainerUtil; import junit.framework.TestCase; import org.jetbrains.annotations.NotNull; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.Collection; import java.util.List; import java.util.Locale; import static com.android.SdkConstants.*; import static com.android.utils.SdkUtils.createPathComment; /** * Tests for {@link BuildOutputParser}. * * These tests MUST be executed on Windows too. */ @SuppressWarnings({"ResultOfMethodCallIgnored", "StringBufferReplaceableByString"}) public class BuildOutputParserTest extends TestCase { private static final String NEWLINE = SystemProperties.getLineSeparator(); private File sourceFile; private String sourceFilePath; private BuildOutputParser parser; @Override public void setUp() throws Exception { super.setUp(); parser = new BuildOutputParser(); } @Override public void tearDown() throws Exception { if (sourceFile != null) { sourceFile.delete(); } super.tearDown(); } public void testParseDisplayingUnhandledMessages() { String output = " **--- HELLO WORLD ---**"; List<GradleMessage> gradleMessages = parser.parseGradleOutput(output); assertEquals(1, gradleMessages.size()); GradleMessage message = gradleMessages.get(0); assertEquals(output, message.getText()); assertEquals(GradleMessage.Kind.SIMPLE, message.getKind()); } public void testParseAaptOutputWithRange1() throws IOException { createTempXmlFile(); writeToFile("<manifest xmlns:android='http://schemas.android.com/apk/res/android'", " android:versionCode='12' android:versionName='2.0' package='com.android.tests.basic'>", " <uses-sdk android:minSdkVersion='16' android:targetSdkVersion='16'/>", " <application android:icon='@drawable/icon' android:label='@string/app_name2'>"); String messageText = "No resource found that matches the given name (at 'label' with value " + "'@string/app_name2')."; String err = sourceFilePath + ":4: error: Error: " + messageText; Collection<GradleMessage> messages = parser.parseGradleOutput(err); assertHasCorrectErrorMessage(messages, messageText, 4, 61); } public void testParseAaptOutputWithRange2() throws IOException { // Check that when the actual aapt error occurs on a line later than the original error line, // the forward search which looks for a value match does not stop on an earlier line that // happens to have the same value prefix createTempXmlFile(); writeToFile("<manifest xmlns:android='http://schemas.android.com/apk/res/android'", " android:versionCode='12' android:versionName='2.0' package='com.android.tests.basic'>", " <uses-sdk android:minSdkVersion='16' android:targetSdkVersion='16'/>", " <application android:icon='@drawable/icon' android:label=", " '@string/app_name2'>"); String messageText = "No resource found that matches the given name (at 'label' with value " + "'@string/app_name2')."; String err = sourceFilePath + ":4: error: Error: " + messageText; Collection<GradleMessage> messages = parser.parseGradleOutput(err); assertHasCorrectErrorMessage(messages, messageText, 5, 8); } public void testParseAaptOutputWithRange3() throws IOException { // Check that when we have a duplicate resource error, we highlight both the original property // and the original definition. // This tests the second, duplicate declaration ration. createTempXmlFile(); writeToFile("<resources xmlns:android='http://schemas.android.com/apk/res/android'>", " <style name='repeatedStyle1'>", " <item name='android:gravity'>left</item>", " </style>", " <style name='repeatedStyle1'>", " <item name='android:gravity'>left</item>"); String messageText = "Resource entry repeatedStyle1 already has bag item android:gravity."; String err = sourceFilePath + ":6: error: " + messageText; Collection<GradleMessage> messages = parser.parseGradleOutput(err); assertHasCorrectErrorMessage(messages, messageText, 6, 17); } public void testParseAaptOutputWithRange4() throws IOException { // Check that when we have a duplicate resource error, we highlight both the original property // and the original definition. // This tests the original definition. Note that we don't have enough position info so we simply // highlight the whitespace portion of the line. createTempXmlFile(); writeToFile("<resources xmlns:android='http://schemas.android.com/apk/res/android'>", " <style name='repeatedStyle1'>", " <item name='android:gravity'>left</item>"); String messageText = "Originally defined here."; String err = sourceFilePath + ":3: " + messageText; Collection<GradleMessage> messages = parser.parseGradleOutput(err); assertHasCorrectErrorMessage(messages, messageText, 3, 5); } public void testParseAaptOutputWithRange5() throws IOException { // Check for aapt error which occurs when the attribute name in an item style declaration is // non-existent. createTempXmlFile(); writeToFile("<resources xmlns:android='http://schemas.android.com/apk/res/android'>", " <style name='wrongAttribute'>", " <item name='nonexistent'>left</item>"); String messageText = "No resource found that matches the given name: attr 'nonexistent'."; String err = sourceFilePath + ":3: error: Error: " + messageText; Collection<GradleMessage> messages = parser.parseGradleOutput(err); assertHasCorrectErrorMessage(messages, messageText, 3, 17); } public void testParseAaptOutputWithRange6() throws IOException { // Test missing resource name. createTempXmlFile(); writeToFile("<resources xmlns:android='http://schemas.android.com/apk/res/android'>", " <style>"); String messageText = "A 'name' attribute is required for <style>"; String err = sourceFilePath + ":2: error: " + messageText; Collection<GradleMessage> messages = parser.parseGradleOutput(err); assertHasCorrectErrorMessage(messages, messageText, 2, 3); } public void testParseAaptOutputWithRange7() throws IOException { createTempXmlFile(); writeToFile("<resources xmlns:android='http://schemas.android.com/apk/res/android'>", " <item>"); String messageText = "A 'type' attribute is required for <item>"; String err = sourceFilePath + ":2: error: " + messageText; Collection<GradleMessage> messages = parser.parseGradleOutput(err); assertHasCorrectErrorMessage(messages, messageText, 2, 3); } public void testParseAaptOutputWithRange8() throws IOException { createTempXmlFile(); writeToFile("<resources xmlns:android='http://schemas.android.com/apk/res/android'>", " <item>"); String messageText = "A 'name' attribute is required for <item>"; String err = sourceFilePath + ":2: error: " + messageText; Collection<GradleMessage> messages = parser.parseGradleOutput(err); assertHasCorrectErrorMessage(messages, messageText, 2, 3); } public void testParseAaptOutputWithRange9() throws IOException { createTempXmlFile(); writeToFile("<resources xmlns:android='http://schemas.android.com/apk/res/android'>", " <style name='test'>", " <item name='android:layout_width'></item>"); String messageText = "String types not allowed (at 'android:layout_width' with value '')."; String err = sourceFilePath + ":3: error: " + messageText; Collection<GradleMessage> messages = parser.parseGradleOutput(err); assertHasCorrectErrorMessage(messages, messageText, 3, 21); } public void testParseAaptOutputWithRange10() throws IOException { createTempXmlFile(); writeToFile("<FrameLayout", " xmlns:android='http://schemas.android.com/apk/res/android'", " android:layout_width='wrap_content'", " android:layout_height='match_parent'>", " <TextView", " android:layout_width='fill_parent'", " android:layout_height='wrap_content'", " android:layout_marginTop=''", " android:layout_marginLeft=''"); String messageText = "String types not allowed (at 'layout_marginTop' with value '')."; String err = sourceFilePath + ":5: error: Error: " + messageText; Collection<GradleMessage> messages = parser.parseGradleOutput(err); assertHasCorrectErrorMessage(messages, messageText, 8, 34); } public void testParseAaptOutputWithRange11() throws IOException { createTempXmlFile(); writeToFile("<FrameLayout", " xmlns:android='http://schemas.android.com/apk/res/android'", " android:layout_width='wrap_content'", " android:layout_height='match_parent'>", " <TextView", " android:layout_width='fill_parent'", " android:layout_height='wrap_content'", " android:layout_marginTop=''", " android:layout_marginLeft=''"); String messageText = "String types not allowed (at 'layout_marginLeft' with value '')."; String err = sourceFilePath + ":5: error: Error: " + messageText; Collection<GradleMessage> messages = parser.parseGradleOutput(err); assertHasCorrectErrorMessage(messages, messageText, 9, 35); } public void testParseAaptOutputWithRange12() throws IOException { createTempXmlFile(); writeToFile("<FrameLayout", " xmlns:android='http://schemas.android.com/apk/res/android'", " android:layout_width='wrap_content'", " android:layout_height='match_parent'>", " <TextView", " android:id=''"); String messageText = "String types not allowed (at 'id' with value '')."; String err = sourceFilePath + ":5: error: Error: " + messageText; Collection<GradleMessage> messages = parser.parseGradleOutput(err); assertHasCorrectErrorMessage(messages, messageText, 6, 20); } private void createTempXmlFile() throws IOException { createTempFile(DOT_XML); } public void testParseJavaOutput1() throws IOException { createTempFile(".java"); writeToFile("public class Test {", " public static void main(String[] args) {", " int v2 = v4"); StringBuilder err = new StringBuilder(); err.append(sourceFilePath).append(":3: error: ").append("cannot find symbol").append(NEWLINE) .append("symbol : variable v4").append(NEWLINE) .append("location: Test").append(NEWLINE) .append(" int v2 = v4").append(NEWLINE) .append(" ^"); Collection<GradleMessage> messages = parser.parseGradleOutput(err.toString()); assertHasCorrectErrorMessage(messages, "error: cannot find symbol variable v4", 3, 14); } public void testParseJavaOutput2() throws IOException { createTempFile(".java"); writeToFile("public class Test {", " public static void main(String[] args) {", " System.out.println();asd"); StringBuilder err = new StringBuilder(); err.append(sourceFilePath).append(":3: error: ").append("not a statement").append(NEWLINE) .append(" System.out.println();asd").append(NEWLINE) .append(" ^").append(NEWLINE); Collection<GradleMessage> messages = parser.parseGradleOutput(err.toString()); assertHasCorrectErrorMessage(messages, "error: not a statement", 3, 26); } public void testParseGradleBuildFileOutput() throws IOException { createTempFile(".gradle"); writeToFile("buildscript {", " repositories {", " mavenCentral()", " }", " dependencies {", " classpath 'com.android.tools.build:gradle:0.4'", " }", "}", "ERROR plugin: 'android'"); StringBuilder err = new StringBuilder(); err.append("FAILURE: Build failed with an exception.").append(NEWLINE).append(NEWLINE); err.append("* Where:").append(NEWLINE); err.append("Build file '").append(sourceFilePath).append("' line: 9").append(NEWLINE).append(NEWLINE); err.append("* What went wrong:").append(NEWLINE); err.append("A problem occurred evaluating project ':project'.").append(NEWLINE); err.append("> Could not find method ERROR() for arguments [{plugin=android}] on project ':project'.").append(NEWLINE).append(NEWLINE); err.append("* Try:").append(NEWLINE); err.append("Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.").append( NEWLINE).append(NEWLINE); err.append("BUILD FAILED").append(NEWLINE).append(NEWLINE); err.append("Total time: 18.303 secs\n"); List<GradleMessage> messages = parser.parseGradleOutput(err.toString()); assertEquals("0: Error:A problem occurred evaluating project ':project'.\n" + "> Could not find method ERROR() for arguments [{plugin=android}] on project ':project'.\n" + "\t" + sourceFilePath + ":9:0\n" + "1: Info:BUILD FAILED\n" + "2: Info:Total time: 18.303 secs\n", toString(messages)); } public void testParseXmlValidationErrorOutput() { StringBuilder err = new StringBuilder(); err.append("[Fatal Error] :5:7: The element type \"error\" must be terminated by the matching end-tag \"</error>\".").append(NEWLINE); err.append("FAILURE: Build failed with an exception.").append(NEWLINE); List<GradleMessage> messages = parser.parseGradleOutput(err.toString()); assertEquals("0: Error:The element type \"error\" must be terminated by the matching end-tag \"</error>\".\n" + "1: Simple:FAILURE: Build failed with an exception.\n", toString(messages)); } public void testParseIncubatingFeatureMessage() { String out = "Parallel execution with configuration on demand is an incubating feature."; List<GradleMessage> messages = parser.parseGradleOutput(out); assertEquals("", toString(messages)); } private void createTempFile(@NotNull String fileExtension) throws IOException { sourceFile = File.createTempFile(BuildOutputParserTest.class.getName(), fileExtension); sourceFilePath = sourceFile.getAbsolutePath(); } @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") private void writeToFile(@NotNull String... lines) throws IOException { BufferedWriter out = null; try { out = new BufferedWriter(new FileWriter(sourceFile)); for (String line : lines) { out.write(line); out.newLine(); } } finally { //noinspection deprecation Closeables.close(out, true /* swallowIOException */); } } private void assertHasCorrectErrorMessage(@NotNull Collection<GradleMessage> messages, @NotNull String expectedText, long expectedLine, long expectedColumn) { assertEquals("[message count]", 1, messages.size()); GradleMessage message = ContainerUtil.getFirstItem(messages); assertNotNull(message); assertEquals("[file path]", sourceFilePath, message.getSourcePath()); assertEquals("[message severity]", GradleMessage.Kind.ERROR, message.getKind()); assertEquals("[message text]", expectedText, message.getText()); assertEquals("[position line]", expectedLine, message.getLineNumber()); assertEquals("[position column]", expectedColumn, message.getColumn()); } public void testRedirectValueLinksOutput() throws Exception { if (!setupSdkHome()) { System.out.println("Skipping testRedirectValueLinksOutput because sdk-common was not found"); return; } // Need file to be named (exactly) values.xml File tempDir = Files.createTempDir(); File valueDir = new File(tempDir, "values-en"); valueDir.mkdirs(); sourceFile = new File(valueDir, "values.xml"); // Keep in sync with MergedResourceWriter.FN_VALUES_XML sourceFilePath = sourceFile.getAbsolutePath(); writeToFile( "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<resources xmlns:ns1=\"urn:oasis:names:tc:xliff:document:1.2\">\n" + "\n" + " <!-- From: src/test/resources/testData/resources/baseSet/values/values.xml -->\n" + " <string-array name=\"string_array\" translatable=\"false\">\n" + " <item/> <!-- 0 -->\n" + " <item/> <!-- 1 -->\n" + " <item>ABC</item> <!-- 2 -->\n" + " <item>DEF</item> <!-- 3 -->\n" + " <item>GHI</item> <!-- 4 -->\n" + " <item>JKL</item> <!-- 5 -->\n" + " <item>MNO</item> <!-- 6 -->\n" + " <item>PQRS</item> <!-- 7 -->\n" + " <item>TUV</item> <!-- 8 -->\n" + " <item>WXYZ</item> <!-- 9 -->\n" + " </string-array>\n" + "\n" + " <attr name=\"dimen_attr\" format=\"dimension\" />\n" + " <attr name=\"enum_attr\">\n" + " <enum name=\"normal\" value=\"0\" />\n" + " <enum name=\"sans\" value=\"1\" />\n" + " <enum name=\"serif\" value=\"2\" />\n" + " <enum name=\"monospace\" value=\"3\" />\n" + " </attr>\n" + " <attr name=\"flag_attr\">\n" + " <flag name=\"normal\" value=\"0\" />\n" + " <flag name=\"bold\" value=\"1\" />\n" + " <flag name=\"italic\" value=\"2\" />\n" + " </attr>\n" + " <attr name=\"string_attr\" format=\"string\" />\n" + " <!-- From: src/test/resources/testData/resources/baseMerge/overlay/values/values.xml -->\n" + " <color name=\"color\">#FFFFFFFF</color>\n" + " <!-- From: src/test/resources/testData/resources/baseSet/values/values.xml -->\n" + " <declare-styleable name=\"declare_styleable\">\n" + "\n" + " <!-- ============== -->\n" + " <!-- Generic styles -->\n" + " <!-- ============== -->\n" + " <eat-comment />\n" + "\n" + " <!-- Default color of foreground imagery. -->\n" + " <attr name=\"blah\" format=\"color\" />\n" + " <!-- Default color of foreground imagery on an inverted background. -->\n" + " <attr name=\"android:colorForegroundInverse\" />\n" + " </declare-styleable>\n" + "\n" + " <dimen name=\"dimen\">164dp</dimen>\n" + "\n" + " <drawable name=\"color_drawable\">#ffffffff</drawable>\n" + " <drawable name=\"drawable_ref\">@drawable/stat_notify_sync_anim0</drawable>\n" + "\n" + " <item name=\"item_id\" type=\"id\"/>\n" + "\n" + " <integer name=\"integer\">75</integer>\n" + " <!-- From: src/test/resources/testData/resources/baseMerge/overlay/values/values.xml -->\n" + " <item name=\"file_replaced_by_alias\" type=\"layout\">@layout/ref</item>\n" + " <!-- From: src/test/resources/testData/resources/baseSet/values/values.xml -->\n" + " <item name=\"layout_ref\" type=\"layout\">@layout/ref</item>\n" + " <!-- From: src/test/resources/testData/resources/baseMerge/overlay/values/values.xml -->\n" + " <string name=\"basic_string\">overlay_string</string>\n" + " <!-- From: src/test/resources/testData/resources/baseSet/values/values.xml -->\n" + " <string name=\"styled_string\">Forgot your username or password\\?\\nVisit <b>google.com/accounts/recovery</b>.</string>\n" + " <string name=\"xliff_string\"><ns1:g id=\"number\" example=\"123\">%1$s</ns1:g><ns1:g id=\"unit\" example=\"KB\">%2$s</ns1:g></string>\n" + "\n" + " <style name=\"style\" parent=\"@android:style/Holo.Light\">\n" + " <item name=\"android:singleLine\">true</item>\n" + " <item name=\"android:textAppearance\">@style/TextAppearance.WindowTitle</item>\n" + " <item name=\"android:shadowColor\">#BB000000</item>\n" + " <item name=\"android:shadowRadius\">2.75</item>\n" + " <item name=\"foo\">foo</item>\n" + " </style>\n" + "\n" + "</resources>\n"); String messageText = "String types not allowed (at 'drawable_ref' with value '@drawable/stat_notify_sync_anim0')."; String err = sourceFilePath + ":46: error: Error: " + messageText; Collection<GradleMessage> messages = parser.parseGradleOutput(err); assertEquals(1, messages.size()); assertEquals("[message count]", 1, messages.size()); GradleMessage message = ContainerUtil.getFirstItem(messages); assertNotNull(message); // NOT sourceFilePath; should be translated back from source comment assertEquals("[file path]", "src/test/resources/testData/resources/baseSet/values/values.xml", getSystemIndependentSourcePath(message)); assertEquals("[message severity]", GradleMessage.Kind.ERROR, message.getKind()); assertEquals("[message text]", messageText, message.getText()); assertEquals("[position line]", 9, message.getLineNumber()); assertEquals("[position column]", 35, message.getColumn()); } @Nullable private static String getSystemIndependentSourcePath(@NotNull GradleMessage message) { String sourcePath = message.getSourcePath(); return sourcePath == null ? null : FileUtil.toSystemIndependentName(sourcePath); } private static boolean setupSdkHome() { String homePath = PathManager.getHomePath(); assertNotNull(homePath); // The relative paths in the output file below is relative to the sdk-common directory in tools/base // (it's from one of the unit tests there) File rootDir = new File(homePath, ".." + File.separator + "base" + File.separator + "sdk-common"); if (!rootDir.isDirectory()) { // Also check for an IDEA project structure where sdk-common is located in this location: rootDir = new File(homePath, "android" + File.separator + "tools-base" + File.separator + "sdk-common"); if (!rootDir.isDirectory()) { return false; } } AbstractAaptOutputParser.ourRootDir = rootDir; return true; } public void testRedirectFileLinksOutput() throws Exception { if (!setupSdkHome()) { System.out.println("Skipping testRedirectFileLinksOutput because sdk-common was not found"); return; } // Need file to be named (exactly) values.xml File tempDir = Files.createTempDir(); File layoutDir = new File(tempDir, "layout-land"); layoutDir.mkdirs(); sourceFile = new File(layoutDir, "main.xml"); sourceFilePath = sourceFile.getAbsolutePath(); writeToFile( "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + " android:orientation=\"vertical\"\n" + " android:layout_width=\"fill_parent\"\n" + " android:layout_height=\"fill_parent\"\n" + " >\n" + "<TextView\n" + " android:layout_width=\"fill_parent\"\n" + " android:layout_height=\"wrap_content\"\n" + " android:text=\"Test App - Basic\"\n" + " android:id=\"@+id/text\"\n" + " />\n" + "</LinearLayout>\n" + "\n" + "<!-- From: file:src/test/resources/testData/resources/incMergeData/filesVsValues/main/layout/main.xml -->"); String messageText = "Random error message here"; String err = sourceFilePath + ":4: error: Error: " + messageText; Collection<GradleMessage> messages = parser.parseGradleOutput(err); assertEquals(1, messages.size()); assertEquals("[message count]", 1, messages.size()); GradleMessage message = ContainerUtil.getFirstItem(messages); assertNotNull(message); // NOT sourceFilePath; should be translated back from source comment String expected = "src/test/resources/testData/resources/incMergeData/filesVsValues/main/layout/main.xml"; assertEquals("[file path]", expected, getSystemIndependentSourcePath(message)); assertEquals("[message severity]", GradleMessage.Kind.ERROR, message.getKind()); assertEquals("[message text]", messageText, message.getText()); assertEquals("[position line]", 4, message.getLineNumber()); //assertEquals("[position column]", 35, message.getColumn()); // TODO: Test encoding issues (e.g. & in path where the XML source comment would be & instead) } public void testGradleAaptErrorParser() throws IOException { createTempXmlFile(); writeToFile("<resources xmlns:android='http://schemas.android.com/apk/res/android'>", " <TextView\n" + " android:layout_width=\"fill_parent\"\n" + " android:layout_height=\"wrap_content\"\n" + " android:text=\"@string/does_not_exist\"\n" + " android:id=\"@+id/text\"\n" + " />\n"); final String messageText = "No resource found that matches the given name (at 'text' with value '@string/does_not_exist')."; String err = "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':five:processDebugResources'.\n" + "> Failed to run command:\n" + " \t/Applications/Android Studio.app/sdk/build-tools/android-4.2.2/aapt package -f --no-crunch -I ...\n" + " Error Code:\n" + " \t1\n" + " Output:\n" + " \t" + sourceFilePath + ":5: error: Error: " + messageText + "\n" + "\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n"; assertEquals("0: Error:Error while executing aapt command\n" + "1: Error:No resource found that matches the given name (at 'text' with value '@string/does_not_exist').\n" + "\t" + sourceFilePath + ":5:27\n" + "2: Error:Execution failed for task ':five:processDebugResources'.\n" + "3: Info:BUILD FAILED\n", toString(parser.parseGradleOutput(err))); } public void testLockOwner() throws Exception { // https://code.google.com/p/android/issues/detail?id=59444 String output = "FAILURE: Build failed with an exception.\n" + "* What went wrong:\n" + " A problem occurred configuring project ':MyApplication1'.\n" + "> Failed to notify project evaluation listener.\n" + " > Could not resolve all dependencies for configuration ':MyApplication1:_DebugCompile'.\n" + " > Problems pinging owner of lock '-7513739537696464924' at port: 55416\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 24.154 secs"; assertEquals("0: Error:Possibly unstable network connection: Failed to connect to lock owner. Try to rebuild.\n" + "1: Error: A problem occurred configuring project ':MyApplication1'.\n" + "> Failed to notify project evaluation listener.\n" + " > Could not resolve all dependencies for configuration ':MyApplication1:_DebugCompile'.\n" + " > Problems pinging owner of lock '-7513739537696464924' at port: 55416\n" + "2: Info:BUILD FAILED\n" + "3: Info:Total time: 24.154 secs\n", toString(parser.parseGradleOutput(output))); } public void testDuplicateResources() throws Exception { // To reproduce, create a source file with two duplicate string item definitions createTempXmlFile(); String output = "Failed to parse " + sourceFilePath + "\n" + "java.io.IOException: Found item String/drawer_open more than one time\n" + "\tat com.android.ide.common.res2.ValueResourceParser2.checkDuplicate(ValueResourceParser2.java:249)\n" + "\tat com.android.ide.common.res2.ValueResourceParser2.parseFile(ValueResourceParser2.java:103)\n" + "\tat com.android.ide.common.res2.ResourceSet.createResourceFile(ResourceSet.java:273)\n" + "\tat com.android.ide.common.res2.ResourceSet.parseFolder(ResourceSet.java:248)\n" + // ... "\tat org.gradle.launcher.daemon.server.DefaultIncomingConnectionHandler$ConnectionWorker.run(DefaultIncomingConnectionHandler.java:116)\n" + "\tat org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:66)\n" + "\tat java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)\n" + "\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)\n" + "\tat java.lang.Thread.run(Thread.java:680)\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':MyApp:mergeDebugResources'.\n" + "> Found item String/drawer_open more than one time\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n"; assertEquals("0: Error:Found item String/drawer_open more than one time: Failed to parse " + sourceFilePath + "\n" + "\t" + sourceFilePath + ":-1:-1\n" + "1: Error:Execution failed for task ':MyApp:mergeDebugResources'.\n" + "> Found item String/drawer_open more than one time\n" + "\t" + sourceFilePath + ":-1:-1\n", toString(parser.parseGradleOutput(output))); // Also test CRLF handling: output = output.replace("\n", "\r\n"); assertEquals("0: Error:Found item String/drawer_open more than one time: Failed to parse " + sourceFilePath + "\n" + "\t" + sourceFilePath + ":-1:-1\n" + "1: Error:Execution failed for task ':MyApp:mergeDebugResources'.\n" + "> Found item String/drawer_open more than one time\n" + "\t" + sourceFilePath + ":-1:-1\n", toString(parser.parseGradleOutput(output))); } public void testDuplicateResources2() throws Exception { File file1 = File.createTempFile(BuildOutputParserTest.class.getName(), DOT_XML); File file2 = File.createTempFile(BuildOutputParserTest.class.getName(), DOT_XML); String path1 = file1.getPath(); String path2 = file2.getPath(); Files.write( "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<resources xmlns:ns1=\"urn:oasis:names:tc:xliff:document:1.2\">\n" + " <!-- This is just a comment: group2_string -->" + " <item name=\"group1\" type=\"id\"/>\n" + " <string name=\"group2_string\">Hello</string>\n" + "\n" + "</resources>\n", file1, Charsets.UTF_8); Files.write( "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<resources xmlns:ns1=\"urn:oasis:names:tc:xliff:document:1.2\">\n" + " <item type=\"string\" name=\"group2_string\">Hello</item>\n" + "</resources>\n", file2, Charsets.UTF_8); String output = ":preBuild UP-TO-DATE\n" + ":preF2FaDebugBuild UP-TO-DATE\n" + ":prepareF2FaDebugDependencies\n" + ":compileF2FaDebugRenderscript UP-TO-DATE\n" + ":mergeF2FaDebugResources FAILED\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':mergeF2FaDebugResources'.\n" + "> Duplicate resources: " + path1 + ":string/group2_string, " + path2 + ":string/group2_string\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 6.462 secs"; assertEquals("0: Simple::preBuild UP-TO-DATE\n" + "1: Simple::preF2FaDebugBuild UP-TO-DATE\n" + "2: Simple::prepareF2FaDebugDependencies\n" + "3: Simple::compileF2FaDebugRenderscript UP-TO-DATE\n" + "4: Simple::mergeF2FaDebugResources FAILED\n" + "5: Error:> Duplicate resources: " + path1 + ":string/group2_string, " + path2 + ":string/group2_string\n" + "\t" + path1 + ":4:-1\n" + "6: Error:Other duplicate occurrence here\n" + "\t" + path2 + ":3:-1\n" + "7: Error:Execution failed for task ':mergeF2FaDebugResources'.\n" + "\t" + path1 + ":4:-1\n" + "8: Info:BUILD FAILED\n" + "9: Info:Total time: 6.462 secs\n", toString(parser.parseGradleOutput(output))); file1.delete(); file2.delete(); } public void testUnexpectedOutput() throws Exception { // To reproduce, create a source file with two duplicate string item definitions createTempXmlFile(); String output = "This output is not expected.\n" + "Nor is this.\n" + "java.io.SurpriseSurpriseError: Bet you didn't expect to see this\n" + "\tat com.android.ide.common.res2.ValueResourceParser2.checkSurpriseSurprise(ValueResourceParser2.java:249)\n" + "\tat com.android.ide.common.res2.ValueResourceParser2.parseFile(ValueResourceParser2.java:103)\n" + "\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)\n" + "\tat java.lang.Thread.run(Thread.java:680)\n" + "More unexpected output.\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':MyApp:mergeDebugResources'.\n" + "> I was surprised\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n"; assertEquals("0: Simple:This output is not expected.\n" + "1: Simple:Nor is this.\n" + "2: Simple:java.io.SurpriseSurpriseError: Bet you didn't expect to see this\n" + "3: Simple:\tat com.android.ide.common.res2.ValueResourceParser2.checkSurpriseSurprise(ValueResourceParser2.java:249)\n" + "4: Simple:\tat com.android.ide.common.res2.ValueResourceParser2.parseFile(ValueResourceParser2.java:103)\n" + "5: Simple:\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)\n" + "6: Simple:\tat java.lang.Thread.run(Thread.java:680)\n" + "7: Simple:More unexpected output.\n" + "8: Error:Execution failed for task ':MyApp:mergeDebugResources'.\n" + "> I was surprised\n", toString(parser.parseGradleOutput(output))); } public void testXmlError() throws Exception { createTempXmlFile(); String output = "[Fatal Error] :7:18: Open quote is expected for attribute \"{1}\" associated with an element type \"name\".\n" + "Failed to parse " + sourceFilePath + "\n" + "java.io.IOException: org.xml.sax.SAXParseException: Open quote is expected for attribute \"{1}\" associated with an element type \"name\".\n" + "\tat com.android.ide.common.res2.ValueResourceParser2.parseDocument(ValueResourceParser2.java:193)\n" + "\tat com.android.ide.common.res2.ValueResourceParser2.parseFile(ValueResourceParser2.java:78)\n" + "\tat com.android.ide.common.res2.ResourceSet.createResourceFile(ResourceSet.java:273)\n" + "\tat com.android.ide.common.res2.ResourceSet.parseFolder(ResourceSet.java:248)\n" + // ... "\tat org.gradle.wrapper.WrapperExecutor.execute(WrapperExecutor.java:130)\n" + "\tat org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)\n" + "Caused by: org.xml.sax.SAXParseException: Open quote is expected for attribute \"{1}\" associated with an element type \"name\".\n" + "\tat com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:246)\n" + "\tat com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:284)\n" + "\tat com.android.ide.common.res2.ValueResourceParser2.parseDocument(ValueResourceParser2.java:189)\n" + "\t... 109 more\n" + ":MyApp:mergeDebugResources FAILED\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':MyApp:mergeDebugResources'.\n" + "> org.xml.sax.SAXParseException: Open quote is expected for attribute \"{1}\" associated with an element type \"name\".\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 7.245 secs\n"; assertEquals("0: Error:Open quote is expected for attribute \"{1}\" associated with an element type \"name\".\n" + "\t" + sourceFilePath + ":7:18\n" + "1: Simple:java.io.IOException: org.xml.sax.SAXParseException: Open quote is expected for attribute \"{1}\" associated with an element type \"name\".\n" + "2: Simple:\tat com.android.ide.common.res2.ValueResourceParser2.parseDocument(ValueResourceParser2.java:193)\n" + "3: Simple:\tat com.android.ide.common.res2.ValueResourceParser2.parseFile(ValueResourceParser2.java:78)\n" + "4: Simple:\tat com.android.ide.common.res2.ResourceSet.createResourceFile(ResourceSet.java:273)\n" + "5: Simple:\tat com.android.ide.common.res2.ResourceSet.parseFolder(ResourceSet.java:248)\n" + "6: Simple:\tat org.gradle.wrapper.WrapperExecutor.execute(WrapperExecutor.java:130)\n" + "7: Simple:\tat org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:61)\n" + "8: Error:org.xml.sax.SAXParseException: Open quote is expected for attribute \"{1}\" associated with an element type \"name\".\n" + "9: Simple:\tat com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:246)\n" + "10: Simple:\tat com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:284)\n" + "11: Simple:\tat com.android.ide.common.res2.ValueResourceParser2.parseDocument(ValueResourceParser2.java:189)\n" + "12: Simple:\t... 109 more\n" + "13: Simple::MyApp:mergeDebugResources FAILED\n" + "14: Error:Execution failed for task ':MyApp:mergeDebugResources'.\n" + "> org.xml.sax.SAXParseException: Open quote is expected for attribute \"{1}\" associated with an element type \"name\".\n" + "\t" + sourceFilePath + ":7:18\n" + "15: Info:BUILD FAILED\n" + "16: Info:Total time: 7.245 secs\n", toString(parser.parseGradleOutput(output))); } public void testJavac() throws Exception { createTempFile(".java"); String output = sourceFilePath + ":70: <identifier> expected\n" + "x\n" + " ^\n" + sourceFilePath + ":71: <identifier> expected\n" + " @Override\n" + " ^\n" + "2 errors\n" + ":MyApp:compileDebug FAILED\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':MyApp:compileDebug'.\n" + "> Compilation failed; see the compiler error output for details.\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 12.42 secs"; assertEquals("0: Error:<identifier> expected\n" + "\t" + sourceFilePath + ":70:2\n" + "1: Error:<identifier> expected\n" + "\t" + sourceFilePath + ":71:14\n" + "2: Simple::MyApp:compileDebug FAILED\n" + "3: Error:Execution failed for task ':MyApp:compileDebug'.\n" + "> Compilation failed; see the compiler error output for details.\n" + "4: Info:BUILD FAILED\n" + "5: Info:Total time: 12.42 secs\n", toString(parser.parseGradleOutput(output))); } public void testOom() throws Exception { createTempFile(".java"); String output = // Came across this output on StackOverflow: "FAILURE: Build failed with an exception.\n" + "* What went wrong:\n" + "A problem occurred configuring project ':EpicMix'.\n" + "> Failed to notify project evaluation listener.\n" + " > A problem occurred configuring project ':facebook'.\n" + " > Failed to notify project evaluation listener.\n" + " > java.lang.OutOfMemoryError: PermGen space" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 24.154 secs"; assertEquals("0: Error:A problem occurred configuring project ':EpicMix'.\n" + "> Failed to notify project evaluation listener.\n" + " > A problem occurred configuring project ':facebook'.\n" + " > Failed to notify project evaluation listener.\n" + " > java.lang.OutOfMemoryError: PermGen space\n" + "1: Info:BUILD FAILED\n" + "2: Info:Total time: 24.154 secs\n", toString(parser.parseGradleOutput(output))); String output2 = "To honour the JVM settings for this build a new JVM will be forked. Please consider using the daemon: http://gradle.org/docs/1.7/userguide/gradle_daemon.html.\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "A problem occurred configuring project ':MyNewApp'.\n" + "> Failed to notify project evaluation listener.\n" + " > java.lang.OutOfMemoryError: Java heap space\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 24.154 secs"; assertEquals("0: Simple:To honour the JVM settings for this build a new JVM will be forked. Please consider using the daemon: http://gradle.org/docs/1.7/userguide/gradle_daemon.html.\n" + "1: Error:A problem occurred configuring project ':MyNewApp'.\n" + "> Failed to notify project evaluation listener.\n" + " > java.lang.OutOfMemoryError: Java heap space\n" + "2: Info:BUILD FAILED\n" + "3: Info:Total time: 24.154 secs\n", toString(parser.parseGradleOutput(output2))); } public void test() throws Exception { File tempDir = Files.createTempDir(); sourceFile = new File(tempDir, "values.xml"); // Name matters for position search sourceFilePath = sourceFile.getAbsolutePath(); File source = new File(tempDir, "dimens.xml"); Files.write("<resources>\n" + " <!-- Default screen margins, per the Android Design guidelines. -->\n" + " <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n" + " <dimen name=\"activity_vertical_margin\">16dp</dimen>\n" + " <dimen name=\"new_name\">50</dimen>\n" + "</resources>", source, Charsets.UTF_8); source.deleteOnExit(); Files.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<resources>\n" + " <!-- From: file:/Users/unittest/AndroidStudioProjects/BlankProject1Project/BlankProject1/build/exploded-bundles/ComAndroidSupportAppcompatV71800.aar/res/values/values.xml -->\n" + " <dimen name=\"abc_action_bar_default_height\">48dip</dimen>\n" + " <dimen name=\"abc_action_bar_icon_vertical_padding\">8dip</dimen>\n" + " <!-- From: file:" + source.getPath() + " -->\n" + " <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n" + " <dimen name=\"activity_vertical_margin\">16dp</dimen>\n" + " <dimen name=\"ok\">50dp</dimen>\n" + " <dimen name=\"new_name\">50</dimen>\n" + " <!-- From: file:/Users/unittest/AndroidStudioProjects/BlankProject1Project/BlankProject1/build/exploded-bundles/ComAndroidSupportAppcompatV71800.aar/res/values/values.xml -->\n" + " <item name=\"action_bar_activity_content\" type=\"id\"/>\n" + " <item name=\"action_menu_divider\" type=\"id\"/>\n" + " <item name=\"action_menu_presenter\" type=\"id\"/>\n" + " <item name=\"home\" type=\"id\"/>\n" + "</resources>\n", sourceFile, Charsets.UTF_8); String output = "Relying on packaging to define the extension of the main artifact has been deprecated and is scheduled to be removed in Gradle 2.0\n" + ":BlankProject1:prepareComAndroidSupportAppcompatV71800Library UP-TO-DATE\n" + ":BlankProject1:prepareDebugDependencies\n" + ":BlankProject1:mergeDebugAssets UP-TO-DATE\n" + ":BlankProject1:compileDebugRenderscript UP-TO-DATE\n" + ":BlankProject1:mergeDebugResources UP-TO-DATE\n" + ":BlankProject1:processDebugManifest UP-TO-DATE\n" + ":BlankProject1:processDebugResources\n" + sourceFilePath + ":10: error: Error: Integer types not allowed (at 'new_name' with value '50').\n" + ":BlankProject1:processDebugResources FAILED\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':BlankProject1:processDebugResources'.\n" + "> Failed to run command:\n" + " \t/Users/tnorbye/dev/sdks/build-tools/18.0.1/aapt package -f --no-crunch -I ...\n" + " Error Code:\n" + " \t1\n" + " Output:\n" + " \t" + sourceFilePath + ":10: error: Error: Integer types not allowed (at 'new_name' with value '50').\n" + "\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 5.435 secs"; assertEquals("0: Simple::BlankProject1:prepareComAndroidSupportAppcompatV71800Library UP-TO-DATE\n" + "1: Simple::BlankProject1:prepareDebugDependencies\n" + "2: Simple::BlankProject1:mergeDebugAssets UP-TO-DATE\n" + "3: Simple::BlankProject1:compileDebugRenderscript UP-TO-DATE\n" + "4: Simple::BlankProject1:mergeDebugResources UP-TO-DATE\n" + "5: Simple::BlankProject1:processDebugManifest UP-TO-DATE\n" + "6: Simple::BlankProject1:processDebugResources\n" + "7: Error:Integer types not allowed (at 'new_name' with value '50').\n" + "\t" + source.getPath() + ":5:28\n" + "8: Simple::BlankProject1:processDebugResources FAILED\n" + "9: Error:Error while executing aapt command\n" + "10: Error:Integer types not allowed (at 'new_name' with value '50').\n" + "\t" + source.getPath() + ":5:28\n" + "11: Error:Execution failed for task ':BlankProject1:processDebugResources'.\n" + "12: Info:BUILD FAILED\n" + "13: Info:Total time: 5.435 secs\n", toString(parser.parseGradleOutput(output))); sourceFile.delete(); source.delete(); tempDir.delete(); } public void testDashes() throws Exception { File tempDir = Files.createTempDir(); String dirName = currentPlatform() == PLATFORM_WINDOWS ? "My -- Q&A Dir" : "My -- Q&A< Dir"; File dir = new File(tempDir, dirName); // path which should force encoding of path chars, see for example issue 60050 dir.mkdirs(); sourceFile = new File(dir, "values.xml"); // Name matters for position search sourceFilePath = sourceFile.getAbsolutePath(); File source = new File(dir, "dimens.xml"); Files.write("<resources>\n" + " <!-- Default screen margins, per the Android Design guidelines. -->\n" + " <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n" + " <dimen name=\"activity_vertical_margin\">16dp</dimen>\n" + " <dimen name=\"new_name\">50</dimen>\n" + "</resources>", source, Charsets.UTF_8); source.deleteOnExit(); Files.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<resources>\n" + " <!-- From: file:/Users/unittest/AndroidStudioProjects/BlankProject1Project/BlankProject1/build/exploded-bundles/ComAndroidSupportAppcompatV71800.aar/res/values/values.xml -->\n" + " <dimen name=\"abc_action_bar_default_height\">48dip</dimen>\n" + " <dimen name=\"abc_action_bar_icon_vertical_padding\">8dip</dimen>\n" + " <!-- " + createPathComment(source, false) + " -->\n" + " <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n" + " <dimen name=\"activity_vertical_margin\">16dp</dimen>\n" + " <dimen name=\"ok\">50dp</dimen>\n" + " <dimen name=\"new_name\">50</dimen>\n" + " <!-- From: file:/Users/unittest/AndroidStudioProjects/BlankProject1Project/BlankProject1/build/exploded-bundles/ComAndroidSupportAppcompatV71800.aar/res/values/values.xml -->\n" + " <item name=\"action_bar_activity_content\" type=\"id\"/>\n" + " <item name=\"action_menu_divider\" type=\"id\"/>\n" + " <item name=\"action_menu_presenter\" type=\"id\"/>\n" + " <item name=\"home\" type=\"id\"/>\n" + "</resources>\n", sourceFile, Charsets.UTF_8); // TODO: Test layout too String output = "Relying on packaging to define the extension of the main artifact has been deprecated and is scheduled to be removed in Gradle 2.0\n" + ":BlankProject1:prepareComAndroidSupportAppcompatV71800Library UP-TO-DATE\n" + ":BlankProject1:prepareDebugDependencies\n" + ":BlankProject1:mergeDebugAssets UP-TO-DATE\n" + ":BlankProject1:compileDebugRenderscript UP-TO-DATE\n" + ":BlankProject1:mergeDebugResources UP-TO-DATE\n" + ":BlankProject1:processDebugManifest UP-TO-DATE\n" + ":BlankProject1:processDebugResources\n" + sourceFilePath + ":10: error: Error: Integer types not allowed (at 'new_name' with value '50').\n" + ":BlankProject1:processDebugResources FAILED\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':BlankProject1:processDebugResources'.\n" + "> Failed to run command:\n" + " \t/Users/tnorbye/dev/sdks/build-tools/18.0.1/aapt package -f --no-crunch -I ...\n" + " Error Code:\n" + " \t1\n" + " Output:\n" + " \t" + sourceFilePath + ":10: error: Error: Integer types not allowed (at 'new_name' with value '50').\n" + "\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 5.435 secs"; assertEquals("0: Simple::BlankProject1:prepareComAndroidSupportAppcompatV71800Library UP-TO-DATE\n" + "1: Simple::BlankProject1:prepareDebugDependencies\n" + "2: Simple::BlankProject1:mergeDebugAssets UP-TO-DATE\n" + "3: Simple::BlankProject1:compileDebugRenderscript UP-TO-DATE\n" + "4: Simple::BlankProject1:mergeDebugResources UP-TO-DATE\n" + "5: Simple::BlankProject1:processDebugManifest UP-TO-DATE\n" + "6: Simple::BlankProject1:processDebugResources\n" + "7: Error:Integer types not allowed (at 'new_name' with value '50').\n" + "\t" + source.getPath() + ":5:28\n" + "8: Simple::BlankProject1:processDebugResources FAILED\n" + "9: Error:Error while executing aapt command\n" + "10: Error:Integer types not allowed (at 'new_name' with value '50').\n" + "\t" + source.getPath() + ":5:28\n" + "11: Error:Execution failed for task ':BlankProject1:processDebugResources'.\n" + "12: Info:BUILD FAILED\n" + "13: Info:Total time: 5.435 secs\n", toString(parser.parseGradleOutput(output))); sourceFile.delete(); source.delete(); dir.delete(); tempDir.delete(); } public void testLayoutFileSuffix() throws Exception { File tempDir = Files.createTempDir(); sourceFile = new File(tempDir, "layout.xml"); sourceFilePath = sourceFile.getAbsolutePath(); File source = new File(tempDir, "real-layout.xml"); Files.write("<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + " xmlns:tools=\"http://schemas.android.com/tools\"\n" + " android:layout_width=\"match_parent\"\n" + " android:layout_height=\"match_parent\"\n" + " android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n" + " android:paddingRight=\"@dimen/activity_horizontal_margin\"\n" + " android:paddingTop=\"@dimen/activity_vertical_margin\"\n" + " android:paddingBottom=\"@dimen/activity_vertical_margin\"\n" + " tools:context=\".MainActivity\">\n" + "\n" + "\n" + " <Button\n" + " android:layout_width=\"wrap_content\"\n" + " android:layout_height=\"wrap_content\"\n" + " android:hint=\"fy faen\"\n" + " android:text=\"@string/hello_world\"\n" + " android:slayout_alignParentTop=\"true\"\n" + " android:layout_alignParentLeft=\"true\" />\n" + "\n" + "</RelativeLayout>\n", source, Charsets.UTF_8); source.deleteOnExit(); Files.write("<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + " xmlns:tools=\"http://schemas.android.com/tools\"\n" + " android:layout_width=\"match_parent\"\n" + " android:layout_height=\"match_parent\"\n" + " android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n" + " android:paddingRight=\"@dimen/activity_horizontal_margin\"\n" + " android:paddingTop=\"@dimen/activity_vertical_margin\"\n" + " android:paddingBottom=\"@dimen/activity_vertical_margin\"\n" + " tools:context=\".MainActivity\">\n" + "\n" + " <!--style=\"@style/Buttons\"-->\n" + " <Button\n" + " android:layout_width=\"wrap_content\"\n" + " android:layout_height=\"wrap_content\"\n" + " android:hint=\"fy faen\"\n" + " android:text=\"@string/hello_world\"\n" + " android:slayout_alignParentTop=\"true\"\n" + " android:layout_alignParentLeft=\"true\" />\n" + "\n" + "</RelativeLayout>\n" + "<!-- " + createPathComment(source, false) + " -->", sourceFile, Charsets.UTF_8); String output = "Relying on packaging to define the extension of the main artifact has been deprecated and is scheduled to be removed in Gradle 2.0\n" + ":BlankProject1:preBuild UP-TO-DATE\n" + ":BlankProject1:preDebugBuild UP-TO-DATE\n" + ":BlankProject1:preReleaseBuild UP-TO-DATE\n" + ":BlankProject1:prepareComAndroidSupportAppcompatV71800Library UP-TO-DATE\n" + ":BlankProject1:prepareDebugDependencies\n" + ":BlankProject1:compileDebugAidl UP-TO-DATE\n" + ":BlankProject1:compileDebugRenderscript UP-TO-DATE\n" + ":BlankProject1:generateDebugBuildConfig UP-TO-DATE\n" + ":BlankProject1:mergeDebugAssets UP-TO-DATE\n" + ":BlankProject1:mergeDebugResources UP-TO-DATE\n" + ":BlankProject1:processDebugManifest UP-TO-DATE\n" + ":BlankProject1:processDebugResources\n" + sourceFilePath + ":12: error: No resource identifier found for attribute 'slayout_alignParentTop' in package 'android'\n" + ":BlankProject1:processDebugResources FAILED\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':BlankProject1:processDebugResources'.\n" + "> Failed to run command:\n" + " \t/Users/tnorbye/dev/sdks/build-tools/18.0.1/aapt package -f --no-crunch -I ... " + " Error Code:\n" + " \t1\n" + " Output:\n" + " \t" + sourceFilePath + ":12: error: No resource identifier found for attribute 'slayout_alignParentTop' in package 'android'\n" + "\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n"; assertEquals("0: Simple::BlankProject1:preBuild UP-TO-DATE\n" + "1: Simple::BlankProject1:preDebugBuild UP-TO-DATE\n" + "2: Simple::BlankProject1:preReleaseBuild UP-TO-DATE\n" + "3: Simple::BlankProject1:prepareComAndroidSupportAppcompatV71800Library UP-TO-DATE\n" + "4: Simple::BlankProject1:prepareDebugDependencies\n" + "5: Simple::BlankProject1:compileDebugAidl UP-TO-DATE\n" + "6: Simple::BlankProject1:compileDebugRenderscript UP-TO-DATE\n" + "7: Simple::BlankProject1:generateDebugBuildConfig UP-TO-DATE\n" + "8: Simple::BlankProject1:mergeDebugAssets UP-TO-DATE\n" + "9: Simple::BlankProject1:mergeDebugResources UP-TO-DATE\n" + "10: Simple::BlankProject1:processDebugManifest UP-TO-DATE\n" + "11: Simple::BlankProject1:processDebugResources\n" + "12: Error:No resource identifier found for attribute 'slayout_alignParentTop' in package 'android'\n" + "\t" + source.getPath() + ":12:-1\n" + "13: Simple::BlankProject1:processDebugResources FAILED\n" + "14: Error:Error while executing aapt command\n" + "15: Error:No resource identifier found for attribute 'slayout_alignParentTop' in package 'android'\n" + "\t" + source.getPath() + ":12:-1\n" + "16: Error:Execution failed for task ':BlankProject1:processDebugResources'.\n" + "17: Info:BUILD FAILED\n", toString(parser.parseGradleOutput(output))); sourceFile.delete(); source.delete(); tempDir.delete(); } public void testChangedFile() throws Exception { createTempXmlFile(); String output = ":MyApp:compileReleaseRenderscript UP-TO-DATE\n" + ":MyApp:mergeReleaseResources FAILED\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':MyApp:mergeReleaseResources'.\n" + "> In DataSet 'main', no data file for changedFile '" + sourceFilePath + "'\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 15.612 secs"; assertEquals("0: Simple::MyApp:compileReleaseRenderscript UP-TO-DATE\n" + "1: Simple::MyApp:mergeReleaseResources FAILED\n" + "2: Error:Execution failed for task ':MyApp:mergeReleaseResources'.\n" + "> In DataSet 'main', no data file for changedFile '" + sourceFilePath + "'\n" + "\t" + sourceFilePath + ":-1:-1\n" + "3: Info:BUILD FAILED\n" + "4: Info:Total time: 15.612 secs\n", toString(parser.parseGradleOutput(output))); sourceFile.delete(); } public void testChangedFile2() throws Exception { createTempXmlFile(); String output = ":MyApp:compileReleaseRenderscript UP-TO-DATE\n" + ":MyApp:mergeReleaseResources FAILED\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':MyApp:mergeReleaseResources'.\n" + "> In DataSet 'main', no data file for changedFile '" + sourceFilePath + "'. This is an internal error in the incremental builds code; to work around it, try doing a full clean build.\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 15.612 secs"; assertEquals("0: Simple::MyApp:compileReleaseRenderscript UP-TO-DATE\n" + "1: Simple::MyApp:mergeReleaseResources FAILED\n" + "2: Error:Execution failed for task ':MyApp:mergeReleaseResources'.\n" + "> In DataSet 'main', no data file for changedFile '" + sourceFilePath + "'. This is an internal error in the incremental builds code; to work around it, try doing a full clean build.\n" + "\t" + sourceFilePath + ":-1:-1\n" + "3: Info:BUILD FAILED\n" + "4: Info:Total time: 15.612 secs\n", toString(parser.parseGradleOutput(output))); sourceFile.delete(); } public void testMismatchedTag() throws Exception { // https://code.google.com/p/android/issues/detail?id=59824 createTempXmlFile(); String output = ":AudioPlayer:prepareDebugDependencies\n" + ":AudioPlayer:compileDebugAidl UP-TO-DATE\n" + ":AudioPlayer:generateDebugBuildConfig UP-TO-DATE\n" + ":AudioPlayer:mergeDebugAssets UP-TO-DATE\n" + ":AudioPlayer:compileDebugRenderscript UP-TO-DATE\n" + ":AudioPlayer:mergeDebugResources UP-TO-DATE\n" + ":AudioPlayer:processDebugManifest UP-TO-DATE\n" + ":AudioPlayer:processDebugResources\n" + sourceFilePath + ":101: error: Error parsing XML: mismatched tag\n" + ":AudioPlayer:processDebugResources FAILED\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':AudioPlayer:processDebugResources'.\n" + "> Failed to run command:\n" + " \t/Users/sbarta/sdk/build-tools/android-4.2.2/aapt package -f --no-crunch -I ...\n" + " Error Code:\n" + " \t1\n" + " Output:\n" + " \t" + sourceFilePath + ":101: error: Error parsing XML: mismatched tag\n" + "\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 3.836 secs"; assertEquals("0: Simple::AudioPlayer:prepareDebugDependencies\n" + "1: Simple::AudioPlayer:compileDebugAidl UP-TO-DATE\n" + "2: Simple::AudioPlayer:generateDebugBuildConfig UP-TO-DATE\n" + "3: Simple::AudioPlayer:mergeDebugAssets UP-TO-DATE\n" + "4: Simple::AudioPlayer:compileDebugRenderscript UP-TO-DATE\n" + "5: Simple::AudioPlayer:mergeDebugResources UP-TO-DATE\n" + "6: Simple::AudioPlayer:processDebugManifest UP-TO-DATE\n" + "7: Simple::AudioPlayer:processDebugResources\n" + "8: Error:Error parsing XML: mismatched tag\n" + "\t" + sourceFilePath + ":101:-1\n" + "9: Simple::AudioPlayer:processDebugResources FAILED\n" + "10: Error:Error while executing aapt command\n" + "11: Error:Error parsing XML: mismatched tag\n" + "\t" + sourceFilePath + ":101:-1\n" + "12: Error:Execution failed for task ':AudioPlayer:processDebugResources'.\n" + "13: Info:BUILD FAILED\n" + "14: Info:Total time: 3.836 secs\n", toString(parser.parseGradleOutput(output))); sourceFile.delete(); } public void testDuplicateResources3() throws Exception { // Duplicate resource exception: New gradle output format (using MergingException) createTempXmlFile(); String output = "Relying on packaging to define the extension of the main artifact has been deprecated and is scheduled to be removed in Gradle 2.0\n" + ":MyApplication589:preBuild UP-TO-DATE\n" + ":MyApplication589:preDebugBuild UP-TO-DATE\n" + ":MyApplication589:preReleaseBuild UP-TO-DATE\n" + ":MyApplication589:prepareComAndroidSupportAppcompatV71800Library UP-TO-DATE\n" + ":MyApplication589:prepareDebugDependencies\n" + ":MyApplication589:compileDebugAidl UP-TO-DATE\n" + ":MyApplication589:compileDebugRenderscript UP-TO-DATE\n" + ":MyApplication589:generateDebugBuildConfig UP-TO-DATE\n" + ":MyApplication589:mergeDebugAssets UP-TO-DATE\n" + ":MyApplication589:mergeDebugResources\n" + sourceFilePath + ": Error: Duplicate resources: " + sourceFilePath + ", /some/other/path/src/main/res/values/strings.xml:string/action_settings\n" + ":MyApplication589:mergeDebugResources FAILED\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':MyApplication589:mergeDebugResources'.\n" + "> " + sourceFilePath + ": Error: Duplicate resources: " + sourceFilePath + ", /some/other/path/src/main/res/values/strings.xml:string/action_settings\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 4.861 secs"; assertEquals("0: Simple::MyApplication589:preBuild UP-TO-DATE\n" + "1: Simple::MyApplication589:preDebugBuild UP-TO-DATE\n" + "2: Simple::MyApplication589:preReleaseBuild UP-TO-DATE\n" + "3: Simple::MyApplication589:prepareComAndroidSupportAppcompatV71800Library UP-TO-DATE\n" + "4: Simple::MyApplication589:prepareDebugDependencies\n" + "5: Simple::MyApplication589:compileDebugAidl UP-TO-DATE\n" + "6: Simple::MyApplication589:compileDebugRenderscript UP-TO-DATE\n" + "7: Simple::MyApplication589:generateDebugBuildConfig UP-TO-DATE\n" + "8: Simple::MyApplication589:mergeDebugAssets UP-TO-DATE\n" + "9: Simple::MyApplication589:mergeDebugResources\n" + "10: Error:Error: Duplicate resources: " + sourceFilePath +", /some/other/path/src/main/res/values/strings.xml:string/action_settings\n" + "\t" + sourceFilePath + ":-1:-1\n" + "11: Simple::MyApplication589:mergeDebugResources FAILED\n" + "12: Error:Execution failed for task ':MyApplication589:mergeDebugResources'.\n" + "> " + sourceFilePath + ": Error: Duplicate resources: " + sourceFilePath + ", /some/other/path/src/main/res/values/strings.xml:string/action_settings\n" + "\t" + sourceFilePath + ":-1:-1\n" + "13: Info:BUILD FAILED\n" + "14: Info:Total time: 4.861 secs\n", toString(parser.parseGradleOutput(output))); sourceFile.delete(); } public void testXmlError2() throws Exception { // XML error; Added "<" on separate line; new gradle output format (using MergingException) createTempXmlFile(); String output = "Relying on packaging to define the extension of the main artifact has been deprecated and is scheduled to be removed in Gradle 2.0\n" + ":MyApplication:preBuild UP-TO-DATE\n" + ":MyApplication:preDebugBuild UP-TO-DATE\n" + ":MyApplication:preReleaseBuild UP-TO-DATE\n" + ":MyApplication:prepareComAndroidSupportAppcompatV71800Library UP-TO-DATE\n" + ":MyApplication:prepareDebugDependencies\n" + ":MyApplication:compileDebugAidl UP-TO-DATE\n" + ":MyApplication:compileDebugRenderscript UP-TO-DATE\n" + ":MyApplication:generateDebugBuildConfig UP-TO-DATE\n" + ":MyApplication:mergeDebugAssets UP-TO-DATE\n" + ":MyApplication:mergeDebugResources\n" + "[Fatal Error] :5:2: The content of elements must consist of well-formed character data or markup.\n" + sourceFilePath + ":4:1: Error: The content of elements must consist of well-formed character data or markup.\n" + ":MyApplication:mergeDebugResources FAILED\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':MyApplication:mergeDebugResources'.\n" + "> " + sourceFilePath + ":4:1: Error: The content of elements must consist of well-formed character data or markup.\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 5.187 secs"; assertEquals("0: Simple::MyApplication:preBuild UP-TO-DATE\n" + "1: Simple::MyApplication:preDebugBuild UP-TO-DATE\n" + "2: Simple::MyApplication:preReleaseBuild UP-TO-DATE\n" + "3: Simple::MyApplication:prepareComAndroidSupportAppcompatV71800Library UP-TO-DATE\n" + "4: Simple::MyApplication:prepareDebugDependencies\n" + "5: Simple::MyApplication:compileDebugAidl UP-TO-DATE\n" + "6: Simple::MyApplication:compileDebugRenderscript UP-TO-DATE\n" + "7: Simple::MyApplication:generateDebugBuildConfig UP-TO-DATE\n" + "8: Simple::MyApplication:mergeDebugAssets UP-TO-DATE\n" + "9: Simple::MyApplication:mergeDebugResources\n" + "10: Error:The content of elements must consist of well-formed character data or markup.\n" + "11: Error:Error: The content of elements must consist of well-formed character data or markup.\n" + "\t" + sourceFilePath + ":4:1\n" + "12: Simple::MyApplication:mergeDebugResources FAILED\n" + "13: Error:Execution failed for task ':MyApplication:mergeDebugResources'.\n" + "> " + sourceFilePath + ":4:1: Error: The content of elements must consist of well-formed character data or markup.\n" + "\t" + sourceFilePath + ":4:1\n" + "14: Info:BUILD FAILED\n" + "15: Info:Total time: 5.187 secs\n", toString(parser.parseGradleOutput(output))); sourceFile.delete(); } public void testXmlErrorBadLinenumbers() throws Exception { // Like testXmlError2, but with tweaked line numbers to check the MergingExceptionParser parser createTempXmlFile(); String output = "[Fatal Error] :5:2: The content of elements must consist of well-formed character data or markup.\n" + sourceFilePath + ":42: Error: The content of elements must consist of well-formed character data or markup.\n" + sourceFilePath + ":-1: Error: The content of elements must consist of well-formed character data or markup.\n" + sourceFilePath + ":-1:-1: Error: The content of elements must consist of well-formed character data or markup."; assertEquals("0: Error:The content of elements must consist of well-formed character data or markup.\n" + "1: Error:Error: The content of elements must consist of well-formed character data or markup.\n" + "\t" + sourceFilePath + ":42:-1\n" + "2: Error:Error: The content of elements must consist of well-formed character data or markup.\n" + "\t" + sourceFilePath + ":-1:-1\n" + "3: Error:Error: The content of elements must consist of well-formed character data or markup.\n" + "\t" + sourceFilePath + ":-1:-1\n", toString(parser.parseGradleOutput(output))); sourceFile.delete(); } public void testXmlError3() throws Exception { // XML error; Added <dimen name=activity_horizontal_margin">16dp</dimen> (missing quote createTempXmlFile(); String output = "Relying on packaging to define the extension of the main artifact has been deprecated and is scheduled to be removed in Gradle 2.0\n" + ":MyApplication:preBuild UP-TO-DATE\n" + ":MyApplication:preDebugBuild UP-TO-DATE\n" + ":MyApplication:preReleaseBuild UP-TO-DATE\n" + ":MyApplication:prepareComAndroidSupportAppcompatV71800Library UP-TO-DATE\n" + ":MyApplication:prepareDebugDependencies\n" + ":MyApplication:compileDebugAidl UP-TO-DATE\n" + ":MyApplication:compileDebugRenderscript UP-TO-DATE\n" + ":MyApplication:generateDebugBuildConfig UP-TO-DATE\n" + ":MyApplication:mergeDebugAssets UP-TO-DATE\n" + ":MyApplication:mergeDebugResources\n" + "[Fatal Error] :3:17: Open quote is expected for attribute \"{1}\" associated with an element type \"name\".\n" + sourceFilePath + ":2:16: Error: Open quote is expected for attribute \"{1}\" associated with an element type \"name\".\n" + ":MyApplication:mergeDebugResources FAILED\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':MyApplication:mergeDebugResources'.\n" + "> " + sourceFilePath + ":2:16: Error: Open quote is expected for attribute \"{1}\" associated with an element type \"name\".\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 4.951 secs"; assertEquals("0: Simple::MyApplication:preBuild UP-TO-DATE\n" + "1: Simple::MyApplication:preDebugBuild UP-TO-DATE\n" + "2: Simple::MyApplication:preReleaseBuild UP-TO-DATE\n" + "3: Simple::MyApplication:prepareComAndroidSupportAppcompatV71800Library UP-TO-DATE\n" + "4: Simple::MyApplication:prepareDebugDependencies\n" + "5: Simple::MyApplication:compileDebugAidl UP-TO-DATE\n" + "6: Simple::MyApplication:compileDebugRenderscript UP-TO-DATE\n" + "7: Simple::MyApplication:generateDebugBuildConfig UP-TO-DATE\n" + "8: Simple::MyApplication:mergeDebugAssets UP-TO-DATE\n" + "9: Simple::MyApplication:mergeDebugResources\n" + "10: Error:Open quote is expected for attribute \"{1}\" associated with an element type \"name\".\n" + "11: Error:Error: Open quote is expected for attribute \"{1}\" associated with an element type \"name\".\n" + "\t" + sourceFilePath + ":2:16\n" + "12: Simple::MyApplication:mergeDebugResources FAILED\n" + "13: Error:Execution failed for task ':MyApplication:mergeDebugResources'.\n" + "> "+ sourceFilePath + ":2:16: Error: Open quote is expected for attribute \"{1}\" associated with an element type \"name\".\n" + "\t" + sourceFilePath + ":2:16\n" + "14: Info:BUILD FAILED\n" + "15: Info:Total time: 4.951 secs\n", toString(parser.parseGradleOutput(output))); sourceFile.delete(); } public void testJavacError() throws Exception { // Javac error createTempXmlFile(); String output = "Relying on packaging to define the extension of the main artifact has been deprecated and is scheduled to be removed in Gradle 2.0\n" + ":MyApplication:preBuild UP-TO-DATE\n" + ":MyApplication:preDebugBuild UP-TO-DATE\n" + ":MyApplication:preReleaseBuild UP-TO-DATE\n" + ":MyApplication:prepareComAndroidSupportAppcompatV71800Library UP-TO-DATE\n" + ":MyApplication:prepareDebugDependencies\n" + ":MyApplication:compileDebugAidl UP-TO-DATE\n" + ":MyApplication:compileDebugRenderscript UP-TO-DATE\n" + ":MyApplication:generateDebugBuildConfig UP-TO-DATE\n" + ":MyApplication:mergeDebugAssets UP-TO-DATE\n" + ":MyApplication:mergeDebugResources UP-TO-DATE\n" + ":MyApplication:processDebugManifest UP-TO-DATE\n" + ":MyApplication:processDebugResources UP-TO-DATE\n" + ":MyApplication:generateDebugSources UP-TO-DATE\n" + ":MyApplication:compileDebug\n" + "Ignoring platform 'android-1': build.prop is missing.\n" + sourceFilePath + ":12: not a statement\n" + "x super.onCreate(savedInstanceState);\n" + "^\n" + sourceFilePath + ":12: ';' expected\n" + "x super.onCreate(savedInstanceState);\n" + " ^\n" + "2 errors\n" + ":MyApplication:compileDebug FAILED\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':MyApplication:compileDebug'.\n" + "> Compilation failed; see the compiler error output for details.\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 6.177 secs"; assertEquals("0: Simple::MyApplication:preBuild UP-TO-DATE\n" + "1: Simple::MyApplication:preDebugBuild UP-TO-DATE\n" + "2: Simple::MyApplication:preReleaseBuild UP-TO-DATE\n" + "3: Simple::MyApplication:prepareComAndroidSupportAppcompatV71800Library UP-TO-DATE\n" + "4: Simple::MyApplication:prepareDebugDependencies\n" + "5: Simple::MyApplication:compileDebugAidl UP-TO-DATE\n" + "6: Simple::MyApplication:compileDebugRenderscript UP-TO-DATE\n" + "7: Simple::MyApplication:generateDebugBuildConfig UP-TO-DATE\n" + "8: Simple::MyApplication:mergeDebugAssets UP-TO-DATE\n" + "9: Simple::MyApplication:mergeDebugResources UP-TO-DATE\n" + "10: Simple::MyApplication:processDebugManifest UP-TO-DATE\n" + "11: Simple::MyApplication:processDebugResources UP-TO-DATE\n" + "12: Simple::MyApplication:generateDebugSources UP-TO-DATE\n" + "13: Simple::MyApplication:compileDebug\n" + "14: Simple:Ignoring platform 'android-1': build.prop is missing.\n" + "15: Error:not a statement\n" + "\t" + sourceFilePath + ":12:-1\n" + "16: Simple:x super.onCreate(savedInstanceState);\n" + "17: Simple:^\n" + "18: Error:';' expected\n" + "\t" + sourceFilePath + ":12:-1\n" + "19: Simple:x super.onCreate(savedInstanceState);\n" + "20: Simple: ^\n" + "21: Simple::MyApplication:compileDebug FAILED\n" + "22: Error:Execution failed for task ':MyApplication:compileDebug'.\n" + "> Compilation failed; see the compiler error output for details.\n" + "23: Info:BUILD FAILED\n" + "24: Info:Total time: 6.177 secs\n", toString(parser.parseGradleOutput(output))); sourceFile.delete(); } public void testMissingSourceCompat() throws Exception { // Wrong target (source, not target // Should rewrite to suggest checking JAVA_HOME createTempXmlFile(); String output = ":MyApplication:preBuild UP-TO-DATE\n" + ":MyApplication:preFreeDebugBuild UP-TO-DATE\n" + ":MyApplication:preFreeReleaseBuild UP-TO-DATE\n" + ":MyApplication:preProDebugBuild UP-TO-DATE\n" + ":MyApplication:preProReleaseBuild UP-TO-DATE\n" + ":MyApplication:prepareComAndroidSupportAppcompatV71800Library UP-TO-DATE\n" + ":MyApplication:prepareFreeDebugDependencies\n" + ":MyApplication:compileFreeDebugAidl UP-TO-DATE\n" + ":MyApplication:compileFreeDebugRenderscript UP-TO-DATE\n" + ":MyApplication:generateFreeDebugBuildConfig UP-TO-DATE\n" + ":MyApplication:mergeFreeDebugAssets UP-TO-DATE\n" + ":MyApplication:mergeFreeDebugResources UP-TO-DATE\n" + ":MyApplication:processFreeDebugManifest UP-TO-DATE\n" + ":MyApplication:processFreeDebugResources UP-TO-DATE\n" + ":MyApplication:generateFreeDebugSources UP-TO-DATE\n" + ":MyApplication:compileFreeDebug\n" + "Ignoring platform 'android-1': build.prop is missing.\n" + ":MyApplication:compileFreeDebug FAILED\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':MyApplication:compileFreeDebug'.\n" + "> invalid source release: 1.7\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 5.47 secs"; assertEquals("0: Simple::MyApplication:preBuild UP-TO-DATE\n" + "1: Simple::MyApplication:preFreeDebugBuild UP-TO-DATE\n" + "2: Simple::MyApplication:preFreeReleaseBuild UP-TO-DATE\n" + "3: Simple::MyApplication:preProDebugBuild UP-TO-DATE\n" + "4: Simple::MyApplication:preProReleaseBuild UP-TO-DATE\n" + "5: Simple::MyApplication:prepareComAndroidSupportAppcompatV71800Library UP-TO-DATE\n" + "6: Simple::MyApplication:prepareFreeDebugDependencies\n" + "7: Simple::MyApplication:compileFreeDebugAidl UP-TO-DATE\n" + "8: Simple::MyApplication:compileFreeDebugRenderscript UP-TO-DATE\n" + "9: Simple::MyApplication:generateFreeDebugBuildConfig UP-TO-DATE\n" + "10: Simple::MyApplication:mergeFreeDebugAssets UP-TO-DATE\n" + "11: Simple::MyApplication:mergeFreeDebugResources UP-TO-DATE\n" + "12: Simple::MyApplication:processFreeDebugManifest UP-TO-DATE\n" + "13: Simple::MyApplication:processFreeDebugResources UP-TO-DATE\n" + "14: Simple::MyApplication:generateFreeDebugSources UP-TO-DATE\n" + "15: Simple::MyApplication:compileFreeDebug\n" + "16: Simple:Ignoring platform 'android-1': build.prop is missing.\n" + "17: Simple::MyApplication:compileFreeDebug FAILED\n" + "18: Error:Execution failed for task ':MyApplication:compileFreeDebug'.\n" + // TODO: This is all we currently get. We should find a way to trap this and point to the // right source file where the invalid source flag is set "> invalid source release: 1.7\n" + "19: Info:BUILD FAILED\n" + "20: Info:Total time: 5.47 secs\n", toString(parser.parseGradleOutput(output))); sourceFile.delete(); } public void testInvalidLayoutName() throws Exception { // Invalid layout name createTempXmlFile(); String output = "Relying on packaging to define the extension of the main artifact has been deprecated and is scheduled to be removed in Gradle 2.0\n" + ":MyApplication585:preBuild UP-TO-DATE\n" + ":MyApplication585:preDebugBuild UP-TO-DATE\n" + ":MyApplication585:preReleaseBuild UP-TO-DATE\n" + ":MyApplication585:prepareComAndroidSupportAppcompatV71800Library UP-TO-DATE\n" + ":MyApplication585:prepareDebugDependencies\n" + ":MyApplication585:compileDebugAidl UP-TO-DATE\n" + ":MyApplication585:compileDebugRenderscript UP-TO-DATE\n" + ":MyApplication585:generateDebugBuildConfig UP-TO-DATE\n" + ":MyApplication585:mergeDebugAssets UP-TO-DATE\n" + ":MyApplication585:mergeDebugResources\n" + sourceFilePath + ": Error: Invalid file name: must contain only lowercase letters and digits ([a-z0-9_.])\n" + ":MyApplication585:mergeDebugResources FAILED\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':MyApplication585:mergeDebugResources'.\n" + "> " + sourceFilePath + ": Error: Invalid file name: must contain only lowercase letters and digits ([a-z0-9_.])\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 8.91 secs"; assertEquals("0: Simple::MyApplication585:preBuild UP-TO-DATE\n" + "1: Simple::MyApplication585:preDebugBuild UP-TO-DATE\n" + "2: Simple::MyApplication585:preReleaseBuild UP-TO-DATE\n" + "3: Simple::MyApplication585:prepareComAndroidSupportAppcompatV71800Library UP-TO-DATE\n" + "4: Simple::MyApplication585:prepareDebugDependencies\n" + "5: Simple::MyApplication585:compileDebugAidl UP-TO-DATE\n" + "6: Simple::MyApplication585:compileDebugRenderscript UP-TO-DATE\n" + "7: Simple::MyApplication585:generateDebugBuildConfig UP-TO-DATE\n" + "8: Simple::MyApplication585:mergeDebugAssets UP-TO-DATE\n" + "9: Simple::MyApplication585:mergeDebugResources\n" + "10: Error:Error: Invalid file name: must contain only lowercase letters and digits ([a-z0-9_.])\n" + "\t" + sourceFilePath + ":-1:-1\n" + "11: Simple::MyApplication585:mergeDebugResources FAILED\n" + "12: Error:Execution failed for task ':MyApplication585:mergeDebugResources'.\n" + "> " + sourceFilePath + ": Error: Invalid file name: must contain only lowercase letters and digits ([a-z0-9_.])\n" + "\t" + sourceFilePath + ":-1:-1\n" + "13: Info:BUILD FAILED\n" + "14: Info:Total time: 8.91 secs\n", toString(parser.parseGradleOutput(output))); sourceFile.delete(); } public void testInvalidLayoutName2() throws Exception { // Like testInvalidLayoutName, but with line numbers in the error pattern createTempXmlFile(); String output = "Relying on packaging to define the extension of the main artifact has been deprecated and is scheduled to be removed in Gradle 2.0\n" + ":MyApplication585:preBuild UP-TO-DATE\n" + ":MyApplication585:preDebugBuild UP-TO-DATE\n" + ":MyApplication585:preReleaseBuild UP-TO-DATE\n" + ":MyApplication585:prepareComAndroidSupportAppcompatV71800Library UP-TO-DATE\n" + ":MyApplication585:prepareDebugDependencies\n" + ":MyApplication585:compileDebugAidl UP-TO-DATE\n" + ":MyApplication585:compileDebugRenderscript UP-TO-DATE\n" + ":MyApplication585:generateDebugBuildConfig UP-TO-DATE\n" + ":MyApplication585:mergeDebugAssets UP-TO-DATE\n" + ":MyApplication585:mergeDebugResources\n" + sourceFilePath + ":4: Error: Invalid file name: must contain only lowercase letters and digits ([a-z0-9_.])\n" + ":MyApplication585:mergeDebugResources FAILED\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':MyApplication585:mergeDebugResources'.\n" + "> " + sourceFilePath + ":4: Error: Invalid file name: must contain only lowercase letters and digits ([a-z0-9_.])\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 8.91 secs"; assertEquals("0: Simple::MyApplication585:preBuild UP-TO-DATE\n" + "1: Simple::MyApplication585:preDebugBuild UP-TO-DATE\n" + "2: Simple::MyApplication585:preReleaseBuild UP-TO-DATE\n" + "3: Simple::MyApplication585:prepareComAndroidSupportAppcompatV71800Library UP-TO-DATE\n" + "4: Simple::MyApplication585:prepareDebugDependencies\n" + "5: Simple::MyApplication585:compileDebugAidl UP-TO-DATE\n" + "6: Simple::MyApplication585:compileDebugRenderscript UP-TO-DATE\n" + "7: Simple::MyApplication585:generateDebugBuildConfig UP-TO-DATE\n" + "8: Simple::MyApplication585:mergeDebugAssets UP-TO-DATE\n" + "9: Simple::MyApplication585:mergeDebugResources\n" + "10: Error:Error: Invalid file name: must contain only lowercase letters and digits ([a-z0-9_.])\n" + "\t" + sourceFilePath + ":4:-1\n" + "11: Simple::MyApplication585:mergeDebugResources FAILED\n" + "12: Error:Execution failed for task ':MyApplication585:mergeDebugResources'.\n" + "> " + sourceFilePath + ":4: Error: Invalid file name: must contain only lowercase letters and digits ([a-z0-9_.])\n" + "\t" + sourceFilePath + ":4:-1\n" + "13: Info:BUILD FAILED\n" + "14: Info:Total time: 8.91 secs\n", toString(parser.parseGradleOutput(output))); sourceFile.delete(); } public void testMultipleResourcesInSameFile() throws Exception { // Multiple items (repeated) createTempXmlFile(); String output = "Relying on packaging to define the extension of the main artifact has been deprecated and is scheduled to be removed in Gradle 2.0\n" + ":MyApplication:preBuild UP-TO-DATE\n" + ":MyApplication:preDebugBuild UP-TO-DATE\n" + ":MyApplication:preReleaseBuild UP-TO-DATE\n" + ":MyApplication:prepareComAndroidSupportAppcompatV71800Library UP-TO-DATE\n" + ":MyApplication:prepareDebugDependencies\n" + ":MyApplication:compileDebugAidl UP-TO-DATE\n" + ":MyApplication:compileDebugRenderscript UP-TO-DATE\n" + ":MyApplication:generateDebugBuildConfig UP-TO-DATE\n" + ":MyApplication:mergeDebugAssets UP-TO-DATE\n" + ":MyApplication:mergeDebugResources\n" + sourceFilePath + ": Error: Found item Dimension/activity_horizontal_margin more than one time\n" + ":MyApplication:mergeDebugResources FAILED\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':MyApplication:mergeDebugResources'.\n" + "> " + sourceFilePath + ": Error: Found item Dimension/activity_horizontal_margin more than one time\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 5.623 secs"; assertEquals("0: Simple::MyApplication:preBuild UP-TO-DATE\n" + "1: Simple::MyApplication:preDebugBuild UP-TO-DATE\n" + "2: Simple::MyApplication:preReleaseBuild UP-TO-DATE\n" + "3: Simple::MyApplication:prepareComAndroidSupportAppcompatV71800Library UP-TO-DATE\n" + "4: Simple::MyApplication:prepareDebugDependencies\n" + "5: Simple::MyApplication:compileDebugAidl UP-TO-DATE\n" + "6: Simple::MyApplication:compileDebugRenderscript UP-TO-DATE\n" + "7: Simple::MyApplication:generateDebugBuildConfig UP-TO-DATE\n" + "8: Simple::MyApplication:mergeDebugAssets UP-TO-DATE\n" + "9: Simple::MyApplication:mergeDebugResources\n" + "10: Error:Error: Found item Dimension/activity_horizontal_margin more than one time\n" + "\t" + sourceFilePath + ":-1:-1\n" + "11: Simple::MyApplication:mergeDebugResources FAILED\n" + "12: Error:Execution failed for task ':MyApplication:mergeDebugResources'.\n" + "> " + sourceFilePath + ": Error: Found item Dimension/activity_horizontal_margin more than one time\n" + "\t" + sourceFilePath + ":-1:-1\n" + "13: Info:BUILD FAILED\n" + "14: Info:Total time: 5.623 secs\n", toString(parser.parseGradleOutput(output))); sourceFile.delete(); } public void testNdkWarningOutputUnix() throws Exception { createTempXmlFile(); String output = ":foolib:compileLint\n" + ":foolib:copyDebugLint UP-TO-DATE\n" + ":foolib:mergeDebugProguardFiles UP-TO-DATE\n" + ":foolib:buildNative\n" + "Unexpected close tag: MANIFEST, expecting APPLICATION\n" + "jni/Android.mk:24: warning: overriding commands for target `dump'\n" + "jni/Android.mk:24: warning: ignoring old commands for target `dump'\n" + "jni/Android.mk:24: warning: overriding commands for target `dump'\n" + "jni/Android.mk:24: warning: ignoring old commands for target `dump'\n" + sourceFilePath + ":393: warning: overriding commands for target `obj/local/x86/objs/blah/src/blah3_a_16.o'\n" + sourceFilePath + ":393: warning: ignoring old commands for target `obj/local/x86/objs/blah/src/blah3_a_16.o'\n" + sourceFilePath + ":393: warning: overriding commands for target `obj/local/x86/objs/blah/src/blah3_a_9.o'\n" + sourceFilePath + ":393: warning: ignoring old commands for target `obj/local/x86/objs/blah/src/blah3_a_9.o'\n" + sourceFilePath + ":393: warning: overriding commands for target `obj/local/x86/objs/blah/src/blah3_b_18.o'\n" + sourceFilePath + ":393: warning: ignoring old commands for target `obj/local/x86/objs/blah/src/blah3_b_18.o'\n" + sourceFilePath + ":393: warning: overriding commands for target `obj/local/x86/objs/blah/src/blah3_c.o'\n" + sourceFilePath + ":393: warning: ignoring old commands for target `obj/local/x86/objs/blah/src/blah3_c.o'\n" + "jni/Android.mk:24: warning: overriding commands for target `dump'\n" + "jni/Android.mk:24: warning: ignoring old commands for target `dump'\n" + "[armeabi-v7a] Install : libaacdecoder.so => libs/armeabi-v7a/libaacdecoder.so\n" + "[armeabi] Install : libaacdecoder.so => libs/armeabi/libaacdecoder.so\n" + "[x86] Install : libaacdecoder.so => libs/x86/libaacdecoder.so\n" + "[mips] Install : libaacdecoder.so => libs/mips/libaacdecoder.so\n" + ":foolib:copyNativeLibs UP-TO-DATE" + ":app:assembleDebug UP-TO-DATE\n" + "\n" + "BUILD SUCCESSFUL\n" + "\n" + "Total time: 11.965 secs"; assertEquals("0: Simple::foolib:compileLint\n" + "1: Simple::foolib:copyDebugLint UP-TO-DATE\n" + "2: Simple::foolib:mergeDebugProguardFiles UP-TO-DATE\n" + "3: Simple::foolib:buildNative\n" + "4: Simple:Unexpected close tag: MANIFEST, expecting APPLICATION\n" + "5: Warning:warning: overriding commands for target `dump'\n" + "\tjni/Android.mk:24:-1\n" + "6: Warning:warning: ignoring old commands for target `dump'\n" + "\tjni/Android.mk:24:-1\n" + "7: Warning:warning: overriding commands for target `dump'\n" + "\tjni/Android.mk:24:-1\n" + "8: Warning:warning: ignoring old commands for target `dump'\n" + "\tjni/Android.mk:24:-1\n" + "9: Warning:warning: overriding commands for target `obj/local/x86/objs/blah/src/blah3_a_16.o'\n" + "\t" + sourceFilePath + ":393:-1\n" + "10: Warning:warning: ignoring old commands for target `obj/local/x86/objs/blah/src/blah3_a_16.o'\n" + "\t" + sourceFilePath + ":393:-1\n" + "11: Warning:warning: overriding commands for target `obj/local/x86/objs/blah/src/blah3_a_9.o'\n" + "\t" + sourceFilePath + ":393:-1\n" + "12: Warning:warning: ignoring old commands for target `obj/local/x86/objs/blah/src/blah3_a_9.o'\n" + "\t" + sourceFilePath + ":393:-1\n" + "13: Warning:warning: overriding commands for target `obj/local/x86/objs/blah/src/blah3_b_18.o'\n" + "\t" + sourceFilePath + ":393:-1\n" + "14: Warning:warning: ignoring old commands for target `obj/local/x86/objs/blah/src/blah3_b_18.o'\n" + "\t" + sourceFilePath + ":393:-1\n" + "15: Warning:warning: overriding commands for target `obj/local/x86/objs/blah/src/blah3_c.o'\n" + "\t" + sourceFilePath + ":393:-1\n" + "16: Warning:warning: ignoring old commands for target `obj/local/x86/objs/blah/src/blah3_c.o'\n" + "\t" + sourceFilePath + ":393:-1\n" + "17: Warning:warning: overriding commands for target `dump'\n" + "\tjni/Android.mk:24:-1\n" + "18: Warning:warning: ignoring old commands for target `dump'\n" + "\tjni/Android.mk:24:-1\n" + "19: Simple:[armeabi-v7a] Install : libaacdecoder.so => libs/armeabi-v7a/libaacdecoder.so\n" + "20: Simple:[armeabi] Install : libaacdecoder.so => libs/armeabi/libaacdecoder.so\n" + "21: Simple:[x86] Install : libaacdecoder.so => libs/x86/libaacdecoder.so\n" + "22: Simple:[mips] Install : libaacdecoder.so => libs/mips/libaacdecoder.so\n" + "23: Simple::foolib:copyNativeLibs UP-TO-DATE:app:assembleDebug UP-TO-DATE\n" + "24: Info:BUILD SUCCESSFUL\n" + "25: Info:Total time: 11.965 secs\n", toString(parser.parseGradleOutput(output))); sourceFile.delete(); } public void testNdErrorOutputUnix() throws Exception { createTempFile(".cpp"); String output = ":foolib:mergeDebugProguardFiles UP-TO-DATE\n" + ":foolib:buildNative\n" + sourceFilePath + ": In function 'void foo_bar(STRUCT_FOO_BAR*)':\n" + sourceFilePath + ":182:1: error: 'xyz' was not declared in this scope\n" + sourceFilePath + ": In function 'void foo_bar(STRUCT_FOO_BAR*)':\n" + sourceFilePath + ":190:1: warning: some random warning here\n" + "make: *** [obj/local/armeabi-v7a/objs/foo/src/bar.o] Error 1\n" + ":foolib:buildNative FAILED\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':foolib:buildNative'.\n" + "> Process 'command '/Users/tnorbye/dev/android-ndk-r9d/ndk-build'' finished with non-zero exit value 2\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 7.994 secs"; assertEquals("0: Simple::foolib:mergeDebugProguardFiles UP-TO-DATE\n" + "1: Simple::foolib:buildNative\n" + "2: Simple:" + sourceFilePath + ": In function 'void foo_bar(STRUCT_FOO_BAR*)':\n" + "3: Error:error: 'xyz' was not declared in this scope\n" + "\t" + sourceFilePath + ":182:1\n" + "4: Simple:" + sourceFilePath + ": In function 'void foo_bar(STRUCT_FOO_BAR*)':\n" + "5: Warning:warning: some random warning here\n" + "\t" + sourceFilePath + ":190:1\n" + "6: Simple:make: *** [obj/local/armeabi-v7a/objs/foo/src/bar.o] Error 1\n" + "7: Simple::foolib:buildNative FAILED\n" + "8: Error:Execution failed for task ':foolib:buildNative'.\n" + "> Process 'command '/Users/tnorbye/dev/android-ndk-r9d/ndk-build'' finished with non-zero exit value 2\n" + "9: Info:BUILD FAILED\n" + "10: Info:Total time: 7.994 secs\n", toString(parser.parseGradleOutput(output))); sourceFile.delete(); } public void testWrongGradleVersion() throws Exception { // Wrong gradle createTempFile(DOT_GRADLE); String output = "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* Where:\n" + "Build file '" + sourceFilePath +"' line: 24\n" + "\n" + "* What went wrong:\n" + "A problem occurred evaluating project ':MyApplication'.\n" + "> Gradle version 1.8 is required. Current version is 1.7. If using the gradle wrapper, try editing the distributionUrl in /some/path/gradle.properties to gradle-1.8-all.zip\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 4.467 secs"; assertEquals("0: Error:A problem occurred evaluating project ':MyApplication'.\n" + // TODO: Link to the gradle.properties file directly! // However, we have an import hyperlink helper to do it automatically, so may not be necessary "> Gradle version 1.8 is required. Current version is 1.7. If using the gradle wrapper, try editing the distributionUrl in /some/path/gradle.properties to gradle-1.8-all.zip\n" + "\t" + sourceFilePath + ":24:0\n" + "1: Info:BUILD FAILED\n" + "2: Info:Total time: 4.467 secs\n", toString(parser.parseGradleOutput(output))); sourceFile.delete(); } public void testAndroidPluginStructuredOutput() { String output = "WARNING|:project:app1|A minor warning\n" + "WARNING|:project:app2|A|minor|warning\n" + "ERROR|:project:libs:lib1|Serious error\n"; assertEquals("0: Warning:A minor warning\n" + ":project:app1\n" + "1: Warning:A|minor|warning\n" + ":project:app2\n" + "2: Error:Serious error\n" + ":project:libs:lib1\n", toString(parser.parseGradleOutput(output))); } public void testNewManifestMergeError() throws Exception { createTempFile(DOT_XML); String output = sourceFilePath + ":50:4 Warning:\n" + "\tElement intent-filter#android.intent.action.VIEW+android.intent.category.DEFAULT at AndroidManifest.xml:50:4 duplicated with element declared at AndroidManifest.xml:45:4\n" + "C:\\foo:62:4 Error:\n" + "\tElement intent-filter#android.intent.action.VIEW+android.intent.category.DEFAULT at AndroidManifest.xml:62:4 duplicated with element declared at AndroidManifest.xml:50:4\n" + sourceFilePath + ":0:0 Error:\n" + "\tValidation failed, exiting\n"; assertEquals("0: Warning:Element intent-filter#android.intent.action.VIEW+android.intent.category.DEFAULT at AndroidManifest.xml:50:4 duplicated with element declared at AndroidManifest.xml:45:4\n" + "\t" + sourceFilePath + ":50:4\n" + "1: Error:Element intent-filter#android.intent.action.VIEW+android.intent.category.DEFAULT at AndroidManifest.xml:62:4 duplicated with element declared at AndroidManifest.xml:50:4\n" + "\tC:\\foo:62:4\n", toString(parser.parseGradleOutput(output))); } public void testManifestMergeError() throws Exception { createTempFile(DOT_XML); String output = ":processFlavor1DebugManifest\n" + "[" + sourceFilePath + ":1] Could not find element /manifest/application.\n" + ":processFlavor1DebugManifest FAILED\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':processFlavor1DebugManifest'.\n" + "> Manifest merging failed. See console for more info.\n" + "\n" + "* Try:\n" + "Run with --info or --debug option to get more log output.\n"; assertEquals("0: Simple::processFlavor1DebugManifest\n" + "1: Error:Could not find element /manifest/application.\n" + "\t" + sourceFilePath + ":1:-1\n" + "2: Simple::processFlavor1DebugManifest FAILED\n" + "3: Simple:FAILURE: Build failed with an exception.\n", toString(parser.parseGradleOutput(output))); sourceFile.delete(); } public void testManifestMergeWindowsError() throws Exception { createTempFile(DOT_XML); String output = ":processFlavor1DebugManifest\n" + "[C:\\Users\\Android\\AppData\\Local\\Temp\\com.android.tools.idea.gradle.output.parser.GradleErrorOutputParserTest4437574780178007978.xml:1] Could not find element /manifest/application.\n" + ":processFlavor1DebugManifest FAILED\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':processFlavor1DebugManifest'.\n" + "> Manifest merging failed. See console for more info.\n" + "\n" + "* Try:\n" + "Run with --info or --debug option to get more log output.\n"; assertEquals("0: Simple::processFlavor1DebugManifest\n" + "1: Error:Could not find element /manifest/application.\n" + "\tC:\\Users\\Android\\AppData\\Local\\Temp\\com.android.tools.idea.gradle.output.parser.GradleErrorOutputParserTest4437574780178007978.xml:1:-1\n" + "2: Simple::processFlavor1DebugManifest FAILED\n" + "3: Simple:FAILURE: Build failed with an exception.\n", toString(parser.parseGradleOutput(output))); sourceFile.delete(); } public void testDexDuplicateClassException() throws Exception { String output = ":two:dexDebug\n" + "UNEXPECTED TOP-LEVEL EXCEPTION:\n" + "java.lang.IllegalArgumentException: already added: Lcom/example/two/MainActivity;\n" + "\tat com.android.dx.dex.file.ClassDefsSection.add(ClassDefsSection.java:122)\n" + "\tat com.android.dx.dex.file.DexFile.add(DexFile.java:161)\n" + "\tat com.android.dx.command.dexer.Main.processClass(Main.java:685)\n" + "\tat com.android.dx.command.dexer.Main.processFileBytes(Main.java:634)\n" + "\tat com.android.dx.command.dexer.Main.access$600(Main.java:78)\n" + "\tat com.android.dx.command.dexer.Main$1.processFileBytes(Main.java:572)\n" + "\tat com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:284)\n" + "\tat com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:166)\n" + "\tat com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:144)\n" + "\tat com.android.dx.command.dexer.Main.processOne(Main.java:596)\n" + "\tat com.android.dx.command.dexer.Main.processAllFiles(Main.java:498)\n" + "\tat com.android.dx.command.dexer.Main.runMonoDex(Main.java:264)\n" + "\tat com.android.dx.command.dexer.Main.run(Main.java:230)\n" + "\tat com.android.dx.command.dexer.Main.main(Main.java:199)\n" + "\tat com.android.dx.command.Main.main(Main.java:103)\n" + "1 error; aborting\n" + " FAILED\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':two:dexDebug'.\n" + "> Could not call IncrementalTask.taskAction() on task ':two:dexDebug'\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 9.491 secs"; assertEquals("0: Simple::two:dexDebug\n" + "1: Error:Class com.example.two.MainActivity has already been added to output. Please remove duplicate copies.\n" + "2: Simple:1 error; aborting\n" + "3: Error:Execution failed for task ':two:dexDebug'.\n" + "> Could not call IncrementalTask.taskAction() on task ':two:dexDebug'\n" + "4: Info:BUILD FAILED\n" + "5: Info:Total time: 9.491 secs\n", toString(parser.parseGradleOutput(output))); } public void testMultilineCompileError() throws Exception { createTempFile(DOT_JAVA); String output = ":two:compileDebug\n" + sourceFilePath + ":20: incompatible types\n" + "found : java.util.ArrayList<java.lang.String>\n" + "required: java.util.Set<java.lang.String>\n" + " Set<String> checkedList = new ArrayList<String>();\n" + " ^\n" + "1 error\n" + ":two:compileDebug FAILED\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':two:compileDebug'.\n" + "> Compilation failed; see the compiler error output for details.\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 5.354 secs\n"; assertEquals("0: Simple::two:compileDebug\n" + "1: Error:incompatible types\n" + "found : java.util.ArrayList<java.lang.String>\n" + "required: java.util.Set<java.lang.String>\n" + "\t" + sourceFilePath + ":20:35\n" + "2: Simple::two:compileDebug FAILED\n" + "3: Error:Execution failed for task ':two:compileDebug'.\n" + "> Compilation failed; see the compiler error output for details.\n" + "4: Info:BUILD FAILED\n" + "5: Info:Total time: 5.354 secs\n", toString(parser.parseGradleOutput(output)).replaceAll("\r\n","\n")); sourceFile.delete(); } public void testRewriteManifestPaths1() throws Exception { File tempDir = Files.createTempDir(); sourceFile = new File(tempDir, ANDROID_MANIFEST_XML); sourceFilePath = sourceFile.getAbsolutePath(); File source = new File(tempDir, "real-manifest.xml"); Files.write("<<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + " package=\"com.example.app\"\n" + " android:versionCode=\"1\"\n" + " android:versionName=\"1.0\" >\n" + "\n" + " <uses-sdk\n" + " android:minSdkVersion=\"7\"\n" + " android:targetSdkVersion=\"19\" />\n" + "\n" + " <application\n" + " android:allowBackup=\"true\"\n" + " android:icon=\"@drawable/ic_xlauncher\"\n" + " android:label=\"@string/app_name\"\n" + " android:theme=\"@style/AppTheme\" >\n" + " <activity\n" + " android:name=\"com.example.app.MainActivity\"\n" + " android:label=\"@string/app_name\" >\n" + " <intent-filter>\n" + " <action android:name=\"android.intent.action.MAIN\" />\n" + "\n" + " <category android:name=\"android.intent.category.LAUNCHER\" />\n" + " </intent-filter>\n" + " </activity>\n" + " </application>\n" + "\n" + "</manifest>\n", source, Charsets.UTF_8); source.deleteOnExit(); Files.write("<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" android:versionCode=\"1\" android:versionName=\"1.0\" package=\"com.example.app\">\n" + "\n" + " <!-- " + createPathComment(source, false) + " -->\n" + "\n" + " <uses-sdk android:minSdkVersion=\"7\" android:targetSdkVersion=\"19\"/>\n" + "\n" + " <application android:allowBackup=\"true\" android:icon=\"@drawable/ic_xlauncher\" android:label=\"@string/app_name\" android:theme=\"@style/AppTheme\">\n" + " <activity android:label=\"@string/app_name\" android:name=\"com.example.app.MainActivity\">\n" + " <intent-filter>\n" + " <action android:name=\"android.intent.action.MAIN\"/>\n" + "\n" + " <category android:name=\"android.intent.category.LAUNCHER\"/>\n" + " </intent-filter>\n" + " </activity>\n" + " </application>\n" + " <!-- From: /path/to/App/src/debug/AndroidManifest.xml -->\n" + " <uses-permission android:name=\"android.permission.ACCESS_MOCK_LOCATION\"/>\n" + "\n" + " <!-- " + createPathComment(source, false) + " -->\n" + " </manifest>", sourceFile, Charsets.UTF_8); String output = "Relying on packaging to define the extension of the main artifact has been deprecated and is scheduled to be removed in Gradle 2.0\n" + ":App:compileDefaultFlavorDebugNdk UP-TO-DATE\n" + ":App:preBuild UP-TO-DATE\n" + ":App:preDefaultFlavorDebugBuild UP-TO-DATE\n" + ":App:preDefaultFlavorReleaseBuild UP-TO-DATE\n" + ":App:prepareComAndroidSupportAppcompatV71900Library UP-TO-DATE\n" + ":App:prepareDefaultFlavorDebugDependencies\n" + ":App:compileDefaultFlavorDebugAidl UP-TO-DATE\n" + ":App:compileDefaultFlavorDebugRenderscript UP-TO-DATE\n" + ":App:generateDefaultFlavorDebugBuildConfig UP-TO-DATE\n" + ":App:mergeDefaultFlavorDebugAssets UP-TO-DATE\n" + ":App:mergeDefaultFlavorDebugResources UP-TO-DATE\n" + ":App:processDefaultFlavorDebugManifest UP-TO-DATE\n" + ":App:processDefaultFlavorDebugResources\n" + sourceFilePath + ":7: error: Error: No resource found that matches the given name (at 'icon' with value '@drawable/ic_xlauncher').\n" + ":App:processDefaultFlavorDebugResources FAILED\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':App:processDefaultFlavorDebugResources'.\n" + "> com.android.ide.common.internal.LoggedErrorException: Failed to run command:\n" + " \tSDK/build-tools/android-4.4/aapt package -f --no-crunch " + "-I SDK/platforms/android-19/android.jar " + "-M PROJECT/App/build/manifests/defaultFlavor/debug/AndroidManifest.xml " + "-S PROJECT/App/build/res/all/defaultFlavor/debug " + "-A PROJECT/App/build/assets/defaultFlavor/debug " + "-m -J PROJECT/App/build/source/r/defaultFlavor/debug " + "-F PROJECT/App/build/libs/App-defaultFlavor-debug.ap_ " + "--debug-mode --custom-package com.example.app " + "--output-text-symbols PROJECT/App/build/symbols/defaultFlavor/debug\n" + " Error Code:\n" + " \t1\n" + " Output:\n" + " \t" + sourceFilePath + ":7: error: Error: No resource found that matches the given name (at 'icon' with value '@drawable/ic_xlauncher').\n" + "\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 7.024 secs"; assertEquals("0: Simple::App:compileDefaultFlavorDebugNdk UP-TO-DATE\n" + "1: Simple::App:preBuild UP-TO-DATE\n" + "2: Simple::App:preDefaultFlavorDebugBuild UP-TO-DATE\n" + "3: Simple::App:preDefaultFlavorReleaseBuild UP-TO-DATE\n" + "4: Simple::App:prepareComAndroidSupportAppcompatV71900Library UP-TO-DATE\n" + "5: Simple::App:prepareDefaultFlavorDebugDependencies\n" + "6: Simple::App:compileDefaultFlavorDebugAidl UP-TO-DATE\n" + "7: Simple::App:compileDefaultFlavorDebugRenderscript UP-TO-DATE\n" + "8: Simple::App:generateDefaultFlavorDebugBuildConfig UP-TO-DATE\n" + "9: Simple::App:mergeDefaultFlavorDebugAssets UP-TO-DATE\n" + "10: Simple::App:mergeDefaultFlavorDebugResources UP-TO-DATE\n" + "11: Simple::App:processDefaultFlavorDebugManifest UP-TO-DATE\n" + "12: Simple::App:processDefaultFlavorDebugResources\n" + "13: Error:No resource found that matches the given name (at 'icon' with value '@drawable/ic_xlauncher').\n" + "\t" + source.getPath() + ":13:23\n" + "14: Simple::App:processDefaultFlavorDebugResources FAILED\n" + "15: Error:Execution failed for task ':App:processDefaultFlavorDebugResources'.\n" + "> com.android.ide.common.internal.LoggedErrorException: Failed to run command:\n" + " \tSDK/build-tools/android-4.4/aapt package -f --no-crunch -I SDK/platforms/android-19/android.jar" + " -M PROJECT/App/build/manifests/defaultFlavor/debug/AndroidManifest.xml" + " -S PROJECT/App/build/res/all/defaultFlavor/debug" + " -A PROJECT/App/build/assets/defaultFlavor/debug" + " -m -J PROJECT/App/build/source/r/defaultFlavor/debug" + " -F PROJECT/App/build/libs/App-defaultFlavor-debug.ap_" + " --debug-mode --custom-package com.example.app" + " --output-text-symbols PROJECT/App/build/symbols/defaultFlavor/debug\n" + " Error Code:\n" + " \t1\n" + " Output:\n" + " \t" + sourceFilePath + ":7: error: Error: No resource found that matches the given name (at 'icon' with value '@drawable/ic_xlauncher').\n" + "\t" + source.getPath() + ":13:23\n" + "16: Info:BUILD FAILED\n" + "17: Info:Total time: 7.024 secs\n", toString(parser.parseGradleOutput(output))); sourceFile.delete(); source.delete(); tempDir.delete(); } public void testRewriteManifestPaths2() throws Exception { // Like testRewriteManifestPaths1, but with a source comment at the end of the file // (which happens when there is only a single manifest, so no files are merged and it's a straight // file copy in the gradle plugin) File tempDir = Files.createTempDir(); sourceFile = new File(tempDir, ANDROID_MANIFEST_XML); sourceFilePath = sourceFile.getAbsolutePath(); File source = new File(tempDir, "real-manifest.xml"); Files.write("<<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + " package=\"com.example.app\"\n" + " android:versionCode=\"1\"\n" + " android:versionName=\"1.0\" >\n" + "\n" + " <uses-sdk\n" + " android:minSdkVersion=\"7\"\n" + " android:targetSdkVersion=\"19\" />\n" + "\n" + " <application\n" + " android:allowBackup=\"true\"\n" + " android:icon=\"@drawable/ic_xlauncher\"\n" + " android:label=\"@string/app_name\"\n" + " android:theme=\"@style/AppTheme\" >\n" + " <activity\n" + " android:name=\"com.example.app.MainActivity\"\n" + " android:label=\"@string/app_name\" >\n" + " <intent-filter>\n" + " <action android:name=\"android.intent.action.MAIN\" />\n" + "\n" + " <category android:name=\"android.intent.category.LAUNCHER\" />\n" + " </intent-filter>\n" + " </activity>\n" + " </application>\n" + "\n" + "</manifest>\n", source, Charsets.UTF_8); source.deleteOnExit(); Files.write("<<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + " package=\"com.example.app\"\n" + " android:versionCode=\"1\"\n" + " android:versionName=\"1.0\" >\n" + "\n" + " <uses-sdk\n" + " android:minSdkVersion=\"7\"\n" + " android:targetSdkVersion=\"19\" />\n" + "\n" + " <application\n" + " android:allowBackup=\"true\"\n" + " android:icon=\"@drawable/ic_xlauncher\"\n" + " android:label=\"@string/app_name\"\n" + " android:theme=\"@style/AppTheme\" >\n" + " <activity\n" + " android:name=\"com.example.app.MainActivity\"\n" + " android:label=\"@string/app_name\" >\n" + " <intent-filter>\n" + " <action android:name=\"android.intent.action.MAIN\" />\n" + "\n" + " <category android:name=\"android.intent.category.LAUNCHER\" />\n" + " </intent-filter>\n" + " </activity>\n" + " </application>\n" + "\n" + "</manifest><!-- " + createPathComment(source, false) + " -->", sourceFile, Charsets.UTF_8); String output = "Relying on packaging to define the extension of the main artifact has been deprecated and is scheduled to be removed in Gradle 2.0\n" + ":App:compileDefaultFlavorDebugNdk UP-TO-DATE\n" + ":App:preBuild UP-TO-DATE\n" + ":App:preDefaultFlavorDebugBuild UP-TO-DATE\n" + ":App:preDefaultFlavorReleaseBuild UP-TO-DATE\n" + ":App:prepareComAndroidSupportAppcompatV71900Library UP-TO-DATE\n" + ":App:prepareDefaultFlavorDebugDependencies\n" + ":App:compileDefaultFlavorDebugAidl UP-TO-DATE\n" + ":App:compileDefaultFlavorDebugRenderscript UP-TO-DATE\n" + ":App:generateDefaultFlavorDebugBuildConfig UP-TO-DATE\n" + ":App:mergeDefaultFlavorDebugAssets UP-TO-DATE\n" + ":App:mergeDefaultFlavorDebugResources UP-TO-DATE\n" + ":App:processDefaultFlavorDebugManifest UP-TO-DATE\n" + ":App:processDefaultFlavorDebugResources\n" + sourceFilePath + ":7: error: Error: No resource found that matches the given name (at 'icon' with value '@drawable/ic_xlauncher').\n" + ":App:processDefaultFlavorDebugResources FAILED\n" + "\n" + "FAILURE: Build failed with an exception.\n" + "\n" + "* What went wrong:\n" + "Execution failed for task ':App:processDefaultFlavorDebugResources'.\n" + "> com.android.ide.common.internal.LoggedErrorException: Failed to run command:\n" + " \tSDK/build-tools/android-4.4/aapt package -f --no-crunch " + "-I SDK/platforms/android-19/android.jar " + "-M PROJECT/App/build/manifests/defaultFlavor/debug/AndroidManifest.xml " + "-S PROJECT/App/build/res/all/defaultFlavor/debug " + "-A PROJECT/App/build/assets/defaultFlavor/debug " + "-m -J PROJECT/App/build/source/r/defaultFlavor/debug " + "-F PROJECT/App/build/libs/App-defaultFlavor-debug.ap_ " + "--debug-mode --custom-package com.example.app " + "--output-text-symbols PROJECT/App/build/symbols/defaultFlavor/debug\n" + " Error Code:\n" + " \t1\n" + " Output:\n" + " \t" + sourceFilePath + ":7: error: Error: No resource found that matches the given name (at 'icon' with value '@drawable/ic_xlauncher').\n" + "\n" + "\n" + "* Try:\n" + "Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.\n" + "\n" + "BUILD FAILED\n" + "\n" + "Total time: 7.024 secs"; assertEquals("0: Simple::App:compileDefaultFlavorDebugNdk UP-TO-DATE\n" + "1: Simple::App:preBuild UP-TO-DATE\n" + "2: Simple::App:preDefaultFlavorDebugBuild UP-TO-DATE\n" + "3: Simple::App:preDefaultFlavorReleaseBuild UP-TO-DATE\n" + "4: Simple::App:prepareComAndroidSupportAppcompatV71900Library UP-TO-DATE\n" + "5: Simple::App:prepareDefaultFlavorDebugDependencies\n" + "6: Simple::App:compileDefaultFlavorDebugAidl UP-TO-DATE\n" + "7: Simple::App:compileDefaultFlavorDebugRenderscript UP-TO-DATE\n" + "8: Simple::App:generateDefaultFlavorDebugBuildConfig UP-TO-DATE\n" + "9: Simple::App:mergeDefaultFlavorDebugAssets UP-TO-DATE\n" + "10: Simple::App:mergeDefaultFlavorDebugResources UP-TO-DATE\n" + "11: Simple::App:processDefaultFlavorDebugManifest UP-TO-DATE\n" + "12: Simple::App:processDefaultFlavorDebugResources\n" + "13: Error:No resource found that matches the given name (at 'icon' with value '@drawable/ic_xlauncher').\n" + "\t" + source.getPath() + ":13:23\n" + "14: Simple::App:processDefaultFlavorDebugResources FAILED\n" + "15: Error:Execution failed for task ':App:processDefaultFlavorDebugResources'.\n" + "> com.android.ide.common.internal.LoggedErrorException: Failed to run command:\n" + " \tSDK/build-tools/android-4.4/aapt package -f --no-crunch -I SDK/platforms/android-19/android.jar" + " -M PROJECT/App/build/manifests/defaultFlavor/debug/AndroidManifest.xml" + " -S PROJECT/App/build/res/all/defaultFlavor/debug" + " -A PROJECT/App/build/assets/defaultFlavor/debug" + " -m -J PROJECT/App/build/source/r/defaultFlavor/debug" + " -F PROJECT/App/build/libs/App-defaultFlavor-debug.ap_" + " --debug-mode --custom-package com.example.app" + " --output-text-symbols PROJECT/App/build/symbols/defaultFlavor/debug\n" + " Error Code:\n" + " \t1\n" + " Output:\n" + " \t" + sourceFilePath + ":7: error: Error: No resource found that matches the given name (at 'icon' with value '@drawable/ic_xlauncher').\n" + "\t" + source.getPath() + ":13:23\n" + "16: Info:BUILD FAILED\n" + "17: Info:Total time: 7.024 secs\n", toString(parser.parseGradleOutput(output))); sourceFile.delete(); source.delete(); tempDir.delete(); } @NotNull private static String toString(@NotNull List<GradleMessage> messages) { StringBuilder sb = new StringBuilder(); for (int i = 0, n = messages.size(); i < n; i++) { GradleMessage message = messages.get(i); sb.append(Integer.toString(i)).append(':').append(' '); sb.append(StringUtil.capitalize(message.getKind().toString().toLowerCase(Locale.US))).append(':'); // INFO => Info sb.append(message.getText()); if (message.getSourcePath() != null) { sb.append('\n'); sb.append('\t'); sb.append(message.getSourcePath()); sb.append(':').append(Long.toString(message.getLineNumber())); sb.append(':').append(Long.toString(message.getColumn())); } if (message instanceof GradleProjectAwareMessage) { sb.append('\n'); sb.append(((GradleProjectAwareMessage)message).getGradlePath()); } sb.append('\n'); } return sb.toString(); } }