[aapt2] Improve dump chunks for string pools, fix diff

- `dump chunks` command now prints extra header data for the
  string pool, and outputs all style information for styled
  strings.

- `diff` command used to only correctly compare the first span
  in the StyledString data type, making them appear different
  if there was a string with more than one span

Flag: EXEMPT bugfix
Test: atest aapt2_tests
Change-Id: I377718c03d6a464cb4db22399b0f067e6a6e04d6
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 6a17ef8..df1d51e 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -763,10 +763,35 @@
     pool->setTo(chunk, android::util::DeviceToHost32(
                            (reinterpret_cast<const ResChunk_header*>(chunk))->size));
 
-    printer_->Print("\n");
+    printer_->Print(StringPrintf(" strings: %zd styles %zd flags: %s|%s\n", pool->size(),
+                                 pool->styleCount(), pool->isUTF8() ? "UTF-8" : "UTF-16",
+                                 pool->isSorted() ? "SORTED" : "NON-SORTED"));
 
     for (size_t i = 0; i < pool->size(); i++) {
       printer_->Print(StringPrintf("#%zd : %s\n", i, android::util::GetString(*pool, i).c_str()));
+      if (i < pool->styleCount()) {
+        printer_->Print(" [Style] ");
+        auto maybe_style = pool->styleAt(i);
+        if (!maybe_style) {
+          printer_->Print("??? missing\n");
+        } else {
+          std::vector<const ResStringPool_span*> spans;
+          for (auto style = maybe_style.value().unsafe_ptr();
+               style->name.index != android::ResStringPool_span::END; ++style) {
+            spans.push_back(style);
+          }
+          printer_->Print(StringPrintf("(%zd)", spans.size()));
+          if (!spans.empty()) {
+            printer_->Print(" :");
+            for (const auto& span : spans) {
+              printer_->Print(StringPrintf(
+                  " %s:%u,%u", android::util::GetString(*pool, span->name.index).c_str(),
+                  span->firstChar, span->lastChar));
+            }
+            printer_->Print("\n");
+          }
+        }
+      }
     }
   }
 
diff --git a/tools/aapt2/ResourceValues_test.cpp b/tools/aapt2/ResourceValues_test.cpp
index d788e3f..b30348d 100644
--- a/tools/aapt2/ResourceValues_test.cpp
+++ b/tools/aapt2/ResourceValues_test.cpp
@@ -184,6 +184,35 @@
   EXPECT_THAT(pool_b.strings()[0]->value, StrEq("hello"));
 }
 
+TEST(ResourcesValuesTest, StringEquals) {
+  android::StringPool pool;
+
+  String str(pool.MakeRef("hello", android::StringPool::Context(test::ParseConfigOrDie("en"))));
+  String str2(pool.MakeRef("hello"));
+  EXPECT_TRUE(str.Equals(&str2));
+  EXPECT_TRUE(str2.Equals(&str));
+
+  String str3(pool.MakeRef("how are you"));
+  EXPECT_FALSE(str.Equals(&str3));
+}
+
+TEST(ResourcesValuesTest, StyledStringEquals) {
+  android::StringPool pool;
+
+  StyledString ss(pool.MakeRef(android::StyleString{"hello", {{"b", 0, 1}, {"u", 2, 4}}}));
+  StyledString ss2(pool.MakeRef(android::StyleString{"hello", {{"b", 0, 1}, {"u", 2, 4}}}));
+  StyledString ss3(pool.MakeRef(android::StyleString{"hi", {{"b", 0, 1}, {"u", 2, 4}}}));
+  StyledString ss4(pool.MakeRef(android::StyleString{"hello", {{"b", 0, 1}}}));
+  StyledString ss5(pool.MakeRef(android::StyleString{"hello", {{"b", 0, 1}, {"u", 3, 4}}}));
+  StyledString ss6(pool.MakeRef(android::StyleString{"hello", {{"b", 0, 1}, {"s", 2, 4}}}));
+  EXPECT_TRUE(ss.Equals(&ss2));
+  EXPECT_TRUE(ss2.Equals(&ss));
+  EXPECT_FALSE(ss.Equals(&ss3));
+  EXPECT_FALSE(ss.Equals(&ss4));
+  EXPECT_FALSE(ss.Equals(&ss5));
+  EXPECT_FALSE(ss.Equals(&ss6));
+}
+
 TEST(ResourceValuesTest, StyleMerges) {
   android::StringPool pool_a;
   android::StringPool pool_b;
diff --git a/tools/aapt2/cmd/Diff.cpp b/tools/aapt2/cmd/Diff.cpp
index 5bfc732..6da3176 100644
--- a/tools/aapt2/cmd/Diff.cpp
+++ b/tools/aapt2/cmd/Diff.cpp
@@ -106,7 +106,7 @@
   if (!value_a->Equals(value_b)) {
     std::stringstream str_stream;
     str_stream << "value " << pkg_a.name << ":" << type_a.named_type << "/" << entry_a.name
-               << " config=" << config_value_a->config << " does not match:\n";
+               << " config='" << config_value_a->config << "' does not match:\n";
     value_a->Print(&str_stream);
     str_stream << "\n vs \n";
     value_b->Print(&str_stream);
diff --git a/tools/aapt2/test/Fixture.h b/tools/aapt2/test/Fixture.h
index ba4a734..14298d16 100644
--- a/tools/aapt2/test/Fixture.h
+++ b/tools/aapt2/test/Fixture.h
@@ -127,4 +127,4 @@
 
 } // namespace aapt
 
-#endif  // AAPT_TEST_FIXTURE_H
\ No newline at end of file
+#endif  // AAPT_TEST_FIXTURE_H