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"
25004511660671511ae88e0e837a6f92db28eadaefAdam Lesinski#include "io/StringStream.h"
26d0f116b619feede0cfdb647157ce5ab4d50a1c46Adam Lesinski#include "test/Test.h"
27467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski#include "xml/XmlPullParser.h"
286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
29efeb7af13be4446ce4a511a2ca707691e9a67c1eAdam Lesinskiusing ::aapt::io::StringInputStream;
30a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinskiusing ::aapt::test::StrValueEq;
31bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinskiusing ::aapt::test::ValueEq;
32a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinskiusing ::android::Res_value;
3371be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinskiusing ::android::ResTable_map;
34e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinskiusing ::android::StringPiece;
35e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinskiusing ::testing::Eq;
36a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinskiusing ::testing::IsEmpty;
37a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinskiusing ::testing::IsNull;
38e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinskiusing ::testing::NotNull;
39bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinskiusing ::testing::Pointee;
40a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinskiusing ::testing::SizeIs;
4171be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinskiusing ::testing::StrEq;
42d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski
436f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskinamespace aapt {
446f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
45bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinskiconstexpr const char* kXmlPreamble = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
466f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
471ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiTEST(ResourceParserSingleTest, FailToParseWithNoRootResourcesElement) {
48ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
49cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ResourceTable table;
50ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceParser parser(context->GetDiagnostics(), &table, Source{"test"}, {});
51efeb7af13be4446ce4a511a2ca707691e9a67c1eAdam Lesinski
52efeb7af13be4446ce4a511a2ca707691e9a67c1eAdam Lesinski  std::string input = kXmlPreamble;
53efeb7af13be4446ce4a511a2ca707691e9a67c1eAdam Lesinski  input += R"(<attr name="foo"/>)";
54efeb7af13be4446ce4a511a2ca707691e9a67c1eAdam Lesinski  StringInputStream in(input);
55efeb7af13be4446ce4a511a2ca707691e9a67c1eAdam Lesinski  xml::XmlPullParser xml_parser(&in);
56ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_FALSE(parser.Parse(&xml_parser));
57769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
58769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
59ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskiclass ResourceParserTest : public ::testing::Test {
60ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski public:
61bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  void SetUp() override {
62bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski    context_ = test::ContextBuilder().Build();
63bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  }
641ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
65ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ::testing::AssertionResult TestParse(const StringPiece& str) {
66ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    return TestParse(str, ConfigDescription{});
67cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
6852364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski
69bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  ::testing::AssertionResult TestParse(const StringPiece& str, const ConfigDescription& config) {
70cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    ResourceParserOptions parserOptions;
71bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski    ResourceParser parser(context_->GetDiagnostics(), &table_, Source{"test"}, config,
72bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski                          parserOptions);
73efeb7af13be4446ce4a511a2ca707691e9a67c1eAdam Lesinski
74efeb7af13be4446ce4a511a2ca707691e9a67c1eAdam Lesinski    std::string input = kXmlPreamble;
75efeb7af13be4446ce4a511a2ca707691e9a67c1eAdam Lesinski    input += "<resources>\n";
76efeb7af13be4446ce4a511a2ca707691e9a67c1eAdam Lesinski    input.append(str.data(), str.size());
77efeb7af13be4446ce4a511a2ca707691e9a67c1eAdam Lesinski    input += "\n</resources>";
78efeb7af13be4446ce4a511a2ca707691e9a67c1eAdam Lesinski    StringInputStream in(input);
79efeb7af13be4446ce4a511a2ca707691e9a67c1eAdam Lesinski    xml::XmlPullParser xmlParser(&in);
80ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    if (parser.Parse(&xmlParser)) {
81cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      return ::testing::AssertionSuccess();
826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski    }
83cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return ::testing::AssertionFailure();
84cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
85ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
86ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski protected:
87ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceTable table_;
88ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  std::unique_ptr<IAaptContext> context_;
896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski};
906f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
916f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseQuotedString) {
92a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<string name="foo">   "  hey there " </string>)"));
936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
94ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
95a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
96a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str, StrValueEq("  hey there "));
97a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->untranslatable_sections, IsEmpty());
982eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski
992eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  ASSERT_TRUE(TestParse(R"(<string name="bar">Isn\'t it cool?</string>)"));
1002eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  str = test::GetValue<String>(&table_, "string/bar");
1012eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  ASSERT_THAT(str, NotNull());
1022eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  EXPECT_THAT(*str, StrValueEq("Isn't it cool?"));
1032eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski
1042eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  ASSERT_TRUE(TestParse(R"(<string name="baz">"Isn't it cool?"</string>)"));
1052eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  str = test::GetValue<String>(&table_, "string/baz");
1062eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  ASSERT_THAT(str, NotNull());
1072eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  EXPECT_THAT(*str, StrValueEq("Isn't it cool?"));
1086f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
1096f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
1106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseEscapedString) {
111a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<string name="foo">\?123</string>)"));
1126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
113ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
114a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
115a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str, StrValueEq("?123"));
116a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->untranslatable_sections, IsEmpty());
117549e437e14f3b92f02bd3abc7d1cd68387132ce1Adam Lesinski
118549e437e14f3b92f02bd3abc7d1cd68387132ce1Adam Lesinski  ASSERT_TRUE(TestParse(R"(<string name="bar">This isn\’t a bad string</string>)"));
119549e437e14f3b92f02bd3abc7d1cd68387132ce1Adam Lesinski  str = test::GetValue<String>(&table_, "string/bar");
120549e437e14f3b92f02bd3abc7d1cd68387132ce1Adam Lesinski  ASSERT_THAT(str, NotNull());
121549e437e14f3b92f02bd3abc7d1cd68387132ce1Adam Lesinski  EXPECT_THAT(*str, StrValueEq("This isn’t a bad string"));
1226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
1236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
1249f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam LesinskiTEST_F(ResourceParserTest, ParseFormattedString) {
125a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_FALSE(TestParse(R"(<string name="foo">%d %s</string>)"));
126a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<string name="foo">%1$d %2$s</string>)"));
1279f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski}
1289f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski
1298c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam LesinskiTEST_F(ResourceParserTest, ParseStyledString) {
130cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // Use a surrogate pair unicode point so that we can verify that the span
1317542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // indices use UTF-16 length and not UTF-8 length.
132cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  std::string input =
1338049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski      "<string name=\"foo\">This is my aunt\u2019s <b>fickle <small>string</small></b></string>";
134ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
1358c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
136ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  StyledString* str = test::GetValue<StyledString>(&table_, "string/foo");
137a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
1388c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
1392eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  EXPECT_THAT(str->value->value, StrEq("This is my aunt\u2019s fickle string"));
140a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->value->spans, SizeIs(2));
141a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->untranslatable_sections, IsEmpty());
1428c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
1432eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  EXPECT_THAT(*str->value->spans[0].name, StrEq("b"));
1442eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  EXPECT_THAT(str->value->spans[0].first_char, Eq(18u));
145a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->value->spans[0].last_char, Eq(30u));
1468049f3da712ea9c3154b57ce2276c97e749d1f2cAdam Lesinski
1472eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  EXPECT_THAT(*str->value->spans[1].name, StrEq("small"));
1482eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  EXPECT_THAT(str->value->spans[1].first_char, Eq(25u));
149a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->value->spans[1].last_char, Eq(30u));
1508c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski}
1518c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
1528c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam LesinskiTEST_F(ResourceParserTest, ParseStringWithWhitespace) {
153a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<string name="foo">  This is what  I think  </string>)"));
1548c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
155ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
156a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
1572eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  EXPECT_THAT(*str->value, StrEq("This is what I think"));
158a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->untranslatable_sections, IsEmpty());
1598c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
160a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<string name="foo2">"  This is what  I think  "</string>)"));
1618c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
162ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  str = test::GetValue<String>(&table_, "string/foo2");
163a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
164a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str, StrValueEq("  This is what  I think  "));
1658c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski}
1668c3f31f022f7e094fd227ef0c2987e0846cb3e43Adam Lesinski
1679beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan MitchellTEST_F(ResourceParserTest, ParseStringTruncateASCII) {
1689beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell  // Tuncate leading and trailing whitespace
1699beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell  EXPECT_TRUE(TestParse(R"(<string name="foo">&#32;Hello&#32;</string>)"));
1709beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell
1719beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell  String* str = test::GetValue<String>(&table_, "string/foo");
1729beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell  ASSERT_THAT(str, NotNull());
1739beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell  EXPECT_THAT(*str->value, StrEq("Hello"));
1749beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell  EXPECT_THAT(str->untranslatable_sections, IsEmpty());
1759beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell
1769beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell  // AAPT does not truncate unicode whitespace
1779beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell  EXPECT_TRUE(TestParse(R"(<string name="foo2">\u0020\Hello\u0020</string>)"));
1789beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell
1799beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell  str = test::GetValue<String>(&table_, "string/foo2");
1809beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell  ASSERT_THAT(str, NotNull());
1819beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell  EXPECT_THAT(*str->value, StrEq(" Hello "));
1829beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell  EXPECT_THAT(str->untranslatable_sections, IsEmpty());
1839beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell
1849beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell  // Preserve non-ASCII whitespace including extended ASCII characters
1859beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell  EXPECT_TRUE(TestParse(R"(<string name="foo3">&#160;Hello&#160;</string>)"));
1869beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell
1879beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell  str = test::GetValue<String>(&table_, "string/foo3");
1889beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell  ASSERT_THAT(str, NotNull());
1899beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell  EXPECT_THAT(*str->value, StrEq("\xC2\xA0Hello\xC2\xA0"));
1909beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell  EXPECT_THAT(str->untranslatable_sections, IsEmpty());
1919beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell
1929beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell  EXPECT_TRUE(TestParse(R"(<string name="foo4">2005年6月1日</string>)"));
1939beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell
1949beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell  str = test::GetValue<String>(&table_, "string/foo4");
1959beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell  ASSERT_THAT(str, NotNull());
1969beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell  EXPECT_THAT(*str->value, StrEq("2005年6月1日"));
1979beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell  EXPECT_THAT(str->untranslatable_sections, IsEmpty());
1989beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell}
1999beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell
2002eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam LesinskiTEST_F(ResourceParserTest, ParseStyledStringWithWhitespace) {
2012eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  std::string input = R"(<string name="foo">  <b> My <i> favorite</i> string </b>  </string>)";
2022eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  ASSERT_TRUE(TestParse(input));
2032eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski
2042eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  StyledString* str = test::GetValue<StyledString>(&table_, "string/foo");
2052eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  ASSERT_THAT(str, NotNull());
2062eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  EXPECT_THAT(str->value->value, StrEq("  My  favorite string  "));
2072eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  EXPECT_THAT(str->untranslatable_sections, IsEmpty());
2082eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski
2092eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  ASSERT_THAT(str->value->spans, SizeIs(2u));
2102eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  EXPECT_THAT(*str->value->spans[0].name, StrEq("b"));
2112eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  EXPECT_THAT(str->value->spans[0].first_char, Eq(1u));
2122eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  EXPECT_THAT(str->value->spans[0].last_char, Eq(21u));
2132eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski
2142eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  EXPECT_THAT(*str->value->spans[1].name, StrEq("i"));
2152eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  EXPECT_THAT(str->value->spans[1].first_char, Eq(5u));
2162eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  EXPECT_THAT(str->value->spans[1].last_char, Eq(13u));
2172eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski}
2182eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski
2197542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, IgnoreXliffTagsOtherThanG) {
220a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
2217542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski      <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
222a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski          There are <xliff:source>no</xliff:source> apples</string>)";
2237542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  ASSERT_TRUE(TestParse(input));
2247542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
2257542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
226a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
227a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str, StrValueEq("There are no apples"));
228a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->untranslatable_sections, IsEmpty());
2297542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski}
2307542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
2317542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, NestedXliffGTagsAreIllegal) {
232a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
2337542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski      <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
234a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski          Do not <xliff:g>translate <xliff:g>this</xliff:g></xliff:g></string>)";
2357542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  EXPECT_FALSE(TestParse(input));
2367542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski}
2377542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
2387542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, RecordUntranslateableXliffSectionsInString) {
239a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
2407542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski      <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
241a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski          There are <xliff:g id="count">%1$d</xliff:g> apples</string>)";
242ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
2431ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
244ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
245a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
246a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str, StrValueEq("There are %1$d apples"));
2477542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
2482eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  ASSERT_THAT(str->untranslatable_sections, SizeIs(1));
2492eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  EXPECT_THAT(str->untranslatable_sections[0].start, Eq(10u));
250a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(str->untranslatable_sections[0].end, Eq(14u));
2517542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski}
2527542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
2537542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam LesinskiTEST_F(ResourceParserTest, RecordUntranslateableXliffSectionsInStyledString) {
254a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
2557542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski      <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
256a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski          There are <b><xliff:g id="count">%1$d</xliff:g></b> apples</string>)";
2577542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  ASSERT_TRUE(TestParse(input));
2587542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
2597542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  StyledString* str = test::GetValue<StyledString>(&table_, "string/foo");
260a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
2612eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  EXPECT_THAT(str->value->value, Eq(" There are %1$d apples"));
2622eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski
263a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str->untranslatable_sections, SizeIs(1));
2642eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  EXPECT_THAT(str->untranslatable_sections[0].start, Eq(11u));
2652eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  EXPECT_THAT(str->untranslatable_sections[0].end, Eq(15u));
2667542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski
2672eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  ASSERT_THAT(str->value->spans, SizeIs(1u));
2682eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  EXPECT_THAT(*str->value->spans[0].name, StrEq("b"));
2692eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  EXPECT_THAT(str->value->spans[0].first_char, Eq(11u));
2702eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski  EXPECT_THAT(str->value->spans[0].last_char, Eq(14u));
2711ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
2721ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
273dfa5e0705ff82f15e228ba076bc192893bcbe118Adam LesinskiTEST_F(ResourceParserTest, ParseNull) {
274a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(<integer name="foo">@null</integer>)";
275ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
276cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
277cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // The Android runtime treats a value of android::Res_value::TYPE_NULL as
278cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // a non-existing value, and this causes problems in styles when trying to
2797542162cb1b1fd2ce8a26dd7f3fedc8de8160d38Adam Lesinski  // resolve an attribute. Null values must be encoded as android::Res_value::TYPE_REFERENCE
280cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // with a data value of 0.
281bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  Reference* null_ref = test::GetValue<Reference>(&table_, "integer/foo");
282bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  ASSERT_THAT(null_ref, NotNull());
283bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  EXPECT_FALSE(null_ref->name);
284bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  EXPECT_FALSE(null_ref->id);
285a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(null_ref->reference_type, Eq(Reference::Type::kResource));
286dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski}
287dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski
288dfa5e0705ff82f15e228ba076bc192893bcbe118Adam LesinskiTEST_F(ResourceParserTest, ParseEmpty) {
289a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(<integer name="foo">@empty</integer>)";
290ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
291dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski
292bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  BinaryPrimitive* integer = test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
293a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(integer, NotNull());
294a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(integer->value.dataType, Eq(Res_value::TYPE_NULL));
295a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(integer->value.data, Eq(Res_value::DATA_NULL_EMPTY));
296dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski}
297dfa5e0705ff82f15e228ba076bc192893bcbe118Adam Lesinski
2986f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAttr) {
299a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
300a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <attr name="foo" format="string"/>
301a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <attr name="bar"/>)";
302ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
303cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
304ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
305a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
306a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->type_mask, Eq(ResTable_map::TYPE_STRING));
307cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
308ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  attr = test::GetValue<Attribute>(&table_, "attr/bar");
309a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
310a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->type_mask, Eq(ResTable_map::TYPE_ANY));
311cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski}
312cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
313a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski// Old AAPT allowed attributes to be defined under different configurations, but ultimately
314a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski// stored them with the default configuration. Check that we have the same behavior.
315bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam LesinskiTEST_F(ResourceParserTest, ParseAttrAndDeclareStyleableUnderConfigButRecordAsNoConfig) {
316ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  const ConfigDescription watch_config = test::ParseConfigOrDie("watch");
317bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  std::string input = R"(
318bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski      <attr name="foo" />
319bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski      <declare-styleable name="bar">
320bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski        <attr name="baz" />
321bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski      </declare-styleable>)";
322ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input, watch_config));
32352364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski
324a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(test::GetValueForConfig<Attribute>(&table_, "attr/foo", watch_config), IsNull());
325a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(test::GetValueForConfig<Attribute>(&table_, "attr/baz", watch_config), IsNull());
326a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(test::GetValueForConfig<Styleable>(&table_, "styleable/bar", watch_config), IsNull());
32752364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski
328a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(test::GetValue<Attribute>(&table_, "attr/foo"), NotNull());
329a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(test::GetValue<Attribute>(&table_, "attr/baz"), NotNull());
330a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(test::GetValue<Styleable>(&table_, "styleable/bar"), NotNull());
33152364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski}
33252364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski
333a587065721053ad54e34f484868142407d59512dAdam LesinskiTEST_F(ResourceParserTest, ParseAttrWithMinMax) {
334a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(<attr name="foo" min="10" max="23" format="integer"/>)";
335ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
336a587065721053ad54e34f484868142407d59512dAdam Lesinski
337ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
338a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
339a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->type_mask, Eq(ResTable_map::TYPE_INTEGER));
340a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->min_int, Eq(10));
341a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->max_int, Eq(23));
342a587065721053ad54e34f484868142407d59512dAdam Lesinski}
343a587065721053ad54e34f484868142407d59512dAdam Lesinski
344a587065721053ad54e34f484868142407d59512dAdam LesinskiTEST_F(ResourceParserTest, FailParseAttrWithMinMaxButNotInteger) {
345a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_FALSE(TestParse(R"(<attr name="foo" min="10" max="23" format="string"/>)"));
346a587065721053ad54e34f484868142407d59512dAdam Lesinski}
347a587065721053ad54e34f484868142407d59512dAdam Lesinski
3486f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseUseAndDeclOfAttr) {
349a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
350a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <declare-styleable name="Styleable">
351a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="foo" />
352a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </declare-styleable>
353a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <attr name="foo" format="string"/>)";
354ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
3556f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
356ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
357a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
358a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->type_mask, Eq(ResTable_map::TYPE_STRING));
3596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseDoubleUseOfAttr) {
362a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
363a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <declare-styleable name="Theme">
364a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="foo" />
365a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </declare-styleable>
366a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <declare-styleable name="Window">
367a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="foo" format="boolean"/>
368a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </declare-styleable>)";
369ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
3706f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
371ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
372a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
373a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->type_mask, Eq(ResTable_map::TYPE_BOOLEAN));
3746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
3756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
3766f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseEnumAttr) {
377a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
378a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <attr name="foo">
379a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <enum name="bar" value="0"/>
380a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <enum name="bat" value="1"/>
381a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <enum name="baz" value="2"/>
382a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </attr>)";
383ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
3846f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
385ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* enum_attr = test::GetValue<Attribute>(&table_, "attr/foo");
386a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(enum_attr, NotNull());
387a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(enum_attr->type_mask, Eq(ResTable_map::TYPE_ENUM));
388a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(enum_attr->symbols, SizeIs(3));
3896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
390a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(enum_attr->symbols[0].symbol.name);
391a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(enum_attr->symbols[0].symbol.name.value().entry, Eq("bar"));
392a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(enum_attr->symbols[0].value, Eq(0u));
3936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
394a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(enum_attr->symbols[1].symbol.name);
395a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(enum_attr->symbols[1].symbol.name.value().entry, Eq("bat"));
396a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(enum_attr->symbols[1].value, Eq(1u));
3976f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
398a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(enum_attr->symbols[2].symbol.name);
399a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(enum_attr->symbols[2].symbol.name.value().entry, Eq("baz"));
400a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(enum_attr->symbols[2].value, Eq(2u));
4016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
4026f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
4036f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseFlagAttr) {
404a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
405a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <attr name="foo">
406a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <flag name="bar" value="0"/>
407a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <flag name="bat" value="1"/>
408a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <flag name="baz" value="2"/>
409a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </attr>)";
410ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
4116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
412ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* flag_attr = test::GetValue<Attribute>(&table_, "attr/foo");
413a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(flag_attr, NotNull());
414a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(flag_attr->type_mask, Eq(ResTable_map::TYPE_FLAGS));
415a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(flag_attr->symbols, SizeIs(3));
4166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
417a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(flag_attr->symbols[0].symbol.name);
418a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(flag_attr->symbols[0].symbol.name.value().entry, Eq("bar"));
419a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(flag_attr->symbols[0].value, Eq(0u));
4206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
421a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(flag_attr->symbols[1].symbol.name);
422a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(flag_attr->symbols[1].symbol.name.value().entry, Eq("bat"));
423a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(flag_attr->symbols[1].value, Eq(1u));
4246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
425a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(flag_attr->symbols[2].symbol.name);
426a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(flag_attr->symbols[2].symbol.name.value().entry, Eq("baz"));
427a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(flag_attr->symbols[2].value, Eq(2u));
4286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
429ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  std::unique_ptr<BinaryPrimitive> flag_value =
430ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      ResourceUtils::TryParseFlagSymbol(flag_attr, "baz|bat");
431a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(flag_value, NotNull());
432a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(flag_value->value.data, Eq(1u | 2u));
4336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
4346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
4356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, FailToParseEnumAttrWithNonUniqueKeys) {
436a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
437a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <attr name="foo">
438a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <enum name="bar" value="0"/>
439a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <enum name="bat" value="1"/>
440a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <enum name="bat" value="2"/>
441a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </attr>)";
442ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_FALSE(TestParse(input));
4436f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
4446f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
4456f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseStyle) {
446a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
447a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <style name="foo" parent="@style/fu">
448a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item name="bar">#ffffffff</item>
449a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item name="bat">@string/hey</item>
450a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item name="baz"><b>hey</b></item>
451a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </style>)";
452ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
453cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
454ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
455a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style, NotNull());
456a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(style->parent);
457a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(style->parent.value().name, Eq(make_value(test::ParseNameOrDie("style/fu"))));
458a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style->entries, SizeIs(3));
459cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
460a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(style->entries[0].key.name, Eq(make_value(test::ParseNameOrDie("attr/bar"))));
461a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(style->entries[1].key.name, Eq(make_value(test::ParseNameOrDie("attr/bat"))));
462a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(style->entries[2].key.name, Eq(make_value(test::ParseNameOrDie("attr/baz"))));
4636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
4646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
465769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithShorthandParent) {
466a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<style name="foo" parent="com.app:Theme"/>)"));
467769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
468ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
469a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style, NotNull());
470a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(style->parent);
471a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(style->parent.value().name, Eq(make_value(test::ParseNameOrDie("com.app:style/Theme"))));
472769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski}
473769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski
47424aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPackageAliasedParent) {
475a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
476a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <style xmlns:app="http://schemas.android.com/apk/res/android"
477a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski          name="foo" parent="app:Theme"/>)";
478ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
47924aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
480ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
481a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style, NotNull());
482a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(style->parent);
483a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(style->parent.value().name);
484a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(style->parent.value().name, Eq(make_value(test::ParseNameOrDie("android:style/Theme"))));
48524aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski}
48624aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
48724aad163bc88cb10d2275385e9afc3de7f342d65Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPackageAliasedItems) {
488a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
489a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <style xmlns:app="http://schemas.android.com/apk/res/android" name="foo">
490a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item name="app:bar">0</item>
491a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </style>)";
492ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
49324aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
494ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
495a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style, NotNull());
496a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style->entries, SizeIs(1));
497a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(style->entries[0].key.name, Eq(make_value(test::ParseNameOrDie("android:attr/bar"))));
49824aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski}
49924aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski
500bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam LesinskiTEST_F(ResourceParserTest, ParseStyleWithInferredParent) {
501a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<style name="foo.bar"/>)"));
502bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski
503ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo.bar");
504a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style, NotNull());
505a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(style->parent);
506a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(style->parent.value().name, Eq(make_value(test::ParseNameOrDie("style/foo"))));
507ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(style->parent_inferred);
508bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski}
509bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski
510a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam LesinskiTEST_F(ResourceParserTest, ParseStyleWithInferredParentOverridenByEmptyParentAttribute) {
511a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<style name="foo.bar" parent=""/>)"));
512bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski
513ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo.bar");
514a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style, NotNull());
515a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_FALSE(style->parent);
516ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_FALSE(style->parent_inferred);
517bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski}
518bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski
51924b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam LesinskiTEST_F(ResourceParserTest, ParseStyleWithPrivateParentReference) {
520a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<style name="foo" parent="*android:style/bar" />)"));
52124b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski
522ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Style* style = test::GetValue<Style>(&table_, "style/foo");
523a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(style, NotNull());
524a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(style->parent);
525ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(style->parent.value().private_reference);
52624b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski}
52724b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski
5286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAutoGeneratedIdReference) {
529a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<string name="foo">@+id/bar</string>)"));
530a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValue<Id>(&table_, "id/bar"), NotNull());
5316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
5326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
5336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseAttributesDeclareStyleable) {
534a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
535a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <declare-styleable name="foo">
536a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="bar" />
537a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="bat" format="string|reference"/>
538a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="baz">
539a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski          <enum name="foo" value="1"/>
540a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        </attr>
541a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </declare-styleable>)";
542ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
543cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
544cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  Maybe<ResourceTable::SearchResult> result =
545ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      table_.FindResource(test::ParseNameOrDie("styleable/foo"));
546a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result);
54771be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski  EXPECT_THAT(result.value().entry->visibility.level, Eq(Visibility::Level::kPublic));
548cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
549ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/bar");
550a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
551ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(attr->IsWeak());
552cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
553ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  attr = test::GetValue<Attribute>(&table_, "attr/bat");
554a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
555ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(attr->IsWeak());
556cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
557ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  attr = test::GetValue<Attribute>(&table_, "attr/baz");
558a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
559ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(attr->IsWeak());
560a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->symbols, SizeIs(1));
561cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
562a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(test::GetValue<Id>(&table_, "id/foo"), NotNull());
563cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
564ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo");
565a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(styleable, NotNull());
566a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(styleable->entries, SizeIs(3));
567cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
568a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(styleable->entries[0].name, Eq(make_value(test::ParseNameOrDie("attr/bar"))));
569a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(styleable->entries[1].name, Eq(make_value(test::ParseNameOrDie("attr/bat"))));
570a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(styleable->entries[2].name, Eq(make_value(test::ParseNameOrDie("attr/baz"))));
5716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
5726f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
573467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam LesinskiTEST_F(ResourceParserTest, ParsePrivateAttributesDeclareStyleable) {
574a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
575a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <declare-styleable xmlns:privAndroid="http://schemas.android.com/apk/prv/res/android"
576a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski          name="foo">
577a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="*android:bar" />
578a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="privAndroid:bat" />
579a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </declare-styleable>)";
580ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
581ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo");
582a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(styleable, NotNull());
583a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(styleable->entries, SizeIs(2));
584cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
585ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(styleable->entries[0].private_reference);
586a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(styleable->entries[0].name);
587a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(styleable->entries[0].name.value().package, Eq("android"));
588cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
589ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  EXPECT_TRUE(styleable->entries[1].private_reference);
590a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(styleable->entries[1].name);
591a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(styleable->entries[1].name.value().package, Eq("android"));
592467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski}
593467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski
5946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseArray) {
595a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
596a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <array name="foo">
597a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item>@string/ref</item>
598a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item>hey</item>
599a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item>23</item>
600a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </array>)";
601ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
6026f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
603ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Array* array = test::GetValue<Array>(&table_, "array/foo");
604a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(array, NotNull());
6054ffea040641d3b74ab04b6d2d3e78280bc893d5fAdam Lesinski  ASSERT_THAT(array->elements, SizeIs(3));
6066f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
6074ffea040641d3b74ab04b6d2d3e78280bc893d5fAdam Lesinski  EXPECT_THAT(ValueCast<Reference>(array->elements[0].get()), NotNull());
6084ffea040641d3b74ab04b6d2d3e78280bc893d5fAdam Lesinski  EXPECT_THAT(ValueCast<String>(array->elements[1].get()), NotNull());
6094ffea040641d3b74ab04b6d2d3e78280bc893d5fAdam Lesinski  EXPECT_THAT(ValueCast<BinaryPrimitive>(array->elements[2].get()), NotNull());
6106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
6116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
6129ba47d813075fcb05c5e1532c137c93b394631cbAdam LesinskiTEST_F(ResourceParserTest, ParseStringArray) {
613a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
614d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski      <string-array name="foo">
615d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski        <item>"Werk"</item>"
616a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </string-array>)";
617ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
618a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(test::GetValue<Array>(&table_, "array/foo"), NotNull());
6199ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski}
6209ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski
621d5fd76a2ff78400505ade936fc36e707d69ecf72Adam LesinskiTEST_F(ResourceParserTest, ParseArrayWithFormat) {
622a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
623d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski      <array name="foo" format="string">
624d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski        <item>100</item>
625a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </array>)";
626d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski  ASSERT_TRUE(TestParse(input));
627d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski
628d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski  Array* array = test::GetValue<Array>(&table_, "array/foo");
629a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(array, NotNull());
6304ffea040641d3b74ab04b6d2d3e78280bc893d5fAdam Lesinski  ASSERT_THAT(array->elements, SizeIs(1));
631d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski
6324ffea040641d3b74ab04b6d2d3e78280bc893d5fAdam Lesinski  String* str = ValueCast<String>(array->elements[0].get());
633a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(str, NotNull());
634a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str, StrValueEq("100"));
635d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski}
636d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski
637d5fd76a2ff78400505ade936fc36e707d69ecf72Adam LesinskiTEST_F(ResourceParserTest, ParseArrayWithBadFormat) {
638a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
639d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski      <array name="foo" format="integer">
640d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski        <item>Hi</item>
641a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </array>)";
642d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski  ASSERT_FALSE(TestParse(input));
643d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski}
644d5fd76a2ff78400505ade936fc36e707d69ecf72Adam Lesinski
6456f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParsePlural) {
646a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
647a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <plurals name="foo">
648a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item quantity="other">apples</item>
649a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item quantity="one">apple</item>
650a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </plurals>)";
651ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
6528f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski
6538f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski  Plural* plural = test::GetValue<Plural>(&table_, "plurals/foo");
654a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(plural, NotNull());
655a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(plural->values[Plural::Zero], IsNull());
656a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(plural->values[Plural::Two], IsNull());
657a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(plural->values[Plural::Few], IsNull());
658a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(plural->values[Plural::Many], IsNull());
6598f7c550e20a6edbc9af7bb48675afaf8bcb3783fAdam Lesinski
660a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(plural->values[Plural::One], NotNull());
661a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(plural->values[Plural::Other], NotNull());
6626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
6636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
6646f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParseCommentsWithResource) {
665a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
666a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <!--This is a comment-->
667a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="foo">Hi</string>)";
668ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
6696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
670ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* value = test::GetValue<String>(&table_, "string/foo");
671a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(value, NotNull());
672a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(value->GetComment(), Eq("This is a comment"));
673e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski}
674e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
675e78fd617ec60139a973a01925fa7adad31febb39Adam LesinskiTEST_F(ResourceParserTest, DoNotCombineMultipleComments) {
676a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
677a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <!--One-->
678a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <!--Two-->
679a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="foo">Hi</string>)";
680e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
681ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
682e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
683ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* value = test::GetValue<String>(&table_, "string/foo");
684a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(value, NotNull());
685a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(value->GetComment(), Eq("Two"));
686e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski}
687e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski
688e78fd617ec60139a973a01925fa7adad31febb39Adam LesinskiTEST_F(ResourceParserTest, IgnoreCommentBeforeEndTag) {
689a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
690a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <!--One-->
691a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="foo">
692a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        Hi
693a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <!--Two-->
694a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </string>)";
695ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
6961ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
697ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  String* value = test::GetValue<String>(&table_, "string/foo");
698a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(value, NotNull());
699a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(value->GetComment(), Eq("One"));
7006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
7016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
702ca5638fd85098c3d0a699492751043545f75553aAdam LesinskiTEST_F(ResourceParserTest, ParseNestedComments) {
703cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // We only care about declare-styleable and enum/flag attributes because
704a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  // comments from those end up in R.java
705a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
706a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <declare-styleable name="foo">
707a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <!-- The name of the bar -->
708a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <attr name="barName" format="string|reference" />
709a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </declare-styleable>
710a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski
711a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <attr name="foo">
712a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <!-- The very first -->
713a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <enum name="one" value="1" />
714a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </attr>)";
715ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
716ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
717ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo");
718a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(styleable, NotNull());
719a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(styleable->entries, SizeIs(1));
720a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(styleable->entries[0].GetComment(), Eq("The name of the bar"));
721ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
722ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
723a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr, NotNull());
724a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(attr->symbols, SizeIs(1));
725a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(attr->symbols[0].symbol.GetComment(), Eq("The very first"));
726ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski}
727ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
728a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski// Declaring an ID as public should not require a separate definition (as an ID has no value).
7296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam LesinskiTEST_F(ResourceParserTest, ParsePublicIdAsDefinition) {
730a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<public type="id" name="foo"/>)"));
731a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValue<Id>(&table_, "id/foo"), NotNull());
7326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski}
7336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski
734e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam LesinskiTEST_F(ResourceParserTest, KeepAllProducts) {
735a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
736a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="foo" product="phone">hi</string>
737a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="foo" product="no-sdcard">ho</string>
738a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="bar" product="">wee</string>
739a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="baz">woo</string>
740a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="bit" product="phablet">hoot</string>
741a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <string name="bot" product="default">yes</string>)";
742ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
743ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
744a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValueForConfigAndProduct<String>(&table_, "string/foo", ConfigDescription::DefaultConfig(), "phone"), NotNull());
745a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValueForConfigAndProduct<String>(&table_, "string/foo",ConfigDescription::DefaultConfig(), "no-sdcard"), NotNull());
746a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValueForConfigAndProduct<String>(&table_, "string/bar", ConfigDescription::DefaultConfig(), ""), NotNull());
747a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValueForConfigAndProduct<String>(&table_, "string/baz", ConfigDescription::DefaultConfig(), ""), NotNull());
748a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValueForConfigAndProduct<String>(&table_, "string/bit", ConfigDescription::DefaultConfig(), "phablet"), NotNull());
749a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValueForConfigAndProduct<String>(&table_, "string/bot", ConfigDescription::DefaultConfig(), "default"), NotNull());
7509ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski}
7519ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski
75227afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam LesinskiTEST_F(ResourceParserTest, AutoIncrementIdsInPublicGroup) {
753a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
754a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <public-group type="attr" first-id="0x01010040">
755a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <public name="foo" />
756a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <public name="bar" />
757a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </public-group>)";
758ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ASSERT_TRUE(TestParse(input));
759cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
760a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  Maybe<ResourceTable::SearchResult> result = table_.FindResource(test::ParseNameOrDie("attr/foo"));
761a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result);
762cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
763a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result.value().package->id);
764a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result.value().type->id);
765a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result.value().entry->id);
766ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceId actual_id(result.value().package->id.value(),
767ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                       result.value().type->id.value(),
768ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                       result.value().entry->id.value());
769a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(actual_id, Eq(ResourceId(0x01010040)));
770cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
771ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  result = table_.FindResource(test::ParseNameOrDie("attr/bar"));
772a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result);
773cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
774a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result.value().package->id);
775a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result.value().type->id);
776a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result.value().entry->id);
777ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  actual_id = ResourceId(result.value().package->id.value(),
778ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         result.value().type->id.value(),
779ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                         result.value().entry->id.value());
780a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(actual_id, Eq(ResourceId(0x01010041)));
78127afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski}
78227afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski
78371be70507de9cb619b644e55eda1cc181e3f7e90Adam LesinskiTEST_F(ResourceParserTest, StrongestSymbolVisibilityWins) {
78471be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski  std::string input = R"(
78571be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski      <!-- private -->
78671be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski      <java-symbol type="string" name="foo" />
78771be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski      <!-- public -->
78871be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski      <public type="string" name="foo" id="0x01020000" />
78971be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski      <!-- private2 -->
79071be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski      <java-symbol type="string" name="foo" />)";
79171be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski  ASSERT_TRUE(TestParse(input));
79271be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski
79371be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski  Maybe<ResourceTable::SearchResult> result =
79471be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski      table_.FindResource(test::ParseNameOrDie("string/foo"));
79571be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski  ASSERT_TRUE(result);
79671be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski
79771be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski  ResourceEntry* entry = result.value().entry;
79871be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski  ASSERT_THAT(entry, NotNull());
79971be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski  EXPECT_THAT(entry->visibility.level, Eq(Visibility::Level::kPublic));
80071be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski  EXPECT_THAT(entry->visibility.comment, StrEq("public"));
80171be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski}
80271be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski
803fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam LesinskiTEST_F(ResourceParserTest, ExternalTypesShouldOnlyBeReferences) {
804a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<item type="layout" name="foo">@layout/bar</item>)"));
805a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_FALSE(TestParse(R"(<item type="layout" name="bar">"this is a string"</item>)"));
806fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski}
807fa10505ceaf9d4c41b76bb1b32f257926e96e441Adam Lesinski
8084488f1c74a0f7df09f2b201f7caa228d729e8389Adam LesinskiTEST_F(ResourceParserTest, AddResourcesElementShouldAddEntryWithUndefinedSymbol) {
809a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<add-resource name="bar" type="string" />)"));
810a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski
811cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  Maybe<ResourceTable::SearchResult> result =
812ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      table_.FindResource(test::ParseNameOrDie("string/bar"));
813a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(result);
814cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  const ResourceEntry* entry = result.value().entry;
815a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(entry, NotNull());
81671be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski  EXPECT_THAT(entry->visibility.level, Eq(Visibility::Level::kUndefined));
81771be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski  EXPECT_TRUE(entry->allow_new);
818a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski}
819a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski
8207ff3ee19f4b831a526baf4b928d1ac172d070d82Adam LesinskiTEST_F(ResourceParserTest, ParseItemElementWithFormat) {
821a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<item name="foo" type="integer" format="float">0.3</item>)"));
8227ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski
823e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski  BinaryPrimitive* val = test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
824e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski  ASSERT_THAT(val, NotNull());
825a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(val->value.dataType, Eq(Res_value::TYPE_FLOAT));
826e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski
827a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_FALSE(TestParse(R"(<item name="bar" type="integer" format="fraction">100</item>)"));
828e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski}
829e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski
830e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski// An <item> without a format specifier accepts all types of values.
831e597d68d33c76c2b830f5497ed4ba74c5193a056Adam LesinskiTEST_F(ResourceParserTest, ParseItemElementWithoutFormat) {
832a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<item name="foo" type="integer">100%p</item>)"));
8337ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski
834e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski  BinaryPrimitive* val = test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
835e597d68d33c76c2b830f5497ed4ba74c5193a056Adam Lesinski  ASSERT_THAT(val, NotNull());
836a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(val->value.dataType, Eq(Res_value::TYPE_FRACTION));
8377ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski}
8387ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski
83986d67df8d57b9537666f9b54a9ca563779a2288bAdam LesinskiTEST_F(ResourceParserTest, ParseConfigVaryingItem) {
840a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<item name="foo" type="configVarying">Hey</item>)"));
841a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(test::GetValue<String>(&table_, "configVarying/foo"), NotNull());
84286d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski}
84386d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski
84486d67df8d57b9537666f9b54a9ca563779a2288bAdam LesinskiTEST_F(ResourceParserTest, ParseBagElement) {
845a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  std::string input = R"(
846a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      <bag name="bag" type="configVarying">
847a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski        <item name="test">Hello!</item>
848a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski      </bag>)";
84986d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  ASSERT_TRUE(TestParse(input));
85086d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski
85186d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski  Style* val = test::GetValue<Style>(&table_, "configVarying/bag");
852a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(val, NotNull());
853a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_THAT(val->entries, SizeIs(1));
85486d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski
855a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(val->entries[0].key, Eq(Reference(test::ParseNameOrDie("attr/test"))));
856a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(ValueCast<RawString>(val->entries[0].value.get()), NotNull());
85786d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski}
85886d67df8d57b9537666f9b54a9ca563779a2288bAdam Lesinski
859bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam LesinskiTEST_F(ResourceParserTest, ParseElementWithNoValue) {
860bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  std::string input = R"(
861bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski      <item type="drawable" format="reference" name="foo" />
862bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski      <string name="foo" />)";
863bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  ASSERT_TRUE(TestParse(input));
864bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  ASSERT_THAT(test::GetValue(&table_, "drawable/foo"), Pointee(ValueEq(Reference())));
865bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski
866bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  String* str = test::GetValue<String>(&table_, "string/foo");
867bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski  ASSERT_THAT(str, NotNull());
868a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  EXPECT_THAT(*str, StrValueEq(""));
869bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski}
870bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski
871b9f0548341f98a64a87fa35ef5f58d1daf973ca7Adam LesinskiTEST_F(ResourceParserTest, ParsePlatformIndependentNewline) {
872a45893a5c51cc26f1fd63ec1aa4c39f55911c85bAdam Lesinski  ASSERT_TRUE(TestParse(R"(<string name="foo">%1$s %n %2$s</string>)"));
873b9f0548341f98a64a87fa35ef5f58d1daf973ca7Adam Lesinski}
874b9f0548341f98a64a87fa35ef5f58d1daf973ca7Adam Lesinski
87546c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam LesinskiTEST_F(ResourceParserTest, ParseOverlayableTagWithSystemPolicy) {
87646c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski  std::string input = R"(
87746c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski      <overlayable policy="illegal_policy">
87846c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski        <item type="string" name="foo" />
87946c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski      </overlayable>)";
88046c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski  EXPECT_FALSE(TestParse(input));
88146c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski
88246c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski  input = R"(
88346c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski      <overlayable policy="system">
88446c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski        <item name="foo" />
88546c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski      </overlayable>)";
88646c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski  EXPECT_FALSE(TestParse(input));
88746c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski
88846c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski  input = R"(
88946c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski      <overlayable policy="system">
89046c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski        <item type="attr" />
89146c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski      </overlayable>)";
89246c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski  EXPECT_FALSE(TestParse(input));
89346c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski
89446c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski  input = R"(
89546c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski      <overlayable policy="system">
89646c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski        <item type="bad_type" name="foo" />
89746c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski      </overlayable>)";
89846c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski  EXPECT_FALSE(TestParse(input));
89946c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski
90046c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski  input = R"(<overlayable policy="system" />)";
90146c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski  EXPECT_TRUE(TestParse(input));
90246c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski
90346c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski  input = R"(<overlayable />)";
90446c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski  EXPECT_TRUE(TestParse(input));
90546c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski
90646c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski  input = R"(
90746c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski      <overlayable policy="system">
90846c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski        <item type="string" name="foo" />
90946c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski        <item type="dimen" name="foo" />
91046c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski      </overlayable>)";
91146c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski  ASSERT_TRUE(TestParse(input));
91246c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski
91346c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski  input = R"(
91446c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski      <overlayable>
91546c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski        <item type="string" name="bar" />
91646c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski      </overlayable>)";
91746c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski  ASSERT_TRUE(TestParse(input));
91871be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski
91971be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski  Maybe<ResourceTable::SearchResult> search_result =
92071be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski      table_.FindResource(test::ParseNameOrDie("string/bar"));
92171be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski  ASSERT_TRUE(search_result);
92271be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski  ASSERT_THAT(search_result.value().entry, NotNull());
92371be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski  EXPECT_THAT(search_result.value().entry->visibility.level, Eq(Visibility::Level::kUndefined));
92471be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski  EXPECT_TRUE(search_result.value().entry->overlayable);
92571be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski}
92671be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski
92771be70507de9cb619b644e55eda1cc181e3f7e90Adam LesinskiTEST_F(ResourceParserTest, DuplicateOverlayableIsError) {
92871be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski  std::string input = R"(
92971be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski      <overlayable>
93071be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski        <item type="string" name="foo" />
93171be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski        <item type="string" name="foo" />
93271be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski      </overlayable>)";
93371be70507de9cb619b644e55eda1cc181e3f7e90Adam Lesinski  EXPECT_FALSE(TestParse(input));
93446c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski}
93546c4d72bf0c30d3bc2071b84e2741e404c45e2b7Adam Lesinski
9369efbbef2e060cd5e05f5b652ba5c7aaf687f64d6yTEST_F(ResourceParserTest, ParseIdItem) {
9379efbbef2e060cd5e05f5b652ba5c7aaf687f64d6y  std::string input = R"(
9389efbbef2e060cd5e05f5b652ba5c7aaf687f64d6y    <item name="foo" type="id">@id/bar</item>
9399efbbef2e060cd5e05f5b652ba5c7aaf687f64d6y    <item name="bar" type="id"/>
9409efbbef2e060cd5e05f5b652ba5c7aaf687f64d6y    <item name="baz" type="id"></item>)";
9419efbbef2e060cd5e05f5b652ba5c7aaf687f64d6y  ASSERT_TRUE(TestParse(input));
9429efbbef2e060cd5e05f5b652ba5c7aaf687f64d6y
9439efbbef2e060cd5e05f5b652ba5c7aaf687f64d6y  ASSERT_THAT(test::GetValue<Reference>(&table_, "id/foo"), NotNull());
9449efbbef2e060cd5e05f5b652ba5c7aaf687f64d6y  ASSERT_THAT(test::GetValue<Id>(&table_, "id/bar"), NotNull());
9459efbbef2e060cd5e05f5b652ba5c7aaf687f64d6y  ASSERT_THAT(test::GetValue<Id>(&table_, "id/baz"), NotNull());
9469efbbef2e060cd5e05f5b652ba5c7aaf687f64d6y
947eaf77e1d3a6ad4995ddd92a429802cffbf0f0209Ryan Mitchell  input = R"(
948eaf77e1d3a6ad4995ddd92a429802cffbf0f0209Ryan Mitchell    <id name="foo2">@id/bar</id>
949eaf77e1d3a6ad4995ddd92a429802cffbf0f0209Ryan Mitchell    <id name="bar2"/>
950eaf77e1d3a6ad4995ddd92a429802cffbf0f0209Ryan Mitchell    <id name="baz2"></id>)";
951eaf77e1d3a6ad4995ddd92a429802cffbf0f0209Ryan Mitchell  ASSERT_TRUE(TestParse(input));
952eaf77e1d3a6ad4995ddd92a429802cffbf0f0209Ryan Mitchell
953eaf77e1d3a6ad4995ddd92a429802cffbf0f0209Ryan Mitchell  ASSERT_THAT(test::GetValue<Reference>(&table_, "id/foo2"), NotNull());
954eaf77e1d3a6ad4995ddd92a429802cffbf0f0209Ryan Mitchell  ASSERT_THAT(test::GetValue<Id>(&table_, "id/bar2"), NotNull());
955eaf77e1d3a6ad4995ddd92a429802cffbf0f0209Ryan Mitchell  ASSERT_THAT(test::GetValue<Id>(&table_, "id/baz2"), NotNull());
956eaf77e1d3a6ad4995ddd92a429802cffbf0f0209Ryan Mitchell
9579efbbef2e060cd5e05f5b652ba5c7aaf687f64d6y  // Reject attribute references
958eaf77e1d3a6ad4995ddd92a429802cffbf0f0209Ryan Mitchell  input = R"(<item name="foo3" type="id">?attr/bar"</item>)";
9599efbbef2e060cd5e05f5b652ba5c7aaf687f64d6y  ASSERT_FALSE(TestParse(input));
9609efbbef2e060cd5e05f5b652ba5c7aaf687f64d6y
9619efbbef2e060cd5e05f5b652ba5c7aaf687f64d6y  // Reject non-references
962eaf77e1d3a6ad4995ddd92a429802cffbf0f0209Ryan Mitchell  input = R"(<item name="foo4" type="id">0x7f010001</item>)";
9639efbbef2e060cd5e05f5b652ba5c7aaf687f64d6y  ASSERT_FALSE(TestParse(input));
964eaf77e1d3a6ad4995ddd92a429802cffbf0f0209Ryan Mitchell  input = R"(<item name="foo5" type="id">@drawable/my_image</item>)";
9659efbbef2e060cd5e05f5b652ba5c7aaf687f64d6y  ASSERT_FALSE(TestParse(input));
966eaf77e1d3a6ad4995ddd92a429802cffbf0f0209Ryan Mitchell  input = R"(<item name="foo6" type="id"><string name="biz"></string></item>)";
9679efbbef2e060cd5e05f5b652ba5c7aaf687f64d6y  ASSERT_FALSE(TestParse(input));
9689efbbef2e060cd5e05f5b652ba5c7aaf687f64d6y
9699efbbef2e060cd5e05f5b652ba5c7aaf687f64d6y  // Ids that reference other resource ids cannot be public
970eaf77e1d3a6ad4995ddd92a429802cffbf0f0209Ryan Mitchell  input = R"(<public name="foo7" type="id">@id/bar7</item>)";
9719efbbef2e060cd5e05f5b652ba5c7aaf687f64d6y  ASSERT_FALSE(TestParse(input));
9729efbbef2e060cd5e05f5b652ba5c7aaf687f64d6y}
9739efbbef2e060cd5e05f5b652ba5c7aaf687f64d6y
974cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski}  // namespace aapt
975