ResourceParser_test.cpp revision a45893a5c51cc26f1fd63ec1aa4c39f55911c85b
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());
986f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
996f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
1009f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam LesinskiTEST_F(ResourceParserTest, ParseFormattedString) {
101a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_FALSE(TestParse(R"(<string name="foo">%d %s</string>)"));
102a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<string name="foo">%1$d %2$s</string>)"));
1039f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski}
1049f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski
1058c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam LesinskiTEST_F(ResourceParserTest, ParseStyledString) {
106cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // Use a surrogate pair unicode point so that we can verify that the span
1077542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // indices use UTF-16 length and not UTF-8 length.
108cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
1098049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski      "<string name=\"foo\">This is my aunt\u2019s <b>fickle <small>string</small></b></string>";
110ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
1118c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
112ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  StyledString* str = test::GetValue<StyledString>(&table_, "string/foo");
113a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
1148c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
115a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str->value->str, Eq("This is my aunt\u2019s fickle string"));
116a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->value->spans, SizeIs(2));
117a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->untranslatable_sections, IsEmpty());
1188c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
119a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str->value->spans[0].name, Eq("b"));
120a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->value->spans[0].first_char, Eq(17u));
121a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->value->spans[0].last_char, Eq(30u));
1228049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski
123a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str->value->spans[1].name, Eq("small"));
124a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->value->spans[1].first_char, Eq(24u));
125a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->value->spans[1].last_char, Eq(30u));
1268c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski}
1278c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
1288c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam LesinskiTEST_F(ResourceParserTest, ParseStringWithWhitespace) {
129a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<string name="foo">  This is what  I think  </string>)"));
1308c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
131ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
132a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
133a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str->value, Eq("This is what I think"));
134a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->untranslatable_sections, IsEmpty());
1358c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
136a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<string name="foo2">"  This is what  I think  "</string>)"));
1378c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
138ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  str = test::GetValue<String>(&table_, "string/foo2");
139a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
140a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str, StrValueEq("  This is what  I think  "));
1418c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski}
1428c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
1437542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, IgnoreXliffTagsOtherThanG) {
144a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
1457542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski      <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
146a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski          There are <xliff:source>no</xliff:source> apples</string>)";
1477542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  ASSERT_TRUE(TestParse(input));
1487542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1497542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
150a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
151a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str, StrValueEq("There are no apples"));
152a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->untranslatable_sections, IsEmpty());
1537542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski}
1547542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1557542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, NestedXliffGTagsAreIllegal) {
156a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
1577542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski      <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
158a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski          Do not <xliff:g>translate <xliff:g>this</xliff:g></xliff:g></string>)";
1597542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_FALSE(TestParse(input));
1607542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski}
1617542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1627542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, RecordUntranslateableXliffSectionsInString) {
163a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
1647542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski      <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
165a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski          There are <xliff:g id="count">%1$d</xliff:g> apples</string>)";
166ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
1671ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
168ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
169a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
170a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str, StrValueEq("There are %1$d apples"));
171a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str->untranslatable_sections, SizeIs(1));
1727542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1737542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // We expect indices and lengths that span to include the whitespace
1747542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // before %1$d. This is due to how the StringBuilder withholds whitespace unless
1757542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // needed (to deal with line breaks, etc.).
176a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->untranslatable_sections[0].start, Eq(9u));
177a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->untranslatable_sections[0].end, Eq(14u));
1787542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski}
1797542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1807542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, RecordUntranslateableXliffSectionsInStyledString) {
181a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
1827542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski      <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
183a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski          There are <b><xliff:g id="count">%1$d</xliff:g></b> apples</string>)";
1847542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  ASSERT_TRUE(TestParse(input));
1857542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1867542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  StyledString* str = test::GetValue<StyledString>(&table_, "string/foo");
187a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
188a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str->value->str, Eq("There are %1$d apples"));
189a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str->untranslatable_sections, SizeIs(1));
1907542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1917542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // We expect indices and lengths that span to include the whitespace
1927542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // before %1$d. This is due to how the StringBuilder withholds whitespace unless
1937542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // needed (to deal with line breaks, etc.).
194a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->untranslatable_sections[0].start, Eq(9u));
195a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->untranslatable_sections[0].end, Eq(14u));
1961ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
1971ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
198dfa5e0705ff82f15e228ba076bc192893bcbe118Adam LesinskiTEST_F(ResourceParserTest, ParseNull) {
199a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(<integer name="foo">@null</integer>)";
200ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
201cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
202cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // The Android runtime treats a value of android::Res_value::TYPE_NULL as
203cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // a non-existing value, and this causes problems in styles when trying to
2047542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // resolve an attribute. Null values must be encoded as android::Res_value::TYPE_REFERENCE
205cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // with a data value of 0.
206bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  Reference* null_ref = test::GetValue<Reference>(&table_, "integer/foo");
207bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  ASSERT_THAT(null_ref, NotNull());
208bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  EXPECT_FALSE(null_ref->name);
209bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  EXPECT_FALSE(null_ref->id);
210a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(null_ref->reference_type, Eq(Reference::Type::kResource));
211dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski}
212dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski
213dfa5e0705ff82f15e228ba076bc192893bcbe118Adam LesinskiTEST_F(ResourceParserTest, ParseEmpty) {
214a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(<integer name="foo">@empty</integer>)";
215ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
216dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski
217bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  BinaryPrimitive* integer = test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
218a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(integer, NotNull());
219a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(integer->value.dataType, Eq(Res_value::TYPE_NULL));
220a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(integer->value.data, Eq(Res_value::DATA_NULL_EMPTY));
221dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski}
222dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski
2236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAttr) {
224a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
225a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <attr name="foo" format="string"/>
226a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <attr name="bar"/>)";
227ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
228cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
229ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
230a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
231a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->type_mask, Eq(ResTable_map::TYPE_STRING));
232cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
233ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  attr = test::GetValue<Attribute>(&table_, "attr/bar");
234a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
235a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->type_mask, Eq(ResTable_map::TYPE_ANY));
236cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski}
237cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
238a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski// Old AAPT allowed attributes to be defined under different configurations, but ultimately
239a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski// stored them with the default configuration. Check that we have the same behavior.
240bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam LesinskiTEST_F(ResourceParserTest, ParseAttrAndDeclareStyleableUnderConfigButRecordAsNoConfig) {
241ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  const ConfigDescription watch_config = test::ParseConfigOrDie("watch");
242bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  std::string input = R"(
243bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski      <attr name="foo" />
244bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski      <declare-styleable name="bar">
245bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski        <attr name="baz" />
246bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski      </declare-styleable>)";
247ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input, watch_config));
24852364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski
249a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(test::GetValueForConfig<Attribute>(&table_, "attr/foo", watch_config), IsNull());
250a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(test::GetValueForConfig<Attribute>(&table_, "attr/baz", watch_config), IsNull());
251a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(test::GetValueForConfig<Styleable>(&table_, "styleable/bar", watch_config), IsNull());
25252364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski
253a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(test::GetValue<Attribute>(&table_, "attr/foo"), NotNull());
254a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(test::GetValue<Attribute>(&table_, "attr/baz"), NotNull());
255a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(test::GetValue<Styleable>(&table_, "styleable/bar"), NotNull());
25652364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski}
25752364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski
258a587065721053ad54e34f484868142407d59512dAdam LesinskiTEST_F(ResourceParserTest, ParseAttrWithMinMax) {
259a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(<attr name="foo" min="10" max="23" format="integer"/>)";
260ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
261a587065721053ad54e34f484868142407d59512dAdam Lesinski
262ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
263a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
264a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->type_mask, Eq(ResTable_map::TYPE_INTEGER));
265a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->min_int, Eq(10));
266a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->max_int, Eq(23));
267a587065721053ad54e34f484868142407d59512dAdam Lesinski}
268a587065721053ad54e34f484868142407d59512dAdam Lesinski
269a587065721053ad54e34f484868142407d59512dAdam LesinskiTEST_F(ResourceParserTest, FailParseAttrWithMinMaxButNotInteger) {
270a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_FALSE(TestParse(R"(<attr name="foo" min="10" max="23" format="string"/>)"));
271a587065721053ad54e34f484868142407d59512dAdam Lesinski}
272a587065721053ad54e34f484868142407d59512dAdam Lesinski
2736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseUseAndDeclOfAttr) {
274a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
275a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <declare-styleable name="Styleable">
276a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="foo" />
277a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </declare-styleable>
278a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <attr name="foo" format="string"/>)";
279ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
2806f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
281ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
282a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
283a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->type_mask, Eq(ResTable_map::TYPE_STRING));
2846f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
2856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2866f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseDoubleUseOfAttr) {
287a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
288a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <declare-styleable name="Theme">
289a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="foo" />
290a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </declare-styleable>
291a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <declare-styleable name="Window">
292a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="foo" format="boolean"/>
293a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </declare-styleable>)";
294ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
2956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
296ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
297a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
298a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->type_mask, Eq(ResTable_map::TYPE_BOOLEAN));
2996f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseEnumAttr) {
302a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
303a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <attr name="foo">
304a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <enum name="bar" value="0"/>
305a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <enum name="bat" value="1"/>
306a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <enum name="baz" value="2"/>
307a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </attr>)";
308ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
3096f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
310ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* enum_attr = test::GetValue<Attribute>(&table_, "attr/foo");
311a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(enum_attr, NotNull());
312a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(enum_attr->type_mask, Eq(ResTable_map::TYPE_ENUM));
313a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(enum_attr->symbols, SizeIs(3));
3146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
315a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(enum_attr->symbols[0].symbol.name);
316a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(enum_attr->symbols[0].symbol.name.value().entry, Eq("bar"));
317a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(enum_attr->symbols[0].value, Eq(0u));
3186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
319a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(enum_attr->symbols[1].symbol.name);
320a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(enum_attr->symbols[1].symbol.name.value().entry, Eq("bat"));
321a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(enum_attr->symbols[1].value, Eq(1u));
3226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
323a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(enum_attr->symbols[2].symbol.name);
324a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(enum_attr->symbols[2].symbol.name.value().entry, Eq("baz"));
325a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(enum_attr->symbols[2].value, Eq(2u));
3266f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseFlagAttr) {
329a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
330a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <attr name="foo">
331a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <flag name="bar" value="0"/>
332a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <flag name="bat" value="1"/>
333a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <flag name="baz" value="2"/>
334a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </attr>)";
335ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
3366f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
337ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* flag_attr = test::GetValue<Attribute>(&table_, "attr/foo");
338a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(flag_attr, NotNull());
339a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(flag_attr->type_mask, Eq(ResTable_map::TYPE_FLAGS));
340a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(flag_attr->symbols, SizeIs(3));
3416f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
342a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(flag_attr->symbols[0].symbol.name);
343a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(flag_attr->symbols[0].symbol.name.value().entry, Eq("bar"));
344a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(flag_attr->symbols[0].value, Eq(0u));
3456f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
346a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(flag_attr->symbols[1].symbol.name);
347a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(flag_attr->symbols[1].symbol.name.value().entry, Eq("bat"));
348a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(flag_attr->symbols[1].value, Eq(1u));
3496f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
350a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(flag_attr->symbols[2].symbol.name);
351a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(flag_attr->symbols[2].symbol.name.value().entry, Eq("baz"));
352a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(flag_attr->symbols[2].value, Eq(2u));
3536f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
354ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  std::unique_ptr<BinaryPrimitive> flag_value =
355ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      ResourceUtils::TryParseFlagSymbol(flag_attr, "baz|bat");
356a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(flag_value, NotNull());
357a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(flag_value->value.data, Eq(1u | 2u));
3586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, FailToParseEnumAttrWithNonUniqueKeys) {
361a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
362a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <attr name="foo">
363a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <enum name="bar" value="0"/>
364a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <enum name="bat" value="1"/>
365a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <enum name="bat" value="2"/>
366a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </attr>)";
367ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_FALSE(TestParse(input));
3686f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3706f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseStyle) {
371a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
372a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <style name="foo" parent="@style/fu">
373a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item name="bar">#ffffffff</item>
374a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item name="bat">@string/hey</item>
375a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item name="baz"><b>hey</b></item>
376a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </style>)";
377ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
378cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
379ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
380a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style, NotNull());
381a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(style->parent);
382a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(style->parent.value().name, Eq(make_value(test::ParseNameOrDie("style/fu"))));
383a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style->entries, SizeIs(3));
384cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
385a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(style->entries[0].key.name, Eq(make_value(test::ParseNameOrDie("attr/bar"))));
386a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(style->entries[1].key.name, Eq(make_value(test::ParseNameOrDie("attr/bat"))));
387a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(style->entries[2].key.name, Eq(make_value(test::ParseNameOrDie("attr/baz"))));
3886f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
390769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithShorthandParent) {
391a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<style name="foo" parent="com.app:Theme"/>)"));
392769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
393ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
394a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style, NotNull());
395a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(style->parent);
396a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(style->parent.value().name, Eq(make_value(test::ParseNameOrDie("com.app:style/Theme"))));
397769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
398769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
39924aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPackageAliasedParent) {
400a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
401a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <style xmlns:app="http://schemas.android.com/apk/res/android"
402a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski          name="foo" parent="app:Theme"/>)";
403ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
40424aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
405ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
406a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style, NotNull());
407a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(style->parent);
408a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(style->parent.value().name);
409a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(style->parent.value().name, Eq(make_value(test::ParseNameOrDie("android:style/Theme"))));
41024aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski}
41124aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
41224aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPackageAliasedItems) {
413a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
414a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <style xmlns:app="http://schemas.android.com/apk/res/android" name="foo">
415a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item name="app:bar">0</item>
416a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </style>)";
417ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
41824aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
419ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
420a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style, NotNull());
421a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style->entries, SizeIs(1));
422a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(style->entries[0].key.name, Eq(make_value(test::ParseNameOrDie("android:attr/bar"))));
42324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski}
42424aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
425bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithInferredParent) {
426a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<style name="foo.bar"/>)"));
427bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski
428ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo.bar");
429a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style, NotNull());
430a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(style->parent);
431a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(style->parent.value().name, Eq(make_value(test::ParseNameOrDie("style/foo"))));
432ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(style->parent_inferred);
433bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski}
434bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski
435a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam LesinskiTEST_F(ResourceParserTest, ParseStyleWithInferredParentOverridenByEmptyParentAttribute) {
436a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<style name="foo.bar" parent=""/>)"));
437bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski
438ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo.bar");
439a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style, NotNull());
440a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_FALSE(style->parent);
441ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_FALSE(style->parent_inferred);
442bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski}
443bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski
44424b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPrivateParentReference) {
445a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<style name="foo" parent="*android:style/bar" />)"));
44624b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski
447ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
448a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style, NotNull());
449a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(style->parent);
450ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(style->parent.value().private_reference);
45124b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski}
45224b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski
4536f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAutoGeneratedIdReference) {
454a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<string name="foo">@+id/bar</string>)"));
455a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValue<Id>(&table_, "id/bar"), NotNull());
4566f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
4576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
4586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAttributesDeclareStyleable) {
459a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
460a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <declare-styleable name="foo">
461a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="bar" />
462a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="bat" format="string|reference"/>
463a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="baz">
464a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski          <enum name="foo" value="1"/>
465a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        </attr>
466a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </declare-styleable>)";
467ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
468cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
469cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  Maybe<ResourceTable::SearchResult> result =
470ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      table_.FindResource(test::ParseNameOrDie("styleable/foo"));
471a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result);
472a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(result.value().entry->symbol_status.state, Eq(SymbolState::kPublic));
473cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
474ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/bar");
475a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
476ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(attr->IsWeak());
477cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
478ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  attr = test::GetValue<Attribute>(&table_, "attr/bat");
479a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
480ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(attr->IsWeak());
481cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
482ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  attr = test::GetValue<Attribute>(&table_, "attr/baz");
483a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
484ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(attr->IsWeak());
485a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->symbols, SizeIs(1));
486cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
487a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(test::GetValue<Id>(&table_, "id/foo"), NotNull());
488cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
489ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo");
490a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(styleable, NotNull());
491a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(styleable->entries, SizeIs(3));
492cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
493a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(styleable->entries[0].name, Eq(make_value(test::ParseNameOrDie("attr/bar"))));
494a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(styleable->entries[1].name, Eq(make_value(test::ParseNameOrDie("attr/bat"))));
495a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(styleable->entries[2].name, Eq(make_value(test::ParseNameOrDie("attr/baz"))));
4966f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
4976f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
498467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam LesinskiTEST_F(ResourceParserTest, ParsePrivateAttributesDeclareStyleable) {
499a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
500a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <declare-styleable xmlns:privAndroid="http://schemas.android.com/apk/prv/res/android"
501a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski          name="foo">
502a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="*android:bar" />
503a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="privAndroid:bat" />
504a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </declare-styleable>)";
505ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
506ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo");
507a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(styleable, NotNull());
508a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(styleable->entries, SizeIs(2));
509cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
510ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(styleable->entries[0].private_reference);
511a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(styleable->entries[0].name);
512a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(styleable->entries[0].name.value().package, Eq("android"));
513cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
514ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(styleable->entries[1].private_reference);
515a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(styleable->entries[1].name);
516a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(styleable->entries[1].name.value().package, Eq("android"));
517467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski}
518467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski
5196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseArray) {
520a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
521a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <array name="foo">
522a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item>@string/ref</item>
523a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item>hey</item>
524a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item>23</item>
525a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </array>)";
526ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
5276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
528ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Array* array = test::GetValue<Array>(&table_, "array/foo");
529a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(array, NotNull());
530a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(array->items, SizeIs(3));
5316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
532a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(ValueCast<Reference>(array->items[0].get()), NotNull());
533a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(ValueCast<String>(array->items[1].get()), NotNull());
534a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(ValueCast<BinaryPrimitive>(array->items[2].get()), NotNull());
5356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
5366f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
5379ba47d813075fcb05c5e1532c137c93b394631cbAdam LesinskiTEST_F(ResourceParserTest, ParseStringArray) {
538a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
539d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski      <string-array name="foo">
540d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski        <item>"Werk"</item>"
541a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </string-array>)";
542ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
543a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(test::GetValue<Array>(&table_, "array/foo"), NotNull());
5449ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski}
5459ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski
546d5fd76a2ff78400505ade936fc36e707d69ecf72Adam LesinskiTEST_F(ResourceParserTest, ParseArrayWithFormat) {
547a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
548d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski      <array name="foo" format="string">
549d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski        <item>100</item>
550a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </array>)";
551d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski  ASSERT_TRUE(TestParse(input));
552d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski
553d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski  Array* array = test::GetValue<Array>(&table_, "array/foo");
554a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(array, NotNull());
555a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(array->items, SizeIs(1));
556d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski
557d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski  String* str = ValueCast<String>(array->items[0].get());
558a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
559a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str, StrValueEq("100"));
560d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski}
561d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski
562d5fd76a2ff78400505ade936fc36e707d69ecf72Adam LesinskiTEST_F(ResourceParserTest, ParseArrayWithBadFormat) {
563a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
564d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski      <array name="foo" format="integer">
565d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski        <item>Hi</item>
566a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </array>)";
567d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski  ASSERT_FALSE(TestParse(input));
568d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski}
569d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski
5706f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParsePlural) {
571a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
572a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <plurals name="foo">
573a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item quantity="other">apples</item>
574a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item quantity="one">apple</item>
575a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </plurals>)";
576ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
5778f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski
5788f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski  Plural* plural = test::GetValue<Plural>(&table_, "plurals/foo");
579a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(plural, NotNull());
580a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(plural->values[Plural::Zero], IsNull());
581a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(plural->values[Plural::Two], IsNull());
582a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(plural->values[Plural::Few], IsNull());
583a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(plural->values[Plural::Many], IsNull());
5848f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski
585a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(plural->values[Plural::One], NotNull());
586a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(plural->values[Plural::Other], NotNull());
5876f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
5886f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
5896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseCommentsWithResource) {
590a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
591a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <!--This is a comment-->
592a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="foo">Hi</string>)";
593ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
5946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
595ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* value = test::GetValue<String>(&table_, "string/foo");
596a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(value, NotNull());
597a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(value->GetComment(), Eq("This is a comment"));
598e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski}
599e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
600e78fd617ec60139a973a01925fa7adad31febb39Adam LesinskiTEST_F(ResourceParserTest, DoNotCombineMultipleComments) {
601a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
602a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <!--One-->
603a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <!--Two-->
604a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="foo">Hi</string>)";
605e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
606ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
607e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
608ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* value = test::GetValue<String>(&table_, "string/foo");
609a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(value, NotNull());
610a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(value->GetComment(), Eq("Two"));
611e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski}
612e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
613e78fd617ec60139a973a01925fa7adad31febb39Adam LesinskiTEST_F(ResourceParserTest, IgnoreCommentBeforeEndTag) {
614a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
615a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <!--One-->
616a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="foo">
617a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        Hi
618a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <!--Two-->
619a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </string>)";
620ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
6211ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
622ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* value = test::GetValue<String>(&table_, "string/foo");
623a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(value, NotNull());
624a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(value->GetComment(), Eq("One"));
6256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
6266f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
627ca5638fd85098c3d0a699492751043545f75553aAdam LesinskiTEST_F(ResourceParserTest, ParseNestedComments) {
628cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // We only care about declare-styleable and enum/flag attributes because
629a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  // comments from those end up in R.java
630a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
631a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <declare-styleable name="foo">
632a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <!-- The name of the bar -->
633a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="barName" format="string|reference" />
634a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </declare-styleable>
635a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski
636a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <attr name="foo">
637a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <!-- The very first -->
638a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <enum name="one" value="1" />
639a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </attr>)";
640ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
641ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
642ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo");
643a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(styleable, NotNull());
644a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(styleable->entries, SizeIs(1));
645a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(styleable->entries[0].GetComment(), Eq("The name of the bar"));
646ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
647ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
648a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
649a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr->symbols, SizeIs(1));
650a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->symbols[0].symbol.GetComment(), Eq("The very first"));
651ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski}
652ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
653a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski// Declaring an ID as public should not require a separate definition (as an ID has no value).
6546f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParsePublicIdAsDefinition) {
655a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<public type="id" name="foo"/>)"));
656a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValue<Id>(&table_, "id/foo"), NotNull());
6576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
6586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
659e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam LesinskiTEST_F(ResourceParserTest, KeepAllProducts) {
660a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
661a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="foo" product="phone">hi</string>
662a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="foo" product="no-sdcard">ho</string>
663a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="bar" product="">wee</string>
664a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="baz">woo</string>
665a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="bit" product="phablet">hoot</string>
666a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="bot" product="default">yes</string>)";
667ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
668ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
669a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValueForConfigAndProduct<String>(&table_, "string/foo", ConfigDescription::DefaultConfig(), "phone"), NotNull());
670a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValueForConfigAndProduct<String>(&table_, "string/foo",ConfigDescription::DefaultConfig(), "no-sdcard"), NotNull());
671a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValueForConfigAndProduct<String>(&table_, "string/bar", ConfigDescription::DefaultConfig(), ""), NotNull());
672a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValueForConfigAndProduct<String>(&table_, "string/baz", ConfigDescription::DefaultConfig(), ""), NotNull());
673a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValueForConfigAndProduct<String>(&table_, "string/bit", ConfigDescription::DefaultConfig(), "phablet"), NotNull());
674a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValueForConfigAndProduct<String>(&table_, "string/bot", ConfigDescription::DefaultConfig(), "default"), NotNull());
6759ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski}
6769ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski
67727afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam LesinskiTEST_F(ResourceParserTest, AutoIncrementIdsInPublicGroup) {
678a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
679a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <public-group type="attr" first-id="0x01010040">
680a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <public name="foo" />
681a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <public name="bar" />
682a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </public-group>)";
683ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
684cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
685a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  Maybe<ResourceTable::SearchResult> result = table_.FindResource(test::ParseNameOrDie("attr/foo"));
686a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result);
687cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
688a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result.value().package->id);
689a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result.value().type->id);
690a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result.value().entry->id);
691ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceId actual_id(result.value().package->id.value(),
692ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                       result.value().type->id.value(),
693ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                       result.value().entry->id.value());
694a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(actual_id, Eq(ResourceId(0x01010040)));
695cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
696ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  result = table_.FindResource(test::ParseNameOrDie("attr/bar"));
697a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result);
698cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
699a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result.value().package->id);
700a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result.value().type->id);
701a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result.value().entry->id);
702ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  actual_id = ResourceId(result.value().package->id.value(),
703ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         result.value().type->id.value(),
704ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         result.value().entry->id.value());
705a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(actual_id, Eq(ResourceId(0x01010041)));
70627afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski}
70727afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski
708fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam LesinskiTEST_F(ResourceParserTest, ExternalTypesShouldOnlyBeReferences) {
709a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<item type="layout" name="foo">@layout/bar</item>)"));
710a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_FALSE(TestParse(R"(<item type="layout" name="bar">"this is a string"</item>)"));
711fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski}
712fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski
7134488f1c74a0f7df09f2b201f7caa228d729e8389Adam LesinskiTEST_F(ResourceParserTest, AddResourcesElementShouldAddEntryWithUndefinedSymbol) {
714a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<add-resource name="bar" type="string" />)"));
715a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski
716cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  Maybe<ResourceTable::SearchResult> result =
717ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      table_.FindResource(test::ParseNameOrDie("string/bar"));
718a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result);
719cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  const ResourceEntry* entry = result.value().entry;
720a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(entry, NotNull());
721a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(entry->symbol_status.state, Eq(SymbolState::kUndefined));
7224488f1c74a0f7df09f2b201f7caa228d729e8389Adam Lesinski  EXPECT_TRUE(entry->symbol_status.allow_new);
723a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski}
724a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski
7257ff3ee19f4b831a526baf4b928d1ac172d070d82Adam LesinskiTEST_F(ResourceParserTest, ParseItemElementWithFormat) {
726a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<item name="foo" type="integer" format="float">0.3</item>)"));
7277ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski
728e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski  BinaryPrimitive* val = test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
729e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski  ASSERT_THAT(val, NotNull());
730a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(val->value.dataType, Eq(Res_value::TYPE_FLOAT));
731e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski
732a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_FALSE(TestParse(R"(<item name="bar" type="integer" format="fraction">100</item>)"));
733e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski}
734e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski
735e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski// An <item> without a format specifier accepts all types of values.
736e597d68d33c76c2b830f5497ed4ba74c5193a056Adam LesinskiTEST_F(ResourceParserTest, ParseItemElementWithoutFormat) {
737a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<item name="foo" type="integer">100%p</item>)"));
7387ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski
739e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski  BinaryPrimitive* val = test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
740e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski  ASSERT_THAT(val, NotNull());
741a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(val->value.dataType, Eq(Res_value::TYPE_FRACTION));
7427ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski}
7437ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski
74486d67df8d57b9537666f9b54a9ca563779a2288bAdam LesinskiTEST_F(ResourceParserTest, ParseConfigVaryingItem) {
745a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<item name="foo" type="configVarying">Hey</item>)"));
746a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValue<String>(&table_, "configVarying/foo"), NotNull());
74786d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski}
74886d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski
74986d67df8d57b9537666f9b54a9ca563779a2288bAdam LesinskiTEST_F(ResourceParserTest, ParseBagElement) {
750a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
751a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <bag name="bag" type="configVarying">
752a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item name="test">Hello!</item>
753a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </bag>)";
75486d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  ASSERT_TRUE(TestParse(input));
75586d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski
75686d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  Style* val = test::GetValue<Style>(&table_, "configVarying/bag");
757a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(val, NotNull());
758a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(val->entries, SizeIs(1));
75986d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski
760a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(val->entries[0].key, Eq(Reference(test::ParseNameOrDie("attr/test"))));
761a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(ValueCast<RawString>(val->entries[0].value.get()), NotNull());
76286d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski}
76386d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski
764bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam LesinskiTEST_F(ResourceParserTest, ParseElementWithNoValue) {
765bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  std::string input = R"(
766bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski      <item type="drawable" format="reference" name="foo" />
767bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski      <string name="foo" />)";
768bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  ASSERT_TRUE(TestParse(input));
769bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  ASSERT_THAT(test::GetValue(&table_, "drawable/foo"), Pointee(ValueEq(Reference())));
770bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski
771bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
772bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  ASSERT_THAT(str, NotNull());
773a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str, StrValueEq(""));
774bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski}
775bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski
776b9f0548341f98a64a87fa35ef5f58d1daf973ca7Adam LesinskiTEST_F(ResourceParserTest, ParsePlatformIndependentNewline) {
777a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<string name="foo">%1$s %n %2$s</string>)"));
778b9f0548341f98a64a87fa35ef5f58d1daf973ca7Adam Lesinski}
779b9f0548341f98a64a87fa35ef5f58d1daf973ca7Adam Lesinski
780cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski}  // namespace aapt
781