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";
   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\n"
           + "9: Simple::AudioPlayer:processDebugResources FAILED\n",
       toString(parser.parseToolOutput(output)));
   sourceFile.delete();
 }
 public void testParseDisplayingUnhandledMessages() {
   String output = " **--- HELLO WORLD ---**";
   List<Message> gradleMessages = parser.parseToolOutput(output);
   assertEquals(1, gradleMessages.size());
   Message message = gradleMessages.get(0);
   assertEquals(output, message.getText());
   assertEquals(Message.Kind.SIMPLE, message.getKind());
 }
 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<Message> messages = parser.parseToolOutput(err);
   assertHasCorrectErrorMessage(messages, messageText, 2, 3);
 }
  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<Message> messages = parser.parseToolOutput(err);
    assertEquals("[message count]", 1, messages.size());
    Message message = messages.iterator().next();
    assertNotNull(message);

    // NOT sourceFilePath; should be translated back from source comment
    String expected =
        new File(
                "src/test/resources/testData/resources/incMergeData/filesVsValues/main/layout/main.xml")
            .getAbsolutePath();
    assertEquals("[file path]", expected, getSystemIndependentSourcePath(message));
    assertEquals("[message severity]", Message.Kind.ERROR, message.getKind());
    assertEquals("[message text]", messageText, message.getText());
    assertEquals(
        "[position line]",
        4,
        message.getSourceFilePositions().get(0).getPosition().getStartLine() + 1);
    // assertEquals("[position column]", 35, message.getColumn());

    // TODO: Test encoding issues (e.g. & in path where the XML source comment would be &amp;
    // instead)
  }
 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<Message> messages = parser.parseToolOutput(err);
   assertHasCorrectErrorMessage(messages, messageText, 3, 21);
 }
 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<Message> messages = parser.parseToolOutput(err);
   assertHasCorrectErrorMessage(messages, messageText, 3, 17);
 }
 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<Message> messages = parser.parseToolOutput(err);
   assertHasCorrectErrorMessage(messages, messageText, 6, 20);
 }
 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<Message> messages = parser.parseToolOutput(err);
   assertHasCorrectErrorMessage(messages, messageText, 4, 61);
 }
 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<Message> messages = parser.parseToolOutput(err);
   assertHasCorrectErrorMessage(messages, messageText, 3, 5);
 }
 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<Message> messages = parser.parseToolOutput(err);
   assertHasCorrectErrorMessage(messages, messageText, 6, 17);
 }
 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<Message> messages = parser.parseToolOutput(err);
   assertHasCorrectErrorMessage(messages, messageText, 5, 8);
 }
  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 =
        ":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";

    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\n"
            + "13: Simple::BlankProject1:processDebugResources FAILED\n",
        toString(parser.parseToolOutput(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 =
        ":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";

    String expected =
        "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-30\n"
            + "8: Simple::BlankProject1:processDebugResources FAILED\n";
    String actual = toString(parser.parseToolOutput(output));

    assertEquals(expected, actual);
    sourceFile.delete();
    source.delete();
    dir.delete();
    tempDir.delete();
  }
  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 =
        ":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"; */

    String expected =
        "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-30\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";*/
    String actual = toString(parser.parseToolOutput(output));
    assertEquals(expected, actual);

    sourceFile.delete();
    source.delete();
    tempDir.delete();
  }
  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<Message> messages = parser.parseToolOutput(err);
    assertEquals(1, messages.size());

    assertEquals("[message count]", 1, messages.size());
    Message message = messages.iterator().next();

    assertNotNull(message);

    // NOT sourceFilePath; should be translated back from source comment
    assertEquals(
        new File("src/test/resources/testData/resources/baseSet/values/values.xml")
            .getAbsolutePath(),
        getSystemIndependentSourcePath(message));

    assertEquals("[message severity]", Message.Kind.ERROR, message.getKind());
    assertEquals("[message text]", messageText, message.getText());
    assertEquals(1, message.getSourceFilePositions().size());
    SourcePosition pos = message.getSourceFilePositions().get(0).getPosition();
    assertEquals("[position line]", 9, pos.getStartLine() + 1);
    assertEquals("[position column]", 35, pos.getStartColumn() + 1);
  }