ResourceParser_test.cpp revision 549e437e14f3b92f02bd3abc7d1cd68387132ce1
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
28a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinskiusing ::aapt::test::StrValueEq;
29bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinskiusing ::aapt::test::ValueEq;
30a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinskiusing ::android::ResTable_map;
31a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinskiusing ::android::Res_value;
32e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinskiusing ::android::StringPiece;
33e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinskiusing ::testing::Eq;
34a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinskiusing ::testing::IsEmpty;
35a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinskiusing ::testing::IsNull;
36e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinskiusing ::testing::NotNull;
37bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinskiusing ::testing::Pointee;
38a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinskiusing ::testing::SizeIs;
39d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski
406f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskinamespace aapt {
416f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
42bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinskiconstexpr const char* kXmlPreamble = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
436f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
441ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiTEST(ResourceParserSingleTest, FailToParseWithNoRootResourcesElement) {
45ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
46cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::stringstream input(kXmlPreamble);
47bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  input << R"(<attr name="foo"/>)" << std::endl;
48cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ResourceTable table;
49ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceParser parser(context->GetDiagnostics(), &table, Source{"test"}, {});
50ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  xml::XmlPullParser xml_parser(input);
51ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_FALSE(parser.Parse(&xml_parser));
52769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
53769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
54ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskiclass ResourceParserTest : public ::testing::Test {
55ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski public:
56bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  void SetUp() override {
57bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski    context_ = test::ContextBuilder().Build();
58bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  }
591ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
60ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ::testing::AssertionResult TestParse(const StringPiece& str) {
61ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    return TestParse(str, ConfigDescription{});
62cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
6352364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski
64bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  ::testing::AssertionResult TestParse(const StringPiece& str, const ConfigDescription& config) {
65cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    std::stringstream input(kXmlPreamble);
66cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    input << "<resources>\n" << str << "\n</resources>" << std::endl;
67cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    ResourceParserOptions parserOptions;
68bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski    ResourceParser parser(context_->GetDiagnostics(), &table_, Source{"test"}, config,
69bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski                          parserOptions);
70cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    xml::XmlPullParser xmlParser(input);
71ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    if (parser.Parse(&xmlParser)) {
72cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      return ::testing::AssertionSuccess();
736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
74cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return ::testing::AssertionFailure();
75cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
76ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
77ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski protected:
78ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceTable table_;
79ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  std::unique_ptr<IAaptContext> context_;
806f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski};
816f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseQuotedString) {
83a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<string name="foo">   "  hey there " </string>)"));
846f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
85ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
86a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
87a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str, StrValueEq("  hey there "));
88a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->untranslatable_sections, IsEmpty());
896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
906f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
916f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseEscapedString) {
92a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<string name="foo">\?123</string>)"));
936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
94ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
95a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
96a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str, StrValueEq("?123"));
97a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->untranslatable_sections, IsEmpty());
98549e437e14f3b92f02bd3abc7d1cd68387132ce1Adam Lesinski
99549e437e14f3b92f02bd3abc7d1cd68387132ce1Adam Lesinski  ASSERT_TRUE(TestParse(R"(<string name="bar">This isn\’t a bad string</string>)"));
100549e437e14f3b92f02bd3abc7d1cd68387132ce1Adam Lesinski  str = test::GetValue<String>(&table_, "string/bar");
101549e437e14f3b92f02bd3abc7d1cd68387132ce1Adam Lesinski  ASSERT_THAT(str, NotNull());
102549e437e14f3b92f02bd3abc7d1cd68387132ce1Adam Lesinski  EXPECT_THAT(*str, StrValueEq("This isn’t a bad string"));
1036f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
1046f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
1059f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam LesinskiTEST_F(ResourceParserTest, ParseFormattedString) {
106a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_FALSE(TestParse(R"(<string name="foo">%d %s</string>)"));
107a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<string name="foo">%1$d %2$s</string>)"));
1089f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski}
1099f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski
1108c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam LesinskiTEST_F(ResourceParserTest, ParseStyledString) {
111cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // Use a surrogate pair unicode point so that we can verify that the span
1127542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // indices use UTF-16 length and not UTF-8 length.
113cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
1148049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski      "<string name=\"foo\">This is my aunt\u2019s <b>fickle <small>string</small></b></string>";
115ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
1168c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
117ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  StyledString* str = test::GetValue<StyledString>(&table_, "string/foo");
118a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
1198c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
120a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str->value->str, Eq("This is my aunt\u2019s fickle string"));
121a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->value->spans, SizeIs(2));
122a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->untranslatable_sections, IsEmpty());
1238c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
124a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str->value->spans[0].name, Eq("b"));
125a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->value->spans[0].first_char, Eq(17u));
126a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->value->spans[0].last_char, Eq(30u));
1278049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski
128a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str->value->spans[1].name, Eq("small"));
129a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->value->spans[1].first_char, Eq(24u));
130a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->value->spans[1].last_char, Eq(30u));
1318c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski}
1328c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
1338c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam LesinskiTEST_F(ResourceParserTest, ParseStringWithWhitespace) {
134a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<string name="foo">  This is what  I think  </string>)"));
1358c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
136ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
137a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
138a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str->value, Eq("This is what I think"));
139a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->untranslatable_sections, IsEmpty());
1408c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
141a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<string name="foo2">"  This is what  I think  "</string>)"));
1428c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
143ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  str = test::GetValue<String>(&table_, "string/foo2");
144a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
145a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str, StrValueEq("  This is what  I think  "));
1468c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski}
1478c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
1487542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, IgnoreXliffTagsOtherThanG) {
149a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
1507542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski      <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
151a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski          There are <xliff:source>no</xliff:source> apples</string>)";
1527542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  ASSERT_TRUE(TestParse(input));
1537542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1547542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
155a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
156a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str, StrValueEq("There are no apples"));
157a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->untranslatable_sections, IsEmpty());
1587542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski}
1597542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1607542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, NestedXliffGTagsAreIllegal) {
161a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
1627542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski      <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
163a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski          Do not <xliff:g>translate <xliff:g>this</xliff:g></xliff:g></string>)";
1647542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_FALSE(TestParse(input));
1657542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski}
1667542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1677542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, RecordUntranslateableXliffSectionsInString) {
168a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
1697542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski      <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
170a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski          There are <xliff:g id="count">%1$d</xliff:g> apples</string>)";
171ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
1721ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
173ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
174a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
175a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str, StrValueEq("There are %1$d apples"));
176a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str->untranslatable_sections, SizeIs(1));
1777542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1787542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // We expect indices and lengths that span to include the whitespace
1797542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // before %1$d. This is due to how the StringBuilder withholds whitespace unless
1807542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // needed (to deal with line breaks, etc.).
181a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->untranslatable_sections[0].start, Eq(9u));
182a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->untranslatable_sections[0].end, Eq(14u));
1837542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski}
1847542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1857542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, RecordUntranslateableXliffSectionsInStyledString) {
186a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
1877542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski      <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
188a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski          There are <b><xliff:g id="count">%1$d</xliff:g></b> apples</string>)";
1897542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  ASSERT_TRUE(TestParse(input));
1907542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1917542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  StyledString* str = test::GetValue<StyledString>(&table_, "string/foo");
192a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
193a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str->value->str, Eq("There are %1$d apples"));
194a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str->untranslatable_sections, SizeIs(1));
1957542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1967542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // We expect indices and lengths that span to include the whitespace
1977542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // before %1$d. This is due to how the StringBuilder withholds whitespace unless
1987542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // needed (to deal with line breaks, etc.).
199a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->untranslatable_sections[0].start, Eq(9u));
200a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->untranslatable_sections[0].end, Eq(14u));
2011ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
2021ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
203dfa5e0705ff82f15e228ba076bc192893bcbe118Adam LesinskiTEST_F(ResourceParserTest, ParseNull) {
204a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(<integer name="foo">@null</integer>)";
205ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
206cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
207cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // The Android runtime treats a value of android::Res_value::TYPE_NULL as
208cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // a non-existing value, and this causes problems in styles when trying to
2097542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // resolve an attribute. Null values must be encoded as android::Res_value::TYPE_REFERENCE
210cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // with a data value of 0.
211bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  Reference* null_ref = test::GetValue<Reference>(&table_, "integer/foo");
212bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  ASSERT_THAT(null_ref, NotNull());
213bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  EXPECT_FALSE(null_ref->name);
214bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  EXPECT_FALSE(null_ref->id);
215a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(null_ref->reference_type, Eq(Reference::Type::kResource));
216dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski}
217dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski
218dfa5e0705ff82f15e228ba076bc192893bcbe118Adam LesinskiTEST_F(ResourceParserTest, ParseEmpty) {
219a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(<integer name="foo">@empty</integer>)";
220ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
221dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski
222bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  BinaryPrimitive* integer = test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
223a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(integer, NotNull());
224a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(integer->value.dataType, Eq(Res_value::TYPE_NULL));
225a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(integer->value.data, Eq(Res_value::DATA_NULL_EMPTY));
226dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski}
227dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski
2286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAttr) {
229a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
230a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <attr name="foo" format="string"/>
231a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <attr name="bar"/>)";
232ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
233cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
234ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
235a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
236a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->type_mask, Eq(ResTable_map::TYPE_STRING));
237cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
238ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  attr = test::GetValue<Attribute>(&table_, "attr/bar");
239a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
240a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->type_mask, Eq(ResTable_map::TYPE_ANY));
241cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski}
242cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
243a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski// Old AAPT allowed attributes to be defined under different configurations, but ultimately
244a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski// stored them with the default configuration. Check that we have the same behavior.
245bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam LesinskiTEST_F(ResourceParserTest, ParseAttrAndDeclareStyleableUnderConfigButRecordAsNoConfig) {
246ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  const ConfigDescription watch_config = test::ParseConfigOrDie("watch");
247bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  std::string input = R"(
248bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski      <attr name="foo" />
249bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski      <declare-styleable name="bar">
250bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski        <attr name="baz" />
251bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski      </declare-styleable>)";
252ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input, watch_config));
25352364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski
254a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(test::GetValueForConfig<Attribute>(&table_, "attr/foo", watch_config), IsNull());
255a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(test::GetValueForConfig<Attribute>(&table_, "attr/baz", watch_config), IsNull());
256a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(test::GetValueForConfig<Styleable>(&table_, "styleable/bar", watch_config), IsNull());
25752364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski
258a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(test::GetValue<Attribute>(&table_, "attr/foo"), NotNull());
259a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(test::GetValue<Attribute>(&table_, "attr/baz"), NotNull());
260a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(test::GetValue<Styleable>(&table_, "styleable/bar"), NotNull());
26152364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski}
26252364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski
263a587065721053ad54e34f484868142407d59512dAdam LesinskiTEST_F(ResourceParserTest, ParseAttrWithMinMax) {
264a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(<attr name="foo" min="10" max="23" format="integer"/>)";
265ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
266a587065721053ad54e34f484868142407d59512dAdam Lesinski
267ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
268a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
269a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->type_mask, Eq(ResTable_map::TYPE_INTEGER));
270a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->min_int, Eq(10));
271a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->max_int, Eq(23));
272a587065721053ad54e34f484868142407d59512dAdam Lesinski}
273a587065721053ad54e34f484868142407d59512dAdam Lesinski
274a587065721053ad54e34f484868142407d59512dAdam LesinskiTEST_F(ResourceParserTest, FailParseAttrWithMinMaxButNotInteger) {
275a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_FALSE(TestParse(R"(<attr name="foo" min="10" max="23" format="string"/>)"));
276a587065721053ad54e34f484868142407d59512dAdam Lesinski}
277a587065721053ad54e34f484868142407d59512dAdam Lesinski
2786f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseUseAndDeclOfAttr) {
279a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
280a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <declare-styleable name="Styleable">
281a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="foo" />
282a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </declare-styleable>
283a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <attr name="foo" format="string"/>)";
284ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
2856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
286ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
287a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
288a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->type_mask, Eq(ResTable_map::TYPE_STRING));
2896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
2906f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2916f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseDoubleUseOfAttr) {
292a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
293a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <declare-styleable name="Theme">
294a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="foo" />
295a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </declare-styleable>
296a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <declare-styleable name="Window">
297a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="foo" format="boolean"/>
298a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </declare-styleable>)";
299ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
3006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
301ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
302a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
303a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->type_mask, Eq(ResTable_map::TYPE_BOOLEAN));
3046f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3056f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3066f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseEnumAttr) {
307a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
308a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <attr name="foo">
309a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <enum name="bar" value="0"/>
310a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <enum name="bat" value="1"/>
311a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <enum name="baz" value="2"/>
312a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </attr>)";
313ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
3146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
315ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* enum_attr = test::GetValue<Attribute>(&table_, "attr/foo");
316a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(enum_attr, NotNull());
317a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(enum_attr->type_mask, Eq(ResTable_map::TYPE_ENUM));
318a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(enum_attr->symbols, SizeIs(3));
3196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
320a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(enum_attr->symbols[0].symbol.name);
321a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(enum_attr->symbols[0].symbol.name.value().entry, Eq("bar"));
322a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(enum_attr->symbols[0].value, Eq(0u));
3236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
324a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(enum_attr->symbols[1].symbol.name);
325a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(enum_attr->symbols[1].symbol.name.value().entry, Eq("bat"));
326a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(enum_attr->symbols[1].value, Eq(1u));
3276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
328a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(enum_attr->symbols[2].symbol.name);
329a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(enum_attr->symbols[2].symbol.name.value().entry, Eq("baz"));
330a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(enum_attr->symbols[2].value, Eq(2u));
3316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseFlagAttr) {
334a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
335a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <attr name="foo">
336a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <flag name="bar" value="0"/>
337a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <flag name="bat" value="1"/>
338a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <flag name="baz" value="2"/>
339a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </attr>)";
340ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
3416f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
342ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* flag_attr = test::GetValue<Attribute>(&table_, "attr/foo");
343a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(flag_attr, NotNull());
344a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(flag_attr->type_mask, Eq(ResTable_map::TYPE_FLAGS));
345a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(flag_attr->symbols, SizeIs(3));
3466f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
347a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(flag_attr->symbols[0].symbol.name);
348a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(flag_attr->symbols[0].symbol.name.value().entry, Eq("bar"));
349a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(flag_attr->symbols[0].value, Eq(0u));
3506f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
351a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(flag_attr->symbols[1].symbol.name);
352a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(flag_attr->symbols[1].symbol.name.value().entry, Eq("bat"));
353a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(flag_attr->symbols[1].value, Eq(1u));
3546f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
355a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(flag_attr->symbols[2].symbol.name);
356a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(flag_attr->symbols[2].symbol.name.value().entry, Eq("baz"));
357a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(flag_attr->symbols[2].value, Eq(2u));
3586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
359ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  std::unique_ptr<BinaryPrimitive> flag_value =
360ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      ResourceUtils::TryParseFlagSymbol(flag_attr, "baz|bat");
361a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(flag_value, NotNull());
362a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(flag_value->value.data, Eq(1u | 2u));
3636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3656f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, FailToParseEnumAttrWithNonUniqueKeys) {
366a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
367a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <attr name="foo">
368a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <enum name="bar" value="0"/>
369a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <enum name="bat" value="1"/>
370a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <enum name="bat" value="2"/>
371a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </attr>)";
372ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_FALSE(TestParse(input));
3736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseStyle) {
376a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
377a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <style name="foo" parent="@style/fu">
378a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item name="bar">#ffffffff</item>
379a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item name="bat">@string/hey</item>
380a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item name="baz"><b>hey</b></item>
381a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </style>)";
382ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
383cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
384ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
385a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style, NotNull());
386a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(style->parent);
387a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(style->parent.value().name, Eq(make_value(test::ParseNameOrDie("style/fu"))));
388a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style->entries, SizeIs(3));
389cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
390a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(style->entries[0].key.name, Eq(make_value(test::ParseNameOrDie("attr/bar"))));
391a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(style->entries[1].key.name, Eq(make_value(test::ParseNameOrDie("attr/bat"))));
392a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(style->entries[2].key.name, Eq(make_value(test::ParseNameOrDie("attr/baz"))));
3936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
395769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithShorthandParent) {
396a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<style name="foo" parent="com.app:Theme"/>)"));
397769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
398ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
399a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style, NotNull());
400a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(style->parent);
401a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(style->parent.value().name, Eq(make_value(test::ParseNameOrDie("com.app:style/Theme"))));
402769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
403769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
40424aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPackageAliasedParent) {
405a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
406a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <style xmlns:app="http://schemas.android.com/apk/res/android"
407a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski          name="foo" parent="app:Theme"/>)";
408ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
40924aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
410ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
411a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style, NotNull());
412a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(style->parent);
413a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(style->parent.value().name);
414a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(style->parent.value().name, Eq(make_value(test::ParseNameOrDie("android:style/Theme"))));
41524aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski}
41624aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
41724aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPackageAliasedItems) {
418a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
419a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <style xmlns:app="http://schemas.android.com/apk/res/android" name="foo">
420a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item name="app:bar">0</item>
421a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </style>)";
422ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
42324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
424ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
425a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style, NotNull());
426a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style->entries, SizeIs(1));
427a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(style->entries[0].key.name, Eq(make_value(test::ParseNameOrDie("android:attr/bar"))));
42824aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski}
42924aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
430bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithInferredParent) {
431a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<style name="foo.bar"/>)"));
432bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski
433ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo.bar");
434a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style, NotNull());
435a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(style->parent);
436a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(style->parent.value().name, Eq(make_value(test::ParseNameOrDie("style/foo"))));
437ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(style->parent_inferred);
438bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski}
439bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski
440a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam LesinskiTEST_F(ResourceParserTest, ParseStyleWithInferredParentOverridenByEmptyParentAttribute) {
441a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<style name="foo.bar" parent=""/>)"));
442bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski
443ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo.bar");
444a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style, NotNull());
445a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_FALSE(style->parent);
446ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_FALSE(style->parent_inferred);
447bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski}
448bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski
44924b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPrivateParentReference) {
450a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<style name="foo" parent="*android:style/bar" />)"));
45124b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski
452ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
453a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style, NotNull());
454a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(style->parent);
455ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(style->parent.value().private_reference);
45624b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski}
45724b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski
4586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAutoGeneratedIdReference) {
459a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<string name="foo">@+id/bar</string>)"));
460a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValue<Id>(&table_, "id/bar"), NotNull());
4616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
4626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
4636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAttributesDeclareStyleable) {
464a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
465a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <declare-styleable name="foo">
466a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="bar" />
467a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="bat" format="string|reference"/>
468a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="baz">
469a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski          <enum name="foo" value="1"/>
470a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        </attr>
471a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </declare-styleable>)";
472ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
473cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
474cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  Maybe<ResourceTable::SearchResult> result =
475ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      table_.FindResource(test::ParseNameOrDie("styleable/foo"));
476a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result);
477a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(result.value().entry->symbol_status.state, Eq(SymbolState::kPublic));
478cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
479ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/bar");
480a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
481ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(attr->IsWeak());
482cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
483ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  attr = test::GetValue<Attribute>(&table_, "attr/bat");
484a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
485ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(attr->IsWeak());
486cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
487ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  attr = test::GetValue<Attribute>(&table_, "attr/baz");
488a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
489ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(attr->IsWeak());
490a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->symbols, SizeIs(1));
491cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
492a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(test::GetValue<Id>(&table_, "id/foo"), NotNull());
493cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
494ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo");
495a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(styleable, NotNull());
496a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(styleable->entries, SizeIs(3));
497cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
498a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(styleable->entries[0].name, Eq(make_value(test::ParseNameOrDie("attr/bar"))));
499a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(styleable->entries[1].name, Eq(make_value(test::ParseNameOrDie("attr/bat"))));
500a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(styleable->entries[2].name, Eq(make_value(test::ParseNameOrDie("attr/baz"))));
5016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
5026f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
503467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam LesinskiTEST_F(ResourceParserTest, ParsePrivateAttributesDeclareStyleable) {
504a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
505a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <declare-styleable xmlns:privAndroid="http://schemas.android.com/apk/prv/res/android"
506a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski          name="foo">
507a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="*android:bar" />
508a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="privAndroid:bat" />
509a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </declare-styleable>)";
510ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
511ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo");
512a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(styleable, NotNull());
513a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(styleable->entries, SizeIs(2));
514cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
515ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(styleable->entries[0].private_reference);
516a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(styleable->entries[0].name);
517a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(styleable->entries[0].name.value().package, Eq("android"));
518cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
519ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(styleable->entries[1].private_reference);
520a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(styleable->entries[1].name);
521a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(styleable->entries[1].name.value().package, Eq("android"));
522467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski}
523467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski
5246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseArray) {
525a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
526a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <array name="foo">
527a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item>@string/ref</item>
528a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item>hey</item>
529a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item>23</item>
530a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </array>)";
531ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
5326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
533ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Array* array = test::GetValue<Array>(&table_, "array/foo");
534a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(array, NotNull());
535a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(array->items, SizeIs(3));
5366f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
537a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(ValueCast<Reference>(array->items[0].get()), NotNull());
538a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(ValueCast<String>(array->items[1].get()), NotNull());
539a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(ValueCast<BinaryPrimitive>(array->items[2].get()), NotNull());
5406f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
5416f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
5429ba47d813075fcb05c5e1532c137c93b394631cbAdam LesinskiTEST_F(ResourceParserTest, ParseStringArray) {
543a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
544d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski      <string-array name="foo">
545d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski        <item>"Werk"</item>"
546a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </string-array>)";
547ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
548a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(test::GetValue<Array>(&table_, "array/foo"), NotNull());
5499ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski}
5509ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski
551d5fd76a2ff78400505ade936fc36e707d69ecf72Adam LesinskiTEST_F(ResourceParserTest, ParseArrayWithFormat) {
552a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
553d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski      <array name="foo" format="string">
554d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski        <item>100</item>
555a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </array>)";
556d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski  ASSERT_TRUE(TestParse(input));
557d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski
558d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski  Array* array = test::GetValue<Array>(&table_, "array/foo");
559a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(array, NotNull());
560a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(array->items, SizeIs(1));
561d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski
562d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski  String* str = ValueCast<String>(array->items[0].get());
563a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
564a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str, StrValueEq("100"));
565d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski}
566d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski
567d5fd76a2ff78400505ade936fc36e707d69ecf72Adam LesinskiTEST_F(ResourceParserTest, ParseArrayWithBadFormat) {
568a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
569d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski      <array name="foo" format="integer">
570d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski        <item>Hi</item>
571a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </array>)";
572d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski  ASSERT_FALSE(TestParse(input));
573d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski}
574d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski
5756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParsePlural) {
576a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
577a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <plurals name="foo">
578a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item quantity="other">apples</item>
579a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item quantity="one">apple</item>
580a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </plurals>)";
581ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
5828f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski
5838f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski  Plural* plural = test::GetValue<Plural>(&table_, "plurals/foo");
584a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(plural, NotNull());
585a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(plural->values[Plural::Zero], IsNull());
586a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(plural->values[Plural::Two], IsNull());
587a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(plural->values[Plural::Few], IsNull());
588a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(plural->values[Plural::Many], IsNull());
5898f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski
590a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(plural->values[Plural::One], NotNull());
591a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(plural->values[Plural::Other], NotNull());
5926f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
5936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
5946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseCommentsWithResource) {
595a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
596a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <!--This is a comment-->
597a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="foo">Hi</string>)";
598ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
5996f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
600ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* value = test::GetValue<String>(&table_, "string/foo");
601a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(value, NotNull());
602a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(value->GetComment(), Eq("This is a comment"));
603e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski}
604e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
605e78fd617ec60139a973a01925fa7adad31febb39Adam LesinskiTEST_F(ResourceParserTest, DoNotCombineMultipleComments) {
606a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
607a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <!--One-->
608a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <!--Two-->
609a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="foo">Hi</string>)";
610e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
611ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
612e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
613ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* value = test::GetValue<String>(&table_, "string/foo");
614a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(value, NotNull());
615a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(value->GetComment(), Eq("Two"));
616e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski}
617e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
618e78fd617ec60139a973a01925fa7adad31febb39Adam LesinskiTEST_F(ResourceParserTest, IgnoreCommentBeforeEndTag) {
619a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
620a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <!--One-->
621a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="foo">
622a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        Hi
623a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <!--Two-->
624a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </string>)";
625ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
6261ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
627ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* value = test::GetValue<String>(&table_, "string/foo");
628a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(value, NotNull());
629a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(value->GetComment(), Eq("One"));
6306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
6316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
632ca5638fd85098c3d0a699492751043545f75553aAdam LesinskiTEST_F(ResourceParserTest, ParseNestedComments) {
633cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // We only care about declare-styleable and enum/flag attributes because
634a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  // comments from those end up in R.java
635a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
636a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <declare-styleable name="foo">
637a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <!-- The name of the bar -->
638a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="barName" format="string|reference" />
639a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </declare-styleable>
640a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski
641a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <attr name="foo">
642a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <!-- The very first -->
643a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <enum name="one" value="1" />
644a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </attr>)";
645ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
646ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
647ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo");
648a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(styleable, NotNull());
649a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(styleable->entries, SizeIs(1));
650a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(styleable->entries[0].GetComment(), Eq("The name of the bar"));
651ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
652ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
653a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
654a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr->symbols, SizeIs(1));
655a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->symbols[0].symbol.GetComment(), Eq("The very first"));
656ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski}
657ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
658a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski// Declaring an ID as public should not require a separate definition (as an ID has no value).
6596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParsePublicIdAsDefinition) {
660a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<public type="id" name="foo"/>)"));
661a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValue<Id>(&table_, "id/foo"), NotNull());
6626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
6636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
664e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam LesinskiTEST_F(ResourceParserTest, KeepAllProducts) {
665a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
666a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="foo" product="phone">hi</string>
667a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="foo" product="no-sdcard">ho</string>
668a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="bar" product="">wee</string>
669a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="baz">woo</string>
670a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="bit" product="phablet">hoot</string>
671a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="bot" product="default">yes</string>)";
672ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
673ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
674a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValueForConfigAndProduct<String>(&table_, "string/foo", ConfigDescription::DefaultConfig(), "phone"), NotNull());
675a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValueForConfigAndProduct<String>(&table_, "string/foo",ConfigDescription::DefaultConfig(), "no-sdcard"), NotNull());
676a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValueForConfigAndProduct<String>(&table_, "string/bar", ConfigDescription::DefaultConfig(), ""), NotNull());
677a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValueForConfigAndProduct<String>(&table_, "string/baz", ConfigDescription::DefaultConfig(), ""), NotNull());
678a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValueForConfigAndProduct<String>(&table_, "string/bit", ConfigDescription::DefaultConfig(), "phablet"), NotNull());
679a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValueForConfigAndProduct<String>(&table_, "string/bot", ConfigDescription::DefaultConfig(), "default"), NotNull());
6809ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski}
6819ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski
68227afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam LesinskiTEST_F(ResourceParserTest, AutoIncrementIdsInPublicGroup) {
683a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
684a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <public-group type="attr" first-id="0x01010040">
685a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <public name="foo" />
686a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <public name="bar" />
687a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </public-group>)";
688ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
689cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
690a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  Maybe<ResourceTable::SearchResult> result = table_.FindResource(test::ParseNameOrDie("attr/foo"));
691a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result);
692cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
693a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result.value().package->id);
694a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result.value().type->id);
695a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result.value().entry->id);
696ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceId actual_id(result.value().package->id.value(),
697ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                       result.value().type->id.value(),
698ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                       result.value().entry->id.value());
699a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(actual_id, Eq(ResourceId(0x01010040)));
700cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
701ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  result = table_.FindResource(test::ParseNameOrDie("attr/bar"));
702a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result);
703cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
704a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result.value().package->id);
705a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result.value().type->id);
706a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result.value().entry->id);
707ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  actual_id = ResourceId(result.value().package->id.value(),
708ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         result.value().type->id.value(),
709ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         result.value().entry->id.value());
710a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(actual_id, Eq(ResourceId(0x01010041)));
71127afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski}
71227afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski
713fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam LesinskiTEST_F(ResourceParserTest, ExternalTypesShouldOnlyBeReferences) {
714a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<item type="layout" name="foo">@layout/bar</item>)"));
715a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_FALSE(TestParse(R"(<item type="layout" name="bar">"this is a string"</item>)"));
716fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski}
717fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski
7184488f1c74a0f7df09f2b201f7caa228d729e8389Adam LesinskiTEST_F(ResourceParserTest, AddResourcesElementShouldAddEntryWithUndefinedSymbol) {
719a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<add-resource name="bar" type="string" />)"));
720a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski
721cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  Maybe<ResourceTable::SearchResult> result =
722ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      table_.FindResource(test::ParseNameOrDie("string/bar"));
723a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result);
724cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  const ResourceEntry* entry = result.value().entry;
725a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(entry, NotNull());
726a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(entry->symbol_status.state, Eq(SymbolState::kUndefined));
7274488f1c74a0f7df09f2b201f7caa228d729e8389Adam Lesinski  EXPECT_TRUE(entry->symbol_status.allow_new);
728a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski}
729a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski
7307ff3ee19f4b831a526baf4b928d1ac172d070d82Adam LesinskiTEST_F(ResourceParserTest, ParseItemElementWithFormat) {
731a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<item name="foo" type="integer" format="float">0.3</item>)"));
7327ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski
733e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski  BinaryPrimitive* val = test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
734e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski  ASSERT_THAT(val, NotNull());
735a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(val->value.dataType, Eq(Res_value::TYPE_FLOAT));
736e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski
737a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_FALSE(TestParse(R"(<item name="bar" type="integer" format="fraction">100</item>)"));
738e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski}
739e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski
740e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski// An <item> without a format specifier accepts all types of values.
741e597d68d33c76c2b830f5497ed4ba74c5193a056Adam LesinskiTEST_F(ResourceParserTest, ParseItemElementWithoutFormat) {
742a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<item name="foo" type="integer">100%p</item>)"));
7437ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski
744e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski  BinaryPrimitive* val = test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
745e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski  ASSERT_THAT(val, NotNull());
746a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(val->value.dataType, Eq(Res_value::TYPE_FRACTION));
7477ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski}
7487ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski
74986d67df8d57b9537666f9b54a9ca563779a2288bAdam LesinskiTEST_F(ResourceParserTest, ParseConfigVaryingItem) {
750a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<item name="foo" type="configVarying">Hey</item>)"));
751a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValue<String>(&table_, "configVarying/foo"), NotNull());
75286d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski}
75386d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski
75486d67df8d57b9537666f9b54a9ca563779a2288bAdam LesinskiTEST_F(ResourceParserTest, ParseBagElement) {
755a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
756a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <bag name="bag" type="configVarying">
757a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item name="test">Hello!</item>
758a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </bag>)";
75986d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  ASSERT_TRUE(TestParse(input));
76086d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski
76186d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  Style* val = test::GetValue<Style>(&table_, "configVarying/bag");
762a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(val, NotNull());
763a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(val->entries, SizeIs(1));
76486d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski
765a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(val->entries[0].key, Eq(Reference(test::ParseNameOrDie("attr/test"))));
766a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(ValueCast<RawString>(val->entries[0].value.get()), NotNull());
76786d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski}
76886d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski
769bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam LesinskiTEST_F(ResourceParserTest, ParseElementWithNoValue) {
770bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  std::string input = R"(
771bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski      <item type="drawable" format="reference" name="foo" />
772bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski      <string name="foo" />)";
773bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  ASSERT_TRUE(TestParse(input));
774bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  ASSERT_THAT(test::GetValue(&table_, "drawable/foo"), Pointee(ValueEq(Reference())));
775bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski
776bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
777bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  ASSERT_THAT(str, NotNull());
778a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str, StrValueEq(""));
779bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski}
780bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski
781b9f0548341f98a64a87fa35ef5f58d1daf973ca7Adam LesinskiTEST_F(ResourceParserTest, ParsePlatformIndependentNewline) {
782a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<string name="foo">%1$s %n %2$s</string>)"));
783b9f0548341f98a64a87fa35ef5f58d1daf973ca7Adam Lesinski}
784b9f0548341f98a64a87fa35ef5f58d1daf973ca7Adam Lesinski
785cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski}  // namespace aapt
786