Fix failing Windows tests

Some tests were not written to run on Windows correctly. Compile also
has a bug that caused using the --zip flag to fail on Windows.
iswspace does count the non breaking space as Whiespace on Windows but
not on Unix based systems

Bug: 117156986
Change-Id: I999375162bdfdf86fb25992ee88e2962ab90b577
Test: aapt2_tests and wine aapt2_tests.exe
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index c48765b..de00fca 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -38,6 +38,8 @@
 namespace aapt {
 namespace ResourceUtils {
 
+constexpr int32_t kNonBreakingSpace = 0xa0;
+
 Maybe<ResourceName> ToResourceName(
     const android::ResTable::resource_name& name_in) {
   ResourceName name_out;
@@ -810,7 +812,7 @@
   Utf8Iterator iter(text);
   while (iter.HasNext()) {
     char32_t codepoint = iter.Next();
-    if (!preserve_spaces && !quote_ && iswspace(codepoint)) {
+    if (!preserve_spaces && !quote_ && codepoint != kNonBreakingSpace && iswspace(codepoint)) {
       if (!last_codepoint_was_space_) {
         // Emit a space if it's the first.
         xml_string_.text += ' ';
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index 62c19fb..8060a8de 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -73,9 +73,9 @@
 };
 
 // Resource file paths are expected to look like: [--/res/]type[-config]/name
-static Maybe<ResourcePathData> ExtractResourcePathData(const std::string& path,
+static Maybe<ResourcePathData> ExtractResourcePathData(const std::string& path, const char dir_sep,
                                                        std::string* out_error) {
-  std::vector<std::string> parts = util::Split(path, file::sDirSep);
+  std::vector<std::string> parts = util::Split(path, dir_sep);
   if (parts.size() < 2) {
     if (out_error) *out_error = "bad resource path";
     return {};
@@ -656,7 +656,7 @@
     // Extract resource type information from the full path
     std::string err_str;
     ResourcePathData path_data;
-    if (auto maybe_path_data = ExtractResourcePathData(path, &err_str)) {
+    if (auto maybe_path_data = ExtractResourcePathData(path, inputs->GetDirSeparator(), &err_str)) {
       path_data = maybe_path_data.value();
     } else {
       context->GetDiagnostics()->Error(DiagMessage(file->GetSource()) << err_str);
@@ -731,7 +731,7 @@
   // Collect the resources files to compile
   if (options_.res_dir && options_.res_zip) {
     context.GetDiagnostics()->Error(DiagMessage()
-                                        << "only one of --dir and --zip can be specified");
+                                      << "only one of --dir and --zip can be specified");
     return 1;
   } else if (options_.res_dir) {
     if (!args.empty()) {
diff --git a/tools/aapt2/cmd/Compile_test.cpp b/tools/aapt2/cmd/Compile_test.cpp
index dd5198c..c0c05cd 100644
--- a/tools/aapt2/cmd/Compile_test.cpp
+++ b/tools/aapt2/cmd/Compile_test.cpp
@@ -17,6 +17,9 @@
 #include "Compile.h"
 
 #include "android-base/file.h"
+#include "android-base/stringprintf.h"
+#include "android-base/utf8.h"
+
 #include "io/StringStream.h"
 #include "io/ZipArchive.h"
 #include "java/AnnotationProcessor.h"
@@ -24,8 +27,20 @@
 
 namespace aapt {
 
+std::string BuildPath(std::vector<std::string> args) {
+  std::string out;
+  if (args.empty()) {
+    return out;
+  }
+  out = args[0];
+  for (int i = 1; i < args.size(); i++) {
+    file::AppendPath(&out, args[i]);
+  }
+  return out;
+}
+
 int TestCompile(const std::string& path, const std::string& outDir, bool legacy,
-    StdErrDiagnostics& diag) {
+                StdErrDiagnostics& diag) {
   std::vector<android::StringPiece> args;
   args.push_back(path);
   args.push_back("-o");
@@ -39,95 +54,101 @@
 TEST(CompilerTest, MultiplePeriods) {
   StdErrDiagnostics diag;
   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
-  const std::string kResDir = android::base::Dirname(android::base::GetExecutablePath())
-      + "/integration-tests/CompileTest/res";
+  const std::string kResDir = BuildPath({android::base::Dirname(android::base::GetExecutablePath()),
+                                         "integration-tests", "CompileTest", "res"});
 
   // Resource files without periods in the file name should not throw errors
-  const std::string path0 = kResDir + "/values/values.xml";
-  const std::string path0_out = kResDir + "/values_values.arsc.flat";
-
-  remove(path0_out.c_str());
+  const std::string path0 = BuildPath({kResDir, "values", "values.xml"});
+  const std::string path0_out = BuildPath({kResDir, "values_values.arsc.flat"});
+  ::android::base::utf8::unlink(path0_out.c_str());
   ASSERT_EQ(TestCompile(path0, kResDir, /** legacy */ false, diag), 0);
-  ASSERT_EQ(remove(path0_out.c_str()), 0);
+  ASSERT_EQ(::android::base::utf8::unlink(path0_out.c_str()), 0);
   ASSERT_EQ(TestCompile(path0, kResDir, /** legacy */ true, diag), 0);
-  ASSERT_EQ(remove(path0_out.c_str()), 0);
+  ASSERT_EQ(::android::base::utf8::unlink(path0_out.c_str()), 0);
 
-  const std::string path1 = kResDir + "/drawable/image.png";
-  const std::string path1_out = kResDir + "/drawable_image.png.flat";
-  remove(path1_out.c_str());
+  const std::string path1 = BuildPath({kResDir, "drawable", "image.png"});
+  const std::string path1_out = BuildPath({kResDir, "drawable_image.png.flat"});
+  ::android::base::utf8::unlink(path1_out.c_str());
   ASSERT_EQ(TestCompile(path1, kResDir, /** legacy */ false, diag), 0);
-  ASSERT_EQ(remove(path1_out.c_str()), 0);
+  ASSERT_EQ(::android::base::utf8::unlink(path1_out.c_str()), 0);
   ASSERT_EQ(TestCompile(path1, kResDir, /** legacy */ true, diag), 0);
-  ASSERT_EQ(remove(path1_out.c_str()), 0);
+  ASSERT_EQ(::android::base::utf8::unlink(path1_out.c_str()), 0);
 
-  const std::string path2 = kResDir + "/drawable/image.9.png";
-  const std::string path2_out = kResDir + "/drawable_image.9.png.flat";
-  remove(path2_out.c_str());
+  const std::string path2 = BuildPath({kResDir, "drawable", "image.9.png"});
+  const std::string path2_out = BuildPath({kResDir, "drawable_image.9.png.flat"});
+  ::android::base::utf8::unlink(path2_out.c_str());
   ASSERT_EQ(TestCompile(path2, kResDir, /** legacy */ false, diag), 0);
-  ASSERT_EQ(remove(path2_out.c_str()), 0);
+  ASSERT_EQ(::android::base::utf8::unlink(path2_out.c_str()), 0);
   ASSERT_EQ(TestCompile(path2, kResDir, /** legacy */ true, diag), 0);
-  ASSERT_EQ(remove(path2_out.c_str()), 0);
+  ASSERT_EQ(::android::base::utf8::unlink(path2_out.c_str()), 0);
 
   // Resource files with periods in the file name should fail on non-legacy compilations
-  const std::string path3 = kResDir + "/values/values.all.xml";
-  const std::string path3_out = kResDir + "/values_values.all.arsc.flat";
-  remove(path3_out.c_str());
+  const std::string path3 = BuildPath({kResDir, "values", "values.all.xml"});
+  const std::string path3_out = BuildPath({kResDir, "values_values.all.arsc.flat"});
+  ::android::base::utf8::unlink(path3_out.c_str());
   ASSERT_NE(TestCompile(path3, kResDir, /** legacy */ false, diag), 0);
-  ASSERT_NE(remove(path3_out.c_str()), 0);
+  ASSERT_NE(::android::base::utf8::unlink(path3_out.c_str()), 0);
   ASSERT_EQ(TestCompile(path3, kResDir, /** legacy */ true, diag), 0);
-  ASSERT_EQ(remove(path3_out.c_str()), 0);
+  ASSERT_EQ(::android::base::utf8::unlink(path3_out.c_str()), 0);
 
-  const std::string path4 = kResDir + "/drawable/image.small.png";
-  const std::string path4_out = (kResDir + std::string("/drawable_image.small.png.flat")).c_str();
-  remove(path4_out.c_str());
+  const std::string path4 = BuildPath({kResDir, "drawable", "image.small.png"});
+  const std::string path4_out = BuildPath({kResDir, "drawable_image.small.png.flat"});
+  ::android::base::utf8::unlink(path4_out.c_str());
   ASSERT_NE(TestCompile(path4, kResDir, /** legacy */ false, diag), 0);
-  ASSERT_NE(remove(path4_out.c_str()), 0);
+  ASSERT_NE(::android::base::utf8::unlink(path4_out.c_str()), 0);
   ASSERT_EQ(TestCompile(path4, kResDir, /** legacy */ true, diag), 0);
-  ASSERT_EQ(remove(path4_out.c_str()), 0);
+  ASSERT_EQ(::android::base::utf8::unlink(path4_out.c_str()), 0);
 
-  const std::string path5 = kResDir + "/drawable/image.small.9.png";
-  const std::string path5_out = (kResDir + std::string("/drawable_image.small.9.png.flat")).c_str();
-  remove(path5_out.c_str());
+  const std::string path5 = BuildPath({kResDir, "drawable", "image.small.9.png"});
+  const std::string path5_out = BuildPath({kResDir, "drawable_image.small.9.png.flat"});
+  ::android::base::utf8::unlink(path5_out.c_str());
   ASSERT_NE(TestCompile(path5, kResDir, /** legacy */ false, diag), 0);
-  ASSERT_NE(remove(path5_out.c_str()), 0);
+  ASSERT_NE(::android::base::utf8::unlink(path5_out.c_str()), 0);
   ASSERT_EQ(TestCompile(path5, kResDir, /** legacy */ true, diag), 0);
-  ASSERT_EQ(remove(path5_out.c_str()), 0);
+  ASSERT_EQ(::android::base::utf8::unlink(path5_out.c_str()), 0);
 }
 
 TEST(CompilerTest, DirInput) {
   StdErrDiagnostics diag;
   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
-  const std::string kResDir = android::base::Dirname(android::base::GetExecutablePath())
-                            + "/integration-tests/CompileTest/DirInput/res";
-  const std::string kOutputFlata = android::base::Dirname(android::base::GetExecutablePath())
-                                 + "/integration-tests/CompileTest/DirInput/compiled.flata";
-  remove(kOutputFlata.c_str());
+  const std::string kResDir = BuildPath({android::base::Dirname(android::base::GetExecutablePath()),
+                                         "integration-tests", "CompileTest", "DirInput", "res"});
+  const std::string kOutputFlata =
+      BuildPath({android::base::Dirname(android::base::GetExecutablePath()), "integration-tests",
+                 "CompileTest", "DirInput", "compiled.flata"});
+  ::android::base::utf8::unlink(kOutputFlata.c_str());
 
   std::vector<android::StringPiece> args;
   args.push_back("--dir");
   args.push_back(kResDir);
   args.push_back("-o");
   args.push_back(kOutputFlata);
+  args.push_back("-v");
   ASSERT_EQ(CompileCommand(&diag).Execute(args, &std::cerr), 0);
 
-  // Check for the presence of the compiled files
-  std::string err;
-  std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(kOutputFlata, &err);
-  ASSERT_NE(zip, nullptr) << err;
-  ASSERT_NE(zip->FindFile("drawable_image.png.flat"), nullptr);
-  ASSERT_NE(zip->FindFile("layout_layout.xml.flat"), nullptr);
-  ASSERT_NE(zip->FindFile("values_values.arsc.flat"), nullptr);
-  ASSERT_EQ(remove(kOutputFlata.c_str()), 0);
+  {
+    // Check for the presence of the compiled files
+    std::string err;
+    std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(kOutputFlata, &err);
+    ASSERT_NE(zip, nullptr) << err;
+    ASSERT_NE(zip->FindFile("drawable_image.png.flat"), nullptr);
+    ASSERT_NE(zip->FindFile("layout_layout.xml.flat"), nullptr);
+    ASSERT_NE(zip->FindFile("values_values.arsc.flat"), nullptr);
+  }
+  ASSERT_EQ(::android::base::utf8::unlink(kOutputFlata.c_str()), 0);
 }
 
 TEST(CompilerTest, ZipInput) {
   StdErrDiagnostics diag;
   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
-  const std::string kResZip = android::base::Dirname(android::base::GetExecutablePath())
-                            + "/integration-tests/CompileTest/ZipInput/res.zip";
-  const std::string kOutputFlata = android::base::Dirname(android::base::GetExecutablePath())
-                                 + "/integration-tests/CompileTest/ZipInput/compiled.flata";
-  remove(kOutputFlata.c_str());
+  const std::string kResZip =
+      BuildPath({android::base::Dirname(android::base::GetExecutablePath()), "integration-tests",
+                 "CompileTest", "ZipInput", "res.zip"});
+  const std::string kOutputFlata =
+      BuildPath({android::base::Dirname(android::base::GetExecutablePath()), "integration-tests",
+                 "CompileTest", "ZipInput", "compiled.flata"});
+
+  ::android::base::utf8::unlink(kOutputFlata.c_str());
 
   std::vector<android::StringPiece> args;
   args.push_back("--zip");
@@ -136,14 +157,16 @@
   args.push_back(kOutputFlata);
   ASSERT_EQ(CompileCommand(&diag).Execute(args, &std::cerr), 0);
 
-  // Check for the presence of the compiled files
-  std::string err;
-  std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(kOutputFlata, &err);
-  ASSERT_NE(zip, nullptr) << err;
-  ASSERT_NE(zip->FindFile("drawable_image.png.flat"), nullptr);
-  ASSERT_NE(zip->FindFile("layout_layout.xml.flat"), nullptr);
-  ASSERT_NE(zip->FindFile("values_values.arsc.flat"), nullptr);
-  ASSERT_EQ(remove(kOutputFlata.c_str()), 0);
+  {
+    // Check for the presence of the compiled files
+    std::string err;
+    std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(kOutputFlata, &err);
+    ASSERT_NE(zip, nullptr) << err;
+    ASSERT_NE(zip->FindFile("drawable_image.png.flat"), nullptr);
+    ASSERT_NE(zip->FindFile("layout_layout.xml.flat"), nullptr);
+    ASSERT_NE(zip->FindFile("values_values.arsc.flat"), nullptr);
+  }
+  ASSERT_EQ(::android::base::utf8::unlink(kOutputFlata.c_str()), 0);
 }
 
-} // namespace aapt
\ No newline at end of file
+}  // namespace aapt
\ No newline at end of file
diff --git a/tools/aapt2/cmd/Util_test.cpp b/tools/aapt2/cmd/Util_test.cpp
index 158ef29..6aeff08 100644
--- a/tools/aapt2/cmd/Util_test.cpp
+++ b/tools/aapt2/cmd/Util_test.cpp
@@ -16,12 +16,22 @@
 
 #include "Util.h"
 
+#include "android-base/stringprintf.h"
+
 #include "AppInfo.h"
 #include "split/TableSplitter.h"
 #include "test/Builders.h"
 #include "test/Test.h"
+#include "util/Files.h"
 
 namespace aapt {
+
+#ifdef _WIN32
+#define CREATE_PATH(path) android::base::StringPrintf(";%s", path)
+#else
+#define CREATE_PATH(path) android::base::StringPrintf(":%s", path)
+#endif
+
 #define EXPECT_CONFIG_EQ(constraints, config) \
     EXPECT_EQ(constraints.configs.size(), 1); \
     EXPECT_EQ(*constraints.configs.begin(), config); \
@@ -89,7 +99,7 @@
 }
 
 
-TEST (UtilTest, ParseSplitParameter) {
+TEST (UtilTest, ParseSplitParameters) {
   IDiagnostics* diagnostics = test::ContextBuilder().Build().get()->GetDiagnostics();
   std::string path;
   SplitConstraints constraints;
@@ -98,14 +108,14 @@
   // ========== Test IMSI ==========
   // mcc: 'mcc[0-9]{3}'
   // mnc: 'mnc[0-9]{1,3}'
-  ASSERT_TRUE(ParseSplitParameter(":mcc310",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("mcc310"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setMcc(0x0136)
       .Build();
   EXPECT_CONFIG_EQ(constraints, expected_configuration);
 
-  ASSERT_TRUE(ParseSplitParameter(":mcc310-mnc004",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("mcc310-mnc004"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setMcc(0x0136)
@@ -113,7 +123,7 @@
       .Build();
   EXPECT_CONFIG_EQ(constraints, expected_configuration);
 
-  ASSERT_TRUE(ParseSplitParameter(":mcc310-mnc000",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("mcc310-mnc000"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setMcc(0x0136)
@@ -124,14 +134,14 @@
   // ========== Test LOCALE ==========
   // locale: '[a-z]{2,3}(-r[a-z]{2})?'
   // locale: 'b+[a-z]{2,3}(+[a-z[0-9]]{2})?'
-  ASSERT_TRUE(ParseSplitParameter(":es",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("es"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setLanguage(0x6573)
       .Build();
   EXPECT_CONFIG_EQ(constraints, expected_configuration);
 
-  ASSERT_TRUE(ParseSplitParameter(":fr-rCA",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("fr-rCA"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setLanguage(0x6672)
@@ -139,7 +149,7 @@
       .Build();
   EXPECT_CONFIG_EQ(constraints, expected_configuration);
 
-  ASSERT_TRUE(ParseSplitParameter(":b+es+419",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("b+es+419"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setLanguage(0x6573)
@@ -151,21 +161,21 @@
   // orientation: '(port|land|square)'
   // touchscreen: '(notouch|stylus|finger)'
   // density" '(anydpi|nodpi|ldpi|mdpi|tvdpi|hdpi|xhdpi|xxhdpi|xxxhdpi|[0-9]*dpi)'
-  ASSERT_TRUE(ParseSplitParameter(":square",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("square"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setOrientation(0x03)
       .Build();
   EXPECT_CONFIG_EQ(constraints, expected_configuration);
 
-  ASSERT_TRUE(ParseSplitParameter(":stylus",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("stylus"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setTouchscreen(0x02)
       .Build();
   EXPECT_CONFIG_EQ(constraints, expected_configuration);
 
-  ASSERT_TRUE(ParseSplitParameter(":xxxhdpi",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("xxxhdpi"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setDensity(0x0280)
@@ -173,7 +183,7 @@
       .Build();
   EXPECT_CONFIG_EQ(constraints, expected_configuration);
 
-  ASSERT_TRUE(ParseSplitParameter(":land-xhdpi-finger",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("land-xhdpi-finger"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setOrientation(0x02)
@@ -188,28 +198,28 @@
   // navigation: '(nonav|dpad|trackball|wheel)'
   // inputFlags: '(keysexposed|keyshidden|keyssoft)'
   // inputFlags: '(navexposed|navhidden)'
-  ASSERT_TRUE(ParseSplitParameter(":qwerty",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("qwerty"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setKeyboard(0x02)
       .Build();
   EXPECT_CONFIG_EQ(constraints, expected_configuration);
 
-  ASSERT_TRUE(ParseSplitParameter(":dpad",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("dpad"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setNavigation(0x02)
       .Build();
   EXPECT_CONFIG_EQ(constraints, expected_configuration);
 
-  ASSERT_TRUE(ParseSplitParameter(":keyssoft-navhidden",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("keyssoft-navhidden"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setInputFlags(0x0B)
       .Build();
   EXPECT_CONFIG_EQ(constraints, expected_configuration);
 
-  ASSERT_TRUE(ParseSplitParameter(":keyshidden-nokeys-navexposed-trackball",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("keyshidden-nokeys-navexposed-trackball"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setKeyboard(0x01)
@@ -220,7 +230,7 @@
 
   // ========== Test SCREEN_SIZE ==========
   // screenWidth/screenHeight: '[0-9]+x[0-9]+'
-  ASSERT_TRUE(ParseSplitParameter(":1920x1080",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("1920x1080"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setScreenWidth(0x0780)
@@ -238,14 +248,14 @@
   // uiMode [type]: '(desk|car|television|appliance|watch|vrheadset)'
   // uiMode [night]: '(night|notnight)'
   // smallestScreenWidthDp: 'sw[0-9]dp'
-  ASSERT_TRUE(ParseSplitParameter(":ldrtl",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("ldrtl"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setScreenLayout(0x80)
       .Build();
   EXPECT_CONFIG_EQ(constraints, expected_configuration);
 
-  ASSERT_TRUE(ParseSplitParameter(":small",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("small"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setScreenLayout(0x01)
@@ -253,7 +263,7 @@
       .Build();
   EXPECT_CONFIG_EQ(constraints, expected_configuration);
 
-  ASSERT_TRUE(ParseSplitParameter(":notlong",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("notlong"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setScreenLayout(0x10)
@@ -261,15 +271,15 @@
       .Build();
   EXPECT_CONFIG_EQ(constraints, expected_configuration);
 
-  ASSERT_TRUE(ParseSplitParameter(":ldltr-normal-long",
-                                  diagnostics, &path, &constraints));
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("ldltr-normal-long"),
+                                      diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setScreenLayout(0x62)
       .setSdkVersion(0x0004) // screenLayout (size|long) requires donut
       .Build();
   EXPECT_CONFIG_EQ(constraints, expected_configuration);
 
-  ASSERT_TRUE(ParseSplitParameter(":car",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("car"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setUiMode(0x03)
@@ -277,7 +287,7 @@
       .Build();
   EXPECT_CONFIG_EQ(constraints, expected_configuration);
 
-  ASSERT_TRUE(ParseSplitParameter(":vrheadset",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("vrheadset"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setUiMode(0x07)
@@ -285,7 +295,7 @@
       .Build();
   EXPECT_CONFIG_EQ(constraints, expected_configuration);
 
-  ASSERT_TRUE(ParseSplitParameter(":television-night",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("television-night"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setUiMode(0x24)
@@ -293,7 +303,7 @@
       .Build();
   EXPECT_CONFIG_EQ(constraints, expected_configuration);
 
-  ASSERT_TRUE(ParseSplitParameter(":sw1920dp",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("sw1920dp"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setSmallestScreenWidthDp(0x0780)
@@ -304,7 +314,7 @@
   // ========== Test SCREEN_SIZE_DP ==========
   // screenWidthDp: 'w[0-9]dp'
   // screenHeightDp: 'h[0-9]dp'
-  ASSERT_TRUE(ParseSplitParameter(":w1920dp",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("w1920dp"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setScreenWidthDp(0x0780)
@@ -312,7 +322,7 @@
       .Build();
   EXPECT_CONFIG_EQ(constraints, expected_configuration);
 
-  ASSERT_TRUE(ParseSplitParameter(":h1080dp",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("h1080dp"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setScreenHeightDp(0x0438)
@@ -324,7 +334,7 @@
   // screenLayout2: '(round|notround)'
   // colorMode: '(widecg|nowidecg)'
   // colorMode: '(highhdr|lowdr)'
-  ASSERT_TRUE(ParseSplitParameter(":round",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("round"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setScreenLayout2(0x02)
@@ -332,7 +342,7 @@
       .Build();
   EXPECT_CONFIG_EQ(constraints, expected_configuration);
 
-  ASSERT_TRUE(ParseSplitParameter(":widecg-highdr",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("widecg-highdr"),
                                   diagnostics, &path, &constraints));
   expected_configuration = test::ConfigDescriptionBuilder()
       .setColorMode(0x0A)
@@ -349,10 +359,10 @@
   std::string path;
 
   test_constraints.push_back({});
-  ASSERT_TRUE(ParseSplitParameter(":v7",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("v7"),
                                   diagnostics, &path, &test_constraints.back()));
   test_constraints.push_back({});
-  ASSERT_TRUE(ParseSplitParameter(":xhdpi",
+  ASSERT_TRUE(ParseSplitParameter(CREATE_PATH("xhdpi"),
                                   diagnostics, &path, &test_constraints.back()));
   EXPECT_EQ(test_constraints.size(), 2);
   EXPECT_EQ(test_constraints[0].name, "v7");
diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
index 21fdbd8..74295ab 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -33,6 +33,7 @@
  public:
   MOCK_METHOD1(FindFile, io::IFile*(const StringPiece& path));
   MOCK_METHOD0(Iterator, std::unique_ptr<io::IFileCollectionIterator>());
+  MOCK_METHOD0(GetDirSeparator, char());
 };
 
 TEST(ProtoSerializeTest, SerializeSinglePackage) {
diff --git a/tools/aapt2/io/File.h b/tools/aapt2/io/File.h
index f06e28c..565aad6 100644
--- a/tools/aapt2/io/File.h
+++ b/tools/aapt2/io/File.h
@@ -25,6 +25,7 @@
 
 #include "Source.h"
 #include "io/Data.h"
+#include "util/Files.h"
 #include "util/Util.h"
 
 namespace aapt {
@@ -103,6 +104,7 @@
 
   virtual IFile* FindFile(const android::StringPiece& path) = 0;
   virtual std::unique_ptr<IFileCollectionIterator> Iterator() = 0;
+  virtual char GetDirSeparator() = 0;
 };
 
 }  // namespace io
diff --git a/tools/aapt2/io/FileSystem.cpp b/tools/aapt2/io/FileSystem.cpp
index 16a20f4c..51cc903 100644
--- a/tools/aapt2/io/FileSystem.cpp
+++ b/tools/aapt2/io/FileSystem.cpp
@@ -128,5 +128,9 @@
   return util::make_unique<FileCollectionIterator>(this);
 }
 
+char FileCollection::GetDirSeparator() {
+  return file::sDirSep;
+}
+
 }  // namespace io
 }  // namespace aapt
diff --git a/tools/aapt2/io/FileSystem.h b/tools/aapt2/io/FileSystem.h
index fb6bf6e..04c6fa1 100644
--- a/tools/aapt2/io/FileSystem.h
+++ b/tools/aapt2/io/FileSystem.h
@@ -67,6 +67,7 @@
   IFile* InsertFile(const android::StringPiece& path);
   IFile* FindFile(const android::StringPiece& path) override;
   std::unique_ptr<IFileCollectionIterator> Iterator() override;
+  char GetDirSeparator() override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(FileCollection);
diff --git a/tools/aapt2/io/ZipArchive.cpp b/tools/aapt2/io/ZipArchive.cpp
index 8e6d713..7d0f6b9 100644
--- a/tools/aapt2/io/ZipArchive.cpp
+++ b/tools/aapt2/io/ZipArchive.cpp
@@ -154,6 +154,13 @@
   return util::make_unique<ZipFileCollectionIterator>(this);
 }
 
+char ZipFileCollection::GetDirSeparator() {
+  // According to the zip file specification, section  4.4.17.1:
+  // "All slashes MUST be forward slashes '/' as opposed to backwards slashes '\' for compatibility
+  // with Amiga and UNIX file systems etc."
+  return '/';
+}
+
 ZipFileCollection::~ZipFileCollection() {
   if (handle_) {
     CloseArchive(handle_);
diff --git a/tools/aapt2/io/ZipArchive.h b/tools/aapt2/io/ZipArchive.h
index 8381259..b283e57 100644
--- a/tools/aapt2/io/ZipArchive.h
+++ b/tools/aapt2/io/ZipArchive.h
@@ -66,6 +66,7 @@
 
   io::IFile* FindFile(const android::StringPiece& path) override;
   std::unique_ptr<IFileCollectionIterator> Iterator() override;
+  char GetDirSeparator() override;
 
   ~ZipFileCollection() override;
 
diff --git a/tools/aapt2/util/Files_test.cpp b/tools/aapt2/util/Files_test.cpp
index 219c183..202cc26 100644
--- a/tools/aapt2/util/Files_test.cpp
+++ b/tools/aapt2/util/Files_test.cpp
@@ -18,11 +18,21 @@
 
 #include <sstream>
 
+#include "android-base/stringprintf.h"
+
 #include "test/Test.h"
 
+using ::android::base::StringPrintf;
+
 namespace aapt {
 namespace file {
 
+#ifdef _WIN32
+constexpr const char sTestDirSep = '\\';
+#else
+constexpr const char sTestDirSep = '/';
+#endif
+
 class FilesTest : public ::testing::Test {
  public:
   void SetUp() override {
@@ -42,16 +52,16 @@
 }
 
 TEST_F(FilesTest, AppendPathWithLeadingOrTrailingSeparators) {
-  std::string base = "hello/";
+  std::string base = StringPrintf("hello%c", sTestDirSep);
   AppendPath(&base, "there");
   EXPECT_EQ(expected_path_, base);
 
   base = "hello";
-  AppendPath(&base, "/there");
+  AppendPath(&base, StringPrintf("%cthere", sTestDirSep));
   EXPECT_EQ(expected_path_, base);
 
-  base = "hello/";
-  AppendPath(&base, "/there");
+  base = StringPrintf("hello%c", sTestDirSep);
+  AppendPath(&base, StringPrintf("%cthere", sTestDirSep));
   EXPECT_EQ(expected_path_, base);
 }