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" 18ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 19ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include <sstream> 20ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include <string> 21ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "ResourceTable.h" 231ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "ResourceUtils.h" 246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "ResourceValues.h" 25d0f116b619feede0cfdb647157ce5ab4d50a1c46Adam Lesinski#include "test/Test.h" 26467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski#include "xml/XmlPullParser.h" 276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2890919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinskiusing ::aapt::test::ValueEq; 29e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinskiusing ::android::StringPiece; 30e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinskiusing ::testing::Eq; 31e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinskiusing ::testing::NotNull; 3290919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinskiusing ::testing::Pointee; 33d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski 346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskinamespace aapt { 356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3690919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinskiconstexpr const char* kXmlPreamble = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; 376f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 381ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiTEST(ResourceParserSingleTest, FailToParseWithNoRootResourcesElement) { 39ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); 40cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::stringstream input(kXmlPreamble); 4190919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski input << R"(<attr name="foo"/>)" << std::endl; 42cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ResourceTable table; 43ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceParser parser(context->GetDiagnostics(), &table, Source{"test"}, {}); 44ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski xml::XmlPullParser xml_parser(input); 45ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_FALSE(parser.Parse(&xml_parser)); 46769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski} 47769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski 48ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskiclass ResourceParserTest : public ::testing::Test { 49ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski public: 5090919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski void SetUp() override { 5190919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski context_ = test::ContextBuilder().Build(); 5290919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski } 531ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 54ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ::testing::AssertionResult TestParse(const StringPiece& str) { 55ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return TestParse(str, ConfigDescription{}); 56cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 5752364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski 5890919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski ::testing::AssertionResult TestParse(const StringPiece& str, const ConfigDescription& config) { 59cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::stringstream input(kXmlPreamble); 60cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski input << "<resources>\n" << str << "\n</resources>" << std::endl; 61cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ResourceParserOptions parserOptions; 6290919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski ResourceParser parser(context_->GetDiagnostics(), &table_, Source{"test"}, config, 6390919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski parserOptions); 64cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski xml::XmlPullParser xmlParser(input); 65ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (parser.Parse(&xmlParser)) { 66cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return ::testing::AssertionSuccess(); 676f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 68cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return ::testing::AssertionFailure(); 69cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 70ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 71ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski protected: 72ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceTable table_; 73ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::unique_ptr<IAaptContext> context_; 746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}; 756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 766f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseQuotedString) { 77cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = "<string name=\"foo\"> \" hey there \" </string>"; 78ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 796f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 80ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski String* str = test::GetValue<String>(&table_, "string/foo"); 81cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, str); 82cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(std::string(" hey there "), *str->value); 837542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_TRUE(str->untranslatable_sections.empty()); 846f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 866f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseEscapedString) { 87cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = "<string name=\"foo\">\\?123</string>"; 88ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 90ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski String* str = test::GetValue<String>(&table_, "string/foo"); 91cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, str); 92cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(std::string("?123"), *str->value); 937542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_TRUE(str->untranslatable_sections.empty()); 946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 969f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam LesinskiTEST_F(ResourceParserTest, ParseFormattedString) { 97cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = "<string name=\"foo\">%d %s</string>"; 98ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_FALSE(TestParse(input)); 999f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski 100cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski input = "<string name=\"foo\">%1$d %2$s</string>"; 101ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 1029f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski} 1039f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski 1048c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam LesinskiTEST_F(ResourceParserTest, ParseStyledString) { 105cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Use a surrogate pair unicode point so that we can verify that the span 1067542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski // indices use UTF-16 length and not UTF-8 length. 107cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 1088049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski "<string name=\"foo\">This is my aunt\u2019s <b>fickle <small>string</small></b></string>"; 109ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 1108c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski 111ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski StyledString* str = test::GetValue<StyledString>(&table_, "string/foo"); 112cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, str); 1138c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski 1148049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski const std::string expected_str = "This is my aunt\u2019s fickle string"; 115ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(expected_str, *str->value->str); 1168049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski EXPECT_EQ(2u, str->value->spans.size()); 1177542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_TRUE(str->untranslatable_sections.empty()); 1188c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski 119cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(std::string("b"), *str->value->spans[0].name); 120ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(17u, str->value->spans[0].first_char); 1218049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski EXPECT_EQ(30u, str->value->spans[0].last_char); 1228049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski 1238049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski EXPECT_EQ(std::string("small"), *str->value->spans[1].name); 1248049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski EXPECT_EQ(24u, str->value->spans[1].first_char); 1258049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski EXPECT_EQ(30u, str->value->spans[1].last_char); 1268c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski} 1278c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski 1288c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam LesinskiTEST_F(ResourceParserTest, ParseStringWithWhitespace) { 129cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = "<string name=\"foo\"> This is what I think </string>"; 130ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 1318c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski 132ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski String* str = test::GetValue<String>(&table_, "string/foo"); 133cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, str); 134cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(std::string("This is what I think"), *str->value); 1357542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_TRUE(str->untranslatable_sections.empty()); 1368c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski 137cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski input = "<string name=\"foo2\">\" This is what I think \"</string>"; 138ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 1398c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski 140ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str = test::GetValue<String>(&table_, "string/foo2"); 141cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, str); 142cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(std::string(" This is what I think "), *str->value); 1438c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski} 1448c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski 1457542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, IgnoreXliffTagsOtherThanG) { 1467542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski std::string input = R"EOF( 1477542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> 1487542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski There are <xliff:source>no</xliff:source> apples</string>)EOF"; 1497542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski ASSERT_TRUE(TestParse(input)); 1507542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski 1517542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski String* str = test::GetValue<String>(&table_, "string/foo"); 1527542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski ASSERT_NE(nullptr, str); 1537542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_EQ(StringPiece("There are no apples"), StringPiece(*str->value)); 1547542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_TRUE(str->untranslatable_sections.empty()); 1557542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski} 1567542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski 1577542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, NestedXliffGTagsAreIllegal) { 1587542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski std::string input = R"EOF( 1597542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> 1607542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski Do not <xliff:g>translate <xliff:g>this</xliff:g></xliff:g></string>)EOF"; 1617542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_FALSE(TestParse(input)); 1627542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski} 1637542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski 1647542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, RecordUntranslateableXliffSectionsInString) { 1657542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski std::string input = R"EOF( 1667542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> 1677542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski There are <xliff:g id="count">%1$d</xliff:g> apples</string>)EOF"; 168ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 1691ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 170ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski String* str = test::GetValue<String>(&table_, "string/foo"); 171cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, str); 172cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(StringPiece("There are %1$d apples"), StringPiece(*str->value)); 1737542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski 1747542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski ASSERT_EQ(1u, str->untranslatable_sections.size()); 1757542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski 1767542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski // We expect indices and lengths that span to include the whitespace 1777542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski // before %1$d. This is due to how the StringBuilder withholds whitespace unless 1787542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski // needed (to deal with line breaks, etc.). 1797542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_EQ(9u, str->untranslatable_sections[0].start); 1807542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_EQ(14u, str->untranslatable_sections[0].end); 1817542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski} 1827542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski 1837542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, RecordUntranslateableXliffSectionsInStyledString) { 1847542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski std::string input = R"EOF( 1857542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> 1867542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski There are <b><xliff:g id="count">%1$d</xliff:g></b> apples</string>)EOF"; 1877542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski ASSERT_TRUE(TestParse(input)); 1887542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski 1897542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski StyledString* str = test::GetValue<StyledString>(&table_, "string/foo"); 1907542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski ASSERT_NE(nullptr, str); 1917542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_EQ(StringPiece("There are %1$d apples"), StringPiece(*str->value->str)); 1927542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski 1937542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski ASSERT_EQ(1u, str->untranslatable_sections.size()); 1947542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski 1957542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski // We expect indices and lengths that span to include the whitespace 1967542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski // before %1$d. This is due to how the StringBuilder withholds whitespace unless 1977542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski // needed (to deal with line breaks, etc.). 1987542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_EQ(9u, str->untranslatable_sections[0].start); 1997542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_EQ(14u, str->untranslatable_sections[0].end); 2001ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 2011ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 202dfa5e0705ff82f15e228ba076bc192893bcbe118Adam LesinskiTEST_F(ResourceParserTest, ParseNull) { 203cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = "<integer name=\"foo\">@null</integer>"; 204ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 205cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 206cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // The Android runtime treats a value of android::Res_value::TYPE_NULL as 207cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // a non-existing value, and this causes problems in styles when trying to 2087542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski // resolve an attribute. Null values must be encoded as android::Res_value::TYPE_REFERENCE 209cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // with a data value of 0. 21090919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski Reference* null_ref = test::GetValue<Reference>(&table_, "integer/foo"); 21190919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski ASSERT_THAT(null_ref, NotNull()); 21290919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski EXPECT_FALSE(null_ref->name); 21390919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski EXPECT_FALSE(null_ref->id); 21490919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski EXPECT_EQ(Reference::Type::kResource, null_ref->reference_type); 215dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski} 216dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski 217dfa5e0705ff82f15e228ba076bc192893bcbe118Adam LesinskiTEST_F(ResourceParserTest, ParseEmpty) { 218cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = "<integer name=\"foo\">@empty</integer>"; 219ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 220dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski 22190919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski BinaryPrimitive* integer = test::GetValue<BinaryPrimitive>(&table_, "integer/foo"); 222cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, integer); 223cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(uint16_t(android::Res_value::TYPE_NULL), integer->value.dataType); 224cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(uint32_t(android::Res_value::DATA_NULL_EMPTY), integer->value.data); 225dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski} 226dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski 2276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAttr) { 228cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 229cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<attr name=\"foo\" format=\"string\"/>\n" 230cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<attr name=\"bar\"/>"; 231ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 232cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 233ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo"); 234cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, attr); 235ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_STRING), attr->type_mask); 236cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 237ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski attr = test::GetValue<Attribute>(&table_, "attr/bar"); 238cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, attr); 239ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_ANY), attr->type_mask); 240cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski} 241cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 242cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski// Old AAPT allowed attributes to be defined under different configurations, but 243cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski// ultimately 244cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski// stored them with the default configuration. Check that we have the same 245cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski// behavior. 24690919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam LesinskiTEST_F(ResourceParserTest, ParseAttrAndDeclareStyleableUnderConfigButRecordAsNoConfig) { 247ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const ConfigDescription watch_config = test::ParseConfigOrDie("watch"); 24890919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski std::string input = R"( 24990919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski <attr name="foo" /> 25090919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski <declare-styleable name="bar"> 25190919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski <attr name="baz" /> 25290919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski </declare-styleable>)"; 253ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input, watch_config)); 25452364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski 25590919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski EXPECT_EQ(nullptr, test::GetValueForConfig<Attribute>(&table_, "attr/foo", watch_config)); 25690919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski EXPECT_EQ(nullptr, test::GetValueForConfig<Attribute>(&table_, "attr/baz", watch_config)); 25790919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski EXPECT_EQ(nullptr, test::GetValueForConfig<Styleable>(&table_, "styleable/bar", watch_config)); 25852364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski 259ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_NE(nullptr, test::GetValue<Attribute>(&table_, "attr/foo")); 260ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_NE(nullptr, test::GetValue<Attribute>(&table_, "attr/baz")); 261ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_NE(nullptr, test::GetValue<Styleable>(&table_, "styleable/bar")); 26252364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski} 26352364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski 264a587065721053ad54e34f484868142407d59512dAdam LesinskiTEST_F(ResourceParserTest, ParseAttrWithMinMax) { 265cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 266cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<attr name=\"foo\" min=\"10\" max=\"23\" format=\"integer\"/>"; 267ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 268a587065721053ad54e34f484868142407d59512dAdam Lesinski 269ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo"); 270cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, attr); 271ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_INTEGER), attr->type_mask); 272ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(10, attr->min_int); 273ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(23, attr->max_int); 274a587065721053ad54e34f484868142407d59512dAdam Lesinski} 275a587065721053ad54e34f484868142407d59512dAdam Lesinski 276a587065721053ad54e34f484868142407d59512dAdam LesinskiTEST_F(ResourceParserTest, FailParseAttrWithMinMaxButNotInteger) { 277cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 278cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<attr name=\"foo\" min=\"10\" max=\"23\" format=\"string\"/>"; 279ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_FALSE(TestParse(input)); 280a587065721053ad54e34f484868142407d59512dAdam Lesinski} 281a587065721053ad54e34f484868142407d59512dAdam Lesinski 2826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseUseAndDeclOfAttr) { 283cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 284cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<declare-styleable name=\"Styleable\">\n" 285cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <attr name=\"foo\" />\n" 286cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</declare-styleable>\n" 287cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<attr name=\"foo\" format=\"string\"/>"; 288ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 2896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 290ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo"); 291cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, attr); 292ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_STRING), attr->type_mask); 2936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 2946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseDoubleUseOfAttr) { 296cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 297cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<declare-styleable name=\"Theme\">" 298cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <attr name=\"foo\" />\n" 299cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</declare-styleable>\n" 300cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<declare-styleable name=\"Window\">\n" 301cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <attr name=\"foo\" format=\"boolean\"/>\n" 302cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</declare-styleable>"; 303ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 3046f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 305ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo"); 306cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, attr); 307ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_BOOLEAN), attr->type_mask); 3086f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 3096f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseEnumAttr) { 311cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 312cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<attr name=\"foo\">\n" 313cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <enum name=\"bar\" value=\"0\"/>\n" 314cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <enum name=\"bat\" value=\"1\"/>\n" 315cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <enum name=\"baz\" value=\"2\"/>\n" 316cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</attr>"; 317ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 3186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 319ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Attribute* enum_attr = test::GetValue<Attribute>(&table_, "attr/foo"); 320ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_NE(enum_attr, nullptr); 321ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(enum_attr->type_mask, android::ResTable_map::TYPE_ENUM); 322ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_EQ(enum_attr->symbols.size(), 3u); 3236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 324ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski AAPT_ASSERT_TRUE(enum_attr->symbols[0].symbol.name); 325ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(enum_attr->symbols[0].symbol.name.value().entry, "bar"); 326ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(enum_attr->symbols[0].value, 0u); 3276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 328ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski AAPT_ASSERT_TRUE(enum_attr->symbols[1].symbol.name); 329ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(enum_attr->symbols[1].symbol.name.value().entry, "bat"); 330ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(enum_attr->symbols[1].value, 1u); 3316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 332ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski AAPT_ASSERT_TRUE(enum_attr->symbols[2].symbol.name); 333ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(enum_attr->symbols[2].symbol.name.value().entry, "baz"); 334ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(enum_attr->symbols[2].value, 2u); 3356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 3366f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3376f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseFlagAttr) { 338cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 339cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<attr name=\"foo\">\n" 340cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <flag name=\"bar\" value=\"0\"/>\n" 341cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <flag name=\"bat\" value=\"1\"/>\n" 342cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <flag name=\"baz\" value=\"2\"/>\n" 343cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</attr>"; 344ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 3456f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 346ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Attribute* flag_attr = test::GetValue<Attribute>(&table_, "attr/foo"); 347ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_NE(nullptr, flag_attr); 348ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(flag_attr->type_mask, android::ResTable_map::TYPE_FLAGS); 349ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_EQ(flag_attr->symbols.size(), 3u); 3506f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 351ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski AAPT_ASSERT_TRUE(flag_attr->symbols[0].symbol.name); 352ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(flag_attr->symbols[0].symbol.name.value().entry, "bar"); 353ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(flag_attr->symbols[0].value, 0u); 3546f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 355ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski AAPT_ASSERT_TRUE(flag_attr->symbols[1].symbol.name); 356ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(flag_attr->symbols[1].symbol.name.value().entry, "bat"); 357ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(flag_attr->symbols[1].value, 1u); 3586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 359ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski AAPT_ASSERT_TRUE(flag_attr->symbols[2].symbol.name); 360ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(flag_attr->symbols[2].symbol.name.value().entry, "baz"); 361ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(flag_attr->symbols[2].value, 2u); 3626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 363ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::unique_ptr<BinaryPrimitive> flag_value = 364ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceUtils::TryParseFlagSymbol(flag_attr, "baz|bat"); 365ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_NE(nullptr, flag_value); 366ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(flag_value->value.data, 1u | 2u); 3676f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 3686f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, FailToParseEnumAttrWithNonUniqueKeys) { 370cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 371cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<attr name=\"foo\">\n" 372cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <enum name=\"bar\" value=\"0\"/>\n" 373cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <enum name=\"bat\" value=\"1\"/>\n" 374cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <enum name=\"bat\" value=\"2\"/>\n" 375cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</attr>"; 376ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_FALSE(TestParse(input)); 3776f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 3786f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3796f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseStyle) { 380cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 381cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<style name=\"foo\" parent=\"@style/fu\">\n" 382cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <item name=\"bar\">#ffffffff</item>\n" 383cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <item name=\"bat\">@string/hey</item>\n" 384cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <item name=\"baz\"><b>hey</b></item>\n" 385cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</style>"; 386ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 387cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 388ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Style* style = test::GetValue<Style>(&table_, "style/foo"); 389cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, style); 390cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(style->parent); 391cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(style->parent.value().name); 392ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(test::ParseNameOrDie("style/fu"), 393cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski style->parent.value().name.value()); 394cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_EQ(3u, style->entries.size()); 395cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 396cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(style->entries[0].key.name); 397ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(test::ParseNameOrDie("attr/bar"), 398cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski style->entries[0].key.name.value()); 399cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 400cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(style->entries[1].key.name); 401ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(test::ParseNameOrDie("attr/bat"), 402cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski style->entries[1].key.name.value()); 403cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 404cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(style->entries[2].key.name); 405ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(test::ParseNameOrDie("attr/baz"), 406cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski style->entries[2].key.name.value()); 4076f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 4086f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 409769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithShorthandParent) { 410cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = "<style name=\"foo\" parent=\"com.app:Theme\"/>"; 411ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 412769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski 413ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Style* style = test::GetValue<Style>(&table_, "style/foo"); 414cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, style); 415cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(style->parent); 416cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(style->parent.value().name); 417ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(test::ParseNameOrDie("com.app:style/Theme"), 418cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski style->parent.value().name.value()); 419769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski} 420769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski 42124aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPackageAliasedParent) { 422cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 423cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<style xmlns:app=\"http://schemas.android.com/apk/res/android\"\n" 424cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " name=\"foo\" parent=\"app:Theme\"/>"; 425ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 42624aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski 427ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Style* style = test::GetValue<Style>(&table_, "style/foo"); 428cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, style); 429cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(style->parent); 430cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(style->parent.value().name); 431ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(test::ParseNameOrDie("android:style/Theme"), 432cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski style->parent.value().name.value()); 43324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski} 43424aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski 43524aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPackageAliasedItems) { 436cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 437cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<style xmlns:app=\"http://schemas.android.com/apk/res/android\" " 438cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "name=\"foo\">\n" 439cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <item name=\"app:bar\">0</item>\n" 440cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</style>"; 441ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 44224aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski 443ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Style* style = test::GetValue<Style>(&table_, "style/foo"); 444cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, style); 445cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_EQ(1u, style->entries.size()); 446ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(test::ParseNameOrDie("android:attr/bar"), 447cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski style->entries[0].key.name.value()); 44824aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski} 44924aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski 450bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithInferredParent) { 451cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = "<style name=\"foo.bar\"/>"; 452ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 453bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski 454ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Style* style = test::GetValue<Style>(&table_, "style/foo.bar"); 455cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, style); 456cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(style->parent); 457cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(style->parent.value().name); 458cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(style->parent.value().name.value(), 459ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski test::ParseNameOrDie("style/foo")); 460ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_TRUE(style->parent_inferred); 461bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski} 462bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski 463cacb28f2d60858106e2819cc7d95a65e8bda890bAdam LesinskiTEST_F(ResourceParserTest, 464cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ParseStyleWithInferredParentOverridenByEmptyParentAttribute) { 465cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = "<style name=\"foo.bar\" parent=\"\"/>"; 466ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 467bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski 468ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Style* style = test::GetValue<Style>(&table_, "style/foo.bar"); 469cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, style); 470cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_EXPECT_FALSE(style->parent); 471ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_FALSE(style->parent_inferred); 472bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski} 473bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski 47424b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPrivateParentReference) { 475cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 476cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski R"EOF(<style name="foo" parent="*android:style/bar" />)EOF"; 477ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 47824b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski 479ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Style* style = test::GetValue<Style>(&table_, "style/foo"); 480cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, style); 481cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(style->parent); 482ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_TRUE(style->parent.value().private_reference); 48324b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski} 48424b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski 4856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAutoGeneratedIdReference) { 486cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = "<string name=\"foo\">@+id/bar</string>"; 487ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 4886f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 489ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Id* id = test::GetValue<Id>(&table_, "id/bar"); 490cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(id, nullptr); 4916f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 4926f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 4936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAttributesDeclareStyleable) { 494cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 495cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<declare-styleable name=\"foo\">\n" 496cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <attr name=\"bar\" />\n" 497cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <attr name=\"bat\" format=\"string|reference\"/>\n" 498cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <attr name=\"baz\">\n" 499cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <enum name=\"foo\" value=\"1\"/>\n" 500cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " </attr>\n" 501cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</declare-styleable>"; 502ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 503cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 504cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski Maybe<ResourceTable::SearchResult> result = 505ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski table_.FindResource(test::ParseNameOrDie("styleable/foo")); 506cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(result); 507ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(SymbolState::kPublic, result.value().entry->symbol_status.state); 508cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 509ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Attribute* attr = test::GetValue<Attribute>(&table_, "attr/bar"); 510cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(attr, nullptr); 511ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_TRUE(attr->IsWeak()); 512cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 513ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski attr = test::GetValue<Attribute>(&table_, "attr/bat"); 514cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(attr, nullptr); 515ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_TRUE(attr->IsWeak()); 516cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 517ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski attr = test::GetValue<Attribute>(&table_, "attr/baz"); 518cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(attr, nullptr); 519ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_TRUE(attr->IsWeak()); 520cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(1u, attr->symbols.size()); 521cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 522ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_NE(nullptr, test::GetValue<Id>(&table_, "id/foo")); 523cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 524ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo"); 525cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(styleable, nullptr); 526cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_EQ(3u, styleable->entries.size()); 527cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 528ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(test::ParseNameOrDie("attr/bar"), 529cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski styleable->entries[0].name.value()); 530ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(test::ParseNameOrDie("attr/bat"), 531cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski styleable->entries[1].name.value()); 5326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 5336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 534467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam LesinskiTEST_F(ResourceParserTest, ParsePrivateAttributesDeclareStyleable) { 535cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 536cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<declare-styleable name=\"foo\" " 537cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "xmlns:privAndroid=\"http://schemas.android.com/apk/prv/res/android\">\n" 538cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <attr name=\"*android:bar\" />\n" 539cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <attr name=\"privAndroid:bat\" />\n" 540cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</declare-styleable>"; 541ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 542ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo"); 543cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, styleable); 544cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_EQ(2u, styleable->entries.size()); 545cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 546ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_TRUE(styleable->entries[0].private_reference); 547cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(styleable->entries[0].name); 548cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(std::string("android"), styleable->entries[0].name.value().package); 549cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 550ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_TRUE(styleable->entries[1].private_reference); 551cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(styleable->entries[1].name); 552cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(std::string("android"), styleable->entries[1].name.value().package); 553467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski} 554467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski 5556f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseArray) { 556cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 557cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<array name=\"foo\">\n" 558cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <item>@string/ref</item>\n" 559cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <item>hey</item>\n" 560cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <item>23</item>\n" 561cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</array>"; 562ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 5636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 564ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Array* array = test::GetValue<Array>(&table_, "array/foo"); 565cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(array, nullptr); 566cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_EQ(3u, array->items.size()); 5676f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 568ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_NE(nullptr, ValueCast<Reference>(array->items[0].get())); 569ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_NE(nullptr, ValueCast<String>(array->items[1].get())); 570ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_NE(nullptr, ValueCast<BinaryPrimitive>(array->items[2].get())); 5716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 5726f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 5739ba47d813075fcb05c5e1532c137c93b394631cbAdam LesinskiTEST_F(ResourceParserTest, ParseStringArray) { 574d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski std::string input = R"EOF( 575d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski <string-array name="foo"> 576d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski <item>"Werk"</item>" 577d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski </string-array>)EOF"; 578ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 579ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_NE(nullptr, test::GetValue<Array>(&table_, "array/foo")); 5809ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski} 5819ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski 582d5fd76a2ff78400505ade936fc36e707d69ecf72Adam LesinskiTEST_F(ResourceParserTest, ParseArrayWithFormat) { 583d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski std::string input = R"EOF( 584d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski <array name="foo" format="string"> 585d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski <item>100</item> 586d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski </array>)EOF"; 587d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski ASSERT_TRUE(TestParse(input)); 588d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski 589d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski Array* array = test::GetValue<Array>(&table_, "array/foo"); 590d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski ASSERT_NE(nullptr, array); 591d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski 592d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski ASSERT_EQ(1u, array->items.size()); 593d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski 594d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski String* str = ValueCast<String>(array->items[0].get()); 595d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski ASSERT_NE(nullptr, str); 596d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski EXPECT_EQ(std::string("100"), *str->value); 597d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski} 598d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski 599d5fd76a2ff78400505ade936fc36e707d69ecf72Adam LesinskiTEST_F(ResourceParserTest, ParseArrayWithBadFormat) { 600d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski std::string input = R"EOF( 601d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski <array name="foo" format="integer"> 602d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski <item>Hi</item> 603d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski </array>)EOF"; 604d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski ASSERT_FALSE(TestParse(input)); 605d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski} 606d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski 6076f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParsePlural) { 608cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 609cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<plurals name=\"foo\">\n" 610cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <item quantity=\"other\">apples</item>\n" 611cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <item quantity=\"one\">apple</item>\n" 612cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</plurals>"; 613ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 6148f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski 6158f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski Plural* plural = test::GetValue<Plural>(&table_, "plurals/foo"); 6168f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski ASSERT_NE(nullptr, plural); 6178f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski EXPECT_EQ(nullptr, plural->values[Plural::Zero]); 6188f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski EXPECT_EQ(nullptr, plural->values[Plural::Two]); 6198f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski EXPECT_EQ(nullptr, plural->values[Plural::Few]); 6208f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski EXPECT_EQ(nullptr, plural->values[Plural::Many]); 6218f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski 6228f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski EXPECT_NE(nullptr, plural->values[Plural::One]); 6238f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski EXPECT_NE(nullptr, plural->values[Plural::Other]); 6246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 6256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 6266f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseCommentsWithResource) { 627cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 628cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<!--This is a comment-->\n" 629cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<string name=\"foo\">Hi</string>"; 630ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 6316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 632ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski String* value = test::GetValue<String>(&table_, "string/foo"); 633cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, value); 634ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(value->GetComment(), "This is a comment"); 635e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski} 636e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski 637e78fd617ec60139a973a01925fa7adad31febb39Adam LesinskiTEST_F(ResourceParserTest, DoNotCombineMultipleComments) { 638cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 639cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<!--One-->\n" 640cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<!--Two-->\n" 641cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<string name=\"foo\">Hi</string>"; 642e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski 643ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 644e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski 645ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski String* value = test::GetValue<String>(&table_, "string/foo"); 646cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, value); 647ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(value->GetComment(), "Two"); 648e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski} 649e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski 650e78fd617ec60139a973a01925fa7adad31febb39Adam LesinskiTEST_F(ResourceParserTest, IgnoreCommentBeforeEndTag) { 651cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 652cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<!--One-->\n" 653cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<string name=\"foo\">\n" 654cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " Hi\n" 655cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<!--Two-->\n" 656cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</string>"; 657e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski 658ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 6591ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 660ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski String* value = test::GetValue<String>(&table_, "string/foo"); 661cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, value); 662ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(value->GetComment(), "One"); 6636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 6646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 665ca5638fd85098c3d0a699492751043545f75553aAdam LesinskiTEST_F(ResourceParserTest, ParseNestedComments) { 666cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // We only care about declare-styleable and enum/flag attributes because 667cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // comments 668cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // from those end up in R.java 669cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = R"EOF( 670ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski <declare-styleable name="foo"> 671ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski <!-- The name of the bar --> 672ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski <attr name="barName" format="string|reference" /> 673ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski </declare-styleable> 674ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski 675ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski <attr name="foo"> 676ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski <!-- The very first --> 677ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski <enum name="one" value="1" /> 678ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski </attr>)EOF"; 679ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 680ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski 681ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo"); 682cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, styleable); 683cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_EQ(1u, styleable->entries.size()); 684ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski 685cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(StringPiece("The name of the bar"), 686ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski styleable->entries.front().GetComment()); 687ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski 688ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo"); 689cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, attr); 690cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_EQ(1u, attr->symbols.size()); 691ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski 692cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(StringPiece("The very first"), 693ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski attr->symbols.front().symbol.GetComment()); 694ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski} 695ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski 6966f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/* 6976f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Declaring an ID as public should not require a separate definition 6986f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * (as an ID has no value). 6996f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */ 7006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParsePublicIdAsDefinition) { 701cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = "<public type=\"id\" name=\"foo\"/>"; 702ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 7036f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 704ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Id* id = test::GetValue<Id>(&table_, "id/foo"); 705cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, id); 7066f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 7076f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 708e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam LesinskiTEST_F(ResourceParserTest, KeepAllProducts) { 709cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = R"EOF( 7107751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski <string name="foo" product="phone">hi</string> 7117751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski <string name="foo" product="no-sdcard">ho</string> 7127751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski <string name="bar" product="">wee</string> 7137751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski <string name="baz">woo</string> 7147751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski <string name="bit" product="phablet">hoot</string> 7157751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski <string name="bot" product="default">yes</string> 7167751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski )EOF"; 717ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 718ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 719ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<String>( 720ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski &table_, "string/foo", 721ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ConfigDescription::DefaultConfig(), "phone")); 722ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<String>( 723ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski &table_, "string/foo", 724ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ConfigDescription::DefaultConfig(), "no-sdcard")); 725cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_NE(nullptr, 726ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski test::GetValueForConfigAndProduct<String>( 727ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski &table_, "string/bar", ConfigDescription::DefaultConfig(), "")); 728cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_NE(nullptr, 729ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski test::GetValueForConfigAndProduct<String>( 730ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski &table_, "string/baz", ConfigDescription::DefaultConfig(), "")); 731ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<String>( 732ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski &table_, "string/bit", 733ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ConfigDescription::DefaultConfig(), "phablet")); 734ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<String>( 735ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski &table_, "string/bot", 736ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ConfigDescription::DefaultConfig(), "default")); 7379ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski} 7389ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski 73927afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam LesinskiTEST_F(ResourceParserTest, AutoIncrementIdsInPublicGroup) { 740cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = R"EOF( 74127afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski <public-group type="attr" first-id="0x01010040"> 74227afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski <public name="foo" /> 74327afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski <public name="bar" /> 74427afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski </public-group>)EOF"; 745ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 746cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 747cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski Maybe<ResourceTable::SearchResult> result = 748ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski table_.FindResource(test::ParseNameOrDie("attr/foo")); 749cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(result); 750cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 751cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(result.value().package->id); 752cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(result.value().type->id); 753cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(result.value().entry->id); 754ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceId actual_id(result.value().package->id.value(), 755ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski result.value().type->id.value(), 756ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski result.value().entry->id.value()); 757ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(ResourceId(0x01010040), actual_id); 758cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 759ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski result = table_.FindResource(test::ParseNameOrDie("attr/bar")); 760cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(result); 761cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 762cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(result.value().package->id); 763cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(result.value().type->id); 764cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(result.value().entry->id); 765ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski actual_id = ResourceId(result.value().package->id.value(), 766ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski result.value().type->id.value(), 767ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski result.value().entry->id.value()); 768ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(ResourceId(0x01010041), actual_id); 76927afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski} 77027afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski 771fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam LesinskiTEST_F(ResourceParserTest, ExternalTypesShouldOnlyBeReferences) { 772cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 773cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski R"EOF(<item type="layout" name="foo">@layout/bar</item>)EOF"; 774ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 775fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski 776cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski input = R"EOF(<item type="layout" name="bar">"this is a string"</item>)EOF"; 777ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_FALSE(TestParse(input)); 778fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski} 779fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski 7804488f1c74a0f7df09f2b201f7caa228d729e8389Adam LesinskiTEST_F(ResourceParserTest, AddResourcesElementShouldAddEntryWithUndefinedSymbol) { 781cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = R"EOF(<add-resource name="bar" type="string" />)EOF"; 782ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 783a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 784cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski Maybe<ResourceTable::SearchResult> result = 785ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski table_.FindResource(test::ParseNameOrDie("string/bar")); 786cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(result); 787cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski const ResourceEntry* entry = result.value().entry; 788cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, entry); 789ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(SymbolState::kUndefined, entry->symbol_status.state); 7904488f1c74a0f7df09f2b201f7caa228d729e8389Adam Lesinski EXPECT_TRUE(entry->symbol_status.allow_new); 791a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski} 792a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 7937ff3ee19f4b831a526baf4b928d1ac172d070d82Adam LesinskiTEST_F(ResourceParserTest, ParseItemElementWithFormat) { 794e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski std::string input = R"(<item name="foo" type="integer" format="float">0.3</item>)"; 795ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 7967ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 797e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski BinaryPrimitive* val = test::GetValue<BinaryPrimitive>(&table_, "integer/foo"); 798e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski ASSERT_THAT(val, NotNull()); 799e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski EXPECT_THAT(val->value.dataType, Eq(android::Res_value::TYPE_FLOAT)); 800e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski 801e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski input = R"(<item name="bar" type="integer" format="fraction">100</item>)"; 802e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski ASSERT_FALSE(TestParse(input)); 803e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski} 804e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski 805e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski// An <item> without a format specifier accepts all types of values. 806e597d68d33c76c2b830f5497ed4ba74c5193a056Adam LesinskiTEST_F(ResourceParserTest, ParseItemElementWithoutFormat) { 807e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski std::string input = R"(<item name="foo" type="integer">100%p</item>)"; 808e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski ASSERT_TRUE(TestParse(input)); 8097ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 810e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski BinaryPrimitive* val = test::GetValue<BinaryPrimitive>(&table_, "integer/foo"); 811e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski ASSERT_THAT(val, NotNull()); 812e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski EXPECT_THAT(val->value.dataType, Eq(android::Res_value::TYPE_FRACTION)); 8137ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski} 8147ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 81586d67df8d57b9537666f9b54a9ca563779a2288bAdam LesinskiTEST_F(ResourceParserTest, ParseConfigVaryingItem) { 81686d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski std::string input = R"EOF(<item name="foo" type="configVarying">Hey</item>)EOF"; 81786d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski ASSERT_TRUE(TestParse(input)); 81886d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski ASSERT_NE(nullptr, test::GetValue<String>(&table_, "configVarying/foo")); 81986d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski} 82086d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski 82186d67df8d57b9537666f9b54a9ca563779a2288bAdam LesinskiTEST_F(ResourceParserTest, ParseBagElement) { 82286d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski std::string input = 82386d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski R"EOF(<bag name="bag" type="configVarying"><item name="test">Hello!</item></bag>)EOF"; 82486d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski ASSERT_TRUE(TestParse(input)); 82586d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski 82686d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski Style* val = test::GetValue<Style>(&table_, "configVarying/bag"); 82786d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski ASSERT_NE(nullptr, val); 82886d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski 82986d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski ASSERT_EQ(1u, val->entries.size()); 83086d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski EXPECT_EQ(Reference(test::ParseNameOrDie("attr/test")), val->entries[0].key); 83186d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski EXPECT_NE(nullptr, ValueCast<RawString>(val->entries[0].value.get())); 83286d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski} 83386d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski 83490919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam LesinskiTEST_F(ResourceParserTest, ParseElementWithNoValue) { 83590919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski std::string input = R"( 83690919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski <item type="drawable" format="reference" name="foo" /> 83790919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski <string name="foo" />)"; 83890919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski ASSERT_TRUE(TestParse(input)); 83990919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski ASSERT_THAT(test::GetValue(&table_, "drawable/foo"), Pointee(ValueEq(Reference()))); 84090919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski 84190919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski String* str = test::GetValue<String>(&table_, "string/foo"); 84290919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski ASSERT_THAT(str, NotNull()); 84390919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski EXPECT_THAT(*str->value, Eq("")); 84490919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski} 84590919978e7ccf7dc25622e9d039a7e87ebe7ba11Adam Lesinski 846cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski} // namespace aapt 847