ResourceParser_test.cpp revision 8049f3da712ea9c3154b57ce2276c97e749d1f2c
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 =
1048049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski      "<string name=\"foo\">This is my aunt\u2019s <b>fickle <small>string</small></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
1108049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski  const std::string expected_str = "This is my aunt\u2019s fickle string";
111ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(expected_str, *str->value->str);
1128049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski  EXPECT_EQ(2u, 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);
1178049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski  EXPECT_EQ(30u, str->value->spans[0].last_char);
1188049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski
1198049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski  EXPECT_EQ(std::string("small"), *str->value->spans[1].name);
1208049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski  EXPECT_EQ(24u, str->value->spans[1].first_char);
1218049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski  EXPECT_EQ(30u, str->value->spans[1].last_char);
1228c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski}
1238c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
1248c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam LesinskiTEST_F(ResourceParserTest, ParseStringWithWhitespace) {
125cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<string name=\"foo\">  This is what  I think  </string>";
126ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
1278c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
128ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
129cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, str);
130cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(std::string("This is what I think"), *str->value);
1317542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_TRUE(str->untranslatable_sections.empty());
1328c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
133cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  input = "<string name=\"foo2\">\"  This is what  I think  \"</string>";
134ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
1358c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
136ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  str = test::GetValue<String>(&table_, "string/foo2");
137cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, str);
138cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(std::string("  This is what  I think  "), *str->value);
1398c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski}
1408c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
1417542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, IgnoreXliffTagsOtherThanG) {
1427542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  std::string input = R"EOF(
1437542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski      <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
1447542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski          There are <xliff:source>no</xliff:source> apples</string>)EOF";
1457542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  ASSERT_TRUE(TestParse(input));
1467542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1477542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
1487542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  ASSERT_NE(nullptr, str);
1497542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_EQ(StringPiece("There are no apples"), StringPiece(*str->value));
1507542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_TRUE(str->untranslatable_sections.empty());
1517542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski}
1527542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1537542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, NestedXliffGTagsAreIllegal) {
1547542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  std::string input = R"EOF(
1557542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski      <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
1567542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski          Do not <xliff:g>translate <xliff:g>this</xliff:g></xliff:g></string>)EOF";
1577542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_FALSE(TestParse(input));
1587542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski}
1597542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1607542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, RecordUntranslateableXliffSectionsInString) {
1617542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  std::string input = R"EOF(
1627542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski      <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
1637542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski          There are <xliff:g id="count">%1$d</xliff:g> apples</string>)EOF";
164ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
1651ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
166ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
167cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, str);
168cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(StringPiece("There are %1$d apples"), StringPiece(*str->value));
1697542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1707542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  ASSERT_EQ(1u, str->untranslatable_sections.size());
1717542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1727542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // We expect indices and lengths that span to include the whitespace
1737542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // before %1$d. This is due to how the StringBuilder withholds whitespace unless
1747542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // needed (to deal with line breaks, etc.).
1757542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_EQ(9u, str->untranslatable_sections[0].start);
1767542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_EQ(14u, str->untranslatable_sections[0].end);
1777542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski}
1787542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1797542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, RecordUntranslateableXliffSectionsInStyledString) {
1807542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  std::string input = R"EOF(
1817542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski      <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
1827542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski          There are <b><xliff:g id="count">%1$d</xliff:g></b> apples</string>)EOF";
1837542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  ASSERT_TRUE(TestParse(input));
1847542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1857542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  StyledString* str = test::GetValue<StyledString>(&table_, "string/foo");
1867542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  ASSERT_NE(nullptr, str);
1877542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_EQ(StringPiece("There are %1$d apples"), StringPiece(*str->value->str));
1887542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1897542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  ASSERT_EQ(1u, str->untranslatable_sections.size());
1907542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
1917542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // We expect indices and lengths that span to include the whitespace
1927542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // before %1$d. This is due to how the StringBuilder withholds whitespace unless
1937542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // needed (to deal with line breaks, etc.).
1947542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_EQ(9u, str->untranslatable_sections[0].start);
1957542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_EQ(14u, str->untranslatable_sections[0].end);
1961ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
1971ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
198dfa5e0705ff82f15e228ba076bc192893bcbe118Adam LesinskiTEST_F(ResourceParserTest, ParseNull) {
199cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<integer name=\"foo\">@null</integer>";
200ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
201cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
202cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // The Android runtime treats a value of android::Res_value::TYPE_NULL as
203cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // a non-existing value, and this causes problems in styles when trying to
2047542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // resolve an attribute. Null values must be encoded as android::Res_value::TYPE_REFERENCE
205cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // with a data value of 0.
2067542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  BinaryPrimitive* integer = test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
207cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, integer);
2087542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_EQ(uint16_t(android::Res_value::TYPE_REFERENCE), integer->value.dataType);
209cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(0u, integer->value.data);
210dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski}
211dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski
212dfa5e0705ff82f15e228ba076bc192893bcbe118Adam LesinskiTEST_F(ResourceParserTest, ParseEmpty) {
213cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<integer name=\"foo\">@empty</integer>";
214ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
215dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski
216cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  BinaryPrimitive* integer =
217ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
218cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, integer);
219cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(uint16_t(android::Res_value::TYPE_NULL), integer->value.dataType);
220cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(uint32_t(android::Res_value::DATA_NULL_EMPTY), integer->value.data);
221dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski}
222dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski
2236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAttr) {
224cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
225cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<attr name=\"foo\" format=\"string\"/>\n"
226cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<attr name=\"bar\"/>";
227ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
228cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
229ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
230cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, attr);
231ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_STRING), attr->type_mask);
232cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
233ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  attr = test::GetValue<Attribute>(&table_, "attr/bar");
234cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, attr);
235ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_ANY), attr->type_mask);
236cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski}
237cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
238cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski// Old AAPT allowed attributes to be defined under different configurations, but
239cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski// ultimately
240cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski// stored them with the default configuration. Check that we have the same
241cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski// behavior.
242cacb28f2d60858106e2819cc7d95a65e8bda890bAdam LesinskiTEST_F(ResourceParserTest,
243cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski       ParseAttrAndDeclareStyleableUnderConfigButRecordAsNoConfig) {
244ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  const ConfigDescription watch_config = test::ParseConfigOrDie("watch");
245cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = R"EOF(
24652364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski        <attr name="foo" />
24752364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski        <declare-styleable name="bar">
24852364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski          <attr name="baz" />
24952364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski        </declare-styleable>)EOF";
250ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input, watch_config));
25152364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski
252ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(nullptr, test::GetValueForConfig<Attribute>(&table_, "attr/foo",
253ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                                                        watch_config));
254ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(nullptr, test::GetValueForConfig<Attribute>(&table_, "attr/baz",
255ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                                                        watch_config));
256ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(nullptr, test::GetValueForConfig<Styleable>(
257ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         &table_, "styleable/bar", watch_config));
25852364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski
259ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValue<Attribute>(&table_, "attr/foo"));
260ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValue<Attribute>(&table_, "attr/baz"));
261ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValue<Styleable>(&table_, "styleable/bar"));
26252364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski}
26352364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski
264a587065721053ad54e34f484868142407d59512dAdam LesinskiTEST_F(ResourceParserTest, ParseAttrWithMinMax) {
265cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
266cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<attr name=\"foo\" min=\"10\" max=\"23\" format=\"integer\"/>";
267ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
268a587065721053ad54e34f484868142407d59512dAdam Lesinski
269ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
270cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, attr);
271ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_INTEGER), attr->type_mask);
272ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(10, attr->min_int);
273ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(23, attr->max_int);
274a587065721053ad54e34f484868142407d59512dAdam Lesinski}
275a587065721053ad54e34f484868142407d59512dAdam Lesinski
276a587065721053ad54e34f484868142407d59512dAdam LesinskiTEST_F(ResourceParserTest, FailParseAttrWithMinMaxButNotInteger) {
277cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
278cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<attr name=\"foo\" min=\"10\" max=\"23\" format=\"string\"/>";
279ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_FALSE(TestParse(input));
280a587065721053ad54e34f484868142407d59512dAdam Lesinski}
281a587065721053ad54e34f484868142407d59512dAdam Lesinski
2826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseUseAndDeclOfAttr) {
283cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
284cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<declare-styleable name=\"Styleable\">\n"
285cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <attr name=\"foo\" />\n"
286cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</declare-styleable>\n"
287cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<attr name=\"foo\" format=\"string\"/>";
288ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
2896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
290ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
291cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, attr);
292ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_STRING), attr->type_mask);
2936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
2946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
2956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseDoubleUseOfAttr) {
296cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
297cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<declare-styleable name=\"Theme\">"
298cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <attr name=\"foo\" />\n"
299cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</declare-styleable>\n"
300cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<declare-styleable name=\"Window\">\n"
301cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <attr name=\"foo\" format=\"boolean\"/>\n"
302cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</declare-styleable>";
303ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
3046f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
305ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
306cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, attr);
307ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_BOOLEAN), attr->type_mask);
3086f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3096f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseEnumAttr) {
311cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
312cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<attr name=\"foo\">\n"
313cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <enum name=\"bar\" value=\"0\"/>\n"
314cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <enum name=\"bat\" value=\"1\"/>\n"
315cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <enum name=\"baz\" value=\"2\"/>\n"
316cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</attr>";
317ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
3186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
319ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* enum_attr = test::GetValue<Attribute>(&table_, "attr/foo");
320ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_NE(enum_attr, nullptr);
321ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(enum_attr->type_mask, android::ResTable_map::TYPE_ENUM);
322ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_EQ(enum_attr->symbols.size(), 3u);
3236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
324ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  AAPT_ASSERT_TRUE(enum_attr->symbols[0].symbol.name);
325ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(enum_attr->symbols[0].symbol.name.value().entry, "bar");
326ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(enum_attr->symbols[0].value, 0u);
3276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
328ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  AAPT_ASSERT_TRUE(enum_attr->symbols[1].symbol.name);
329ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(enum_attr->symbols[1].symbol.name.value().entry, "bat");
330ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(enum_attr->symbols[1].value, 1u);
3316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
332ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  AAPT_ASSERT_TRUE(enum_attr->symbols[2].symbol.name);
333ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(enum_attr->symbols[2].symbol.name.value().entry, "baz");
334ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(enum_attr->symbols[2].value, 2u);
3356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3366f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3376f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseFlagAttr) {
338cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
339cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<attr name=\"foo\">\n"
340cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <flag name=\"bar\" value=\"0\"/>\n"
341cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <flag name=\"bat\" value=\"1\"/>\n"
342cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <flag name=\"baz\" value=\"2\"/>\n"
343cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</attr>";
344ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
3456f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
346ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* flag_attr = test::GetValue<Attribute>(&table_, "attr/foo");
347ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_NE(nullptr, flag_attr);
348ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(flag_attr->type_mask, android::ResTable_map::TYPE_FLAGS);
349ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_EQ(flag_attr->symbols.size(), 3u);
3506f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
351ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  AAPT_ASSERT_TRUE(flag_attr->symbols[0].symbol.name);
352ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(flag_attr->symbols[0].symbol.name.value().entry, "bar");
353ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(flag_attr->symbols[0].value, 0u);
3546f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
355ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  AAPT_ASSERT_TRUE(flag_attr->symbols[1].symbol.name);
356ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(flag_attr->symbols[1].symbol.name.value().entry, "bat");
357ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(flag_attr->symbols[1].value, 1u);
3586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
359ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  AAPT_ASSERT_TRUE(flag_attr->symbols[2].symbol.name);
360ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(flag_attr->symbols[2].symbol.name.value().entry, "baz");
361ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(flag_attr->symbols[2].value, 2u);
3626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
363ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  std::unique_ptr<BinaryPrimitive> flag_value =
364ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      ResourceUtils::TryParseFlagSymbol(flag_attr, "baz|bat");
365ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_NE(nullptr, flag_value);
366ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(flag_value->value.data, 1u | 2u);
3676f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3686f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, FailToParseEnumAttrWithNonUniqueKeys) {
370cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
371cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<attr name=\"foo\">\n"
372cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <enum name=\"bar\" value=\"0\"/>\n"
373cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <enum name=\"bat\" value=\"1\"/>\n"
374cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <enum name=\"bat\" value=\"2\"/>\n"
375cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</attr>";
376ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_FALSE(TestParse(input));
3776f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3786f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3796f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseStyle) {
380cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
381cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<style name=\"foo\" parent=\"@style/fu\">\n"
382cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item name=\"bar\">#ffffffff</item>\n"
383cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item name=\"bat\">@string/hey</item>\n"
384cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item name=\"baz\"><b>hey</b></item>\n"
385cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</style>";
386ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
387cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
388ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
389cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, style);
390cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent);
391cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent.value().name);
392ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("style/fu"),
393cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            style->parent.value().name.value());
394cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_EQ(3u, style->entries.size());
395cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
396cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->entries[0].key.name);
397ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("attr/bar"),
398cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            style->entries[0].key.name.value());
399cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
400cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->entries[1].key.name);
401ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("attr/bat"),
402cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            style->entries[1].key.name.value());
403cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
404cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->entries[2].key.name);
405ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("attr/baz"),
406cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            style->entries[2].key.name.value());
4076f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
4086f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
409769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithShorthandParent) {
410cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<style name=\"foo\" parent=\"com.app:Theme\"/>";
411ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
412769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
413ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
414cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, style);
415cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent);
416cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent.value().name);
417ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("com.app:style/Theme"),
418cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            style->parent.value().name.value());
419769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
420769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
42124aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPackageAliasedParent) {
422cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
423cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<style xmlns:app=\"http://schemas.android.com/apk/res/android\"\n"
424cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "       name=\"foo\" parent=\"app:Theme\"/>";
425ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
42624aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
427ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
428cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, style);
429cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent);
430cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent.value().name);
431ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("android:style/Theme"),
432cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            style->parent.value().name.value());
43324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski}
43424aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
43524aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPackageAliasedItems) {
436cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
437cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<style xmlns:app=\"http://schemas.android.com/apk/res/android\" "
438cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "name=\"foo\">\n"
439cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item name=\"app:bar\">0</item>\n"
440cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</style>";
441ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
44224aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
443ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
444cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, style);
445cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_EQ(1u, style->entries.size());
446ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("android:attr/bar"),
447cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            style->entries[0].key.name.value());
44824aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski}
44924aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
450bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithInferredParent) {
451cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<style name=\"foo.bar\"/>";
452ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
453bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski
454ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo.bar");
455cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, style);
456cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent);
457cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent.value().name);
458cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(style->parent.value().name.value(),
459ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            test::ParseNameOrDie("style/foo"));
460ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(style->parent_inferred);
461bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski}
462bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski
463cacb28f2d60858106e2819cc7d95a65e8bda890bAdam LesinskiTEST_F(ResourceParserTest,
464cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski       ParseStyleWithInferredParentOverridenByEmptyParentAttribute) {
465cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<style name=\"foo.bar\" parent=\"\"/>";
466ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
467bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski
468ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo.bar");
469cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, style);
470cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_EXPECT_FALSE(style->parent);
471ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_FALSE(style->parent_inferred);
472bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski}
473bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski
47424b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPrivateParentReference) {
475cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
476cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      R"EOF(<style name="foo" parent="*android:style/bar" />)EOF";
477ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
47824b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski
479ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
480cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, style);
481cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(style->parent);
482ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(style->parent.value().private_reference);
48324b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski}
48424b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski
4856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAutoGeneratedIdReference) {
486cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<string name=\"foo\">@+id/bar</string>";
487ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
4886f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
489ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Id* id = test::GetValue<Id>(&table_, "id/bar");
490cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(id, nullptr);
4916f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
4926f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
4936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAttributesDeclareStyleable) {
494cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
495cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<declare-styleable name=\"foo\">\n"
496cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <attr name=\"bar\" />\n"
497cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <attr name=\"bat\" format=\"string|reference\"/>\n"
498cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <attr name=\"baz\">\n"
499cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "    <enum name=\"foo\" value=\"1\"/>\n"
500cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  </attr>\n"
501cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</declare-styleable>";
502ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
503cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
504cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  Maybe<ResourceTable::SearchResult> result =
505ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      table_.FindResource(test::ParseNameOrDie("styleable/foo"));
506cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result);
507ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(SymbolState::kPublic, result.value().entry->symbol_status.state);
508cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
509ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/bar");
510cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(attr, nullptr);
511ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(attr->IsWeak());
512cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
513ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  attr = test::GetValue<Attribute>(&table_, "attr/bat");
514cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(attr, nullptr);
515ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(attr->IsWeak());
516cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
517ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  attr = test::GetValue<Attribute>(&table_, "attr/baz");
518cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(attr, nullptr);
519ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(attr->IsWeak());
520cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(1u, attr->symbols.size());
521cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
522ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValue<Id>(&table_, "id/foo"));
523cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
524ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo");
525cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(styleable, nullptr);
526cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_EQ(3u, styleable->entries.size());
527cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
528ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("attr/bar"),
529cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            styleable->entries[0].name.value());
530ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(test::ParseNameOrDie("attr/bat"),
531cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            styleable->entries[1].name.value());
5326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
5336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
534467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam LesinskiTEST_F(ResourceParserTest, ParsePrivateAttributesDeclareStyleable) {
535cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
536cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<declare-styleable name=\"foo\" "
537cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "xmlns:privAndroid=\"http://schemas.android.com/apk/prv/res/android\">\n"
538cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <attr name=\"*android:bar\" />\n"
539cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <attr name=\"privAndroid:bat\" />\n"
540cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</declare-styleable>";
541ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
542ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo");
543cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, styleable);
544cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_EQ(2u, styleable->entries.size());
545cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
546ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(styleable->entries[0].private_reference);
547cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(styleable->entries[0].name);
548cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(std::string("android"), styleable->entries[0].name.value().package);
549cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
550ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(styleable->entries[1].private_reference);
551cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(styleable->entries[1].name);
552cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(std::string("android"), styleable->entries[1].name.value().package);
553467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski}
554467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski
5556f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseArray) {
556cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
557cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<array name=\"foo\">\n"
558cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item>@string/ref</item>\n"
559cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item>hey</item>\n"
560cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item>23</item>\n"
561cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</array>";
562ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
5636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
564ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Array* array = test::GetValue<Array>(&table_, "array/foo");
565cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(array, nullptr);
566cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_EQ(3u, array->items.size());
5676f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
568ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, ValueCast<Reference>(array->items[0].get()));
569ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, ValueCast<String>(array->items[1].get()));
570ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, ValueCast<BinaryPrimitive>(array->items[2].get()));
5716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
5726f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
5739ba47d813075fcb05c5e1532c137c93b394631cbAdam LesinskiTEST_F(ResourceParserTest, ParseStringArray) {
574cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
575cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<string-array name=\"foo\">\n"
576cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item>\"Werk\"</item>\n"
577cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</string-array>\n";
578ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
579ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValue<Array>(&table_, "array/foo"));
5809ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski}
5819ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski
5826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParsePlural) {
583cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
584cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<plurals name=\"foo\">\n"
585cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item quantity=\"other\">apples</item>\n"
586cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  <item quantity=\"one\">apple</item>\n"
587cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</plurals>";
588ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
5898f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski
5908f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski  Plural* plural = test::GetValue<Plural>(&table_, "plurals/foo");
5918f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski  ASSERT_NE(nullptr, plural);
5928f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski  EXPECT_EQ(nullptr, plural->values[Plural::Zero]);
5938f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski  EXPECT_EQ(nullptr, plural->values[Plural::Two]);
5948f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski  EXPECT_EQ(nullptr, plural->values[Plural::Few]);
5958f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski  EXPECT_EQ(nullptr, plural->values[Plural::Many]);
5968f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski
5978f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski  EXPECT_NE(nullptr, plural->values[Plural::One]);
5988f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski  EXPECT_NE(nullptr, plural->values[Plural::Other]);
5996f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
6006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
6016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseCommentsWithResource) {
602cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
603cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<!--This is a comment-->\n"
604cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<string name=\"foo\">Hi</string>";
605ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
6066f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
607ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* value = test::GetValue<String>(&table_, "string/foo");
608cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, value);
609ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(value->GetComment(), "This is a comment");
610e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski}
611e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
612e78fd617ec60139a973a01925fa7adad31febb39Adam LesinskiTEST_F(ResourceParserTest, DoNotCombineMultipleComments) {
613cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
614cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<!--One-->\n"
615cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<!--Two-->\n"
616cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<string name=\"foo\">Hi</string>";
617e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
618ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
619e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
620ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* value = test::GetValue<String>(&table_, "string/foo");
621cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, value);
622ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(value->GetComment(), "Two");
623e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski}
624e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
625e78fd617ec60139a973a01925fa7adad31febb39Adam LesinskiTEST_F(ResourceParserTest, IgnoreCommentBeforeEndTag) {
626cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
627cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<!--One-->\n"
628cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<string name=\"foo\">\n"
629cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "  Hi\n"
630cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "<!--Two-->\n"
631cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      "</string>";
632e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
633ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
6341ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
635ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* value = test::GetValue<String>(&table_, "string/foo");
636cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, value);
637ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(value->GetComment(), "One");
6386f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
6396f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
640ca5638fd85098c3d0a699492751043545f75553aAdam LesinskiTEST_F(ResourceParserTest, ParseNestedComments) {
641cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // We only care about declare-styleable and enum/flag attributes because
642cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // comments
643cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // from those end up in R.java
644cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = R"EOF(
645ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        <declare-styleable name="foo">
646ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski          <!-- The name of the bar -->
647ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski          <attr name="barName" format="string|reference" />
648ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        </declare-styleable>
649ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
650ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        <attr name="foo">
651ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski          <!-- The very first -->
652ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski          <enum name="one" value="1" />
653ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        </attr>)EOF";
654ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
655ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
656ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo");
657cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, styleable);
658cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_EQ(1u, styleable->entries.size());
659ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
660cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(StringPiece("The name of the bar"),
661ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            styleable->entries.front().GetComment());
662ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
663ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
664cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, attr);
665cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_EQ(1u, attr->symbols.size());
666ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
667cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(StringPiece("The very first"),
668ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            attr->symbols.front().symbol.GetComment());
669ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski}
670ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
6716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/*
6726f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Declaring an ID as public should not require a separate definition
6736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * (as an ID has no value).
6746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */
6756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParsePublicIdAsDefinition) {
676cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = "<public type=\"id\" name=\"foo\"/>";
677ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
6786f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
679ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Id* id = test::GetValue<Id>(&table_, "id/foo");
680cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, id);
6816f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
6826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
683e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam LesinskiTEST_F(ResourceParserTest, KeepAllProducts) {
684cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = R"EOF(
6857751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski        <string name="foo" product="phone">hi</string>
6867751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski        <string name="foo" product="no-sdcard">ho</string>
6877751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski        <string name="bar" product="">wee</string>
6887751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski        <string name="baz">woo</string>
6897751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski        <string name="bit" product="phablet">hoot</string>
6907751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski        <string name="bot" product="default">yes</string>
6917751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski    )EOF";
692ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
693ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
694ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<String>(
695ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         &table_, "string/foo",
696ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         ConfigDescription::DefaultConfig(), "phone"));
697ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<String>(
698ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         &table_, "string/foo",
699ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         ConfigDescription::DefaultConfig(), "no-sdcard"));
700cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_NE(nullptr,
701ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            test::GetValueForConfigAndProduct<String>(
702ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                &table_, "string/bar", ConfigDescription::DefaultConfig(), ""));
703cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_NE(nullptr,
704ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            test::GetValueForConfigAndProduct<String>(
705ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                &table_, "string/baz", ConfigDescription::DefaultConfig(), ""));
706ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<String>(
707ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         &table_, "string/bit",
708ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         ConfigDescription::DefaultConfig(), "phablet"));
709ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_NE(nullptr, test::GetValueForConfigAndProduct<String>(
710ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         &table_, "string/bot",
711ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         ConfigDescription::DefaultConfig(), "default"));
7129ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski}
7139ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski
71427afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam LesinskiTEST_F(ResourceParserTest, AutoIncrementIdsInPublicGroup) {
715cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = R"EOF(
71627afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski    <public-group type="attr" first-id="0x01010040">
71727afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski      <public name="foo" />
71827afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski      <public name="bar" />
71927afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski    </public-group>)EOF";
720ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
721cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
722cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  Maybe<ResourceTable::SearchResult> result =
723ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      table_.FindResource(test::ParseNameOrDie("attr/foo"));
724cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result);
725cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
726cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result.value().package->id);
727cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result.value().type->id);
728cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result.value().entry->id);
729ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceId actual_id(result.value().package->id.value(),
730ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                       result.value().type->id.value(),
731ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                       result.value().entry->id.value());
732ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(ResourceId(0x01010040), actual_id);
733cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
734ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  result = table_.FindResource(test::ParseNameOrDie("attr/bar"));
735cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result);
736cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
737cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result.value().package->id);
738cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result.value().type->id);
739cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result.value().entry->id);
740ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  actual_id = ResourceId(result.value().package->id.value(),
741ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         result.value().type->id.value(),
742ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         result.value().entry->id.value());
743ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(ResourceId(0x01010041), actual_id);
74427afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski}
74527afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski
746fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam LesinskiTEST_F(ResourceParserTest, ExternalTypesShouldOnlyBeReferences) {
747cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
748cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      R"EOF(<item type="layout" name="foo">@layout/bar</item>)EOF";
749ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
750fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski
751cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  input = R"EOF(<item type="layout" name="bar">"this is a string"</item>)EOF";
752ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_FALSE(TestParse(input));
753fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski}
754fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski
755cacb28f2d60858106e2819cc7d95a65e8bda890bAdam LesinskiTEST_F(ResourceParserTest,
756cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski       AddResourcesElementShouldAddEntryWithUndefinedSymbol) {
757cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input = R"EOF(<add-resource name="bar" type="string" />)EOF";
758ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
759a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski
760cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  Maybe<ResourceTable::SearchResult> result =
761ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      table_.FindResource(test::ParseNameOrDie("string/bar"));
762cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  AAPT_ASSERT_TRUE(result);
763cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  const ResourceEntry* entry = result.value().entry;
764cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, entry);
765ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_EQ(SymbolState::kUndefined, entry->symbol_status.state);
766a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski}
767a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski
7687ff3ee19f4b831a526baf4b928d1ac172d070d82Adam LesinskiTEST_F(ResourceParserTest, ParseItemElementWithFormat) {
769cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
770cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      R"EOF(<item name="foo" type="integer" format="float">0.3</item>)EOF";
771ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
7727ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski
773cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  BinaryPrimitive* val =
774ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
775cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ASSERT_NE(nullptr, val);
7767ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski
777cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  EXPECT_EQ(uint32_t(android::Res_value::TYPE_FLOAT), val->value.dataType);
7787ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski}
7797ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski
78086d67df8d57b9537666f9b54a9ca563779a2288bAdam LesinskiTEST_F(ResourceParserTest, ParseConfigVaryingItem) {
78186d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  std::string input = R"EOF(<item name="foo" type="configVarying">Hey</item>)EOF";
78286d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  ASSERT_TRUE(TestParse(input));
78386d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  ASSERT_NE(nullptr, test::GetValue<String>(&table_, "configVarying/foo"));
78486d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski}
78586d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski
78686d67df8d57b9537666f9b54a9ca563779a2288bAdam LesinskiTEST_F(ResourceParserTest, ParseBagElement) {
78786d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  std::string input =
78886d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski      R"EOF(<bag name="bag" type="configVarying"><item name="test">Hello!</item></bag>)EOF";
78986d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  ASSERT_TRUE(TestParse(input));
79086d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski
79186d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  Style* val = test::GetValue<Style>(&table_, "configVarying/bag");
79286d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  ASSERT_NE(nullptr, val);
79386d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski
79486d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  ASSERT_EQ(1u, val->entries.size());
79586d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  EXPECT_EQ(Reference(test::ParseNameOrDie("attr/test")), val->entries[0].key);
79686d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  EXPECT_NE(nullptr, ValueCast<RawString>(val->entries[0].value.get()));
79786d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski}
79886d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski
799cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski}  // namespace aapt
800