ResourceParser_test.cpp revision 7542162cb1b1fd2ce8a26dd7f3fedc8de8160d38
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
28d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinskiusing android::StringPiece;
29d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski
306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskinamespace aapt {
316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
32cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinskiconstexpr const char* kXmlPreamble =
33cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
351ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiTEST(ResourceParserSingleTest, FailToParseWithNoRootResourcesElement) {
36ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
37cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::stringstream input(kXmlPreamble);
38cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  input << "<attr name=\"foo\"/>" << std::endl;
39cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ResourceTable table;
40ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceParser parser(context->GetDiagnostics(), &table, Source{"test"}, {});
41ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  xml::XmlPullParser xml_parser(input);
42ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_FALSE(parser.Parse(&xml_parser));
43769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
44769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
45ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskiclass ResourceParserTest : public ::testing::Test {
46ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski public:
47ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  void SetUp() override { context_ = test::ContextBuilder().Build(); }
481ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
49ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ::testing::AssertionResult TestParse(const StringPiece& str) {
50ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    return TestParse(str, ConfigDescription{});
51cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
5252364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski
53ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ::testing::AssertionResult TestParse(const StringPiece& str,
54cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                                       const ConfigDescription& config) {
55cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    std::stringstream input(kXmlPreamble);
56cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    input << "<resources>\n" << str << "\n</resources>" << std::endl;
57cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    ResourceParserOptions parserOptions;
58ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    ResourceParser parser(context_->GetDiagnostics(), &table_, Source{"test"},
59cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                          config, parserOptions);
60cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    xml::XmlPullParser xmlParser(input);
61ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    if (parser.Parse(&xmlParser)) {
62cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      return ::testing::AssertionSuccess();
636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
64cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return ::testing::AssertionFailure();
65cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
66ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
67ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski protected:
68ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceTable table_;
69ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  std::unique_ptr<IAaptContext> context_;
706f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski};
716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
726f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseQuotedString) {
73cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<string name=\"foo\">   \"  hey there \" </string>";
74ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
76ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
77cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, str);
78cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(std::string("  hey there "), *str->value);
797542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_TRUE(str->untranslatable_sections.empty());
806f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
816f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseEscapedString) {
83cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<string name=\"foo\">\\?123</string>";
84ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
86ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
87cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, str);
88cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(std::string("?123"), *str->value);
897542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_TRUE(str->untranslatable_sections.empty());
906f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
916f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
929f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam LesinskiTEST_F(ResourceParserTest, ParseFormattedString) {
93cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<string name=\"foo\">%d %s</string>";
94ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_FALSE(TestParse(input));
959f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski
96cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  input = "<string name=\"foo\">%1$d %2$s</string>";
97ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
989f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski}
999f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski
1008c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam LesinskiTEST_F(ResourceParserTest, ParseStyledString) {
101cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // Use a surrogate pair unicode point so that we can verify that the span
1027542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // indices use UTF-16 length and not UTF-8 length.
103cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
104cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<string name=\"foo\">This is my aunt\u2019s <b>string</b></string>";
105ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
1068c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
107ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  StyledString* str = test::GetValue<StyledString>(&table_, "string/foo");
108cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, str);
1098c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
110ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  const std::string expected_str = "This is my aunt\u2019s string";
111ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(expected_str, *str->value->str);
112cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(1u, str->value->spans.size());
1137542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_TRUE(str->untranslatable_sections.empty());
1148c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
115cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(std::string("b"), *str->value->spans[0].name);
116ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(17u, str->value->spans[0].first_char);
117ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(23u, str->value->spans[0].last_char);
1188c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski}
1198c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
1208c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam LesinskiTEST_F(ResourceParserTest, ParseStringWithWhitespace) {
121cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<string name=\"foo\">  This is what  I think  </string>";
122ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
1238c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
124ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
125cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, str);
126cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(std::string("This is what I think"), *str->value);
1277542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_TRUE(str->untranslatable_sections.empty());
1288c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
129cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  input = "<string name=\"foo2\">\"  This is what  I think  \"</string>";
130ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
1318c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
132ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  str = test::GetValue<String>(&table_, "string/foo2");
133cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, str);
134cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(std::string("  This is what  I think  "), *str->value);
1358c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski}
1368c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
1377542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, IgnoreXliffTagsOtherThanG) {
1387542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  std::string input = R"EOF(
1397542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski      <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
1407542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski          There are <xliff:source>no</xliff:source> apples</string>)EOF";
1417542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  ASSERT_TRUE(TestParse(input));
1427542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1437542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
1447542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  ASSERT_NE(nullptr, str);
1457542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_EQ(StringPiece("There are no apples"), StringPiece(*str->value));
1467542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_TRUE(str->untranslatable_sections.empty());
1477542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski}
1487542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1497542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, NestedXliffGTagsAreIllegal) {
1507542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  std::string input = R"EOF(
1517542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski      <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
1527542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski          Do not <xliff:g>translate <xliff:g>this</xliff:g></xliff:g></string>)EOF";
1537542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_FALSE(TestParse(input));
1547542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski}
1557542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1567542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, RecordUntranslateableXliffSectionsInString) {
1577542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  std::string input = R"EOF(
1587542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski      <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
1597542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski          There are <xliff:g id="count">%1$d</xliff:g> apples</string>)EOF";
160ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
1611ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
162ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
163cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, str);
164cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(StringPiece("There are %1$d apples"), StringPiece(*str->value));
1657542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1667542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  ASSERT_EQ(1u, str->untranslatable_sections.size());
1677542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1687542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // We expect indices and lengths that span to include the whitespace
1697542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // before %1$d. This is due to how the StringBuilder withholds whitespace unless
1707542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // needed (to deal with line breaks, etc.).
1717542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_EQ(9u, str->untranslatable_sections[0].start);
1727542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_EQ(14u, str->untranslatable_sections[0].end);
1737542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski}
1747542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1757542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, RecordUntranslateableXliffSectionsInStyledString) {
1767542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  std::string input = R"EOF(
1777542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski      <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
1787542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski          There are <b><xliff:g id="count">%1$d</xliff:g></b> apples</string>)EOF";
1797542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  ASSERT_TRUE(TestParse(input));
1807542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1817542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  StyledString* str = test::GetValue<StyledString>(&table_, "string/foo");
1827542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  ASSERT_NE(nullptr, str);
1837542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_EQ(StringPiece("There are %1$d apples"), StringPiece(*str->value->str));
1847542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1857542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  ASSERT_EQ(1u, str->untranslatable_sections.size());
1867542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1877542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // We expect indices and lengths that span to include the whitespace
1887542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // before %1$d. This is due to how the StringBuilder withholds whitespace unless
1897542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // needed (to deal with line breaks, etc.).
1907542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_EQ(9u, str->untranslatable_sections[0].start);
1917542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_EQ(14u, str->untranslatable_sections[0].end);
1921ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
1931ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
194dfa5e0705ff82f15e228ba076bc192893bcbe118Adam LesinskiTEST_F(ResourceParserTest, ParseNull) {
195cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<integer name=\"foo\">@null</integer>";
196ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
197cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
198cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // The Android runtime treats a value of android::Res_value::TYPE_NULL as
199cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // a non-existing value, and this causes problems in styles when trying to
2007542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // resolve an attribute. Null values must be encoded as android::Res_value::TYPE_REFERENCE
201cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // with a data value of 0.
2027542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  BinaryPrimitive* integer = test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
203cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, integer);
2047542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_EQ(uint16_t(android::Res_value::TYPE_REFERENCE), integer->value.dataType);
205cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(0u, integer->value.data);
206dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski}
207dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski
208dfa5e0705ff82f15e228ba076bc192893bcbe118Adam LesinskiTEST_F(ResourceParserTest, ParseEmpty) {
209cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<integer name=\"foo\">@empty</integer>";
210ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
211dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski
212cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  BinaryPrimitive* integer =
213ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
214cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, integer);
215cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(uint16_t(android::Res_value::TYPE_NULL), integer->value.dataType);
216cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(uint32_t(android::Res_value::DATA_NULL_EMPTY), integer->value.data);
217dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski}
218dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski
2196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAttr) {
220cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
221cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<attr name=\"foo\" format=\"string\"/>\n"
222cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<attr name=\"bar\"/>";
223ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
224cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
225ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
226cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, attr);
227ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_STRING), attr->type_mask);
228cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
229ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  attr = test::GetValue<Attribute>(&table_, "attr/bar");
230cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, attr);
231ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_ANY), attr->type_mask);
232cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski}
233cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
234cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski// Old AAPT allowed attributes to be defined under different configurations, but
235cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski// ultimately
236cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski// stored them with the default configuration. Check that we have the same
237cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski// behavior.
238cacb28f2d60858106e2819cc7d95a65e8bda890bAdam LesinskiTEST_F(ResourceParserTest,
239cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski       ParseAttrAndDeclareStyleableUnderConfigButRecordAsNoConfig) {
240ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  const ConfigDescription watch_config = test::ParseConfigOrDie("watch");
241cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = R"EOF(
24252364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski        <attr name="foo" />
24352364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski        <declare-styleable name="bar">
24452364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski          <attr name="baz" />
24552364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski        </declare-styleable>)EOF";
246ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input, watch_config));
24752364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski
248ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(nullptr, test::GetValueForConfig<Attribute>(&table_, "attr/foo",
249ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                                                        watch_config));
250ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(nullptr, test::GetValueForConfig<Attribute>(&table_, "attr/baz",
251ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                                                        watch_config));
252ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(nullptr, test::GetValueForConfig<Styleable>(
253ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         &table_, "styleable/bar", watch_config));
25452364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski
255ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValue<Attribute>(&table_, "attr/foo"));
256ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValue<Attribute>(&table_, "attr/baz"));
257ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValue<Styleable>(&table_, "styleable/bar"));
25852364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski}
25952364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski
260a587065721053ad54e34f484868142407d59512dAdam LesinskiTEST_F(ResourceParserTest, ParseAttrWithMinMax) {
261cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
262cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<attr name=\"foo\" min=\"10\" max=\"23\" format=\"integer\"/>";
263ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
264a587065721053ad54e34f484868142407d59512dAdam Lesinski
265ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
266cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, attr);
267ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_INTEGER), attr->type_mask);
268ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(10, attr->min_int);
269ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(23, attr->max_int);
270a587065721053ad54e34f484868142407d59512dAdam Lesinski}
271a587065721053ad54e34f484868142407d59512dAdam Lesinski
272a587065721053ad54e34f484868142407d59512dAdam LesinskiTEST_F(ResourceParserTest, FailParseAttrWithMinMaxButNotInteger) {
273cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
274cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<attr name=\"foo\" min=\"10\" max=\"23\" format=\"string\"/>";
275ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_FALSE(TestParse(input));
276a587065721053ad54e34f484868142407d59512dAdam Lesinski}
277a587065721053ad54e34f484868142407d59512dAdam Lesinski
2786f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseUseAndDeclOfAttr) {
279cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
280cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<declare-styleable name=\"Styleable\">\n"
281cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <attr name=\"foo\" />\n"
282cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</declare-styleable>\n"
283cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<attr name=\"foo\" format=\"string\"/>";
284ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
2856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
286ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
287cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, attr);
288ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_STRING), attr->type_mask);
2896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
2906f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2916f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseDoubleUseOfAttr) {
292cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
293cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<declare-styleable name=\"Theme\">"
294cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <attr name=\"foo\" />\n"
295cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</declare-styleable>\n"
296cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<declare-styleable name=\"Window\">\n"
297cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <attr name=\"foo\" format=\"boolean\"/>\n"
298cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</declare-styleable>";
299ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
3006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
301ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
302cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, attr);
303ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_BOOLEAN), attr->type_mask);
3046f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3056f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3066f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseEnumAttr) {
307cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
308cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<attr name=\"foo\">\n"
309cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <enum name=\"bar\" value=\"0\"/>\n"
310cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <enum name=\"bat\" value=\"1\"/>\n"
311cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <enum name=\"baz\" value=\"2\"/>\n"
312cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</attr>";
313ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
3146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
315ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* enum_attr = test::GetValue<Attribute>(&table_, "attr/foo");
316ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_NE(enum_attr, nullptr);
317ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(enum_attr->type_mask, android::ResTable_map::TYPE_ENUM);
318ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_EQ(enum_attr->symbols.size(), 3u);
3196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
320ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  AAPT_ASSERT_TRUE(enum_attr->symbols[0].symbol.name);
321ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(enum_attr->symbols[0].symbol.name.value().entry, "bar");
322ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(enum_attr->symbols[0].value, 0u);
3236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
324ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  AAPT_ASSERT_TRUE(enum_attr->symbols[1].symbol.name);
325ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(enum_attr->symbols[1].symbol.name.value().entry, "bat");
326ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(enum_attr->symbols[1].value, 1u);
3276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
328ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  AAPT_ASSERT_TRUE(enum_attr->symbols[2].symbol.name);
329ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(enum_attr->symbols[2].symbol.name.value().entry, "baz");
330ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(enum_attr->symbols[2].value, 2u);
3316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseFlagAttr) {
334cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
335cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<attr name=\"foo\">\n"
336cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <flag name=\"bar\" value=\"0\"/>\n"
337cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <flag name=\"bat\" value=\"1\"/>\n"
338cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <flag name=\"baz\" value=\"2\"/>\n"
339cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</attr>";
340ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
3416f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
342ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* flag_attr = test::GetValue<Attribute>(&table_, "attr/foo");
343ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_NE(nullptr, flag_attr);
344ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(flag_attr->type_mask, android::ResTable_map::TYPE_FLAGS);
345ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_EQ(flag_attr->symbols.size(), 3u);
3466f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
347ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  AAPT_ASSERT_TRUE(flag_attr->symbols[0].symbol.name);
348ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(flag_attr->symbols[0].symbol.name.value().entry, "bar");
349ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(flag_attr->symbols[0].value, 0u);
3506f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
351ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  AAPT_ASSERT_TRUE(flag_attr->symbols[1].symbol.name);
352ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(flag_attr->symbols[1].symbol.name.value().entry, "bat");
353ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(flag_attr->symbols[1].value, 1u);
3546f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
355ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  AAPT_ASSERT_TRUE(flag_attr->symbols[2].symbol.name);
356ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(flag_attr->symbols[2].symbol.name.value().entry, "baz");
357ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(flag_attr->symbols[2].value, 2u);
3586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
359ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  std::unique_ptr<BinaryPrimitive> flag_value =
360ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      ResourceUtils::TryParseFlagSymbol(flag_attr, "baz|bat");
361ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_NE(nullptr, flag_value);
362ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(flag_value->value.data, 1u | 2u);
3636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3656f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, FailToParseEnumAttrWithNonUniqueKeys) {
366cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
367cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<attr name=\"foo\">\n"
368cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <enum name=\"bar\" value=\"0\"/>\n"
369cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <enum name=\"bat\" value=\"1\"/>\n"
370cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <enum name=\"bat\" value=\"2\"/>\n"
371cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</attr>";
372ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_FALSE(TestParse(input));
3736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseStyle) {
376cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
377cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<style name=\"foo\" parent=\"@style/fu\">\n"
378cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item name=\"bar\">#ffffffff</item>\n"
379cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item name=\"bat\">@string/hey</item>\n"
380cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item name=\"baz\"><b>hey</b></item>\n"
381cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</style>";
382ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
383cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
384ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
385cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, style);
386cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent);
387cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent.value().name);
388ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("style/fu"),
389cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            style->parent.value().name.value());
390cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_EQ(3u, style->entries.size());
391cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
392cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->entries[0].key.name);
393ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("attr/bar"),
394cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            style->entries[0].key.name.value());
395cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
396cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->entries[1].key.name);
397ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("attr/bat"),
398cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            style->entries[1].key.name.value());
399cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
400cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->entries[2].key.name);
401ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("attr/baz"),
402cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            style->entries[2].key.name.value());
4036f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
4046f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
405769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithShorthandParent) {
406cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<style name=\"foo\" parent=\"com.app:Theme\"/>";
407ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
408769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
409ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
410cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, style);
411cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent);
412cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent.value().name);
413ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("com.app:style/Theme"),
414cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            style->parent.value().name.value());
415769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
416769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
41724aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPackageAliasedParent) {
418cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
419cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<style xmlns:app=\"http://schemas.android.com/apk/res/android\"\n"
420cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "       name=\"foo\" parent=\"app:Theme\"/>";
421ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
42224aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
423ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
424cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, style);
425cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent);
426cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent.value().name);
427ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("android:style/Theme"),
428cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            style->parent.value().name.value());
42924aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski}
43024aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
43124aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPackageAliasedItems) {
432cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
433cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<style xmlns:app=\"http://schemas.android.com/apk/res/android\" "
434cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "name=\"foo\">\n"
435cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item name=\"app:bar\">0</item>\n"
436cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</style>";
437ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
43824aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
439ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
440cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, style);
441cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_EQ(1u, style->entries.size());
442ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("android:attr/bar"),
443cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            style->entries[0].key.name.value());
44424aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski}
44524aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
446bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithInferredParent) {
447cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<style name=\"foo.bar\"/>";
448ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
449bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski
450ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo.bar");
451cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, style);
452cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent);
453cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent.value().name);
454cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(style->parent.value().name.value(),
455ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            test::ParseNameOrDie("style/foo"));
456ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(style->parent_inferred);
457bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski}
458bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski
459cacb28f2d60858106e2819cc7d95a65e8bda890bAdam LesinskiTEST_F(ResourceParserTest,
460cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski       ParseStyleWithInferredParentOverridenByEmptyParentAttribute) {
461cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<style name=\"foo.bar\" parent=\"\"/>";
462ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
463bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski
464ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo.bar");
465cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, style);
466cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_EXPECT_FALSE(style->parent);
467ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_FALSE(style->parent_inferred);
468bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski}
469bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski
47024b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPrivateParentReference) {
471cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
472cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      R"EOF(<style name="foo" parent="*android:style/bar" />)EOF";
473ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
47424b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski
475ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
476cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, style);
477cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent);
478ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(style->parent.value().private_reference);
47924b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski}
48024b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski
4816f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAutoGeneratedIdReference) {
482cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<string name=\"foo\">@+id/bar</string>";
483ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
4846f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
485ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Id* id = test::GetValue<Id>(&table_, "id/bar");
486cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(id, nullptr);
4876f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
4886f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
4896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAttributesDeclareStyleable) {
490cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
491cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<declare-styleable name=\"foo\">\n"
492cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <attr name=\"bar\" />\n"
493cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <attr name=\"bat\" format=\"string|reference\"/>\n"
494cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <attr name=\"baz\">\n"
495cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "    <enum name=\"foo\" value=\"1\"/>\n"
496cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  </attr>\n"
497cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</declare-styleable>";
498ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
499cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
500cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  Maybe<ResourceTable::SearchResult> result =
501ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      table_.FindResource(test::ParseNameOrDie("styleable/foo"));
502cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result);
503ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(SymbolState::kPublic, result.value().entry->symbol_status.state);
504cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
505ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/bar");
506cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(attr, nullptr);
507ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(attr->IsWeak());
508cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
509ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  attr = test::GetValue<Attribute>(&table_, "attr/bat");
510cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(attr, nullptr);
511ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(attr->IsWeak());
512cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
513ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  attr = test::GetValue<Attribute>(&table_, "attr/baz");
514cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(attr, nullptr);
515ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(attr->IsWeak());
516cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(1u, attr->symbols.size());
517cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
518ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValue<Id>(&table_, "id/foo"));
519cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
520ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo");
521cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(styleable, nullptr);
522cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_EQ(3u, styleable->entries.size());
523cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
524ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("attr/bar"),
525cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            styleable->entries[0].name.value());
526ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("attr/bat"),
527cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            styleable->entries[1].name.value());
5286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
5296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
530467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam LesinskiTEST_F(ResourceParserTest, ParsePrivateAttributesDeclareStyleable) {
531cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
532cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<declare-styleable name=\"foo\" "
533cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "xmlns:privAndroid=\"http://schemas.android.com/apk/prv/res/android\">\n"
534cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <attr name=\"*android:bar\" />\n"
535cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <attr name=\"privAndroid:bat\" />\n"
536cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</declare-styleable>";
537ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
538ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo");
539cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, styleable);
540cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_EQ(2u, styleable->entries.size());
541cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
542ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(styleable->entries[0].private_reference);
543cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(styleable->entries[0].name);
544cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(std::string("android"), styleable->entries[0].name.value().package);
545cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
546ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(styleable->entries[1].private_reference);
547cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(styleable->entries[1].name);
548cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(std::string("android"), styleable->entries[1].name.value().package);
549467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski}
550467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski
5516f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseArray) {
552cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
553cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<array name=\"foo\">\n"
554cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item>@string/ref</item>\n"
555cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item>hey</item>\n"
556cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item>23</item>\n"
557cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</array>";
558ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
5596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
560ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Array* array = test::GetValue<Array>(&table_, "array/foo");
561cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(array, nullptr);
562cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_EQ(3u, array->items.size());
5636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
564ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, ValueCast<Reference>(array->items[0].get()));
565ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, ValueCast<String>(array->items[1].get()));
566ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, ValueCast<BinaryPrimitive>(array->items[2].get()));
5676f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
5686f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
5699ba47d813075fcb05c5e1532c137c93b394631cbAdam LesinskiTEST_F(ResourceParserTest, ParseStringArray) {
570cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
571cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<string-array name=\"foo\">\n"
572cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item>\"Werk\"</item>\n"
573cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</string-array>\n";
574ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
575ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValue<Array>(&table_, "array/foo"));
5769ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski}
5779ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski
5786f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParsePlural) {
579cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
580cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<plurals name=\"foo\">\n"
581cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item quantity=\"other\">apples</item>\n"
582cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item quantity=\"one\">apple</item>\n"
583cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</plurals>";
584ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
5856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
5866f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
5876f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseCommentsWithResource) {
588cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
589cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<!--This is a comment-->\n"
590cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<string name=\"foo\">Hi</string>";
591ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
5926f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
593ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* value = test::GetValue<String>(&table_, "string/foo");
594cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, value);
595ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(value->GetComment(), "This is a comment");
596e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski}
597e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
598e78fd617ec60139a973a01925fa7adad31febb39Adam LesinskiTEST_F(ResourceParserTest, DoNotCombineMultipleComments) {
599cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
600cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<!--One-->\n"
601cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<!--Two-->\n"
602cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<string name=\"foo\">Hi</string>";
603e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
604ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
605e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
606ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* value = test::GetValue<String>(&table_, "string/foo");
607cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, value);
608ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(value->GetComment(), "Two");
609e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski}
610e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
611e78fd617ec60139a973a01925fa7adad31febb39Adam LesinskiTEST_F(ResourceParserTest, IgnoreCommentBeforeEndTag) {
612cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
613cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<!--One-->\n"
614cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<string name=\"foo\">\n"
615cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  Hi\n"
616cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<!--Two-->\n"
617cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</string>";
618e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
619ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
6201ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
621ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* value = test::GetValue<String>(&table_, "string/foo");
622cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, value);
623ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(value->GetComment(), "One");
6246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
6256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
626ca5638fd85098c3d0a699492751043545f75553aAdam LesinskiTEST_F(ResourceParserTest, ParseNestedComments) {
627cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // We only care about declare-styleable and enum/flag attributes because
628cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // comments
629cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // from those end up in R.java
630cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = R"EOF(
631ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        <declare-styleable name="foo">
632ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski          <!-- The name of the bar -->
633ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski          <attr name="barName" format="string|reference" />
634ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        </declare-styleable>
635ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
636ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        <attr name="foo">
637ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski          <!-- The very first -->
638ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski          <enum name="one" value="1" />
639ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        </attr>)EOF";
640ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
641ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
642ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo");
643cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, styleable);
644cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_EQ(1u, styleable->entries.size());
645ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
646cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(StringPiece("The name of the bar"),
647ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            styleable->entries.front().GetComment());
648ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
649ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
650cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, attr);
651cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_EQ(1u, attr->symbols.size());
652ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
653cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(StringPiece("The very first"),
654ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            attr->symbols.front().symbol.GetComment());
655ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski}
656ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
6576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/*
6586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Declaring an ID as public should not require a separate definition
6596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * (as an ID has no value).
6606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */
6616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParsePublicIdAsDefinition) {
662cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<public type=\"id\" name=\"foo\"/>";
663ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
6646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
665ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Id* id = test::GetValue<Id>(&table_, "id/foo");
666cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, id);
6676f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
6686f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
669e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam LesinskiTEST_F(ResourceParserTest, KeepAllProducts) {
670cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = R"EOF(
6717751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski        <string name="foo" product="phone">hi</string>
6727751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski        <string name="foo" product="no-sdcard">ho</string>
6737751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski        <string name="bar" product="">wee</string>
6747751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski        <string name="baz">woo</string>
6757751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski        <string name="bit" product="phablet">hoot</string>
6767751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski        <string name="bot" product="default">yes</string>
6777751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski    )EOF";
678ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
679ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
680ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<String>(
681ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         &table_, "string/foo",
682ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         ConfigDescription::DefaultConfig(), "phone"));
683ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<String>(
684ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         &table_, "string/foo",
685ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         ConfigDescription::DefaultConfig(), "no-sdcard"));
686cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_NE(nullptr,
687ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            test::GetValueForConfigAndProduct<String>(
688ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                &table_, "string/bar", ConfigDescription::DefaultConfig(), ""));
689cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_NE(nullptr,
690ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            test::GetValueForConfigAndProduct<String>(
691ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                &table_, "string/baz", ConfigDescription::DefaultConfig(), ""));
692ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<String>(
693ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         &table_, "string/bit",
694ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         ConfigDescription::DefaultConfig(), "phablet"));
695ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<String>(
696ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         &table_, "string/bot",
697ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         ConfigDescription::DefaultConfig(), "default"));
6989ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski}
6999ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski
70027afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam LesinskiTEST_F(ResourceParserTest, AutoIncrementIdsInPublicGroup) {
701cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = R"EOF(
70227afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski    <public-group type="attr" first-id="0x01010040">
70327afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski      <public name="foo" />
70427afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski      <public name="bar" />
70527afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski    </public-group>)EOF";
706ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
707cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
708cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  Maybe<ResourceTable::SearchResult> result =
709ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      table_.FindResource(test::ParseNameOrDie("attr/foo"));
710cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result);
711cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
712cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result.value().package->id);
713cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result.value().type->id);
714cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result.value().entry->id);
715ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceId actual_id(result.value().package->id.value(),
716ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                       result.value().type->id.value(),
717ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                       result.value().entry->id.value());
718ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(ResourceId(0x01010040), actual_id);
719cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
720ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  result = table_.FindResource(test::ParseNameOrDie("attr/bar"));
721cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result);
722cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
723cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result.value().package->id);
724cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result.value().type->id);
725cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result.value().entry->id);
726ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  actual_id = ResourceId(result.value().package->id.value(),
727ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         result.value().type->id.value(),
728ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         result.value().entry->id.value());
729ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(ResourceId(0x01010041), actual_id);
73027afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski}
73127afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski
732fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam LesinskiTEST_F(ResourceParserTest, ExternalTypesShouldOnlyBeReferences) {
733cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
734cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      R"EOF(<item type="layout" name="foo">@layout/bar</item>)EOF";
735ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
736fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski
737cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  input = R"EOF(<item type="layout" name="bar">"this is a string"</item>)EOF";
738ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_FALSE(TestParse(input));
739fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski}
740fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski
741cacb28f2d60858106e2819cc7d95a65e8bda890bAdam LesinskiTEST_F(ResourceParserTest,
742cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski       AddResourcesElementShouldAddEntryWithUndefinedSymbol) {
743cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = R"EOF(<add-resource name="bar" type="string" />)EOF";
744ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
745a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski
746cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  Maybe<ResourceTable::SearchResult> result =
747ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      table_.FindResource(test::ParseNameOrDie("string/bar"));
748cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result);
749cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  const ResourceEntry* entry = result.value().entry;
750cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, entry);
751ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(SymbolState::kUndefined, entry->symbol_status.state);
752a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski}
753a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski
7547ff3ee19f4b831a526baf4b928d1ac172d070d82Adam LesinskiTEST_F(ResourceParserTest, ParseItemElementWithFormat) {
755cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
756cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      R"EOF(<item name="foo" type="integer" format="float">0.3</item>)EOF";
757ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
7587ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski
759cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  BinaryPrimitive* val =
760ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
761cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, val);
7627ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski
763cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(uint32_t(android::Res_value::TYPE_FLOAT), val->value.dataType);
7647ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski}
7657ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski
76686d67df8d57b9537666f9b54a9ca563779a2288bAdam LesinskiTEST_F(ResourceParserTest, ParseConfigVaryingItem) {
76786d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  std::string input = R"EOF(<item name="foo" type="configVarying">Hey</item>)EOF";
76886d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  ASSERT_TRUE(TestParse(input));
76986d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  ASSERT_NE(nullptr, test::GetValue<String>(&table_, "configVarying/foo"));
77086d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski}
77186d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski
77286d67df8d57b9537666f9b54a9ca563779a2288bAdam LesinskiTEST_F(ResourceParserTest, ParseBagElement) {
77386d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  std::string input =
77486d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski      R"EOF(<bag name="bag" type="configVarying"><item name="test">Hello!</item></bag>)EOF";
77586d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  ASSERT_TRUE(TestParse(input));
77686d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski
77786d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  Style* val = test::GetValue<Style>(&table_, "configVarying/bag");
77886d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  ASSERT_NE(nullptr, val);
77986d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski
78086d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  ASSERT_EQ(1u, val->entries.size());
78186d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  EXPECT_EQ(Reference(test::ParseNameOrDie("attr/test")), val->entries[0].key);
78286d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  EXPECT_NE(nullptr, ValueCast<RawString>(val->entries[0].value.get()));
78386d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski}
78486d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski
785cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski}  // namespace aapt
786