diff --git a/libs/androidfw/include/androidfw/StringPiece.h b/libs/androidfw/include/androidfw/StringPiece.h index a873d66803e75..99b424568a1f5 100644 --- a/libs/androidfw/include/androidfw/StringPiece.h +++ b/libs/androidfw/include/androidfw/StringPiece.h @@ -37,6 +37,7 @@ class BasicStringPiece { public: using const_iterator = const TChar*; using difference_type = size_t; + using size_type = size_t; // End of string marker. constexpr static const size_t npos = static_cast(-1); diff --git a/tools/aapt2/flatten/XmlFlattener.cpp b/tools/aapt2/flatten/XmlFlattener.cpp index 0711749d03789..bfebedef2a1eb 100644 --- a/tools/aapt2/flatten/XmlFlattener.cpp +++ b/tools/aapt2/flatten/XmlFlattener.cpp @@ -257,9 +257,11 @@ class XmlFlattenerVisitor : public xml::Visitor { // Process plain strings to make sure they get properly escaped. StringPiece raw_value = xml_attr->value; - util::StringBuilder str_builder; + + util::StringBuilder str_builder(true /*preserve_spaces*/); + str_builder.Append(xml_attr->value); + if (!options_.keep_raw_values) { - str_builder.Append(xml_attr->value); raw_value = str_builder.ToString(); } diff --git a/tools/aapt2/flatten/XmlFlattener_test.cpp b/tools/aapt2/flatten/XmlFlattener_test.cpp index f1e903f2151ec..a57e3178accda 100644 --- a/tools/aapt2/flatten/XmlFlattener_test.cpp +++ b/tools/aapt2/flatten/XmlFlattener_test.cpp @@ -23,7 +23,13 @@ #include "util/BigBuffer.h" #include "util/Util.h" -using android::StringPiece16; +using ::aapt::test::StrEq; +using ::android::StringPiece16; +using ::testing::Eq; +using ::testing::Ge; +using ::testing::IsNull; +using ::testing::Ne; +using ::testing::NotNull; namespace aapt { @@ -72,163 +78,138 @@ class XmlFlattenerTest : public ::testing::Test { }; TEST_F(XmlFlattenerTest, FlattenXmlWithNoCompiledAttributes) { - std::unique_ptr doc = test::BuildXmlDom(R"EOF( - - - Some text\\ - )EOF"); + std::unique_ptr doc = test::BuildXmlDom(R"( + + + Some text\\ + )"); android::ResXMLTree tree; ASSERT_TRUE(Flatten(doc.get(), &tree)); - - ASSERT_EQ(android::ResXMLTree::START_NAMESPACE, tree.next()); + ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_NAMESPACE)); size_t len; - const char16_t* namespace_prefix = tree.getNamespacePrefix(&len); - EXPECT_EQ(StringPiece16(u"test"), StringPiece16(namespace_prefix, len)); + EXPECT_THAT(tree.getNamespacePrefix(&len), StrEq(u"test")); + EXPECT_THAT(tree.getNamespaceUri(&len), StrEq(u"http://com.test")); - const char16_t* namespace_uri = tree.getNamespaceUri(&len); - ASSERT_EQ(StringPiece16(u"http://com.test"), StringPiece16(namespace_uri, len)); + ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); + EXPECT_THAT(tree.getElementNamespace(&len), IsNull()); + EXPECT_THAT(tree.getElementName(&len), StrEq(u"View")); - ASSERT_EQ(android::ResXMLTree::START_TAG, tree.next()); + ASSERT_THAT(tree.getAttributeCount(), Eq(1u)); + EXPECT_THAT(tree.getAttributeNamespace(0, &len), IsNull()); + EXPECT_THAT(tree.getAttributeName(0, &len), StrEq(u"attr")); - ASSERT_EQ(nullptr, tree.getElementNamespace(&len)); - const char16_t* tag_name = tree.getElementName(&len); - EXPECT_EQ(StringPiece16(u"View"), StringPiece16(tag_name, len)); + const StringPiece16 kAttr(u"attr"); + EXPECT_THAT(tree.indexOfAttribute(nullptr, 0, kAttr.data(), kAttr.size()), Eq(0)); - ASSERT_EQ(1u, tree.getAttributeCount()); - ASSERT_EQ(nullptr, tree.getAttributeNamespace(0, &len)); - const char16_t* attr_name = tree.getAttributeName(0, &len); - EXPECT_EQ(StringPiece16(u"attr"), StringPiece16(attr_name, len)); + ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); + EXPECT_THAT(tree.getElementNamespace(&len), IsNull()); + EXPECT_THAT(tree.getElementName(&len), StrEq(u"Layout")); - EXPECT_EQ(0, tree.indexOfAttribute(nullptr, 0, u"attr", StringPiece16(u"attr").size())); + ASSERT_THAT(tree.getAttributeCount(), Eq(1u)); + EXPECT_THAT(tree.getAttributeNamespace(0, &len), StrEq(u"http://com.test")); + EXPECT_THAT(tree.getAttributeName(0, &len), StrEq(u"hello")); - ASSERT_EQ(android::ResXMLTree::START_TAG, tree.next()); + ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); + ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); - ASSERT_EQ(nullptr, tree.getElementNamespace(&len)); - tag_name = tree.getElementName(&len); - EXPECT_EQ(StringPiece16(u"Layout"), StringPiece16(tag_name, len)); + EXPECT_THAT(tree.getElementNamespace(&len), IsNull()); + EXPECT_THAT(tree.getElementName(&len), StrEq(u"Layout")); + ASSERT_THAT(tree.getAttributeCount(), Eq(0u)); - ASSERT_EQ(1u, tree.getAttributeCount()); - const char16_t* attr_namespace = tree.getAttributeNamespace(0, &len); - EXPECT_EQ(StringPiece16(u"http://com.test"), StringPiece16(attr_namespace, len)); + ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); + EXPECT_THAT(tree.getText(&len), StrEq(u"Some text\\")); - attr_name = tree.getAttributeName(0, &len); - EXPECT_EQ(StringPiece16(u"hello"), StringPiece16(attr_name, len)); + ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); + EXPECT_THAT(tree.getElementNamespace(&len), IsNull()); + EXPECT_THAT(tree.getElementName(&len), StrEq(u"Layout")); - ASSERT_EQ(android::ResXMLTree::END_TAG, tree.next()); - ASSERT_EQ(android::ResXMLTree::START_TAG, tree.next()); + ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); + EXPECT_THAT(tree.getElementNamespace(&len), IsNull()); + EXPECT_THAT(tree.getElementName(&len), StrEq(u"View")); - ASSERT_EQ(nullptr, tree.getElementNamespace(&len)); - tag_name = tree.getElementName(&len); - EXPECT_EQ(StringPiece16(u"Layout"), StringPiece16(tag_name, len)); - ASSERT_EQ(0u, tree.getAttributeCount()); + ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_NAMESPACE)); + EXPECT_THAT(tree.getNamespacePrefix(&len), StrEq(u"test")); + EXPECT_THAT(tree.getNamespaceUri(&len), StrEq(u"http://com.test")); - ASSERT_EQ(android::ResXMLTree::TEXT, tree.next()); - const char16_t* text = tree.getText(&len); - EXPECT_EQ(StringPiece16(u"Some text\\"), StringPiece16(text, len)); - - ASSERT_EQ(android::ResXMLTree::END_TAG, tree.next()); - ASSERT_EQ(nullptr, tree.getElementNamespace(&len)); - tag_name = tree.getElementName(&len); - EXPECT_EQ(StringPiece16(u"Layout"), StringPiece16(tag_name, len)); - - ASSERT_EQ(android::ResXMLTree::END_TAG, tree.next()); - ASSERT_EQ(nullptr, tree.getElementNamespace(&len)); - tag_name = tree.getElementName(&len); - EXPECT_EQ(StringPiece16(u"View"), StringPiece16(tag_name, len)); - - ASSERT_EQ(android::ResXMLTree::END_NAMESPACE, tree.next()); - namespace_prefix = tree.getNamespacePrefix(&len); - EXPECT_EQ(StringPiece16(u"test"), StringPiece16(namespace_prefix, len)); - - namespace_uri = tree.getNamespaceUri(&len); - ASSERT_EQ(StringPiece16(u"http://com.test"), StringPiece16(namespace_uri, len)); - - ASSERT_EQ(android::ResXMLTree::END_DOCUMENT, tree.next()); + ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_DOCUMENT)); } TEST_F(XmlFlattenerTest, FlattenCompiledXmlAndStripOnlyTools) { - std::unique_ptr doc = test::BuildXmlDom(R"EOF( - )EOF"); + std::unique_ptr doc = test::BuildXmlDom(R"( + )"); android::ResXMLTree tree; ASSERT_TRUE(Flatten(doc.get(), &tree)); - - ASSERT_EQ(tree.next(), android::ResXMLTree::START_NAMESPACE); + ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_NAMESPACE)); size_t len; - const char16_t* namespace_prefix = tree.getNamespacePrefix(&len); - EXPECT_EQ(StringPiece16(namespace_prefix, len), u"foo"); + EXPECT_THAT(tree.getNamespacePrefix(&len), StrEq(u"foo")); + EXPECT_THAT(tree.getNamespaceUri(&len), StrEq(u"http://schemas.android.com/foo")); + ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); - const char16_t* namespace_uri = tree.getNamespaceUri(&len); - ASSERT_EQ(StringPiece16(namespace_uri, len), - u"http://schemas.android.com/foo"); - - ASSERT_EQ(tree.next(), android::ResXMLTree::START_TAG); - - EXPECT_EQ(tree.indexOfAttribute("http://schemas.android.com/tools", "ignore"), - android::NAME_NOT_FOUND); - EXPECT_GE(tree.indexOfAttribute("http://schemas.android.com/foo", "bar"), 0); + EXPECT_THAT(tree.indexOfAttribute("http://schemas.android.com/tools", "ignore"), + Eq(android::NAME_NOT_FOUND)); + EXPECT_THAT(tree.indexOfAttribute("http://schemas.android.com/foo", "bar"), Ge(0)); } TEST_F(XmlFlattenerTest, AssignSpecialAttributeIndices) { - std::unique_ptr doc = test::BuildXmlDom(R"EOF( - )EOF"); + std::unique_ptr doc = test::BuildXmlDom(R"( + )"); android::ResXMLTree tree; ASSERT_TRUE(Flatten(doc.get(), &tree)); while (tree.next() != android::ResXMLTree::START_TAG) { - ASSERT_NE(tree.getEventType(), android::ResXMLTree::BAD_DOCUMENT); - ASSERT_NE(tree.getEventType(), android::ResXMLTree::END_DOCUMENT); + ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); + ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); } - EXPECT_EQ(tree.indexOfClass(), 0); - EXPECT_EQ(tree.indexOfStyle(), 1); + EXPECT_THAT(tree.indexOfClass(), Eq(0)); + EXPECT_THAT(tree.indexOfStyle(), Eq(1)); } // The device ResXMLParser in libandroidfw differentiates between empty namespace and null // namespace. TEST_F(XmlFlattenerTest, NoNamespaceIsNotTheSameAsEmptyNamespace) { - std::unique_ptr doc = test::BuildXmlDom(""); + std::unique_ptr doc = test::BuildXmlDom(R"()"); android::ResXMLTree tree; ASSERT_TRUE(Flatten(doc.get(), &tree)); while (tree.next() != android::ResXMLTree::START_TAG) { - ASSERT_NE(tree.getEventType(), android::ResXMLTree::BAD_DOCUMENT); - ASSERT_NE(tree.getEventType(), android::ResXMLTree::END_DOCUMENT); + ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); + ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); } const StringPiece16 kPackage = u"package"; - EXPECT_GE(tree.indexOfAttribute(nullptr, 0, kPackage.data(), kPackage.size()), 0); + EXPECT_THAT(tree.indexOfAttribute(nullptr, 0, kPackage.data(), kPackage.size()), Ge(0)); } TEST_F(XmlFlattenerTest, EmptyStringValueInAttributeIsNotNull) { - std::unique_ptr doc = test::BuildXmlDom(""); + std::unique_ptr doc = test::BuildXmlDom(R"()"); android::ResXMLTree tree; ASSERT_TRUE(Flatten(doc.get(), &tree)); while (tree.next() != android::ResXMLTree::START_TAG) { - ASSERT_NE(tree.getEventType(), android::ResXMLTree::BAD_DOCUMENT); - ASSERT_NE(tree.getEventType(), android::ResXMLTree::END_DOCUMENT); + ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); + ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); } const StringPiece16 kPackage = u"package"; ssize_t idx = tree.indexOfAttribute(nullptr, 0, kPackage.data(), kPackage.size()); - ASSERT_GE(idx, 0); + ASSERT_THAT(idx, Ge(0)); size_t len; - EXPECT_NE(nullptr, tree.getAttributeStringValue(idx, &len)); + EXPECT_THAT(tree.getAttributeStringValue(idx, &len), NotNull()); } TEST_F(XmlFlattenerTest, FlattenNonStandardPackageId) { @@ -236,11 +217,11 @@ TEST_F(XmlFlattenerTest, FlattenNonStandardPackageId) { context_->SetPackageId(0x80); context_->SetNameManglerPolicy({"com.app.test.feature"}); - std::unique_ptr doc = test::BuildXmlDomForPackageName(context_.get(), R"EOF( + std::unique_ptr doc = test::BuildXmlDomForPackageName(context_.get(), R"( )EOF"); + app:foo="@id/foo" />)"); XmlReferenceLinker linker; ASSERT_TRUE(linker.Consume(context_.get(), doc.get())); @@ -253,59 +234,57 @@ TEST_F(XmlFlattenerTest, FlattenNonStandardPackageId) { ASSERT_TRUE(Flatten(doc.get(), &tree)); while (tree.next() != android::ResXMLTree::START_TAG) { - ASSERT_NE(android::ResXMLTree::BAD_DOCUMENT, tree.getEventType()); - ASSERT_NE(android::ResXMLTree::END_DOCUMENT, tree.getEventType()); + ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); + ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); } ssize_t idx; idx = tree.indexOfAttribute(xml::kSchemaAndroid, "id"); - ASSERT_GE(idx, 0); - EXPECT_EQ(idx, tree.indexOfID()); - EXPECT_EQ(ResourceId(0x010100d0), ResourceId(tree.getAttributeNameResID(idx))); + ASSERT_THAT(idx, Ge(0)); + EXPECT_THAT(tree.indexOfID(), Eq(idx)); + EXPECT_THAT(tree.getAttributeNameResID(idx), Eq(0x010100d0u)); idx = tree.indexOfAttribute(xml::kSchemaAuto, "foo"); - ASSERT_GE(idx, 0); - EXPECT_EQ(ResourceId(0x80010000), ResourceId(tree.getAttributeNameResID(idx))); - EXPECT_EQ(android::Res_value::TYPE_REFERENCE, tree.getAttributeDataType(idx)); - EXPECT_EQ(ResourceId(0x80020000), tree.getAttributeData(idx)); + ASSERT_THAT(idx, Ge(0)); + EXPECT_THAT(tree.getAttributeNameResID(idx), Eq(0x80010000u)); + EXPECT_THAT(tree.getAttributeDataType(idx), Eq(android::Res_value::TYPE_REFERENCE)); + EXPECT_THAT(tree.getAttributeData(idx), Eq(int32_t(0x80020000))); } TEST_F(XmlFlattenerTest, ProcessEscapedStrings) { std::unique_ptr doc = test::BuildXmlDom( - R"EOF(\\d{5})EOF"); + R"(\\d{5})"); android::ResXMLTree tree; ASSERT_TRUE(Flatten(doc.get(), &tree)); while (tree.next() != android::ResXMLTree::START_TAG) { - ASSERT_NE(tree.getEventType(), android::ResXMLTree::BAD_DOCUMENT); - ASSERT_NE(tree.getEventType(), android::ResXMLTree::END_DOCUMENT); + ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); + ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); } const StringPiece16 kValue = u"value"; const StringPiece16 kPattern = u"pattern"; + const StringPiece16 kOther = u"other"; size_t len; ssize_t idx; - const char16_t* str16; idx = tree.indexOfAttribute(nullptr, 0, kValue.data(), kValue.size()); - ASSERT_GE(idx, 0); - str16 = tree.getAttributeStringValue(idx, &len); - ASSERT_NE(nullptr, str16); - EXPECT_EQ(StringPiece16(u"?hello"), StringPiece16(str16, len)); + ASSERT_THAT(idx, Ge(0)); + EXPECT_THAT(tree.getAttributeStringValue(idx, &len), StrEq(u"?hello")); idx = tree.indexOfAttribute(nullptr, 0, kPattern.data(), kPattern.size()); - ASSERT_GE(idx, 0); - str16 = tree.getAttributeStringValue(idx, &len); - ASSERT_NE(nullptr, str16); - EXPECT_EQ(StringPiece16(u"\\d{5}"), StringPiece16(str16, len)); + ASSERT_THAT(idx, Ge(0)); + EXPECT_THAT(tree.getAttributeStringValue(idx, &len), StrEq(u"\\d{5}")); - ASSERT_EQ(android::ResXMLTree::TEXT, tree.next()); - str16 = tree.getText(&len); - ASSERT_NE(nullptr, str16); - EXPECT_EQ(StringPiece16(u"\\d{5}"), StringPiece16(str16, len)); + idx = tree.indexOfAttribute(nullptr, 0, kOther.data(), kOther.size()); + ASSERT_THAT(idx, Ge(0)); + EXPECT_THAT(tree.getAttributeStringValue(idx, &len), StrEq(u"\"")); + + ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); + EXPECT_THAT(tree.getText(&len), StrEq(u"\\d{5}")); } } // namespace aapt diff --git a/tools/aapt2/test/Common.h b/tools/aapt2/test/Common.h index 05851485e2164..01b2d143de501 100644 --- a/tools/aapt2/test/Common.h +++ b/tools/aapt2/test/Common.h @@ -145,6 +145,12 @@ void PrintTo(const Maybe& value, std::ostream* out) { namespace test { +MATCHER_P(StrEq, a, + std::string(negation ? "isn't" : "is") + " equal to " + + ::testing::PrintToString(android::StringPiece16(a))) { + return android::StringPiece16(arg) == a; +} + MATCHER_P(ValueEq, a, std::string(negation ? "isn't" : "is") + " equal to " + ::testing::PrintToString(a)) { return arg.Equals(&a); diff --git a/tools/aapt2/util/Maybe.h b/tools/aapt2/util/Maybe.h index b43f8e87fd684..9a82418e0a5a0 100644 --- a/tools/aapt2/util/Maybe.h +++ b/tools/aapt2/util/Maybe.h @@ -281,16 +281,12 @@ inline Maybe make_nothing() { return Maybe(); } -/** - * Define the == operator between Maybe and Maybe only if the operator T - * == U is defined. - * That way the compiler will show an error at the callsite when comparing two - * Maybe<> objects - * whose inner types can't be compared. - */ +// Define the == operator between Maybe and Maybe only if the operator T == U is defined. +// That way the compiler will show an error at the callsite when comparing two Maybe<> objects +// whose inner types can't be compared. template -typename std::enable_if::value, bool>::type operator==( - const Maybe& a, const Maybe& b) { +typename std::enable_if::value, bool>::type operator==(const Maybe& a, + const Maybe& b) { if (a && b) { return a.value() == b.value(); } else if (!a && !b) { @@ -299,18 +295,22 @@ typename std::enable_if::value, bool>::type operator==( return false; } -/** - * Same as operator== but negated. - */ template -typename std::enable_if::value, bool>::type operator!=( - const Maybe& a, const Maybe& b) { +typename std::enable_if::value, bool>::type operator==(const Maybe& a, + const U& b) { + return a ? a.value() == b : false; +} + +// Same as operator== but negated. +template +typename std::enable_if::value, bool>::type operator!=(const Maybe& a, + const Maybe& b) { return !(a == b); } template -typename std::enable_if::value, bool>::type operator<( - const Maybe& a, const Maybe& b) { +typename std::enable_if::value, bool>::type operator<(const Maybe& a, + const Maybe& b) { if (a && b) { return a.value() < b.value(); } else if (!a && !b) { diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp index 28e952e25a67d..8a8be858cb4ce 100644 --- a/tools/aapt2/util/Util.cpp +++ b/tools/aapt2/util/Util.cpp @@ -312,6 +312,9 @@ static Maybe ParseUnicodeCodepoint(const char** start, return result_utf8; } +StringBuilder::StringBuilder(bool preserve_spaces) : preserve_spaces_(preserve_spaces) { +} + StringBuilder& StringBuilder::Append(const StringPiece& str) { if (!error_.empty()) { return *this; @@ -368,14 +371,12 @@ StringBuilder& StringBuilder::Append(const StringPiece& str) { } last_char_was_escape_ = false; start = current + 1; - } else if (*current == '"') { + } else if (!preserve_spaces_ && *current == '"') { if (!quote_ && trailing_space_) { - // We found an opening quote, and we have - // trailing space, so we should append that + // We found an opening quote, and we have trailing space, so we should append that // space now. if (trailing_space_) { - // We had trailing whitespace, so - // replace with a single space. + // We had trailing whitespace, so replace with a single space. if (!str_.empty()) { str_ += ' '; } @@ -385,7 +386,7 @@ StringBuilder& StringBuilder::Append(const StringPiece& str) { quote_ = !quote_; str_.append(start, current - start); start = current + 1; - } else if (*current == '\'' && !quote_) { + } else if (!preserve_spaces_ && *current == '\'' && !quote_) { // This should be escaped. error_ = "unescaped apostrophe"; return *this; @@ -402,7 +403,7 @@ StringBuilder& StringBuilder::Append(const StringPiece& str) { str_.append(start, current - start); start = current + 1; last_char_was_escape_ = true; - } else if (!quote_) { + } else if (!preserve_spaces_ && !quote_) { // This is not quoted text, so look for whitespace. if (isspace(*current)) { // We found whitespace, see if we have seen some diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h index 386f74b0301a5..b9ada7704a26d 100644 --- a/tools/aapt2/util/Util.h +++ b/tools/aapt2/util/Util.h @@ -166,6 +166,8 @@ bool VerifyJavaStringFormat(const android::StringPiece& str); class StringBuilder { public: + explicit StringBuilder(bool preserve_spaces = false); + StringBuilder& Append(const android::StringPiece& str); const std::string& ToString() const; const std::string& Error() const; @@ -179,6 +181,7 @@ class StringBuilder { explicit operator bool() const; private: + bool preserve_spaces_; std::string str_; size_t utf16_len_ = 0; bool quote_ = false; diff --git a/tools/aapt2/util/Util_test.cpp b/tools/aapt2/util/Util_test.cpp index e49aee5d50ed3..5cced3e9acabf 100644 --- a/tools/aapt2/util/Util_test.cpp +++ b/tools/aapt2/util/Util_test.cpp @@ -20,16 +20,17 @@ #include "test/Test.h" -using android::StringPiece; +using ::android::StringPiece; +using ::testing::Eq; +using ::testing::Ne; +using ::testing::SizeIs; namespace aapt { TEST(UtilTest, TrimOnlyWhitespace) { - const std::string full = "\n "; - - StringPiece trimmed = util::TrimWhitespace(full); + const StringPiece trimmed = util::TrimWhitespace("\n "); EXPECT_TRUE(trimmed.empty()); - EXPECT_EQ(0u, trimmed.size()); + EXPECT_THAT(trimmed, SizeIs(0u)); } TEST(UtilTest, StringEndsWith) { @@ -41,85 +42,74 @@ TEST(UtilTest, StringStartsWith) { } TEST(UtilTest, StringBuilderSplitEscapeSequence) { - EXPECT_EQ(StringPiece("this is a new\nline."), util::StringBuilder() - .Append("this is a new\\") - .Append("nline.") - .ToString()); + EXPECT_THAT(util::StringBuilder().Append("this is a new\\").Append("nline.").ToString(), + Eq("this is a new\nline.")); } TEST(UtilTest, StringBuilderWhitespaceRemoval) { - EXPECT_EQ(StringPiece("hey guys this is so cool"), - util::StringBuilder() - .Append(" hey guys ") - .Append(" this is so cool ") - .ToString()); - - EXPECT_EQ(StringPiece(" wow, so many \t spaces. what?"), - util::StringBuilder() - .Append(" \" wow, so many \t ") - .Append("spaces. \"what? ") - .ToString()); - - EXPECT_EQ(StringPiece("where is the pie?"), util::StringBuilder() - .Append(" where \t ") - .Append(" \nis the " - " pie?") - .ToString()); + EXPECT_THAT(util::StringBuilder().Append(" hey guys ").Append(" this is so cool ").ToString(), + Eq("hey guys this is so cool")); + EXPECT_THAT( + util::StringBuilder().Append(" \" wow, so many \t ").Append("spaces. \"what? ").ToString(), + Eq(" wow, so many \t spaces. what?")); + EXPECT_THAT(util::StringBuilder().Append(" where \t ").Append(" \nis the pie?").ToString(), + Eq("where is the pie?")); } TEST(UtilTest, StringBuilderEscaping) { - EXPECT_EQ(StringPiece("hey guys\n this \t is so\\ cool"), - util::StringBuilder() - .Append(" hey guys\\n ") - .Append(" this \\t is so\\\\ cool ") - .ToString()); - - EXPECT_EQ(StringPiece("@?#\\\'"), - util::StringBuilder().Append("\\@\\?\\#\\\\\\'").ToString()); + EXPECT_THAT(util::StringBuilder() + .Append(" hey guys\\n ") + .Append(" this \\t is so\\\\ cool ") + .ToString(), + Eq("hey guys\n this \t is so\\ cool")); + EXPECT_THAT(util::StringBuilder().Append("\\@\\?\\#\\\\\\'").ToString(), Eq("@?#\\\'")); } TEST(UtilTest, StringBuilderMisplacedQuote) { - util::StringBuilder builder{}; + util::StringBuilder builder; EXPECT_FALSE(builder.Append("they're coming!")); } TEST(UtilTest, StringBuilderUnicodeCodes) { - EXPECT_EQ(std::string("\u00AF\u0AF0 woah"), - util::StringBuilder().Append("\\u00AF\\u0AF0 woah").ToString()); - + EXPECT_THAT(util::StringBuilder().Append("\\u00AF\\u0AF0 woah").ToString(), + Eq("\u00AF\u0AF0 woah")); EXPECT_FALSE(util::StringBuilder().Append("\\u00 yo")); } +TEST(UtilTest, StringBuilderPreserveSpaces) { + EXPECT_THAT(util::StringBuilder(true /*preserve_spaces*/).Append("\"").ToString(), Eq("\"")); +} + TEST(UtilTest, TokenizeInput) { auto tokenizer = util::Tokenize(StringPiece("this| is|the|end"), '|'); auto iter = tokenizer.begin(); - ASSERT_EQ(*iter, StringPiece("this")); + ASSERT_THAT(*iter, Eq("this")); ++iter; - ASSERT_EQ(*iter, StringPiece(" is")); + ASSERT_THAT(*iter, Eq(" is")); ++iter; - ASSERT_EQ(*iter, StringPiece("the")); + ASSERT_THAT(*iter, Eq("the")); ++iter; - ASSERT_EQ(*iter, StringPiece("end")); + ASSERT_THAT(*iter, Eq("end")); ++iter; - ASSERT_EQ(tokenizer.end(), iter); + ASSERT_THAT(iter, Eq(tokenizer.end())); } TEST(UtilTest, TokenizeEmptyString) { auto tokenizer = util::Tokenize(StringPiece(""), '|'); auto iter = tokenizer.begin(); - ASSERT_NE(tokenizer.end(), iter); - ASSERT_EQ(StringPiece(), *iter); + ASSERT_THAT(iter, Ne(tokenizer.end())); + ASSERT_THAT(*iter, Eq(StringPiece())); ++iter; - ASSERT_EQ(tokenizer.end(), iter); + ASSERT_THAT(iter, Eq(tokenizer.end())); } TEST(UtilTest, TokenizeAtEnd) { auto tokenizer = util::Tokenize(StringPiece("one."), '.'); auto iter = tokenizer.begin(); - ASSERT_EQ(*iter, StringPiece("one")); + ASSERT_THAT(*iter, Eq("one")); ++iter; - ASSERT_NE(iter, tokenizer.end()); - ASSERT_EQ(*iter, StringPiece()); + ASSERT_THAT(iter, Ne(tokenizer.end())); + ASSERT_THAT(*iter, Eq(StringPiece())); } TEST(UtilTest, IsJavaClassName) { diff --git a/tools/aapt2/xml/XmlDom_test.cpp b/tools/aapt2/xml/XmlDom_test.cpp index fb18ea316ca68..031801e1dd2fc 100644 --- a/tools/aapt2/xml/XmlDom_test.cpp +++ b/tools/aapt2/xml/XmlDom_test.cpp @@ -28,17 +28,16 @@ constexpr const char* kXmlPreamble = TEST(XmlDomTest, Inflate) { std::stringstream in(kXmlPreamble); - in << R"EOF( - - - - )EOF"; + in << R"( + + + )"; - const Source source = {"test.xml"}; + const Source source("test.xml"); StdErrDiagnostics diag; std::unique_ptr doc = xml::Inflate(&in, &diag, source); ASSERT_NE(doc, nullptr); @@ -51,8 +50,8 @@ TEST(XmlDomTest, Inflate) { // Escaping is handled after parsing of the values for resource-specific values. TEST(XmlDomTest, ForwardEscapes) { - std::unique_ptr doc = test::BuildXmlDom(R"EOF( - \\d{5})EOF"); + std::unique_ptr doc = test::BuildXmlDom(R"( + \\d{5})"); xml::Element* el = xml::FindRootElement(doc->root.get()); ASSERT_NE(nullptr, el); @@ -65,10 +64,20 @@ TEST(XmlDomTest, ForwardEscapes) { ASSERT_NE(nullptr, attr); EXPECT_EQ("\\?hello", attr->value); - ASSERT_EQ(1u, el->children.size()); xml::Text* text = xml::NodeCast(el->children[0].get()); ASSERT_NE(nullptr, text); EXPECT_EQ("\\\\d{5}", text->text); } +TEST(XmlDomTest, XmlEscapeSequencesAreParsed) { + std::unique_ptr doc = test::BuildXmlDom(R"()"); + + xml::Element* el = xml::FindRootElement(doc.get()); + ASSERT_NE(nullptr, el); + + xml::Attribute* attr = el->FindAttribute({}, "value"); + ASSERT_NE(nullptr, attr); + EXPECT_EQ("\"", attr->value); +} + } // namespace aapt