diff options
Diffstat (limited to 'tools/aapt2/XmlFlattener_test.cpp')
-rw-r--r-- | tools/aapt2/XmlFlattener_test.cpp | 151 |
1 files changed, 130 insertions, 21 deletions
diff --git a/tools/aapt2/XmlFlattener_test.cpp b/tools/aapt2/XmlFlattener_test.cpp index a7d7ac6..b45cd9b 100644 --- a/tools/aapt2/XmlFlattener_test.cpp +++ b/tools/aapt2/XmlFlattener_test.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "Resolver.h" +#include "MockResolver.h" #include "ResourceTable.h" #include "ResourceValues.h" #include "SourceXmlPullParser.h" @@ -36,27 +36,29 @@ constexpr const char* kXmlPreamble = "<?xml version=\"1.0\" encoding=\"utf-8\"?> class XmlFlattenerTest : public ::testing::Test { public: virtual void SetUp() override { - std::shared_ptr<ResourceTable> table = std::make_shared<ResourceTable>(); - table->setPackage(u"android"); - table->setPackageId(0x01); - - table->addResource(ResourceName{ {}, ResourceType::kAttr, u"id" }, - ResourceId{ 0x01010000 }, {}, {}, - util::make_unique<Attribute>(false, ResTable_map::TYPE_ANY)); - - table->addResource(ResourceName{ {}, ResourceType::kId, u"test" }, - ResourceId{ 0x01020000 }, {}, {}, util::make_unique<Id>()); - - mFlattener = std::make_shared<XmlFlattener>(nullptr, - std::make_shared<Resolver>(table, std::make_shared<AssetManager>())); + std::shared_ptr<IResolver> resolver = std::make_shared<MockResolver>( + std::make_shared<ResourceTable>(), + std::map<ResourceName, ResourceId>({ + { ResourceName{ u"android", ResourceType::kAttr, u"attr" }, + ResourceId{ 0x01010000u } }, + { ResourceName{ u"android", ResourceType::kId, u"id" }, + ResourceId{ 0x01020000u } }, + { ResourceName{ u"com.lib", ResourceType::kAttr, u"attr" }, + ResourceId{ 0x01010001u } }, + { ResourceName{ u"com.lib", ResourceType::kId, u"id" }, + ResourceId{ 0x01020001u } }})); + + mFlattener = std::make_shared<XmlFlattener>(nullptr, resolver); } - ::testing::AssertionResult testFlatten(std::istream& in, ResXMLTree* outTree) { + ::testing::AssertionResult testFlatten(const std::string& in, ResXMLTree* outTree) { std::stringstream input(kXmlPreamble); - input << in.rdbuf() << std::endl; + input << in << std::endl; std::shared_ptr<XmlPullParser> xmlParser = std::make_shared<SourceXmlPullParser>(input); BigBuffer outBuffer(1024); - if (!mFlattener->flatten(Source{ "test" }, xmlParser, &outBuffer, {})) { + XmlFlattener::Options xmlOptions; + xmlOptions.defaultPackage = u"android"; + if (!mFlattener->flatten(Source{ "test" }, xmlParser, &outBuffer, xmlOptions)) { return ::testing::AssertionFailure(); } @@ -71,11 +73,22 @@ public: }; TEST_F(XmlFlattenerTest, ParseSimpleView) { - std::stringstream input; - input << "<View xmlns:android=\"http://schemas.android.com/apk/res/android\"" << std::endl - << " android:id=\"@id/test\">" << std::endl - << "</View>" << std::endl; + std::string input = "<View xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + " android:attr=\"@id/id\">\n" + "</View>"; + ResXMLTree tree; + ASSERT_TRUE(testFlatten(input, &tree)); + while (tree.next() != ResXMLTree::END_DOCUMENT) { + ASSERT_NE(tree.getEventType(), ResXMLTree::BAD_DOCUMENT); + } +} + +TEST_F(XmlFlattenerTest, ParseViewWithPackageAlias) { + std::string input = "<View xmlns:ns1=\"http://schemas.android.com/apk/res/android\"\n" + " xmlns:ns2=\"http://schemas.android.com/apk/res/android\"\n" + " ns1:attr=\"@ns2:id/id\">\n" + "</View>"; ResXMLTree tree; ASSERT_TRUE(testFlatten(input, &tree)); @@ -84,4 +97,100 @@ TEST_F(XmlFlattenerTest, ParseSimpleView) { } } +::testing::AssertionResult attributeNameAndValueEquals(ResXMLTree* tree, size_t index, + ResourceId nameId, ResourceId valueId) { + if (index >= tree->getAttributeCount()) { + return ::testing::AssertionFailure() << "index " << index << " is out of bounds (" + << tree->getAttributeCount() << ")"; + } + + if (tree->getAttributeNameResID(index) != nameId.id) { + return ::testing::AssertionFailure() + << "attribute at index " << index << " has ID " + << ResourceId{ (uint32_t) tree->getAttributeNameResID(index) } + << ". Expected ID " << nameId; + } + + if (tree->getAttributeDataType(index) != Res_value::TYPE_REFERENCE) { + return ::testing::AssertionFailure() << "attribute at index " << index << " has value of " + << "type " << std::hex + << tree->getAttributeDataType(index) << std::dec + << ". Expected reference (" << std::hex + << Res_value::TYPE_REFERENCE << std::dec << ")"; + } + + if ((uint32_t) tree->getAttributeData(index) != valueId.id) { + return ::testing::AssertionFailure() + << "attribute at index " << index << " has value " << "with ID " + << ResourceId{ (uint32_t) tree->getAttributeData(index) } + << ". Expected ID " << valueId; + } + return ::testing::AssertionSuccess(); +} + +TEST_F(XmlFlattenerTest, ParseViewWithShadowedPackageAlias) { + std::string input = "<View xmlns:app=\"http://schemas.android.com/apk/res/android\"\n" + " app:attr=\"@app:id/id\">\n" + " <View xmlns:app=\"http://schemas.android.com/apk/res/com.lib\"\n" + " app:attr=\"@app:id/id\"/>\n" + "</View>"; + ResXMLTree tree; + ASSERT_TRUE(testFlatten(input, &tree)); + + while (tree.next() != ResXMLTree::START_TAG) { + ASSERT_NE(tree.getEventType(), ResXMLTree::BAD_DOCUMENT); + ASSERT_NE(tree.getEventType(), ResXMLTree::END_DOCUMENT); + } + + ASSERT_TRUE(attributeNameAndValueEquals(&tree, 0u, ResourceId{ 0x01010000u }, + ResourceId{ 0x01020000u })); + + while (tree.next() != ResXMLTree::START_TAG) { + ASSERT_NE(tree.getEventType(), ResXMLTree::BAD_DOCUMENT); + ASSERT_NE(tree.getEventType(), ResXMLTree::END_DOCUMENT); + } + + ASSERT_TRUE(attributeNameAndValueEquals(&tree, 0u, ResourceId{ 0x01010001u }, + ResourceId{ 0x01020001u })); +} + +TEST_F(XmlFlattenerTest, ParseViewWithLocalPackageAndAliasOfTheSameName) { + std::string input = "<View xmlns:android=\"http://schemas.android.com/apk/res/com.lib\"\n" + " android:attr=\"@id/id\"/>"; + ResXMLTree tree; + ASSERT_TRUE(testFlatten(input, &tree)); + + while (tree.next() != ResXMLTree::START_TAG) { + ASSERT_NE(tree.getEventType(), ResXMLTree::BAD_DOCUMENT); + ASSERT_NE(tree.getEventType(), ResXMLTree::END_DOCUMENT); + } + + // We expect the 'android:attr' to be converted to 'com.lib:attr' due to the namespace + // assignment. + // However, we didn't give '@id/id' a package, so it should use the default package + // 'android', and not be converted from 'android' to 'com.lib'. + ASSERT_TRUE(attributeNameAndValueEquals(&tree, 0u, ResourceId{ 0x01010001u }, + ResourceId{ 0x01020000u })); +} + +/* + * The device ResXMLParser in libandroidfw differentiates between empty namespace and null + * namespace. + */ +TEST_F(XmlFlattenerTest, NoNamespaceIsNotTheSameAsEmptyNamespace) { + std::string input = "<View xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + " package=\"android\"/>"; + + ResXMLTree tree; + ASSERT_TRUE(testFlatten(input, &tree)); + + while (tree.next() != ResXMLTree::START_TAG) { + ASSERT_NE(tree.getEventType(), ResXMLTree::BAD_DOCUMENT); + ASSERT_NE(tree.getEventType(), ResXMLTree::END_DOCUMENT); + } + + const StringPiece16 kPackage = u"package"; + EXPECT_GE(tree.indexOfAttribute(nullptr, 0, kPackage.data(), kPackage.size()), 0); +} + } // namespace aapt |