ResourceParser_test.cpp revision e597d68d33c76c2b830f5497ed4ba74c5193a056
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 28e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinskiusing ::android::StringPiece; 29e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinskiusing ::testing::Eq; 30e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinskiusing ::testing::NotNull; 31d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski 326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskinamespace aapt { 336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 34cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinskiconstexpr const char* kXmlPreamble = 35cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"; 366f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 371ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiTEST(ResourceParserSingleTest, FailToParseWithNoRootResourcesElement) { 38ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); 39cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::stringstream input(kXmlPreamble); 40cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski input << "<attr name=\"foo\"/>" << std::endl; 41cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ResourceTable table; 42ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceParser parser(context->GetDiagnostics(), &table, Source{"test"}, {}); 43ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski xml::XmlPullParser xml_parser(input); 44ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_FALSE(parser.Parse(&xml_parser)); 45769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski} 46769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski 47ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskiclass ResourceParserTest : public ::testing::Test { 48ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski public: 49ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski void SetUp() override { context_ = test::ContextBuilder().Build(); } 501ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 51ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ::testing::AssertionResult TestParse(const StringPiece& str) { 52ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return TestParse(str, ConfigDescription{}); 53cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 5452364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski 55ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ::testing::AssertionResult TestParse(const StringPiece& str, 56cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski const ConfigDescription& config) { 57cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::stringstream input(kXmlPreamble); 58cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski input << "<resources>\n" << str << "\n</resources>" << std::endl; 59cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ResourceParserOptions parserOptions; 60ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceParser parser(context_->GetDiagnostics(), &table_, Source{"test"}, 61cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski config, parserOptions); 62cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski xml::XmlPullParser xmlParser(input); 63ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (parser.Parse(&xmlParser)) { 64cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return ::testing::AssertionSuccess(); 656f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 66cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return ::testing::AssertionFailure(); 67cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 68ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 69ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski protected: 70ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceTable table_; 71ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::unique_ptr<IAaptContext> context_; 726f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}; 736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseQuotedString) { 75cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = "<string name=\"foo\"> \" hey there \" </string>"; 76ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 776f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 78ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski String* str = test::GetValue<String>(&table_, "string/foo"); 79cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, str); 80cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(std::string(" hey there "), *str->value); 817542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_TRUE(str->untranslatable_sections.empty()); 826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 836f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 846f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseEscapedString) { 85cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = "<string name=\"foo\">\\?123</string>"; 86ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 876f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 88ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski String* str = test::GetValue<String>(&table_, "string/foo"); 89cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, str); 90cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(std::string("?123"), *str->value); 917542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_TRUE(str->untranslatable_sections.empty()); 926f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 949f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam LesinskiTEST_F(ResourceParserTest, ParseFormattedString) { 95cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = "<string name=\"foo\">%d %s</string>"; 96ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_FALSE(TestParse(input)); 979f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski 98cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski input = "<string name=\"foo\">%1$d %2$s</string>"; 99ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 1009f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski} 1019f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski 1028c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam LesinskiTEST_F(ResourceParserTest, ParseStyledString) { 103cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Use a surrogate pair unicode point so that we can verify that the span 1047542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski // indices use UTF-16 length and not UTF-8 length. 105cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 1068049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski "<string name=\"foo\">This is my aunt\u2019s <b>fickle <small>string</small></b></string>"; 107ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 1088c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski 109ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski StyledString* str = test::GetValue<StyledString>(&table_, "string/foo"); 110cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, str); 1118c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski 1128049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski const std::string expected_str = "This is my aunt\u2019s fickle string"; 113ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(expected_str, *str->value->str); 1148049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski EXPECT_EQ(2u, str->value->spans.size()); 1157542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_TRUE(str->untranslatable_sections.empty()); 1168c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski 117cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(std::string("b"), *str->value->spans[0].name); 118ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(17u, str->value->spans[0].first_char); 1198049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski EXPECT_EQ(30u, str->value->spans[0].last_char); 1208049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski 1218049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski EXPECT_EQ(std::string("small"), *str->value->spans[1].name); 1228049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski EXPECT_EQ(24u, str->value->spans[1].first_char); 1238049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski EXPECT_EQ(30u, str->value->spans[1].last_char); 1248c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski} 1258c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski 1268c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam LesinskiTEST_F(ResourceParserTest, ParseStringWithWhitespace) { 127cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = "<string name=\"foo\"> This is what I think </string>"; 128ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 1298c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski 130ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski String* str = test::GetValue<String>(&table_, "string/foo"); 131cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, str); 132cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(std::string("This is what I think"), *str->value); 1337542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_TRUE(str->untranslatable_sections.empty()); 1348c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski 135cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski input = "<string name=\"foo2\">\" This is what I think \"</string>"; 136ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 1378c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski 138ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski str = test::GetValue<String>(&table_, "string/foo2"); 139cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, str); 140cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(std::string(" This is what I think "), *str->value); 1418c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski} 1428c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski 1437542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, IgnoreXliffTagsOtherThanG) { 1447542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski std::string input = R"EOF( 1457542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> 1467542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski There are <xliff:source>no</xliff:source> apples</string>)EOF"; 1477542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski ASSERT_TRUE(TestParse(input)); 1487542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski 1497542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski String* str = test::GetValue<String>(&table_, "string/foo"); 1507542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski ASSERT_NE(nullptr, str); 1517542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_EQ(StringPiece("There are no apples"), StringPiece(*str->value)); 1527542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_TRUE(str->untranslatable_sections.empty()); 1537542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski} 1547542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski 1557542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, NestedXliffGTagsAreIllegal) { 1567542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski std::string input = R"EOF( 1577542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> 1587542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski Do not <xliff:g>translate <xliff:g>this</xliff:g></xliff:g></string>)EOF"; 1597542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_FALSE(TestParse(input)); 1607542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski} 1617542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski 1627542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, RecordUntranslateableXliffSectionsInString) { 1637542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski std::string input = R"EOF( 1647542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> 1657542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski There are <xliff:g id="count">%1$d</xliff:g> apples</string>)EOF"; 166ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 1671ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 168ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski String* str = test::GetValue<String>(&table_, "string/foo"); 169cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, str); 170cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(StringPiece("There are %1$d apples"), StringPiece(*str->value)); 1717542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski 1727542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski ASSERT_EQ(1u, str->untranslatable_sections.size()); 1737542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski 1747542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski // We expect indices and lengths that span to include the whitespace 1757542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski // before %1$d. This is due to how the StringBuilder withholds whitespace unless 1767542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski // needed (to deal with line breaks, etc.). 1777542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_EQ(9u, str->untranslatable_sections[0].start); 1787542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_EQ(14u, str->untranslatable_sections[0].end); 1797542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski} 1807542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski 1817542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, RecordUntranslateableXliffSectionsInStyledString) { 1827542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski std::string input = R"EOF( 1837542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> 1847542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski There are <b><xliff:g id="count">%1$d</xliff:g></b> apples</string>)EOF"; 1857542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski ASSERT_TRUE(TestParse(input)); 1867542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski 1877542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski StyledString* str = test::GetValue<StyledString>(&table_, "string/foo"); 1887542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski ASSERT_NE(nullptr, str); 1897542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_EQ(StringPiece("There are %1$d apples"), StringPiece(*str->value->str)); 1907542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski 1917542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski ASSERT_EQ(1u, str->untranslatable_sections.size()); 1927542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski 1937542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski // We expect indices and lengths that span to include the whitespace 1947542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski // before %1$d. This is due to how the StringBuilder withholds whitespace unless 1957542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski // needed (to deal with line breaks, etc.). 1967542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_EQ(9u, str->untranslatable_sections[0].start); 1977542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_EQ(14u, str->untranslatable_sections[0].end); 1981ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 1991ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 200dfa5e0705ff82f15e228ba076bc192893bcbe118Adam LesinskiTEST_F(ResourceParserTest, ParseNull) { 201cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = "<integer name=\"foo\">@null</integer>"; 202ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 203cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 204cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // The Android runtime treats a value of android::Res_value::TYPE_NULL as 205cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // a non-existing value, and this causes problems in styles when trying to 2067542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski // resolve an attribute. Null values must be encoded as android::Res_value::TYPE_REFERENCE 207cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // with a data value of 0. 2087542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski BinaryPrimitive* integer = test::GetValue<BinaryPrimitive>(&table_, "integer/foo"); 209cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, integer); 2107542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski EXPECT_EQ(uint16_t(android::Res_value::TYPE_REFERENCE), integer->value.dataType); 211cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(0u, integer->value.data); 212dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski} 213dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski 214dfa5e0705ff82f15e228ba076bc192893bcbe118Adam LesinskiTEST_F(ResourceParserTest, ParseEmpty) { 215cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = "<integer name=\"foo\">@empty</integer>"; 216ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 217dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski 218cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski BinaryPrimitive* integer = 219ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski test::GetValue<BinaryPrimitive>(&table_, "integer/foo"); 220cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, integer); 221cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(uint16_t(android::Res_value::TYPE_NULL), integer->value.dataType); 222cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(uint32_t(android::Res_value::DATA_NULL_EMPTY), integer->value.data); 223dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski} 224dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski 2256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAttr) { 226cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 227cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<attr name=\"foo\" format=\"string\"/>\n" 228cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<attr name=\"bar\"/>"; 229ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 230cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 231ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo"); 232cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, attr); 233ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_STRING), attr->type_mask); 234cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 235ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski attr = test::GetValue<Attribute>(&table_, "attr/bar"); 236cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, attr); 237ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_ANY), attr->type_mask); 238cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski} 239cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 240cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski// Old AAPT allowed attributes to be defined under different configurations, but 241cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski// ultimately 242cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski// stored them with the default configuration. Check that we have the same 243cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski// behavior. 244cacb28f2d60858106e2819cc7d95a65e8bda890bAdam LesinskiTEST_F(ResourceParserTest, 245cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ParseAttrAndDeclareStyleableUnderConfigButRecordAsNoConfig) { 246ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const ConfigDescription watch_config = test::ParseConfigOrDie("watch"); 247cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = R"EOF( 24852364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski <attr name="foo" /> 24952364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski <declare-styleable name="bar"> 25052364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski <attr name="baz" /> 25152364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski </declare-styleable>)EOF"; 252ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input, watch_config)); 25352364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski 254ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(nullptr, test::GetValueForConfig<Attribute>(&table_, "attr/foo", 255ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski watch_config)); 256ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(nullptr, test::GetValueForConfig<Attribute>(&table_, "attr/baz", 257ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski watch_config)); 258ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(nullptr, test::GetValueForConfig<Styleable>( 259ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski &table_, "styleable/bar", watch_config)); 26052364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski 261ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_NE(nullptr, test::GetValue<Attribute>(&table_, "attr/foo")); 262ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_NE(nullptr, test::GetValue<Attribute>(&table_, "attr/baz")); 263ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_NE(nullptr, test::GetValue<Styleable>(&table_, "styleable/bar")); 26452364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski} 26552364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski 266a587065721053ad54e34f484868142407d59512dAdam LesinskiTEST_F(ResourceParserTest, ParseAttrWithMinMax) { 267cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 268cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<attr name=\"foo\" min=\"10\" max=\"23\" format=\"integer\"/>"; 269ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 270a587065721053ad54e34f484868142407d59512dAdam Lesinski 271ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo"); 272cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, attr); 273ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_INTEGER), attr->type_mask); 274ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(10, attr->min_int); 275ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(23, attr->max_int); 276a587065721053ad54e34f484868142407d59512dAdam Lesinski} 277a587065721053ad54e34f484868142407d59512dAdam Lesinski 278a587065721053ad54e34f484868142407d59512dAdam LesinskiTEST_F(ResourceParserTest, FailParseAttrWithMinMaxButNotInteger) { 279cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 280cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<attr name=\"foo\" min=\"10\" max=\"23\" format=\"string\"/>"; 281ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_FALSE(TestParse(input)); 282a587065721053ad54e34f484868142407d59512dAdam Lesinski} 283a587065721053ad54e34f484868142407d59512dAdam Lesinski 2846f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseUseAndDeclOfAttr) { 285cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 286cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<declare-styleable name=\"Styleable\">\n" 287cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <attr name=\"foo\" />\n" 288cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</declare-styleable>\n" 289cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<attr name=\"foo\" format=\"string\"/>"; 290ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 2916f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 292ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo"); 293cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, attr); 294ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_STRING), attr->type_mask); 2956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 2966f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2976f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseDoubleUseOfAttr) { 298cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 299cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<declare-styleable name=\"Theme\">" 300cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <attr name=\"foo\" />\n" 301cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</declare-styleable>\n" 302cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<declare-styleable name=\"Window\">\n" 303cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <attr name=\"foo\" format=\"boolean\"/>\n" 304cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</declare-styleable>"; 305ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 3066f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 307ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo"); 308cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, attr); 309ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_BOOLEAN), attr->type_mask); 3106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 3116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseEnumAttr) { 313cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 314cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<attr name=\"foo\">\n" 315cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <enum name=\"bar\" value=\"0\"/>\n" 316cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <enum name=\"bat\" value=\"1\"/>\n" 317cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <enum name=\"baz\" value=\"2\"/>\n" 318cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</attr>"; 319ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 3206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 321ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Attribute* enum_attr = test::GetValue<Attribute>(&table_, "attr/foo"); 322ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_NE(enum_attr, nullptr); 323ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(enum_attr->type_mask, android::ResTable_map::TYPE_ENUM); 324ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_EQ(enum_attr->symbols.size(), 3u); 3256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 326ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski AAPT_ASSERT_TRUE(enum_attr->symbols[0].symbol.name); 327ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(enum_attr->symbols[0].symbol.name.value().entry, "bar"); 328ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(enum_attr->symbols[0].value, 0u); 3296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 330ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski AAPT_ASSERT_TRUE(enum_attr->symbols[1].symbol.name); 331ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(enum_attr->symbols[1].symbol.name.value().entry, "bat"); 332ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(enum_attr->symbols[1].value, 1u); 3336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 334ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski AAPT_ASSERT_TRUE(enum_attr->symbols[2].symbol.name); 335ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(enum_attr->symbols[2].symbol.name.value().entry, "baz"); 336ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(enum_attr->symbols[2].value, 2u); 3376f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 3386f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3396f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseFlagAttr) { 340cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 341cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<attr name=\"foo\">\n" 342cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <flag name=\"bar\" value=\"0\"/>\n" 343cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <flag name=\"bat\" value=\"1\"/>\n" 344cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <flag name=\"baz\" value=\"2\"/>\n" 345cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</attr>"; 346ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 3476f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 348ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Attribute* flag_attr = test::GetValue<Attribute>(&table_, "attr/foo"); 349ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_NE(nullptr, flag_attr); 350ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(flag_attr->type_mask, android::ResTable_map::TYPE_FLAGS); 351ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_EQ(flag_attr->symbols.size(), 3u); 3526f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 353ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski AAPT_ASSERT_TRUE(flag_attr->symbols[0].symbol.name); 354ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(flag_attr->symbols[0].symbol.name.value().entry, "bar"); 355ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(flag_attr->symbols[0].value, 0u); 3566f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 357ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski AAPT_ASSERT_TRUE(flag_attr->symbols[1].symbol.name); 358ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(flag_attr->symbols[1].symbol.name.value().entry, "bat"); 359ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(flag_attr->symbols[1].value, 1u); 3606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 361ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski AAPT_ASSERT_TRUE(flag_attr->symbols[2].symbol.name); 362ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(flag_attr->symbols[2].symbol.name.value().entry, "baz"); 363ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(flag_attr->symbols[2].value, 2u); 3646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 365ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::unique_ptr<BinaryPrimitive> flag_value = 366ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceUtils::TryParseFlagSymbol(flag_attr, "baz|bat"); 367ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_NE(nullptr, flag_value); 368ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(flag_value->value.data, 1u | 2u); 3696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 3706f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, FailToParseEnumAttrWithNonUniqueKeys) { 372cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 373cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<attr name=\"foo\">\n" 374cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <enum name=\"bar\" value=\"0\"/>\n" 375cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <enum name=\"bat\" value=\"1\"/>\n" 376cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <enum name=\"bat\" value=\"2\"/>\n" 377cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</attr>"; 378ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_FALSE(TestParse(input)); 3796f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 3806f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3816f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseStyle) { 382cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 383cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<style name=\"foo\" parent=\"@style/fu\">\n" 384cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <item name=\"bar\">#ffffffff</item>\n" 385cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <item name=\"bat\">@string/hey</item>\n" 386cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <item name=\"baz\"><b>hey</b></item>\n" 387cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</style>"; 388ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 389cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 390ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Style* style = test::GetValue<Style>(&table_, "style/foo"); 391cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, style); 392cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(style->parent); 393cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(style->parent.value().name); 394ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(test::ParseNameOrDie("style/fu"), 395cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski style->parent.value().name.value()); 396cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_EQ(3u, style->entries.size()); 397cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 398cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(style->entries[0].key.name); 399ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(test::ParseNameOrDie("attr/bar"), 400cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski style->entries[0].key.name.value()); 401cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 402cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(style->entries[1].key.name); 403ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(test::ParseNameOrDie("attr/bat"), 404cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski style->entries[1].key.name.value()); 405cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 406cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(style->entries[2].key.name); 407ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(test::ParseNameOrDie("attr/baz"), 408cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski style->entries[2].key.name.value()); 4096f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 4106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 411769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithShorthandParent) { 412cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = "<style name=\"foo\" parent=\"com.app:Theme\"/>"; 413ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 414769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski 415ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Style* style = test::GetValue<Style>(&table_, "style/foo"); 416cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, style); 417cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(style->parent); 418cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(style->parent.value().name); 419ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(test::ParseNameOrDie("com.app:style/Theme"), 420cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski style->parent.value().name.value()); 421769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski} 422769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski 42324aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPackageAliasedParent) { 424cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 425cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<style xmlns:app=\"http://schemas.android.com/apk/res/android\"\n" 426cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " name=\"foo\" parent=\"app:Theme\"/>"; 427ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 42824aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski 429ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Style* style = test::GetValue<Style>(&table_, "style/foo"); 430cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, style); 431cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(style->parent); 432cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(style->parent.value().name); 433ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(test::ParseNameOrDie("android:style/Theme"), 434cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski style->parent.value().name.value()); 43524aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski} 43624aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski 43724aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPackageAliasedItems) { 438cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 439cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<style xmlns:app=\"http://schemas.android.com/apk/res/android\" " 440cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "name=\"foo\">\n" 441cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <item name=\"app:bar\">0</item>\n" 442cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</style>"; 443ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 44424aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski 445ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Style* style = test::GetValue<Style>(&table_, "style/foo"); 446cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, style); 447cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_EQ(1u, style->entries.size()); 448ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(test::ParseNameOrDie("android:attr/bar"), 449cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski style->entries[0].key.name.value()); 45024aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski} 45124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski 452bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithInferredParent) { 453cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = "<style name=\"foo.bar\"/>"; 454ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 455bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski 456ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Style* style = test::GetValue<Style>(&table_, "style/foo.bar"); 457cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, style); 458cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(style->parent); 459cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(style->parent.value().name); 460cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(style->parent.value().name.value(), 461ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski test::ParseNameOrDie("style/foo")); 462ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_TRUE(style->parent_inferred); 463bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski} 464bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski 465cacb28f2d60858106e2819cc7d95a65e8bda890bAdam LesinskiTEST_F(ResourceParserTest, 466cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ParseStyleWithInferredParentOverridenByEmptyParentAttribute) { 467cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = "<style name=\"foo.bar\" parent=\"\"/>"; 468ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 469bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski 470ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Style* style = test::GetValue<Style>(&table_, "style/foo.bar"); 471cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, style); 472cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_EXPECT_FALSE(style->parent); 473ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_FALSE(style->parent_inferred); 474bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski} 475bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski 47624b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPrivateParentReference) { 477cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 478cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski R"EOF(<style name="foo" parent="*android:style/bar" />)EOF"; 479ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 48024b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski 481ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Style* style = test::GetValue<Style>(&table_, "style/foo"); 482cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, style); 483cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(style->parent); 484ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_TRUE(style->parent.value().private_reference); 48524b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski} 48624b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski 4876f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAutoGeneratedIdReference) { 488cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = "<string name=\"foo\">@+id/bar</string>"; 489ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 4906f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 491ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Id* id = test::GetValue<Id>(&table_, "id/bar"); 492cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(id, nullptr); 4936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 4946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 4956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAttributesDeclareStyleable) { 496cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 497cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<declare-styleable name=\"foo\">\n" 498cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <attr name=\"bar\" />\n" 499cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <attr name=\"bat\" format=\"string|reference\"/>\n" 500cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <attr name=\"baz\">\n" 501cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <enum name=\"foo\" value=\"1\"/>\n" 502cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " </attr>\n" 503cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</declare-styleable>"; 504ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 505cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 506cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski Maybe<ResourceTable::SearchResult> result = 507ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski table_.FindResource(test::ParseNameOrDie("styleable/foo")); 508cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(result); 509ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(SymbolState::kPublic, result.value().entry->symbol_status.state); 510cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 511ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Attribute* attr = test::GetValue<Attribute>(&table_, "attr/bar"); 512cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(attr, nullptr); 513ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_TRUE(attr->IsWeak()); 514cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 515ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski attr = test::GetValue<Attribute>(&table_, "attr/bat"); 516cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(attr, nullptr); 517ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_TRUE(attr->IsWeak()); 518cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 519ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski attr = test::GetValue<Attribute>(&table_, "attr/baz"); 520cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(attr, nullptr); 521ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_TRUE(attr->IsWeak()); 522cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(1u, attr->symbols.size()); 523cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 524ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_NE(nullptr, test::GetValue<Id>(&table_, "id/foo")); 525cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 526ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo"); 527cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(styleable, nullptr); 528cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_EQ(3u, styleable->entries.size()); 529cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 530ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(test::ParseNameOrDie("attr/bar"), 531cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski styleable->entries[0].name.value()); 532ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(test::ParseNameOrDie("attr/bat"), 533cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski styleable->entries[1].name.value()); 5346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 5356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 536467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam LesinskiTEST_F(ResourceParserTest, ParsePrivateAttributesDeclareStyleable) { 537cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 538cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<declare-styleable name=\"foo\" " 539cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "xmlns:privAndroid=\"http://schemas.android.com/apk/prv/res/android\">\n" 540cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <attr name=\"*android:bar\" />\n" 541cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <attr name=\"privAndroid:bat\" />\n" 542cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</declare-styleable>"; 543ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 544ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo"); 545cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, styleable); 546cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_EQ(2u, styleable->entries.size()); 547cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 548ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_TRUE(styleable->entries[0].private_reference); 549cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(styleable->entries[0].name); 550cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(std::string("android"), styleable->entries[0].name.value().package); 551cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 552ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_TRUE(styleable->entries[1].private_reference); 553cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(styleable->entries[1].name); 554cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(std::string("android"), styleable->entries[1].name.value().package); 555467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski} 556467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski 5576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseArray) { 558cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 559cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<array name=\"foo\">\n" 560cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <item>@string/ref</item>\n" 561cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <item>hey</item>\n" 562cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <item>23</item>\n" 563cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</array>"; 564ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 5656f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 566ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Array* array = test::GetValue<Array>(&table_, "array/foo"); 567cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(array, nullptr); 568cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_EQ(3u, array->items.size()); 5696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 570ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_NE(nullptr, ValueCast<Reference>(array->items[0].get())); 571ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_NE(nullptr, ValueCast<String>(array->items[1].get())); 572ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_NE(nullptr, ValueCast<BinaryPrimitive>(array->items[2].get())); 5736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 5746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 5759ba47d813075fcb05c5e1532c137c93b394631cbAdam LesinskiTEST_F(ResourceParserTest, ParseStringArray) { 576d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski std::string input = R"EOF( 577d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski <string-array name="foo"> 578d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski <item>"Werk"</item>" 579d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski </string-array>)EOF"; 580ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 581ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_NE(nullptr, test::GetValue<Array>(&table_, "array/foo")); 5829ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski} 5839ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski 584d5fd76a2ff78400505ade936fc36e707d69ecf72Adam LesinskiTEST_F(ResourceParserTest, ParseArrayWithFormat) { 585d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski std::string input = R"EOF( 586d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski <array name="foo" format="string"> 587d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski <item>100</item> 588d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski </array>)EOF"; 589d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski ASSERT_TRUE(TestParse(input)); 590d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski 591d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski Array* array = test::GetValue<Array>(&table_, "array/foo"); 592d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski ASSERT_NE(nullptr, array); 593d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski 594d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski ASSERT_EQ(1u, array->items.size()); 595d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski 596d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski String* str = ValueCast<String>(array->items[0].get()); 597d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski ASSERT_NE(nullptr, str); 598d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski EXPECT_EQ(std::string("100"), *str->value); 599d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski} 600d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski 601d5fd76a2ff78400505ade936fc36e707d69ecf72Adam LesinskiTEST_F(ResourceParserTest, ParseArrayWithBadFormat) { 602d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski std::string input = R"EOF( 603d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski <array name="foo" format="integer"> 604d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski <item>Hi</item> 605d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski </array>)EOF"; 606d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski ASSERT_FALSE(TestParse(input)); 607d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski} 608d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski 6096f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParsePlural) { 610cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 611cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<plurals name=\"foo\">\n" 612cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <item quantity=\"other\">apples</item>\n" 613cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " <item quantity=\"one\">apple</item>\n" 614cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</plurals>"; 615ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 6168f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski 6178f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski Plural* plural = test::GetValue<Plural>(&table_, "plurals/foo"); 6188f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski ASSERT_NE(nullptr, plural); 6198f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski EXPECT_EQ(nullptr, plural->values[Plural::Zero]); 6208f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski EXPECT_EQ(nullptr, plural->values[Plural::Two]); 6218f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski EXPECT_EQ(nullptr, plural->values[Plural::Few]); 6228f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski EXPECT_EQ(nullptr, plural->values[Plural::Many]); 6238f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski 6248f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski EXPECT_NE(nullptr, plural->values[Plural::One]); 6258f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski EXPECT_NE(nullptr, plural->values[Plural::Other]); 6266f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 6276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 6286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseCommentsWithResource) { 629cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 630cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<!--This is a comment-->\n" 631cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<string name=\"foo\">Hi</string>"; 632ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 6336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 634ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski String* value = test::GetValue<String>(&table_, "string/foo"); 635cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, value); 636ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(value->GetComment(), "This is a comment"); 637e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski} 638e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski 639e78fd617ec60139a973a01925fa7adad31febb39Adam LesinskiTEST_F(ResourceParserTest, DoNotCombineMultipleComments) { 640cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 641cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<!--One-->\n" 642cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<!--Two-->\n" 643cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<string name=\"foo\">Hi</string>"; 644e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski 645ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 646e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski 647ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski String* value = test::GetValue<String>(&table_, "string/foo"); 648cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, value); 649ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(value->GetComment(), "Two"); 650e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski} 651e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski 652e78fd617ec60139a973a01925fa7adad31febb39Adam LesinskiTEST_F(ResourceParserTest, IgnoreCommentBeforeEndTag) { 653cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 654cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<!--One-->\n" 655cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<string name=\"foo\">\n" 656cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski " Hi\n" 657cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "<!--Two-->\n" 658cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski "</string>"; 659e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski 660ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 6611ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 662ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski String* value = test::GetValue<String>(&table_, "string/foo"); 663cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, value); 664ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(value->GetComment(), "One"); 6656f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 6666f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 667ca5638fd85098c3d0a699492751043545f75553aAdam LesinskiTEST_F(ResourceParserTest, ParseNestedComments) { 668cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // We only care about declare-styleable and enum/flag attributes because 669cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // comments 670cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // from those end up in R.java 671cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = R"EOF( 672ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski <declare-styleable name="foo"> 673ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski <!-- The name of the bar --> 674ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski <attr name="barName" format="string|reference" /> 675ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski </declare-styleable> 676ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski 677ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski <attr name="foo"> 678ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski <!-- The very first --> 679ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski <enum name="one" value="1" /> 680ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski </attr>)EOF"; 681ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 682ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski 683ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo"); 684cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, styleable); 685cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_EQ(1u, styleable->entries.size()); 686ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski 687cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(StringPiece("The name of the bar"), 688ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski styleable->entries.front().GetComment()); 689ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski 690ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo"); 691cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, attr); 692cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_EQ(1u, attr->symbols.size()); 693ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski 694cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_EQ(StringPiece("The very first"), 695ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski attr->symbols.front().symbol.GetComment()); 696ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski} 697ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski 6986f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/* 6996f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Declaring an ID as public should not require a separate definition 7006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * (as an ID has no value). 7016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */ 7026f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParsePublicIdAsDefinition) { 703cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = "<public type=\"id\" name=\"foo\"/>"; 704ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 7056f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 706ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Id* id = test::GetValue<Id>(&table_, "id/foo"); 707cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, id); 7086f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 7096f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 710e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam LesinskiTEST_F(ResourceParserTest, KeepAllProducts) { 711cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = R"EOF( 7127751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski <string name="foo" product="phone">hi</string> 7137751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski <string name="foo" product="no-sdcard">ho</string> 7147751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski <string name="bar" product="">wee</string> 7157751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski <string name="baz">woo</string> 7167751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski <string name="bit" product="phablet">hoot</string> 7177751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski <string name="bot" product="default">yes</string> 7187751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski )EOF"; 719ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 720ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 721ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<String>( 722ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski &table_, "string/foo", 723ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ConfigDescription::DefaultConfig(), "phone")); 724ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<String>( 725ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski &table_, "string/foo", 726ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ConfigDescription::DefaultConfig(), "no-sdcard")); 727cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_NE(nullptr, 728ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski test::GetValueForConfigAndProduct<String>( 729ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski &table_, "string/bar", ConfigDescription::DefaultConfig(), "")); 730cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski EXPECT_NE(nullptr, 731ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski test::GetValueForConfigAndProduct<String>( 732ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski &table_, "string/baz", ConfigDescription::DefaultConfig(), "")); 733ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<String>( 734ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski &table_, "string/bit", 735ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ConfigDescription::DefaultConfig(), "phablet")); 736ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<String>( 737ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski &table_, "string/bot", 738ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ConfigDescription::DefaultConfig(), "default")); 7399ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski} 7409ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski 74127afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam LesinskiTEST_F(ResourceParserTest, AutoIncrementIdsInPublicGroup) { 742cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = R"EOF( 74327afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski <public-group type="attr" first-id="0x01010040"> 74427afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski <public name="foo" /> 74527afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski <public name="bar" /> 74627afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski </public-group>)EOF"; 747ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 748cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 749cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski Maybe<ResourceTable::SearchResult> result = 750ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski table_.FindResource(test::ParseNameOrDie("attr/foo")); 751cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(result); 752cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 753cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(result.value().package->id); 754cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(result.value().type->id); 755cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(result.value().entry->id); 756ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceId actual_id(result.value().package->id.value(), 757ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski result.value().type->id.value(), 758ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski result.value().entry->id.value()); 759ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(ResourceId(0x01010040), actual_id); 760cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 761ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski result = table_.FindResource(test::ParseNameOrDie("attr/bar")); 762cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(result); 763cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 764cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(result.value().package->id); 765cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(result.value().type->id); 766cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(result.value().entry->id); 767ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski actual_id = ResourceId(result.value().package->id.value(), 768ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski result.value().type->id.value(), 769ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski result.value().entry->id.value()); 770ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(ResourceId(0x01010041), actual_id); 77127afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski} 77227afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski 773fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam LesinskiTEST_F(ResourceParserTest, ExternalTypesShouldOnlyBeReferences) { 774cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = 775cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski R"EOF(<item type="layout" name="foo">@layout/bar</item>)EOF"; 776ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 777fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski 778cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski input = R"EOF(<item type="layout" name="bar">"this is a string"</item>)EOF"; 779ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_FALSE(TestParse(input)); 780fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski} 781fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski 7824488f1c74a0f7df09f2b201f7caa228d729e8389Adam LesinskiTEST_F(ResourceParserTest, AddResourcesElementShouldAddEntryWithUndefinedSymbol) { 783cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string input = R"EOF(<add-resource name="bar" type="string" />)EOF"; 784ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 785a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 786cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski Maybe<ResourceTable::SearchResult> result = 787ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski table_.FindResource(test::ParseNameOrDie("string/bar")); 788cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski AAPT_ASSERT_TRUE(result); 789cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski const ResourceEntry* entry = result.value().entry; 790cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ASSERT_NE(nullptr, entry); 791ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski EXPECT_EQ(SymbolState::kUndefined, entry->symbol_status.state); 7924488f1c74a0f7df09f2b201f7caa228d729e8389Adam Lesinski EXPECT_TRUE(entry->symbol_status.allow_new); 793a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski} 794a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 7957ff3ee19f4b831a526baf4b928d1ac172d070d82Adam LesinskiTEST_F(ResourceParserTest, ParseItemElementWithFormat) { 796e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski std::string input = R"(<item name="foo" type="integer" format="float">0.3</item>)"; 797ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ASSERT_TRUE(TestParse(input)); 7987ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 799e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski BinaryPrimitive* val = test::GetValue<BinaryPrimitive>(&table_, "integer/foo"); 800e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski ASSERT_THAT(val, NotNull()); 801e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski EXPECT_THAT(val->value.dataType, Eq(android::Res_value::TYPE_FLOAT)); 802e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski 803e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski input = R"(<item name="bar" type="integer" format="fraction">100</item>)"; 804e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski ASSERT_FALSE(TestParse(input)); 805e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski} 806e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski 807e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski// An <item> without a format specifier accepts all types of values. 808e597d68d33c76c2b830f5497ed4ba74c5193a056Adam LesinskiTEST_F(ResourceParserTest, ParseItemElementWithoutFormat) { 809e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski std::string input = R"(<item name="foo" type="integer">100%p</item>)"; 810e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski ASSERT_TRUE(TestParse(input)); 8117ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 812e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski BinaryPrimitive* val = test::GetValue<BinaryPrimitive>(&table_, "integer/foo"); 813e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski ASSERT_THAT(val, NotNull()); 814e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski EXPECT_THAT(val->value.dataType, Eq(android::Res_value::TYPE_FRACTION)); 8157ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski} 8167ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 81786d67df8d57b9537666f9b54a9ca563779a2288bAdam LesinskiTEST_F(ResourceParserTest, ParseConfigVaryingItem) { 81886d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski std::string input = R"EOF(<item name="foo" type="configVarying">Hey</item>)EOF"; 81986d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski ASSERT_TRUE(TestParse(input)); 82086d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski ASSERT_NE(nullptr, test::GetValue<String>(&table_, "configVarying/foo")); 82186d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski} 82286d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski 82386d67df8d57b9537666f9b54a9ca563779a2288bAdam LesinskiTEST_F(ResourceParserTest, ParseBagElement) { 82486d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski std::string input = 82586d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski R"EOF(<bag name="bag" type="configVarying"><item name="test">Hello!</item></bag>)EOF"; 82686d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski ASSERT_TRUE(TestParse(input)); 82786d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski 82886d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski Style* val = test::GetValue<Style>(&table_, "configVarying/bag"); 82986d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski ASSERT_NE(nullptr, val); 83086d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski 83186d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski ASSERT_EQ(1u, val->entries.size()); 83286d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski EXPECT_EQ(Reference(test::ParseNameOrDie("attr/test")), val->entries[0].key); 83386d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski EXPECT_NE(nullptr, ValueCast<RawString>(val->entries[0].value.get())); 83486d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski} 83586d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski 836cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski} // namespace aapt 837