ResourceParser_test.cpp revision a587065721053ad54e34f484868142407d59512d
16f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/* 26f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Copyright (C) 2015 The Android Open Source Project 36f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * 46f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 56f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * you may not use this file except in compliance with the License. 66f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * You may obtain a copy of the License at 76f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * 86f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 96f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * 106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Unless required by applicable law or agreed to in writing, software 116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * See the License for the specific language governing permissions and 146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * limitations under the License. 156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */ 166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 176f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "ResourceParser.h" 186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "ResourceTable.h" 191ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "ResourceUtils.h" 206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "ResourceValues.h" 211ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "test/Context.h" 22467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski#include "xml/XmlPullParser.h" 236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <gtest/gtest.h> 256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <sstream> 266f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include <string> 276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskinamespace aapt { 296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskiconstexpr const char* kXmlPreamble = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; 316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 321ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiTEST(ResourceParserSingleTest, FailToParseWithNoRootResourcesElement) { 331ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::unique_ptr<IAaptContext> context = test::ContextBuilder().build(); 341ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::stringstream input(kXmlPreamble); 351ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski input << "<attr name=\"foo\"/>" << std::endl; 361ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski ResourceTable table; 371ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski ResourceParser parser(context->getDiagnostics(), &table, Source{ "test" }, {}); 38467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski xml::XmlPullParser xmlParser(input); 391ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski ASSERT_FALSE(parser.parse(&xmlParser)); 40769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski} 41769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski 426f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskistruct ResourceParserTest : public ::testing::Test { 431ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski ResourceTable mTable; 441ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::unique_ptr<IAaptContext> mContext; 451ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 461ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski void SetUp() override { 471ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski mContext = test::ContextBuilder().build(); 486f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 496f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 509ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski ::testing::AssertionResult testParse(const StringPiece& str, 519ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski Maybe<std::u16string> product = {}) { 526f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::stringstream input(kXmlPreamble); 5324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski input << "<resources>\n" << str << "\n</resources>" << std::endl; 549f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski ResourceParserOptions parserOptions; 559f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski parserOptions.product = product; 569ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski ResourceParser parser(mContext->getDiagnostics(), &mTable, Source{ "test" }, {}, 579f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski parserOptions); 58467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski xml::XmlPullParser xmlParser(input); 591ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (parser.parse(&xmlParser)) { 606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return ::testing::AssertionSuccess(); 616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return ::testing::AssertionFailure(); 636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}; 656f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 666f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseQuotedString) { 6724aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski std::string input = "<string name=\"foo\"> \" hey there \" </string>"; 686f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_TRUE(testParse(input)); 696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 701ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski String* str = test::getValue<String>(&mTable, u"@string/foo"); 716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_NE(nullptr, str); 726f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski EXPECT_EQ(std::u16string(u" hey there "), *str->value); 736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseEscapedString) { 7624aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski std::string input = "<string name=\"foo\">\\?123</string>"; 776f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_TRUE(testParse(input)); 786f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 791ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski String* str = test::getValue<String>(&mTable, u"@string/foo"); 806f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_NE(nullptr, str); 816f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski EXPECT_EQ(std::u16string(u"?123"), *str->value); 826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 836f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 849f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam LesinskiTEST_F(ResourceParserTest, ParseFormattedString) { 859f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski std::string input = "<string name=\"foo\">%d %s</string>"; 869f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski ASSERT_FALSE(testParse(input)); 879f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski 889f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski input = "<string name=\"foo\">%1$d %2$s</string>"; 899f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski ASSERT_TRUE(testParse(input)); 909f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski} 919f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski 921ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiTEST_F(ResourceParserTest, IgnoreXliffTags) { 931ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::string input = "<string name=\"foo\" \n" 941ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski " xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n" 951ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski " There are <xliff:g id=\"count\">%1$d</xliff:g> apples</string>"; 961ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski ASSERT_TRUE(testParse(input)); 971ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 981ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski String* str = test::getValue<String>(&mTable, u"@string/foo"); 991ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski ASSERT_NE(nullptr, str); 1001ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski EXPECT_EQ(StringPiece16(u"There are %1$d apples"), StringPiece16(*str->value)); 1011ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 1021ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 103dfa5e0705ff82f15e228ba076bc192893bcbe118Adam LesinskiTEST_F(ResourceParserTest, ParseNull) { 104dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski std::string input = "<integer name=\"foo\">@null</integer>"; 105dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski ASSERT_TRUE(testParse(input)); 106dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski 107dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski // The Android runtime treats a value of android::Res_value::TYPE_NULL as 108dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski // a non-existing value, and this causes problems in styles when trying to resolve 109dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski // an attribute. Null values must be encoded as android::Res_value::TYPE_REFERENCE 110dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski // with a data value of 0. 1111ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski BinaryPrimitive* integer = test::getValue<BinaryPrimitive>(&mTable, u"@integer/foo"); 112dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski ASSERT_NE(nullptr, integer); 113dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski EXPECT_EQ(uint16_t(android::Res_value::TYPE_REFERENCE), integer->value.dataType); 114dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski EXPECT_EQ(0u, integer->value.data); 115dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski} 116dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski 117dfa5e0705ff82f15e228ba076bc192893bcbe118Adam LesinskiTEST_F(ResourceParserTest, ParseEmpty) { 118dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski std::string input = "<integer name=\"foo\">@empty</integer>"; 119dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski ASSERT_TRUE(testParse(input)); 120dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski 1211ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski BinaryPrimitive* integer = test::getValue<BinaryPrimitive>(&mTable, u"@integer/foo"); 122dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski ASSERT_NE(nullptr, integer); 123dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski EXPECT_EQ(uint16_t(android::Res_value::TYPE_NULL), integer->value.dataType); 124dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski EXPECT_EQ(uint32_t(android::Res_value::DATA_NULL_EMPTY), integer->value.data); 125dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski} 126dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski 1276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAttr) { 12824aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski std::string input = "<attr name=\"foo\" format=\"string\"/>\n" 12924aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski "<attr name=\"bar\"/>"; 1306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_TRUE(testParse(input)); 1316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1321ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski Attribute* attr = test::getValue<Attribute>(&mTable, u"@attr/foo"); 1331ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski ASSERT_NE(nullptr, attr); 1346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_STRING), attr->typeMask); 1356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1361ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski attr = test::getValue<Attribute>(&mTable, u"@attr/bar"); 1371ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski ASSERT_NE(nullptr, attr); 1386f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_ANY), attr->typeMask); 1396f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 1406f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 141a587065721053ad54e34f484868142407d59512dAdam LesinskiTEST_F(ResourceParserTest, ParseAttrWithMinMax) { 142a587065721053ad54e34f484868142407d59512dAdam Lesinski std::string input = "<attr name=\"foo\" min=\"10\" max=\"23\" format=\"integer\"/>"; 143a587065721053ad54e34f484868142407d59512dAdam Lesinski ASSERT_TRUE(testParse(input)); 144a587065721053ad54e34f484868142407d59512dAdam Lesinski 145a587065721053ad54e34f484868142407d59512dAdam Lesinski Attribute* attr = test::getValue<Attribute>(&mTable, u"@attr/foo"); 146a587065721053ad54e34f484868142407d59512dAdam Lesinski ASSERT_NE(nullptr, attr); 147a587065721053ad54e34f484868142407d59512dAdam Lesinski EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_INTEGER), attr->typeMask); 148a587065721053ad54e34f484868142407d59512dAdam Lesinski EXPECT_EQ(10, attr->minInt); 149a587065721053ad54e34f484868142407d59512dAdam Lesinski EXPECT_EQ(23, attr->maxInt); 150a587065721053ad54e34f484868142407d59512dAdam Lesinski} 151a587065721053ad54e34f484868142407d59512dAdam Lesinski 152a587065721053ad54e34f484868142407d59512dAdam LesinskiTEST_F(ResourceParserTest, FailParseAttrWithMinMaxButNotInteger) { 153a587065721053ad54e34f484868142407d59512dAdam Lesinski std::string input = "<attr name=\"foo\" min=\"10\" max=\"23\" format=\"string\"/>"; 154a587065721053ad54e34f484868142407d59512dAdam Lesinski ASSERT_FALSE(testParse(input)); 155a587065721053ad54e34f484868142407d59512dAdam Lesinski} 156a587065721053ad54e34f484868142407d59512dAdam Lesinski 1576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseUseAndDeclOfAttr) { 15824aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski std::string input = "<declare-styleable name=\"Styleable\">\n" 15924aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski " <attr name=\"foo\" />\n" 16024aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski "</declare-styleable>\n" 16124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski "<attr name=\"foo\" format=\"string\"/>"; 1626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_TRUE(testParse(input)); 1636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1641ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski Attribute* attr = test::getValue<Attribute>(&mTable, u"@attr/foo"); 1656f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_NE(nullptr, attr); 1666f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_STRING), attr->typeMask); 1676f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 1686f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseDoubleUseOfAttr) { 17024aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski std::string input = "<declare-styleable name=\"Theme\">" 17124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski " <attr name=\"foo\" />\n" 17224aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski "</declare-styleable>\n" 17324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski "<declare-styleable name=\"Window\">\n" 17424aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski " <attr name=\"foo\" format=\"boolean\"/>\n" 17524aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski "</declare-styleable>"; 1766f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_TRUE(testParse(input)); 1776f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1781ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski Attribute* attr = test::getValue<Attribute>(&mTable, u"@attr/foo"); 1796f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_NE(nullptr, attr); 1806f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_BOOLEAN), attr->typeMask); 1816f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 1826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1836f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseEnumAttr) { 18424aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski std::string input = "<attr name=\"foo\">\n" 18524aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski " <enum name=\"bar\" value=\"0\"/>\n" 18624aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski " <enum name=\"bat\" value=\"1\"/>\n" 18724aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski " <enum name=\"baz\" value=\"2\"/>\n" 18824aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski "</attr>"; 1896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_TRUE(testParse(input)); 1906f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1911ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski Attribute* enumAttr = test::getValue<Attribute>(&mTable, u"@attr/foo"); 1926f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_NE(enumAttr, nullptr); 1936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski EXPECT_EQ(enumAttr->typeMask, android::ResTable_map::TYPE_ENUM); 1946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_EQ(enumAttr->symbols.size(), 3u); 1956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1961ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski AAPT_ASSERT_TRUE(enumAttr->symbols[0].symbol.name); 1971ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski EXPECT_EQ(enumAttr->symbols[0].symbol.name.value().entry, u"bar"); 1986f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski EXPECT_EQ(enumAttr->symbols[0].value, 0u); 1996f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2001ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski AAPT_ASSERT_TRUE(enumAttr->symbols[1].symbol.name); 2011ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski EXPECT_EQ(enumAttr->symbols[1].symbol.name.value().entry, u"bat"); 2026f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski EXPECT_EQ(enumAttr->symbols[1].value, 1u); 2036f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2041ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski AAPT_ASSERT_TRUE(enumAttr->symbols[2].symbol.name); 2051ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski EXPECT_EQ(enumAttr->symbols[2].symbol.name.value().entry, u"baz"); 2066f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski EXPECT_EQ(enumAttr->symbols[2].value, 2u); 2076f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 2086f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2096f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseFlagAttr) { 21024aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski std::string input = "<attr name=\"foo\">\n" 21124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski " <flag name=\"bar\" value=\"0\"/>\n" 21224aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski " <flag name=\"bat\" value=\"1\"/>\n" 21324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski " <flag name=\"baz\" value=\"2\"/>\n" 21424aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski "</attr>"; 2156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_TRUE(testParse(input)); 2166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2171ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski Attribute* flagAttr = test::getValue<Attribute>(&mTable, u"@attr/foo"); 2186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_NE(flagAttr, nullptr); 2196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski EXPECT_EQ(flagAttr->typeMask, android::ResTable_map::TYPE_FLAGS); 2206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_EQ(flagAttr->symbols.size(), 3u); 2216f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2221ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski AAPT_ASSERT_TRUE(flagAttr->symbols[0].symbol.name); 2231ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski EXPECT_EQ(flagAttr->symbols[0].symbol.name.value().entry, u"bar"); 2246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski EXPECT_EQ(flagAttr->symbols[0].value, 0u); 2256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2261ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski AAPT_ASSERT_TRUE(flagAttr->symbols[1].symbol.name); 2271ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski EXPECT_EQ(flagAttr->symbols[1].symbol.name.value().entry, u"bat"); 2286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski EXPECT_EQ(flagAttr->symbols[1].value, 1u); 2296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2301ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski AAPT_ASSERT_TRUE(flagAttr->symbols[2].symbol.name); 2311ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski EXPECT_EQ(flagAttr->symbols[2].symbol.name.value().entry, u"baz"); 2326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski EXPECT_EQ(flagAttr->symbols[2].value, 2u); 2336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2341ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::unique_ptr<BinaryPrimitive> flagValue = ResourceUtils::tryParseFlagSymbol(flagAttr, 2351ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski u"baz|bat"); 2366f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_NE(flagValue, nullptr); 2376f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski EXPECT_EQ(flagValue->value.data, 1u | 2u); 2386f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 2396f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2406f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, FailToParseEnumAttrWithNonUniqueKeys) { 24124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski std::string input = "<attr name=\"foo\">\n" 24224aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski " <enum name=\"bar\" value=\"0\"/>\n" 24324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski " <enum name=\"bat\" value=\"1\"/>\n" 24424aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski " <enum name=\"bat\" value=\"2\"/>\n" 24524aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski "</attr>"; 2466f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_FALSE(testParse(input)); 2476f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 2486f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2496f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseStyle) { 25024aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski std::string input = "<style name=\"foo\" parent=\"@style/fu\">\n" 25124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski " <item name=\"bar\">#ffffffff</item>\n" 25224aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski " <item name=\"bat\">@string/hey</item>\n" 25324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski " <item name=\"baz\"><b>hey</b></item>\n" 25424aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski "</style>"; 2556f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_TRUE(testParse(input)); 2566f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2571ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski Style* style = test::getValue<Style>(&mTable, u"@style/foo"); 2586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_NE(style, nullptr); 2591ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski AAPT_ASSERT_TRUE(style->parent); 2601ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski AAPT_ASSERT_TRUE(style->parent.value().name); 2611ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski EXPECT_EQ(test::parseNameOrDie(u"@style/fu"), style->parent.value().name.value()); 2621ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski ASSERT_EQ(3u, style->entries.size()); 2631ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 2641ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski AAPT_ASSERT_TRUE(style->entries[0].key.name); 2651ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski EXPECT_EQ(test::parseNameOrDie(u"@attr/bar"), style->entries[0].key.name.value()); 2661ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 2671ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski AAPT_ASSERT_TRUE(style->entries[1].key.name); 2681ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski EXPECT_EQ(test::parseNameOrDie(u"@attr/bat"), style->entries[1].key.name.value()); 2691ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 2701ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski AAPT_ASSERT_TRUE(style->entries[2].key.name); 2711ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski EXPECT_EQ(test::parseNameOrDie(u"@attr/baz"), style->entries[2].key.name.value()); 2726f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 2736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 274769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithShorthandParent) { 27524aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski std::string input = "<style name=\"foo\" parent=\"com.app:Theme\"/>"; 276769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski ASSERT_TRUE(testParse(input)); 277769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski 2781ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski Style* style = test::getValue<Style>(&mTable, u"@style/foo"); 279769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski ASSERT_NE(style, nullptr); 2801ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski AAPT_ASSERT_TRUE(style->parent); 2811ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski AAPT_ASSERT_TRUE(style->parent.value().name); 2821ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski EXPECT_EQ(test::parseNameOrDie(u"@com.app:style/Theme"), style->parent.value().name.value()); 283769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski} 284769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski 28524aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPackageAliasedParent) { 28624aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski std::string input = "<style xmlns:app=\"http://schemas.android.com/apk/res/android\"\n" 28724aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski " name=\"foo\" parent=\"app:Theme\"/>"; 28824aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski ASSERT_TRUE(testParse(input)); 28924aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski 2901ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski Style* style = test::getValue<Style>(&mTable, u"@style/foo"); 29124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski ASSERT_NE(style, nullptr); 2921ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski AAPT_ASSERT_TRUE(style->parent); 2931ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski AAPT_ASSERT_TRUE(style->parent.value().name); 2941ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski EXPECT_EQ(test::parseNameOrDie(u"@android:style/Theme"), style->parent.value().name.value()); 29524aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski} 29624aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski 29724aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPackageAliasedItems) { 29824aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski std::string input = 29924aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski "<style xmlns:app=\"http://schemas.android.com/apk/res/android\" name=\"foo\">\n" 30024aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski " <item name=\"app:bar\">0</item>\n" 30124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski "</style>"; 30224aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski ASSERT_TRUE(testParse(input)); 30324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski 3041ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski Style* style = test::getValue<Style>(&mTable, u"@style/foo"); 30524aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski ASSERT_NE(style, nullptr); 30624aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski ASSERT_EQ(1u, style->entries.size()); 3071ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski EXPECT_EQ(test::parseNameOrDie(u"@android:attr/bar"), style->entries[0].key.name.value()); 30824aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski} 30924aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski 310bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithInferredParent) { 311bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski std::string input = "<style name=\"foo.bar\"/>"; 312bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski ASSERT_TRUE(testParse(input)); 313bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski 3141ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski Style* style = test::getValue<Style>(&mTable, u"@style/foo.bar"); 315bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski ASSERT_NE(style, nullptr); 3161ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski AAPT_ASSERT_TRUE(style->parent); 3171ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski AAPT_ASSERT_TRUE(style->parent.value().name); 3181ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski EXPECT_EQ(style->parent.value().name.value(), test::parseNameOrDie(u"@style/foo")); 319bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski EXPECT_TRUE(style->parentInferred); 320bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski} 321bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski 322bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithInferredParentOverridenByEmptyParentAttribute) { 323bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski std::string input = "<style name=\"foo.bar\" parent=\"\"/>"; 324bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski ASSERT_TRUE(testParse(input)); 325bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski 3261ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski Style* style = test::getValue<Style>(&mTable, u"@style/foo.bar"); 327bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski ASSERT_NE(style, nullptr); 3281ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski AAPT_EXPECT_FALSE(style->parent); 329bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski EXPECT_FALSE(style->parentInferred); 330bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski} 331bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski 3326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAutoGeneratedIdReference) { 33324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski std::string input = "<string name=\"foo\">@+id/bar</string>"; 3346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_TRUE(testParse(input)); 3356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3361ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski Id* id = test::getValue<Id>(&mTable, u"@id/bar"); 3376f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_NE(id, nullptr); 3386f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 3396f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3406f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAttributesDeclareStyleable) { 34124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski std::string input = "<declare-styleable name=\"foo\">\n" 34224aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski " <attr name=\"bar\" />\n" 34324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski " <attr name=\"bat\" format=\"string|reference\"/>\n" 3449ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski " <attr name=\"baz\">\n" 3459ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski " <enum name=\"foo\" value=\"1\"/>\n" 3469ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski " </attr>\n" 34724aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski "</declare-styleable>"; 3486f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_TRUE(testParse(input)); 3496f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3509f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski Maybe<ResourceTable::SearchResult> result = 3519f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski mTable.findResource(test::parseNameOrDie(u"@styleable/foo")); 3529f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski AAPT_ASSERT_TRUE(result); 3539f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski EXPECT_EQ(SymbolState::kPublic, result.value().entry->symbolStatus.state); 3549f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski 3551ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski Attribute* attr = test::getValue<Attribute>(&mTable, u"@attr/bar"); 3566f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_NE(attr, nullptr); 3576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski EXPECT_TRUE(attr->isWeak()); 3586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3591ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski attr = test::getValue<Attribute>(&mTable, u"@attr/bat"); 3606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_NE(attr, nullptr); 3616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski EXPECT_TRUE(attr->isWeak()); 3626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3639ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski attr = test::getValue<Attribute>(&mTable, u"@attr/baz"); 3649ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski ASSERT_NE(attr, nullptr); 3659ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski EXPECT_TRUE(attr->isWeak()); 3669ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski EXPECT_EQ(1u, attr->symbols.size()); 3679ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski 3689ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski EXPECT_NE(nullptr, test::getValue<Id>(&mTable, u"@id/foo")); 3699ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski 3701ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski Styleable* styleable = test::getValue<Styleable>(&mTable, u"@styleable/foo"); 3716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_NE(styleable, nullptr); 3729ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski ASSERT_EQ(3u, styleable->entries.size()); 3736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3741ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski EXPECT_EQ(test::parseNameOrDie(u"@attr/bar"), styleable->entries[0].name.value()); 3751ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski EXPECT_EQ(test::parseNameOrDie(u"@attr/bat"), styleable->entries[1].name.value()); 3766f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 3776f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 378467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam LesinskiTEST_F(ResourceParserTest, ParsePrivateAttributesDeclareStyleable) { 379467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski std::string input = "<declare-styleable name=\"foo\" xmlns:privAndroid=\"http://schemas.android.com/apk/prv/res/android\">\n" 380467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski " <attr name=\"*android:bar\" />\n" 381467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski " <attr name=\"privAndroid:bat\" />\n" 382467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski "</declare-styleable>"; 383467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski ASSERT_TRUE(testParse(input)); 384467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski Styleable* styleable = test::getValue<Styleable>(&mTable, u"@styleable/foo"); 385467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski ASSERT_NE(nullptr, styleable); 386467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski ASSERT_EQ(2u, styleable->entries.size()); 387467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski 388467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski EXPECT_TRUE(styleable->entries[0].privateReference); 389467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski AAPT_ASSERT_TRUE(styleable->entries[0].name); 390467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski EXPECT_EQ(std::u16string(u"android"), styleable->entries[0].name.value().package); 391467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski 392467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski EXPECT_TRUE(styleable->entries[1].privateReference); 393467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski AAPT_ASSERT_TRUE(styleable->entries[1].name); 394467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski EXPECT_EQ(std::u16string(u"android"), styleable->entries[1].name.value().package); 395467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski} 396467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski 3976f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseArray) { 39824aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski std::string input = "<array name=\"foo\">\n" 39924aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski " <item>@string/ref</item>\n" 40024aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski " <item>hey</item>\n" 40124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski " <item>23</item>\n" 40224aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski "</array>"; 4036f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_TRUE(testParse(input)); 4046f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 4051ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski Array* array = test::getValue<Array>(&mTable, u"@array/foo"); 4066f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_NE(array, nullptr); 4076f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_EQ(3u, array->items.size()); 4086f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 4091ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski EXPECT_NE(nullptr, valueCast<Reference>(array->items[0].get())); 4101ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski EXPECT_NE(nullptr, valueCast<String>(array->items[1].get())); 4111ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski EXPECT_NE(nullptr, valueCast<BinaryPrimitive>(array->items[2].get())); 4126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 4136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 4149ba47d813075fcb05c5e1532c137c93b394631cbAdam LesinskiTEST_F(ResourceParserTest, ParseStringArray) { 4159ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski std::string input = "<string-array name=\"foo\">\n" 4169ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski " <item>\"Werk\"</item>\n" 4179ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski "</string-array>\n"; 4189ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski ASSERT_TRUE(testParse(input)); 4199ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski EXPECT_NE(nullptr, test::getValue<Array>(&mTable, u"@array/foo")); 4209ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski} 4219ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski 4226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParsePlural) { 42324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski std::string input = "<plurals name=\"foo\">\n" 42424aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski " <item quantity=\"other\">apples</item>\n" 42524aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski " <item quantity=\"one\">apple</item>\n" 42624aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski "</plurals>"; 4276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_TRUE(testParse(input)); 4286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 4296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 4306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseCommentsWithResource) { 431e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski std::string input = "<!--This is a comment-->\n" 43224aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski "<string name=\"foo\">Hi</string>"; 4336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_TRUE(testParse(input)); 4346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 435e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski String* value = test::getValue<String>(&mTable, u"@string/foo"); 436e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski ASSERT_NE(nullptr, value); 437e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski EXPECT_EQ(value->getComment(), u"This is a comment"); 438e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski} 439e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski 440e78fd617ec60139a973a01925fa7adad31febb39Adam LesinskiTEST_F(ResourceParserTest, DoNotCombineMultipleComments) { 441e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski std::string input = "<!--One-->\n" 442e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski "<!--Two-->\n" 443e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski "<string name=\"foo\">Hi</string>"; 444e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski 445e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski ASSERT_TRUE(testParse(input)); 446e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski 447e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski String* value = test::getValue<String>(&mTable, u"@string/foo"); 448e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski ASSERT_NE(nullptr, value); 449e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski EXPECT_EQ(value->getComment(), u"Two"); 450e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski} 451e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski 452e78fd617ec60139a973a01925fa7adad31febb39Adam LesinskiTEST_F(ResourceParserTest, IgnoreCommentBeforeEndTag) { 453e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski std::string input = "<!--One-->\n" 454e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski "<string name=\"foo\">\n" 455e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski " Hi\n" 456e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski "<!--Two-->\n" 457e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski "</string>"; 458e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski 459e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski ASSERT_TRUE(testParse(input)); 4601ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 461e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski String* value = test::getValue<String>(&mTable, u"@string/foo"); 462e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski ASSERT_NE(nullptr, value); 463e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski EXPECT_EQ(value->getComment(), u"One"); 4646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 4656f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 466ca5638fd85098c3d0a699492751043545f75553aAdam LesinskiTEST_F(ResourceParserTest, ParseNestedComments) { 467ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski // We only care about declare-styleable and enum/flag attributes because comments 468ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski // from those end up in R.java 469ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski std::string input = R"EOF( 470ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski <declare-styleable name="foo"> 471ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski <!-- The name of the bar --> 472ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski <attr name="barName" format="string|reference" /> 473ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski </declare-styleable> 474ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski 475ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski <attr name="foo"> 476ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski <!-- The very first --> 477ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski <enum name="one" value="1" /> 478ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski </attr>)EOF"; 479ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski ASSERT_TRUE(testParse(input)); 480ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski 481ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski Styleable* styleable = test::getValue<Styleable>(&mTable, u"@styleable/foo"); 482ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski ASSERT_NE(nullptr, styleable); 483ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski ASSERT_EQ(1u, styleable->entries.size()); 484ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski 485ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski EXPECT_EQ(StringPiece16(u"The name of the bar"), styleable->entries.front().getComment()); 486ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski 487ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski Attribute* attr = test::getValue<Attribute>(&mTable, u"@attr/foo"); 488ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski ASSERT_NE(nullptr, attr); 489ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski ASSERT_EQ(1u, attr->symbols.size()); 490ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski 491ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski EXPECT_EQ(StringPiece16(u"The very first"), attr->symbols.front().symbol.getComment()); 492ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski} 493ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski 4946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/* 4956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Declaring an ID as public should not require a separate definition 4966f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * (as an ID has no value). 4976f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */ 4986f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParsePublicIdAsDefinition) { 49924aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski std::string input = "<public type=\"id\" name=\"foo\"/>"; 5006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_TRUE(testParse(input)); 5016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 5021ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski Id* id = test::getValue<Id>(&mTable, u"@id/foo"); 5036f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski ASSERT_NE(nullptr, id); 5046f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 5056f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 5069ba47d813075fcb05c5e1532c137c93b394631cbAdam LesinskiTEST_F(ResourceParserTest, FilterProductsThatDontMatch) { 5079ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski std::string input = "<string name=\"foo\" product=\"phone\">hi</string>\n" 5089ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski "<string name=\"foo\" product=\"no-sdcard\">ho</string>\n" 5099ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski "<string name=\"bar\" product=\"\">wee</string>\n" 5109ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski "<string name=\"baz\">woo</string>\n"; 5119ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski ASSERT_TRUE(testParse(input, std::u16string(u"no-sdcard"))); 5129ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski 5139ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski String* fooStr = test::getValue<String>(&mTable, u"@string/foo"); 5149ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski ASSERT_NE(nullptr, fooStr); 5159ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski EXPECT_EQ(StringPiece16(u"ho"), *fooStr->value); 5169ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski 5179ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski EXPECT_NE(nullptr, test::getValue<String>(&mTable, u"@string/bar")); 5189ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski EXPECT_NE(nullptr, test::getValue<String>(&mTable, u"@string/baz")); 5199ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski} 5209ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski 5219ba47d813075fcb05c5e1532c137c93b394631cbAdam LesinskiTEST_F(ResourceParserTest, FailWhenProductFilterStripsOutAllVersionsOfResource) { 5229ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski std::string input = "<string name=\"foo\" product=\"tablet\">hello</string>\n"; 5239ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski ASSERT_FALSE(testParse(input, std::u16string(u"phone"))); 5249ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski} 5259ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski 52627afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam LesinskiTEST_F(ResourceParserTest, AutoIncrementIdsInPublicGroup) { 52727afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski std::string input = R"EOF( 52827afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski <public-group type="attr" first-id="0x01010040"> 52927afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski <public name="foo" /> 53027afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski <public name="bar" /> 53127afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski </public-group>)EOF"; 53227afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski ASSERT_TRUE(testParse(input)); 53327afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski 53427afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski Maybe<ResourceTable::SearchResult> result = mTable.findResource( 53527afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski test::parseNameOrDie(u"@attr/foo")); 53627afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski AAPT_ASSERT_TRUE(result); 53727afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski 53827afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski AAPT_ASSERT_TRUE(result.value().package->id); 53927afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski AAPT_ASSERT_TRUE(result.value().type->id); 54027afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski AAPT_ASSERT_TRUE(result.value().entry->id); 54127afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski ResourceId actualId(result.value().package->id.value(), 54227afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski result.value().type->id.value(), 54327afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski result.value().entry->id.value()); 54427afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski EXPECT_EQ(ResourceId(0x01010040), actualId); 54527afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski 54627afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski result = mTable.findResource(test::parseNameOrDie(u"@attr/bar")); 54727afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski AAPT_ASSERT_TRUE(result); 54827afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski 54927afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski AAPT_ASSERT_TRUE(result.value().package->id); 55027afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski AAPT_ASSERT_TRUE(result.value().type->id); 55127afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski AAPT_ASSERT_TRUE(result.value().entry->id); 55227afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski actualId = ResourceId(result.value().package->id.value(), 55327afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski result.value().type->id.value(), 55427afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski result.value().entry->id.value()); 55527afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski EXPECT_EQ(ResourceId(0x01010041), actualId); 55627afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski} 55727afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski 558fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam LesinskiTEST_F(ResourceParserTest, ExternalTypesShouldOnlyBeReferences) { 559fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski std::string input = R"EOF(<item type="layout" name="foo">@layout/bar</item>)EOF"; 560fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski ASSERT_TRUE(testParse(input)); 561fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski 562fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski input = R"EOF(<item type="layout" name="bar">"this is a string"</item>)EOF"; 563fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski ASSERT_FALSE(testParse(input)); 564fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski} 565fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski 5666f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} // namespace aapt 567