ResourceParser_test.cpp revision ce5e56e243d262a9b65459c3bd0bb9eaadd40628
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
286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskinamespace aapt {
296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
30cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinskiconstexpr const char* kXmlPreamble =
31cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
331ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiTEST(ResourceParserSingleTest, FailToParseWithNoRootResourcesElement) {
34ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
35cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::stringstream input(kXmlPreamble);
36cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  input << "<attr name=\"foo\"/>" << std::endl;
37cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ResourceTable table;
38ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceParser parser(context->GetDiagnostics(), &table, Source{"test"}, {});
39ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  xml::XmlPullParser xml_parser(input);
40ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_FALSE(parser.Parse(&xml_parser));
41769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
42769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
43ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskiclass ResourceParserTest : public ::testing::Test {
44ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski public:
45ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  void SetUp() override { context_ = test::ContextBuilder().Build(); }
461ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
47ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ::testing::AssertionResult TestParse(const StringPiece& str) {
48ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    return TestParse(str, ConfigDescription{});
49cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
5052364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski
51ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ::testing::AssertionResult TestParse(const StringPiece& str,
52cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                                       const ConfigDescription& config) {
53cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    std::stringstream input(kXmlPreamble);
54cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    input << "<resources>\n" << str << "\n</resources>" << std::endl;
55cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    ResourceParserOptions parserOptions;
56ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    ResourceParser parser(context_->GetDiagnostics(), &table_, Source{"test"},
57cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                          config, parserOptions);
58cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    xml::XmlPullParser xmlParser(input);
59ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    if (parser.Parse(&xmlParser)) {
60cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      return ::testing::AssertionSuccess();
616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
62cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return ::testing::AssertionFailure();
63cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
64ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
65ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski protected:
66ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceTable table_;
67ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  std::unique_ptr<IAaptContext> context_;
686f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski};
696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
706f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseQuotedString) {
71cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<string name=\"foo\">   \"  hey there \" </string>";
72ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
74ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
75cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, str);
76cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(std::string("  hey there "), *str->value);
776f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
786f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
796f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseEscapedString) {
80cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<string name=\"foo\">\\?123</string>";
81ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
83ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
84cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, str);
85cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(std::string("?123"), *str->value);
866f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
876f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
889f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam LesinskiTEST_F(ResourceParserTest, ParseFormattedString) {
89cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<string name=\"foo\">%d %s</string>";
90ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_FALSE(TestParse(input));
919f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski
92cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  input = "<string name=\"foo\">%1$d %2$s</string>";
93ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
949f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski}
959f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski
968c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam LesinskiTEST_F(ResourceParserTest, ParseStyledString) {
97cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // Use a surrogate pair unicode point so that we can verify that the span
98cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // indices
99cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // use UTF-16 length and not UTF-18 length.
100cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
101cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<string name=\"foo\">This is my aunt\u2019s <b>string</b></string>";
102ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
1038c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
104ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  StyledString* str = test::GetValue<StyledString>(&table_, "string/foo");
105cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, str);
1068c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
107ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  const std::string expected_str = "This is my aunt\u2019s string";
108ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(expected_str, *str->value->str);
109cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(1u, str->value->spans.size());
1108c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
111cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(std::string("b"), *str->value->spans[0].name);
112ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(17u, str->value->spans[0].first_char);
113ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(23u, str->value->spans[0].last_char);
1148c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski}
1158c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
1168c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam LesinskiTEST_F(ResourceParserTest, ParseStringWithWhitespace) {
117cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<string name=\"foo\">  This is what  I think  </string>";
118ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
1198c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
120ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
121cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, str);
122cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(std::string("This is what I think"), *str->value);
1238c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
124cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  input = "<string name=\"foo2\">\"  This is what  I think  \"</string>";
125ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
1268c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
127ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  str = test::GetValue<String>(&table_, "string/foo2");
128cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, str);
129cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(std::string("  This is what  I think  "), *str->value);
1308c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski}
1318c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
1321ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiTEST_F(ResourceParserTest, IgnoreXliffTags) {
133cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
134cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<string name=\"foo\" \n"
135cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "        xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n"
136cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  There are <xliff:g id=\"count\">%1$d</xliff:g> apples</string>";
137ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
1381ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
139ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
140cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, str);
141cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(StringPiece("There are %1$d apples"), StringPiece(*str->value));
1421ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
1431ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
144dfa5e0705ff82f15e228ba076bc192893bcbe118Adam LesinskiTEST_F(ResourceParserTest, ParseNull) {
145cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<integer name=\"foo\">@null</integer>";
146ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
147cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
148cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // The Android runtime treats a value of android::Res_value::TYPE_NULL as
149cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // a non-existing value, and this causes problems in styles when trying to
150cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // resolve
151cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // an attribute. Null values must be encoded as
152cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // android::Res_value::TYPE_REFERENCE
153cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // with a data value of 0.
154cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  BinaryPrimitive* integer =
155ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
156cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, integer);
157cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(uint16_t(android::Res_value::TYPE_REFERENCE),
158cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            integer->value.dataType);
159cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(0u, integer->value.data);
160dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski}
161dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski
162dfa5e0705ff82f15e228ba076bc192893bcbe118Adam LesinskiTEST_F(ResourceParserTest, ParseEmpty) {
163cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<integer name=\"foo\">@empty</integer>";
164ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
165dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski
166cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  BinaryPrimitive* integer =
167ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
168cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, integer);
169cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(uint16_t(android::Res_value::TYPE_NULL), integer->value.dataType);
170cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(uint32_t(android::Res_value::DATA_NULL_EMPTY), integer->value.data);
171dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski}
172dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski
1736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAttr) {
174cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
175cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<attr name=\"foo\" format=\"string\"/>\n"
176cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<attr name=\"bar\"/>";
177ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
178cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
179ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
180cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, attr);
181ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_STRING), attr->type_mask);
182cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
183ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  attr = test::GetValue<Attribute>(&table_, "attr/bar");
184cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, attr);
185ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_ANY), attr->type_mask);
186cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski}
187cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
188cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski// Old AAPT allowed attributes to be defined under different configurations, but
189cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski// ultimately
190cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski// stored them with the default configuration. Check that we have the same
191cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski// behavior.
192cacb28f2d60858106e2819cc7d95a65e8bda890bAdam LesinskiTEST_F(ResourceParserTest,
193cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski       ParseAttrAndDeclareStyleableUnderConfigButRecordAsNoConfig) {
194ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  const ConfigDescription watch_config = test::ParseConfigOrDie("watch");
195cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = R"EOF(
19652364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski        <attr name="foo" />
19752364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski        <declare-styleable name="bar">
19852364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski          <attr name="baz" />
19952364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski        </declare-styleable>)EOF";
200ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input, watch_config));
20152364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski
202ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(nullptr, test::GetValueForConfig<Attribute>(&table_, "attr/foo",
203ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                                                        watch_config));
204ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(nullptr, test::GetValueForConfig<Attribute>(&table_, "attr/baz",
205ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                                                        watch_config));
206ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(nullptr, test::GetValueForConfig<Styleable>(
207ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         &table_, "styleable/bar", watch_config));
20852364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski
209ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValue<Attribute>(&table_, "attr/foo"));
210ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValue<Attribute>(&table_, "attr/baz"));
211ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValue<Styleable>(&table_, "styleable/bar"));
21252364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski}
21352364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski
214a587065721053ad54e34f484868142407d59512dAdam LesinskiTEST_F(ResourceParserTest, ParseAttrWithMinMax) {
215cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
216cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<attr name=\"foo\" min=\"10\" max=\"23\" format=\"integer\"/>";
217ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
218a587065721053ad54e34f484868142407d59512dAdam Lesinski
219ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
220cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, attr);
221ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_INTEGER), attr->type_mask);
222ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(10, attr->min_int);
223ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(23, attr->max_int);
224a587065721053ad54e34f484868142407d59512dAdam Lesinski}
225a587065721053ad54e34f484868142407d59512dAdam Lesinski
226a587065721053ad54e34f484868142407d59512dAdam LesinskiTEST_F(ResourceParserTest, FailParseAttrWithMinMaxButNotInteger) {
227cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
228cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<attr name=\"foo\" min=\"10\" max=\"23\" format=\"string\"/>";
229ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_FALSE(TestParse(input));
230a587065721053ad54e34f484868142407d59512dAdam Lesinski}
231a587065721053ad54e34f484868142407d59512dAdam Lesinski
2326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseUseAndDeclOfAttr) {
233cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
234cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<declare-styleable name=\"Styleable\">\n"
235cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <attr name=\"foo\" />\n"
236cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</declare-styleable>\n"
237cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<attr name=\"foo\" format=\"string\"/>";
238ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
2396f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
240ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
241cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, attr);
242ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_STRING), attr->type_mask);
2436f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
2446f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2456f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseDoubleUseOfAttr) {
246cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
247cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<declare-styleable name=\"Theme\">"
248cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <attr name=\"foo\" />\n"
249cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</declare-styleable>\n"
250cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<declare-styleable name=\"Window\">\n"
251cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <attr name=\"foo\" format=\"boolean\"/>\n"
252cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</declare-styleable>";
253ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
2546f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
255ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
256cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, attr);
257ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_BOOLEAN), attr->type_mask);
2586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
2596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseEnumAttr) {
261cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
262cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<attr name=\"foo\">\n"
263cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <enum name=\"bar\" value=\"0\"/>\n"
264cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <enum name=\"bat\" value=\"1\"/>\n"
265cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <enum name=\"baz\" value=\"2\"/>\n"
266cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</attr>";
267ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
2686f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
269ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* enum_attr = test::GetValue<Attribute>(&table_, "attr/foo");
270ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_NE(enum_attr, nullptr);
271ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(enum_attr->type_mask, android::ResTable_map::TYPE_ENUM);
272ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_EQ(enum_attr->symbols.size(), 3u);
2736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
274ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  AAPT_ASSERT_TRUE(enum_attr->symbols[0].symbol.name);
275ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(enum_attr->symbols[0].symbol.name.value().entry, "bar");
276ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(enum_attr->symbols[0].value, 0u);
2776f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
278ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  AAPT_ASSERT_TRUE(enum_attr->symbols[1].symbol.name);
279ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(enum_attr->symbols[1].symbol.name.value().entry, "bat");
280ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(enum_attr->symbols[1].value, 1u);
2816f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
282ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  AAPT_ASSERT_TRUE(enum_attr->symbols[2].symbol.name);
283ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(enum_attr->symbols[2].symbol.name.value().entry, "baz");
284ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(enum_attr->symbols[2].value, 2u);
2856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
2866f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2876f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseFlagAttr) {
288cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
289cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<attr name=\"foo\">\n"
290cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <flag name=\"bar\" value=\"0\"/>\n"
291cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <flag name=\"bat\" value=\"1\"/>\n"
292cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <flag name=\"baz\" value=\"2\"/>\n"
293cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</attr>";
294ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
2956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
296ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* flag_attr = test::GetValue<Attribute>(&table_, "attr/foo");
297ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_NE(nullptr, flag_attr);
298ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(flag_attr->type_mask, android::ResTable_map::TYPE_FLAGS);
299ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_EQ(flag_attr->symbols.size(), 3u);
3006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
301ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  AAPT_ASSERT_TRUE(flag_attr->symbols[0].symbol.name);
302ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(flag_attr->symbols[0].symbol.name.value().entry, "bar");
303ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(flag_attr->symbols[0].value, 0u);
3046f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
305ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  AAPT_ASSERT_TRUE(flag_attr->symbols[1].symbol.name);
306ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(flag_attr->symbols[1].symbol.name.value().entry, "bat");
307ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(flag_attr->symbols[1].value, 1u);
3086f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
309ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  AAPT_ASSERT_TRUE(flag_attr->symbols[2].symbol.name);
310ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(flag_attr->symbols[2].symbol.name.value().entry, "baz");
311ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(flag_attr->symbols[2].value, 2u);
3126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
313ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  std::unique_ptr<BinaryPrimitive> flag_value =
314ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      ResourceUtils::TryParseFlagSymbol(flag_attr, "baz|bat");
315ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_NE(nullptr, flag_value);
316ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(flag_value->value.data, 1u | 2u);
3176f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, FailToParseEnumAttrWithNonUniqueKeys) {
320cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
321cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<attr name=\"foo\">\n"
322cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <enum name=\"bar\" value=\"0\"/>\n"
323cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <enum name=\"bat\" value=\"1\"/>\n"
324cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <enum name=\"bat\" value=\"2\"/>\n"
325cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</attr>";
326ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_FALSE(TestParse(input));
3276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseStyle) {
330cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
331cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<style name=\"foo\" parent=\"@style/fu\">\n"
332cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item name=\"bar\">#ffffffff</item>\n"
333cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item name=\"bat\">@string/hey</item>\n"
334cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item name=\"baz\"><b>hey</b></item>\n"
335cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</style>";
336ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
337cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
338ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
339cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, style);
340cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent);
341cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent.value().name);
342ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("style/fu"),
343cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            style->parent.value().name.value());
344cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_EQ(3u, style->entries.size());
345cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
346cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->entries[0].key.name);
347ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("attr/bar"),
348cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            style->entries[0].key.name.value());
349cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
350cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->entries[1].key.name);
351ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("attr/bat"),
352cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            style->entries[1].key.name.value());
353cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
354cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->entries[2].key.name);
355ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("attr/baz"),
356cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            style->entries[2].key.name.value());
3576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
359769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithShorthandParent) {
360cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<style name=\"foo\" parent=\"com.app:Theme\"/>";
361ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
362769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
363ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
364cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, style);
365cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent);
366cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent.value().name);
367ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("com.app:style/Theme"),
368cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            style->parent.value().name.value());
369769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
370769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
37124aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPackageAliasedParent) {
372cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
373cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<style xmlns:app=\"http://schemas.android.com/apk/res/android\"\n"
374cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "       name=\"foo\" parent=\"app:Theme\"/>";
375ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
37624aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
377ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
378cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, style);
379cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent);
380cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent.value().name);
381ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("android:style/Theme"),
382cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            style->parent.value().name.value());
38324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski}
38424aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
38524aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPackageAliasedItems) {
386cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
387cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<style xmlns:app=\"http://schemas.android.com/apk/res/android\" "
388cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "name=\"foo\">\n"
389cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item name=\"app:bar\">0</item>\n"
390cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</style>";
391ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
39224aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
393ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
394cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, style);
395cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_EQ(1u, style->entries.size());
396ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("android:attr/bar"),
397cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            style->entries[0].key.name.value());
39824aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski}
39924aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
400bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithInferredParent) {
401cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<style name=\"foo.bar\"/>";
402ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
403bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski
404ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo.bar");
405cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, style);
406cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent);
407cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent.value().name);
408cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(style->parent.value().name.value(),
409ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            test::ParseNameOrDie("style/foo"));
410ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(style->parent_inferred);
411bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski}
412bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski
413cacb28f2d60858106e2819cc7d95a65e8bda890bAdam LesinskiTEST_F(ResourceParserTest,
414cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski       ParseStyleWithInferredParentOverridenByEmptyParentAttribute) {
415cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<style name=\"foo.bar\" parent=\"\"/>";
416ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
417bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski
418ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo.bar");
419cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, style);
420cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_EXPECT_FALSE(style->parent);
421ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_FALSE(style->parent_inferred);
422bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski}
423bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski
42424b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPrivateParentReference) {
425cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
426cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      R"EOF(<style name="foo" parent="*android:style/bar" />)EOF";
427ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
42824b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski
429ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
430cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, style);
431cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent);
432ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(style->parent.value().private_reference);
43324b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski}
43424b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski
4356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAutoGeneratedIdReference) {
436cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<string name=\"foo\">@+id/bar</string>";
437ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
4386f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
439ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Id* id = test::GetValue<Id>(&table_, "id/bar");
440cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(id, nullptr);
4416f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
4426f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
4436f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAttributesDeclareStyleable) {
444cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
445cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<declare-styleable name=\"foo\">\n"
446cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <attr name=\"bar\" />\n"
447cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <attr name=\"bat\" format=\"string|reference\"/>\n"
448cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <attr name=\"baz\">\n"
449cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "    <enum name=\"foo\" value=\"1\"/>\n"
450cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  </attr>\n"
451cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</declare-styleable>";
452ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
453cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
454cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  Maybe<ResourceTable::SearchResult> result =
455ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      table_.FindResource(test::ParseNameOrDie("styleable/foo"));
456cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result);
457ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(SymbolState::kPublic, result.value().entry->symbol_status.state);
458cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
459ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/bar");
460cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(attr, nullptr);
461ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(attr->IsWeak());
462cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
463ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  attr = test::GetValue<Attribute>(&table_, "attr/bat");
464cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(attr, nullptr);
465ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(attr->IsWeak());
466cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
467ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  attr = test::GetValue<Attribute>(&table_, "attr/baz");
468cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(attr, nullptr);
469ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(attr->IsWeak());
470cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(1u, attr->symbols.size());
471cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
472ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValue<Id>(&table_, "id/foo"));
473cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
474ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo");
475cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(styleable, nullptr);
476cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_EQ(3u, styleable->entries.size());
477cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
478ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("attr/bar"),
479cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            styleable->entries[0].name.value());
480ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("attr/bat"),
481cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            styleable->entries[1].name.value());
4826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
4836f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
484467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam LesinskiTEST_F(ResourceParserTest, ParsePrivateAttributesDeclareStyleable) {
485cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
486cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<declare-styleable name=\"foo\" "
487cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "xmlns:privAndroid=\"http://schemas.android.com/apk/prv/res/android\">\n"
488cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <attr name=\"*android:bar\" />\n"
489cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <attr name=\"privAndroid:bat\" />\n"
490cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</declare-styleable>";
491ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
492ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo");
493cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, styleable);
494cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_EQ(2u, styleable->entries.size());
495cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
496ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(styleable->entries[0].private_reference);
497cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(styleable->entries[0].name);
498cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(std::string("android"), styleable->entries[0].name.value().package);
499cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
500ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(styleable->entries[1].private_reference);
501cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(styleable->entries[1].name);
502cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(std::string("android"), styleable->entries[1].name.value().package);
503467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski}
504467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski
5056f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseArray) {
506cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
507cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<array name=\"foo\">\n"
508cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item>@string/ref</item>\n"
509cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item>hey</item>\n"
510cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item>23</item>\n"
511cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</array>";
512ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
5136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
514ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Array* array = test::GetValue<Array>(&table_, "array/foo");
515cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(array, nullptr);
516cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_EQ(3u, array->items.size());
5176f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
518ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, ValueCast<Reference>(array->items[0].get()));
519ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, ValueCast<String>(array->items[1].get()));
520ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, ValueCast<BinaryPrimitive>(array->items[2].get()));
5216f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
5226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
5239ba47d813075fcb05c5e1532c137c93b394631cbAdam LesinskiTEST_F(ResourceParserTest, ParseStringArray) {
524cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
525cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<string-array name=\"foo\">\n"
526cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item>\"Werk\"</item>\n"
527cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</string-array>\n";
528ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
529ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValue<Array>(&table_, "array/foo"));
5309ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski}
5319ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski
5326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParsePlural) {
533cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
534cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<plurals name=\"foo\">\n"
535cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item quantity=\"other\">apples</item>\n"
536cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item quantity=\"one\">apple</item>\n"
537cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</plurals>";
538ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
5396f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
5406f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
5416f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseCommentsWithResource) {
542cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
543cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<!--This is a comment-->\n"
544cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<string name=\"foo\">Hi</string>";
545ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
5466f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
547ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* value = test::GetValue<String>(&table_, "string/foo");
548cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, value);
549ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(value->GetComment(), "This is a comment");
550e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski}
551e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
552e78fd617ec60139a973a01925fa7adad31febb39Adam LesinskiTEST_F(ResourceParserTest, DoNotCombineMultipleComments) {
553cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
554cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<!--One-->\n"
555cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<!--Two-->\n"
556cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<string name=\"foo\">Hi</string>";
557e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
558ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
559e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
560ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* value = test::GetValue<String>(&table_, "string/foo");
561cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, value);
562ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(value->GetComment(), "Two");
563e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski}
564e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
565e78fd617ec60139a973a01925fa7adad31febb39Adam LesinskiTEST_F(ResourceParserTest, IgnoreCommentBeforeEndTag) {
566cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
567cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<!--One-->\n"
568cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<string name=\"foo\">\n"
569cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  Hi\n"
570cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<!--Two-->\n"
571cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</string>";
572e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
573ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
5741ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
575ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* value = test::GetValue<String>(&table_, "string/foo");
576cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, value);
577ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(value->GetComment(), "One");
5786f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
5796f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
580ca5638fd85098c3d0a699492751043545f75553aAdam LesinskiTEST_F(ResourceParserTest, ParseNestedComments) {
581cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // We only care about declare-styleable and enum/flag attributes because
582cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // comments
583cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // from those end up in R.java
584cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = R"EOF(
585ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        <declare-styleable name="foo">
586ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski          <!-- The name of the bar -->
587ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski          <attr name="barName" format="string|reference" />
588ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        </declare-styleable>
589ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
590ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        <attr name="foo">
591ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski          <!-- The very first -->
592ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski          <enum name="one" value="1" />
593ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        </attr>)EOF";
594ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
595ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
596ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo");
597cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, styleable);
598cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_EQ(1u, styleable->entries.size());
599ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
600cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(StringPiece("The name of the bar"),
601ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            styleable->entries.front().GetComment());
602ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
603ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
604cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, attr);
605cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_EQ(1u, attr->symbols.size());
606ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
607cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(StringPiece("The very first"),
608ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            attr->symbols.front().symbol.GetComment());
609ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski}
610ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
6116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/*
6126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Declaring an ID as public should not require a separate definition
6136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * (as an ID has no value).
6146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */
6156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParsePublicIdAsDefinition) {
616cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<public type=\"id\" name=\"foo\"/>";
617ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
6186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
619ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Id* id = test::GetValue<Id>(&table_, "id/foo");
620cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, id);
6216f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
6226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
623e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam LesinskiTEST_F(ResourceParserTest, KeepAllProducts) {
624cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = R"EOF(
6257751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski        <string name="foo" product="phone">hi</string>
6267751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski        <string name="foo" product="no-sdcard">ho</string>
6277751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski        <string name="bar" product="">wee</string>
6287751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski        <string name="baz">woo</string>
6297751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski        <string name="bit" product="phablet">hoot</string>
6307751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski        <string name="bot" product="default">yes</string>
6317751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski    )EOF";
632ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
633ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
634ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<String>(
635ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         &table_, "string/foo",
636ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         ConfigDescription::DefaultConfig(), "phone"));
637ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<String>(
638ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         &table_, "string/foo",
639ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         ConfigDescription::DefaultConfig(), "no-sdcard"));
640cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_NE(nullptr,
641ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            test::GetValueForConfigAndProduct<String>(
642ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                &table_, "string/bar", ConfigDescription::DefaultConfig(), ""));
643cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_NE(nullptr,
644ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            test::GetValueForConfigAndProduct<String>(
645ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                &table_, "string/baz", ConfigDescription::DefaultConfig(), ""));
646ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<String>(
647ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         &table_, "string/bit",
648ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         ConfigDescription::DefaultConfig(), "phablet"));
649ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<String>(
650ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         &table_, "string/bot",
651ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         ConfigDescription::DefaultConfig(), "default"));
6529ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski}
6539ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski
65427afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam LesinskiTEST_F(ResourceParserTest, AutoIncrementIdsInPublicGroup) {
655cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = R"EOF(
65627afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski    <public-group type="attr" first-id="0x01010040">
65727afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski      <public name="foo" />
65827afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski      <public name="bar" />
65927afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski    </public-group>)EOF";
660ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
661cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
662cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  Maybe<ResourceTable::SearchResult> result =
663ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      table_.FindResource(test::ParseNameOrDie("attr/foo"));
664cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result);
665cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
666cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result.value().package->id);
667cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result.value().type->id);
668cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result.value().entry->id);
669ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceId actual_id(result.value().package->id.value(),
670ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                       result.value().type->id.value(),
671ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                       result.value().entry->id.value());
672ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(ResourceId(0x01010040), actual_id);
673cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
674ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  result = table_.FindResource(test::ParseNameOrDie("attr/bar"));
675cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result);
676cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
677cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result.value().package->id);
678cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result.value().type->id);
679cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result.value().entry->id);
680ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  actual_id = ResourceId(result.value().package->id.value(),
681ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         result.value().type->id.value(),
682ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         result.value().entry->id.value());
683ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(ResourceId(0x01010041), actual_id);
68427afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski}
68527afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski
686fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam LesinskiTEST_F(ResourceParserTest, ExternalTypesShouldOnlyBeReferences) {
687cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
688cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      R"EOF(<item type="layout" name="foo">@layout/bar</item>)EOF";
689ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
690fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski
691cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  input = R"EOF(<item type="layout" name="bar">"this is a string"</item>)EOF";
692ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_FALSE(TestParse(input));
693fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski}
694fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski
695cacb28f2d60858106e2819cc7d95a65e8bda890bAdam LesinskiTEST_F(ResourceParserTest,
696cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski       AddResourcesElementShouldAddEntryWithUndefinedSymbol) {
697cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = R"EOF(<add-resource name="bar" type="string" />)EOF";
698ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
699a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski
700cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  Maybe<ResourceTable::SearchResult> result =
701ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      table_.FindResource(test::ParseNameOrDie("string/bar"));
702cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result);
703cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  const ResourceEntry* entry = result.value().entry;
704cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, entry);
705ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(SymbolState::kUndefined, entry->symbol_status.state);
706a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski}
707a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski
7087ff3ee19f4b831a526baf4b928d1ac172d070d82Adam LesinskiTEST_F(ResourceParserTest, ParseItemElementWithFormat) {
709cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
710cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      R"EOF(<item name="foo" type="integer" format="float">0.3</item>)EOF";
711ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
7127ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski
713cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  BinaryPrimitive* val =
714ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
715cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, val);
7167ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski
717cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(uint32_t(android::Res_value::TYPE_FLOAT), val->value.dataType);
7187ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski}
7197ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski
720cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski}  // namespace aapt
721