Home | History | Annotate | Download | only in aapt2
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "ResourceParser.h"
     18 
     19 #include <sstream>
     20 #include <string>
     21 
     22 #include "ResourceTable.h"
     23 #include "ResourceUtils.h"
     24 #include "ResourceValues.h"
     25 #include "io/StringInputStream.h"
     26 #include "test/Test.h"
     27 #include "xml/XmlPullParser.h"
     28 
     29 using ::aapt::io::StringInputStream;
     30 using ::aapt::test::StrValueEq;
     31 using ::aapt::test::ValueEq;
     32 using ::android::ResTable_map;
     33 using ::android::Res_value;
     34 using ::android::StringPiece;
     35 using ::testing::Eq;
     36 using ::testing::IsEmpty;
     37 using ::testing::IsNull;
     38 using ::testing::NotNull;
     39 using ::testing::Pointee;
     40 using ::testing::SizeIs;
     41 
     42 namespace aapt {
     43 
     44 constexpr const char* kXmlPreamble = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
     45 
     46 TEST(ResourceParserSingleTest, FailToParseWithNoRootResourcesElement) {
     47   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
     48   ResourceTable table;
     49   ResourceParser parser(context->GetDiagnostics(), &table, Source{"test"}, {});
     50 
     51   std::string input = kXmlPreamble;
     52   input += R"(<attr name="foo"/>)";
     53   StringInputStream in(input);
     54   xml::XmlPullParser xml_parser(&in);
     55   ASSERT_FALSE(parser.Parse(&xml_parser));
     56 }
     57 
     58 class ResourceParserTest : public ::testing::Test {
     59  public:
     60   void SetUp() override {
     61     context_ = test::ContextBuilder().Build();
     62   }
     63 
     64   ::testing::AssertionResult TestParse(const StringPiece& str) {
     65     return TestParse(str, ConfigDescription{});
     66   }
     67 
     68   ::testing::AssertionResult TestParse(const StringPiece& str, const ConfigDescription& config) {
     69     ResourceParserOptions parserOptions;
     70     ResourceParser parser(context_->GetDiagnostics(), &table_, Source{"test"}, config,
     71                           parserOptions);
     72 
     73     std::string input = kXmlPreamble;
     74     input += "<resources>\n";
     75     input.append(str.data(), str.size());
     76     input += "\n</resources>";
     77     StringInputStream in(input);
     78     xml::XmlPullParser xmlParser(&in);
     79     if (parser.Parse(&xmlParser)) {
     80       return ::testing::AssertionSuccess();
     81     }
     82     return ::testing::AssertionFailure();
     83   }
     84 
     85  protected:
     86   ResourceTable table_;
     87   std::unique_ptr<IAaptContext> context_;
     88 };
     89 
     90 TEST_F(ResourceParserTest, ParseQuotedString) {
     91   ASSERT_TRUE(TestParse(R"(<string name="foo">   "  hey there " </string>)"));
     92 
     93   String* str = test::GetValue<String>(&table_, "string/foo");
     94   ASSERT_THAT(str, NotNull());
     95   EXPECT_THAT(*str, StrValueEq("  hey there "));
     96   EXPECT_THAT(str->untranslatable_sections, IsEmpty());
     97 }
     98 
     99 TEST_F(ResourceParserTest, ParseEscapedString) {
    100   ASSERT_TRUE(TestParse(R"(<string name="foo">\?123</string>)"));
    101 
    102   String* str = test::GetValue<String>(&table_, "string/foo");
    103   ASSERT_THAT(str, NotNull());
    104   EXPECT_THAT(*str, StrValueEq("?123"));
    105   EXPECT_THAT(str->untranslatable_sections, IsEmpty());
    106 
    107   ASSERT_TRUE(TestParse(R"(<string name="bar">This isn\t a bad string</string>)"));
    108   str = test::GetValue<String>(&table_, "string/bar");
    109   ASSERT_THAT(str, NotNull());
    110   EXPECT_THAT(*str, StrValueEq("This isnt a bad string"));
    111 }
    112 
    113 TEST_F(ResourceParserTest, ParseFormattedString) {
    114   ASSERT_FALSE(TestParse(R"(<string name="foo">%d %s</string>)"));
    115   ASSERT_TRUE(TestParse(R"(<string name="foo">%1$d %2$s</string>)"));
    116 }
    117 
    118 TEST_F(ResourceParserTest, ParseStyledString) {
    119   // Use a surrogate pair unicode point so that we can verify that the span
    120   // indices use UTF-16 length and not UTF-8 length.
    121   std::string input =
    122       "<string name=\"foo\">This is my aunt\u2019s <b>fickle <small>string</small></b></string>";
    123   ASSERT_TRUE(TestParse(input));
    124 
    125   StyledString* str = test::GetValue<StyledString>(&table_, "string/foo");
    126   ASSERT_THAT(str, NotNull());
    127 
    128   EXPECT_THAT(str->value->value, Eq("This is my aunt\u2019s fickle string"));
    129   EXPECT_THAT(str->value->spans, SizeIs(2));
    130   EXPECT_THAT(str->untranslatable_sections, IsEmpty());
    131 
    132   EXPECT_THAT(*str->value->spans[0].name, Eq("b"));
    133   EXPECT_THAT(str->value->spans[0].first_char, Eq(17u));
    134   EXPECT_THAT(str->value->spans[0].last_char, Eq(30u));
    135 
    136   EXPECT_THAT(*str->value->spans[1].name, Eq("small"));
    137   EXPECT_THAT(str->value->spans[1].first_char, Eq(24u));
    138   EXPECT_THAT(str->value->spans[1].last_char, Eq(30u));
    139 }
    140 
    141 TEST_F(ResourceParserTest, ParseStringWithWhitespace) {
    142   ASSERT_TRUE(TestParse(R"(<string name="foo">  This is what  I think  </string>)"));
    143 
    144   String* str = test::GetValue<String>(&table_, "string/foo");
    145   ASSERT_THAT(str, NotNull());
    146   EXPECT_THAT(*str->value, Eq("This is what I think"));
    147   EXPECT_THAT(str->untranslatable_sections, IsEmpty());
    148 
    149   ASSERT_TRUE(TestParse(R"(<string name="foo2">"  This is what  I think  "</string>)"));
    150 
    151   str = test::GetValue<String>(&table_, "string/foo2");
    152   ASSERT_THAT(str, NotNull());
    153   EXPECT_THAT(*str, StrValueEq("  This is what  I think  "));
    154 }
    155 
    156 TEST_F(ResourceParserTest, IgnoreXliffTagsOtherThanG) {
    157   std::string input = R"(
    158       <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    159           There are <xliff:source>no</xliff:source> apples</string>)";
    160   ASSERT_TRUE(TestParse(input));
    161 
    162   String* str = test::GetValue<String>(&table_, "string/foo");
    163   ASSERT_THAT(str, NotNull());
    164   EXPECT_THAT(*str, StrValueEq("There are no apples"));
    165   EXPECT_THAT(str->untranslatable_sections, IsEmpty());
    166 }
    167 
    168 TEST_F(ResourceParserTest, NestedXliffGTagsAreIllegal) {
    169   std::string input = R"(
    170       <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    171           Do not <xliff:g>translate <xliff:g>this</xliff:g></xliff:g></string>)";
    172   EXPECT_FALSE(TestParse(input));
    173 }
    174 
    175 TEST_F(ResourceParserTest, RecordUntranslateableXliffSectionsInString) {
    176   std::string input = R"(
    177       <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    178           There are <xliff:g id="count">%1$d</xliff:g> apples</string>)";
    179   ASSERT_TRUE(TestParse(input));
    180 
    181   String* str = test::GetValue<String>(&table_, "string/foo");
    182   ASSERT_THAT(str, NotNull());
    183   EXPECT_THAT(*str, StrValueEq("There are %1$d apples"));
    184   ASSERT_THAT(str->untranslatable_sections, SizeIs(1));
    185 
    186   // We expect indices and lengths that span to include the whitespace
    187   // before %1$d. This is due to how the StringBuilder withholds whitespace unless
    188   // needed (to deal with line breaks, etc.).
    189   EXPECT_THAT(str->untranslatable_sections[0].start, Eq(9u));
    190   EXPECT_THAT(str->untranslatable_sections[0].end, Eq(14u));
    191 }
    192 
    193 TEST_F(ResourceParserTest, RecordUntranslateableXliffSectionsInStyledString) {
    194   std::string input = R"(
    195       <string name="foo" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    196           There are <b><xliff:g id="count">%1$d</xliff:g></b> apples</string>)";
    197   ASSERT_TRUE(TestParse(input));
    198 
    199   StyledString* str = test::GetValue<StyledString>(&table_, "string/foo");
    200   ASSERT_THAT(str, NotNull());
    201   EXPECT_THAT(str->value->value, Eq("There are %1$d apples"));
    202   ASSERT_THAT(str->untranslatable_sections, SizeIs(1));
    203 
    204   // We expect indices and lengths that span to include the whitespace
    205   // before %1$d. This is due to how the StringBuilder withholds whitespace unless
    206   // needed (to deal with line breaks, etc.).
    207   EXPECT_THAT(str->untranslatable_sections[0].start, Eq(9u));
    208   EXPECT_THAT(str->untranslatable_sections[0].end, Eq(14u));
    209 }
    210 
    211 TEST_F(ResourceParserTest, ParseNull) {
    212   std::string input = R"(<integer name="foo">@null</integer>)";
    213   ASSERT_TRUE(TestParse(input));
    214 
    215   // The Android runtime treats a value of android::Res_value::TYPE_NULL as
    216   // a non-existing value, and this causes problems in styles when trying to
    217   // resolve an attribute. Null values must be encoded as android::Res_value::TYPE_REFERENCE
    218   // with a data value of 0.
    219   Reference* null_ref = test::GetValue<Reference>(&table_, "integer/foo");
    220   ASSERT_THAT(null_ref, NotNull());
    221   EXPECT_FALSE(null_ref->name);
    222   EXPECT_FALSE(null_ref->id);
    223   EXPECT_THAT(null_ref->reference_type, Eq(Reference::Type::kResource));
    224 }
    225 
    226 TEST_F(ResourceParserTest, ParseEmpty) {
    227   std::string input = R"(<integer name="foo">@empty</integer>)";
    228   ASSERT_TRUE(TestParse(input));
    229 
    230   BinaryPrimitive* integer = test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
    231   ASSERT_THAT(integer, NotNull());
    232   EXPECT_THAT(integer->value.dataType, Eq(Res_value::TYPE_NULL));
    233   EXPECT_THAT(integer->value.data, Eq(Res_value::DATA_NULL_EMPTY));
    234 }
    235 
    236 TEST_F(ResourceParserTest, ParseAttr) {
    237   std::string input = R"(
    238       <attr name="foo" format="string"/>
    239       <attr name="bar"/>)";
    240   ASSERT_TRUE(TestParse(input));
    241 
    242   Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
    243   ASSERT_THAT(attr, NotNull());
    244   EXPECT_THAT(attr->type_mask, Eq(ResTable_map::TYPE_STRING));
    245 
    246   attr = test::GetValue<Attribute>(&table_, "attr/bar");
    247   ASSERT_THAT(attr, NotNull());
    248   EXPECT_THAT(attr->type_mask, Eq(ResTable_map::TYPE_ANY));
    249 }
    250 
    251 // Old AAPT allowed attributes to be defined under different configurations, but ultimately
    252 // stored them with the default configuration. Check that we have the same behavior.
    253 TEST_F(ResourceParserTest, ParseAttrAndDeclareStyleableUnderConfigButRecordAsNoConfig) {
    254   const ConfigDescription watch_config = test::ParseConfigOrDie("watch");
    255   std::string input = R"(
    256       <attr name="foo" />
    257       <declare-styleable name="bar">
    258         <attr name="baz" />
    259       </declare-styleable>)";
    260   ASSERT_TRUE(TestParse(input, watch_config));
    261 
    262   EXPECT_THAT(test::GetValueForConfig<Attribute>(&table_, "attr/foo", watch_config), IsNull());
    263   EXPECT_THAT(test::GetValueForConfig<Attribute>(&table_, "attr/baz", watch_config), IsNull());
    264   EXPECT_THAT(test::GetValueForConfig<Styleable>(&table_, "styleable/bar", watch_config), IsNull());
    265 
    266   EXPECT_THAT(test::GetValue<Attribute>(&table_, "attr/foo"), NotNull());
    267   EXPECT_THAT(test::GetValue<Attribute>(&table_, "attr/baz"), NotNull());
    268   EXPECT_THAT(test::GetValue<Styleable>(&table_, "styleable/bar"), NotNull());
    269 }
    270 
    271 TEST_F(ResourceParserTest, ParseAttrWithMinMax) {
    272   std::string input = R"(<attr name="foo" min="10" max="23" format="integer"/>)";
    273   ASSERT_TRUE(TestParse(input));
    274 
    275   Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
    276   ASSERT_THAT(attr, NotNull());
    277   EXPECT_THAT(attr->type_mask, Eq(ResTable_map::TYPE_INTEGER));
    278   EXPECT_THAT(attr->min_int, Eq(10));
    279   EXPECT_THAT(attr->max_int, Eq(23));
    280 }
    281 
    282 TEST_F(ResourceParserTest, FailParseAttrWithMinMaxButNotInteger) {
    283   ASSERT_FALSE(TestParse(R"(<attr name="foo" min="10" max="23" format="string"/>)"));
    284 }
    285 
    286 TEST_F(ResourceParserTest, ParseUseAndDeclOfAttr) {
    287   std::string input = R"(
    288       <declare-styleable name="Styleable">
    289         <attr name="foo" />
    290       </declare-styleable>
    291       <attr name="foo" format="string"/>)";
    292   ASSERT_TRUE(TestParse(input));
    293 
    294   Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
    295   ASSERT_THAT(attr, NotNull());
    296   EXPECT_THAT(attr->type_mask, Eq(ResTable_map::TYPE_STRING));
    297 }
    298 
    299 TEST_F(ResourceParserTest, ParseDoubleUseOfAttr) {
    300   std::string input = R"(
    301       <declare-styleable name="Theme">
    302         <attr name="foo" />
    303       </declare-styleable>
    304       <declare-styleable name="Window">
    305         <attr name="foo" format="boolean"/>
    306       </declare-styleable>)";
    307   ASSERT_TRUE(TestParse(input));
    308 
    309   Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
    310   ASSERT_THAT(attr, NotNull());
    311   EXPECT_THAT(attr->type_mask, Eq(ResTable_map::TYPE_BOOLEAN));
    312 }
    313 
    314 TEST_F(ResourceParserTest, ParseEnumAttr) {
    315   std::string input = R"(
    316       <attr name="foo">
    317         <enum name="bar" value="0"/>
    318         <enum name="bat" value="1"/>
    319         <enum name="baz" value="2"/>
    320       </attr>)";
    321   ASSERT_TRUE(TestParse(input));
    322 
    323   Attribute* enum_attr = test::GetValue<Attribute>(&table_, "attr/foo");
    324   ASSERT_THAT(enum_attr, NotNull());
    325   EXPECT_THAT(enum_attr->type_mask, Eq(ResTable_map::TYPE_ENUM));
    326   ASSERT_THAT(enum_attr->symbols, SizeIs(3));
    327 
    328   ASSERT_TRUE(enum_attr->symbols[0].symbol.name);
    329   EXPECT_THAT(enum_attr->symbols[0].symbol.name.value().entry, Eq("bar"));
    330   EXPECT_THAT(enum_attr->symbols[0].value, Eq(0u));
    331 
    332   ASSERT_TRUE(enum_attr->symbols[1].symbol.name);
    333   EXPECT_THAT(enum_attr->symbols[1].symbol.name.value().entry, Eq("bat"));
    334   EXPECT_THAT(enum_attr->symbols[1].value, Eq(1u));
    335 
    336   ASSERT_TRUE(enum_attr->symbols[2].symbol.name);
    337   EXPECT_THAT(enum_attr->symbols[2].symbol.name.value().entry, Eq("baz"));
    338   EXPECT_THAT(enum_attr->symbols[2].value, Eq(2u));
    339 }
    340 
    341 TEST_F(ResourceParserTest, ParseFlagAttr) {
    342   std::string input = R"(
    343       <attr name="foo">
    344         <flag name="bar" value="0"/>
    345         <flag name="bat" value="1"/>
    346         <flag name="baz" value="2"/>
    347       </attr>)";
    348   ASSERT_TRUE(TestParse(input));
    349 
    350   Attribute* flag_attr = test::GetValue<Attribute>(&table_, "attr/foo");
    351   ASSERT_THAT(flag_attr, NotNull());
    352   EXPECT_THAT(flag_attr->type_mask, Eq(ResTable_map::TYPE_FLAGS));
    353   ASSERT_THAT(flag_attr->symbols, SizeIs(3));
    354 
    355   ASSERT_TRUE(flag_attr->symbols[0].symbol.name);
    356   EXPECT_THAT(flag_attr->symbols[0].symbol.name.value().entry, Eq("bar"));
    357   EXPECT_THAT(flag_attr->symbols[0].value, Eq(0u));
    358 
    359   ASSERT_TRUE(flag_attr->symbols[1].symbol.name);
    360   EXPECT_THAT(flag_attr->symbols[1].symbol.name.value().entry, Eq("bat"));
    361   EXPECT_THAT(flag_attr->symbols[1].value, Eq(1u));
    362 
    363   ASSERT_TRUE(flag_attr->symbols[2].symbol.name);
    364   EXPECT_THAT(flag_attr->symbols[2].symbol.name.value().entry, Eq("baz"));
    365   EXPECT_THAT(flag_attr->symbols[2].value, Eq(2u));
    366 
    367   std::unique_ptr<BinaryPrimitive> flag_value =
    368       ResourceUtils::TryParseFlagSymbol(flag_attr, "baz|bat");
    369   ASSERT_THAT(flag_value, NotNull());
    370   EXPECT_THAT(flag_value->value.data, Eq(1u | 2u));
    371 }
    372 
    373 TEST_F(ResourceParserTest, FailToParseEnumAttrWithNonUniqueKeys) {
    374   std::string input = R"(
    375       <attr name="foo">
    376         <enum name="bar" value="0"/>
    377         <enum name="bat" value="1"/>
    378         <enum name="bat" value="2"/>
    379       </attr>)";
    380   ASSERT_FALSE(TestParse(input));
    381 }
    382 
    383 TEST_F(ResourceParserTest, ParseStyle) {
    384   std::string input = R"(
    385       <style name="foo" parent="@style/fu">
    386         <item name="bar">#ffffffff</item>
    387         <item name="bat">@string/hey</item>
    388         <item name="baz"><b>hey</b></item>
    389       </style>)";
    390   ASSERT_TRUE(TestParse(input));
    391 
    392   Style* style = test::GetValue<Style>(&table_, "style/foo");
    393   ASSERT_THAT(style, NotNull());
    394   ASSERT_TRUE(style->parent);
    395   EXPECT_THAT(style->parent.value().name, Eq(make_value(test::ParseNameOrDie("style/fu"))));
    396   ASSERT_THAT(style->entries, SizeIs(3));
    397 
    398   EXPECT_THAT(style->entries[0].key.name, Eq(make_value(test::ParseNameOrDie("attr/bar"))));
    399   EXPECT_THAT(style->entries[1].key.name, Eq(make_value(test::ParseNameOrDie("attr/bat"))));
    400   EXPECT_THAT(style->entries[2].key.name, Eq(make_value(test::ParseNameOrDie("attr/baz"))));
    401 }
    402 
    403 TEST_F(ResourceParserTest, ParseStyleWithShorthandParent) {
    404   ASSERT_TRUE(TestParse(R"(<style name="foo" parent="com.app:Theme"/>)"));
    405 
    406   Style* style = test::GetValue<Style>(&table_, "style/foo");
    407   ASSERT_THAT(style, NotNull());
    408   ASSERT_TRUE(style->parent);
    409   EXPECT_THAT(style->parent.value().name, Eq(make_value(test::ParseNameOrDie("com.app:style/Theme"))));
    410 }
    411 
    412 TEST_F(ResourceParserTest, ParseStyleWithPackageAliasedParent) {
    413   std::string input = R"(
    414       <style xmlns:app="http://schemas.android.com/apk/res/android"
    415           name="foo" parent="app:Theme"/>)";
    416   ASSERT_TRUE(TestParse(input));
    417 
    418   Style* style = test::GetValue<Style>(&table_, "style/foo");
    419   ASSERT_THAT(style, NotNull());
    420   ASSERT_TRUE(style->parent);
    421   ASSERT_TRUE(style->parent.value().name);
    422   EXPECT_THAT(style->parent.value().name, Eq(make_value(test::ParseNameOrDie("android:style/Theme"))));
    423 }
    424 
    425 TEST_F(ResourceParserTest, ParseStyleWithPackageAliasedItems) {
    426   std::string input = R"(
    427       <style xmlns:app="http://schemas.android.com/apk/res/android" name="foo">
    428         <item name="app:bar">0</item>
    429       </style>)";
    430   ASSERT_TRUE(TestParse(input));
    431 
    432   Style* style = test::GetValue<Style>(&table_, "style/foo");
    433   ASSERT_THAT(style, NotNull());
    434   ASSERT_THAT(style->entries, SizeIs(1));
    435   EXPECT_THAT(style->entries[0].key.name, Eq(make_value(test::ParseNameOrDie("android:attr/bar"))));
    436 }
    437 
    438 TEST_F(ResourceParserTest, ParseStyleWithInferredParent) {
    439   ASSERT_TRUE(TestParse(R"(<style name="foo.bar"/>)"));
    440 
    441   Style* style = test::GetValue<Style>(&table_, "style/foo.bar");
    442   ASSERT_THAT(style, NotNull());
    443   ASSERT_TRUE(style->parent);
    444   EXPECT_THAT(style->parent.value().name, Eq(make_value(test::ParseNameOrDie("style/foo"))));
    445   EXPECT_TRUE(style->parent_inferred);
    446 }
    447 
    448 TEST_F(ResourceParserTest, ParseStyleWithInferredParentOverridenByEmptyParentAttribute) {
    449   ASSERT_TRUE(TestParse(R"(<style name="foo.bar" parent=""/>)"));
    450 
    451   Style* style = test::GetValue<Style>(&table_, "style/foo.bar");
    452   ASSERT_THAT(style, NotNull());
    453   EXPECT_FALSE(style->parent);
    454   EXPECT_FALSE(style->parent_inferred);
    455 }
    456 
    457 TEST_F(ResourceParserTest, ParseStyleWithPrivateParentReference) {
    458   ASSERT_TRUE(TestParse(R"(<style name="foo" parent="*android:style/bar" />)"));
    459 
    460   Style* style = test::GetValue<Style>(&table_, "style/foo");
    461   ASSERT_THAT(style, NotNull());
    462   ASSERT_TRUE(style->parent);
    463   EXPECT_TRUE(style->parent.value().private_reference);
    464 }
    465 
    466 TEST_F(ResourceParserTest, ParseAutoGeneratedIdReference) {
    467   ASSERT_TRUE(TestParse(R"(<string name="foo">@+id/bar</string>)"));
    468   ASSERT_THAT(test::GetValue<Id>(&table_, "id/bar"), NotNull());
    469 }
    470 
    471 TEST_F(ResourceParserTest, ParseAttributesDeclareStyleable) {
    472   std::string input = R"(
    473       <declare-styleable name="foo">
    474         <attr name="bar" />
    475         <attr name="bat" format="string|reference"/>
    476         <attr name="baz">
    477           <enum name="foo" value="1"/>
    478         </attr>
    479       </declare-styleable>)";
    480   ASSERT_TRUE(TestParse(input));
    481 
    482   Maybe<ResourceTable::SearchResult> result =
    483       table_.FindResource(test::ParseNameOrDie("styleable/foo"));
    484   ASSERT_TRUE(result);
    485   EXPECT_THAT(result.value().entry->symbol_status.state, Eq(SymbolState::kPublic));
    486 
    487   Attribute* attr = test::GetValue<Attribute>(&table_, "attr/bar");
    488   ASSERT_THAT(attr, NotNull());
    489   EXPECT_TRUE(attr->IsWeak());
    490 
    491   attr = test::GetValue<Attribute>(&table_, "attr/bat");
    492   ASSERT_THAT(attr, NotNull());
    493   EXPECT_TRUE(attr->IsWeak());
    494 
    495   attr = test::GetValue<Attribute>(&table_, "attr/baz");
    496   ASSERT_THAT(attr, NotNull());
    497   EXPECT_TRUE(attr->IsWeak());
    498   EXPECT_THAT(attr->symbols, SizeIs(1));
    499 
    500   EXPECT_THAT(test::GetValue<Id>(&table_, "id/foo"), NotNull());
    501 
    502   Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo");
    503   ASSERT_THAT(styleable, NotNull());
    504   ASSERT_THAT(styleable->entries, SizeIs(3));
    505 
    506   EXPECT_THAT(styleable->entries[0].name, Eq(make_value(test::ParseNameOrDie("attr/bar"))));
    507   EXPECT_THAT(styleable->entries[1].name, Eq(make_value(test::ParseNameOrDie("attr/bat"))));
    508   EXPECT_THAT(styleable->entries[2].name, Eq(make_value(test::ParseNameOrDie("attr/baz"))));
    509 }
    510 
    511 TEST_F(ResourceParserTest, ParsePrivateAttributesDeclareStyleable) {
    512   std::string input = R"(
    513       <declare-styleable xmlns:privAndroid="http://schemas.android.com/apk/prv/res/android"
    514           name="foo">
    515         <attr name="*android:bar" />
    516         <attr name="privAndroid:bat" />
    517       </declare-styleable>)";
    518   ASSERT_TRUE(TestParse(input));
    519   Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo");
    520   ASSERT_THAT(styleable, NotNull());
    521   ASSERT_THAT(styleable->entries, SizeIs(2));
    522 
    523   EXPECT_TRUE(styleable->entries[0].private_reference);
    524   ASSERT_TRUE(styleable->entries[0].name);
    525   EXPECT_THAT(styleable->entries[0].name.value().package, Eq("android"));
    526 
    527   EXPECT_TRUE(styleable->entries[1].private_reference);
    528   ASSERT_TRUE(styleable->entries[1].name);
    529   EXPECT_THAT(styleable->entries[1].name.value().package, Eq("android"));
    530 }
    531 
    532 TEST_F(ResourceParserTest, ParseArray) {
    533   std::string input = R"(
    534       <array name="foo">
    535         <item>@string/ref</item>
    536         <item>hey</item>
    537         <item>23</item>
    538       </array>)";
    539   ASSERT_TRUE(TestParse(input));
    540 
    541   Array* array = test::GetValue<Array>(&table_, "array/foo");
    542   ASSERT_THAT(array, NotNull());
    543   ASSERT_THAT(array->elements, SizeIs(3));
    544 
    545   EXPECT_THAT(ValueCast<Reference>(array->elements[0].get()), NotNull());
    546   EXPECT_THAT(ValueCast<String>(array->elements[1].get()), NotNull());
    547   EXPECT_THAT(ValueCast<BinaryPrimitive>(array->elements[2].get()), NotNull());
    548 }
    549 
    550 TEST_F(ResourceParserTest, ParseStringArray) {
    551   std::string input = R"(
    552       <string-array name="foo">
    553         <item>"Werk"</item>"
    554       </string-array>)";
    555   ASSERT_TRUE(TestParse(input));
    556   EXPECT_THAT(test::GetValue<Array>(&table_, "array/foo"), NotNull());
    557 }
    558 
    559 TEST_F(ResourceParserTest, ParseArrayWithFormat) {
    560   std::string input = R"(
    561       <array name="foo" format="string">
    562         <item>100</item>
    563       </array>)";
    564   ASSERT_TRUE(TestParse(input));
    565 
    566   Array* array = test::GetValue<Array>(&table_, "array/foo");
    567   ASSERT_THAT(array, NotNull());
    568   ASSERT_THAT(array->elements, SizeIs(1));
    569 
    570   String* str = ValueCast<String>(array->elements[0].get());
    571   ASSERT_THAT(str, NotNull());
    572   EXPECT_THAT(*str, StrValueEq("100"));
    573 }
    574 
    575 TEST_F(ResourceParserTest, ParseArrayWithBadFormat) {
    576   std::string input = R"(
    577       <array name="foo" format="integer">
    578         <item>Hi</item>
    579       </array>)";
    580   ASSERT_FALSE(TestParse(input));
    581 }
    582 
    583 TEST_F(ResourceParserTest, ParsePlural) {
    584   std::string input = R"(
    585       <plurals name="foo">
    586         <item quantity="other">apples</item>
    587         <item quantity="one">apple</item>
    588       </plurals>)";
    589   ASSERT_TRUE(TestParse(input));
    590 
    591   Plural* plural = test::GetValue<Plural>(&table_, "plurals/foo");
    592   ASSERT_THAT(plural, NotNull());
    593   EXPECT_THAT(plural->values[Plural::Zero], IsNull());
    594   EXPECT_THAT(plural->values[Plural::Two], IsNull());
    595   EXPECT_THAT(plural->values[Plural::Few], IsNull());
    596   EXPECT_THAT(plural->values[Plural::Many], IsNull());
    597 
    598   EXPECT_THAT(plural->values[Plural::One], NotNull());
    599   EXPECT_THAT(plural->values[Plural::Other], NotNull());
    600 }
    601 
    602 TEST_F(ResourceParserTest, ParseCommentsWithResource) {
    603   std::string input = R"(
    604       <!--This is a comment-->
    605       <string name="foo">Hi</string>)";
    606   ASSERT_TRUE(TestParse(input));
    607 
    608   String* value = test::GetValue<String>(&table_, "string/foo");
    609   ASSERT_THAT(value, NotNull());
    610   EXPECT_THAT(value->GetComment(), Eq("This is a comment"));
    611 }
    612 
    613 TEST_F(ResourceParserTest, DoNotCombineMultipleComments) {
    614   std::string input = R"(
    615       <!--One-->
    616       <!--Two-->
    617       <string name="foo">Hi</string>)";
    618 
    619   ASSERT_TRUE(TestParse(input));
    620 
    621   String* value = test::GetValue<String>(&table_, "string/foo");
    622   ASSERT_THAT(value, NotNull());
    623   EXPECT_THAT(value->GetComment(), Eq("Two"));
    624 }
    625 
    626 TEST_F(ResourceParserTest, IgnoreCommentBeforeEndTag) {
    627   std::string input = R"(
    628       <!--One-->
    629       <string name="foo">
    630         Hi
    631       <!--Two-->
    632       </string>)";
    633   ASSERT_TRUE(TestParse(input));
    634 
    635   String* value = test::GetValue<String>(&table_, "string/foo");
    636   ASSERT_THAT(value, NotNull());
    637   EXPECT_THAT(value->GetComment(), Eq("One"));
    638 }
    639 
    640 TEST_F(ResourceParserTest, ParseNestedComments) {
    641   // We only care about declare-styleable and enum/flag attributes because
    642   // comments from those end up in R.java
    643   std::string input = R"(
    644       <declare-styleable name="foo">
    645         <!-- The name of the bar -->
    646         <attr name="barName" format="string|reference" />
    647       </declare-styleable>
    648 
    649       <attr name="foo">
    650         <!-- The very first -->
    651         <enum name="one" value="1" />
    652       </attr>)";
    653   ASSERT_TRUE(TestParse(input));
    654 
    655   Styleable* styleable = test::GetValue<Styleable>(&table_, "styleable/foo");
    656   ASSERT_THAT(styleable, NotNull());
    657   ASSERT_THAT(styleable->entries, SizeIs(1));
    658   EXPECT_THAT(styleable->entries[0].GetComment(), Eq("The name of the bar"));
    659 
    660   Attribute* attr = test::GetValue<Attribute>(&table_, "attr/foo");
    661   ASSERT_THAT(attr, NotNull());
    662   ASSERT_THAT(attr->symbols, SizeIs(1));
    663   EXPECT_THAT(attr->symbols[0].symbol.GetComment(), Eq("The very first"));
    664 }
    665 
    666 // Declaring an ID as public should not require a separate definition (as an ID has no value).
    667 TEST_F(ResourceParserTest, ParsePublicIdAsDefinition) {
    668   ASSERT_TRUE(TestParse(R"(<public type="id" name="foo"/>)"));
    669   ASSERT_THAT(test::GetValue<Id>(&table_, "id/foo"), NotNull());
    670 }
    671 
    672 TEST_F(ResourceParserTest, KeepAllProducts) {
    673   std::string input = R"(
    674       <string name="foo" product="phone">hi</string>
    675       <string name="foo" product="no-sdcard">ho</string>
    676       <string name="bar" product="">wee</string>
    677       <string name="baz">woo</string>
    678       <string name="bit" product="phablet">hoot</string>
    679       <string name="bot" product="default">yes</string>)";
    680   ASSERT_TRUE(TestParse(input));
    681 
    682   ASSERT_THAT(test::GetValueForConfigAndProduct<String>(&table_, "string/foo", ConfigDescription::DefaultConfig(), "phone"), NotNull());
    683   ASSERT_THAT(test::GetValueForConfigAndProduct<String>(&table_, "string/foo",ConfigDescription::DefaultConfig(), "no-sdcard"), NotNull());
    684   ASSERT_THAT(test::GetValueForConfigAndProduct<String>(&table_, "string/bar", ConfigDescription::DefaultConfig(), ""), NotNull());
    685   ASSERT_THAT(test::GetValueForConfigAndProduct<String>(&table_, "string/baz", ConfigDescription::DefaultConfig(), ""), NotNull());
    686   ASSERT_THAT(test::GetValueForConfigAndProduct<String>(&table_, "string/bit", ConfigDescription::DefaultConfig(), "phablet"), NotNull());
    687   ASSERT_THAT(test::GetValueForConfigAndProduct<String>(&table_, "string/bot", ConfigDescription::DefaultConfig(), "default"), NotNull());
    688 }
    689 
    690 TEST_F(ResourceParserTest, AutoIncrementIdsInPublicGroup) {
    691   std::string input = R"(
    692       <public-group type="attr" first-id="0x01010040">
    693         <public name="foo" />
    694         <public name="bar" />
    695       </public-group>)";
    696   ASSERT_TRUE(TestParse(input));
    697 
    698   Maybe<ResourceTable::SearchResult> result = table_.FindResource(test::ParseNameOrDie("attr/foo"));
    699   ASSERT_TRUE(result);
    700 
    701   ASSERT_TRUE(result.value().package->id);
    702   ASSERT_TRUE(result.value().type->id);
    703   ASSERT_TRUE(result.value().entry->id);
    704   ResourceId actual_id(result.value().package->id.value(),
    705                        result.value().type->id.value(),
    706                        result.value().entry->id.value());
    707   EXPECT_THAT(actual_id, Eq(ResourceId(0x01010040)));
    708 
    709   result = table_.FindResource(test::ParseNameOrDie("attr/bar"));
    710   ASSERT_TRUE(result);
    711 
    712   ASSERT_TRUE(result.value().package->id);
    713   ASSERT_TRUE(result.value().type->id);
    714   ASSERT_TRUE(result.value().entry->id);
    715   actual_id = ResourceId(result.value().package->id.value(),
    716                          result.value().type->id.value(),
    717                          result.value().entry->id.value());
    718   EXPECT_THAT(actual_id, Eq(ResourceId(0x01010041)));
    719 }
    720 
    721 TEST_F(ResourceParserTest, ExternalTypesShouldOnlyBeReferences) {
    722   ASSERT_TRUE(TestParse(R"(<item type="layout" name="foo">@layout/bar</item>)"));
    723   ASSERT_FALSE(TestParse(R"(<item type="layout" name="bar">"this is a string"</item>)"));
    724 }
    725 
    726 TEST_F(ResourceParserTest, AddResourcesElementShouldAddEntryWithUndefinedSymbol) {
    727   ASSERT_TRUE(TestParse(R"(<add-resource name="bar" type="string" />)"));
    728 
    729   Maybe<ResourceTable::SearchResult> result =
    730       table_.FindResource(test::ParseNameOrDie("string/bar"));
    731   ASSERT_TRUE(result);
    732   const ResourceEntry* entry = result.value().entry;
    733   ASSERT_THAT(entry, NotNull());
    734   EXPECT_THAT(entry->symbol_status.state, Eq(SymbolState::kUndefined));
    735   EXPECT_TRUE(entry->symbol_status.allow_new);
    736 }
    737 
    738 TEST_F(ResourceParserTest, ParseItemElementWithFormat) {
    739   ASSERT_TRUE(TestParse(R"(<item name="foo" type="integer" format="float">0.3</item>)"));
    740 
    741   BinaryPrimitive* val = test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
    742   ASSERT_THAT(val, NotNull());
    743   EXPECT_THAT(val->value.dataType, Eq(Res_value::TYPE_FLOAT));
    744 
    745   ASSERT_FALSE(TestParse(R"(<item name="bar" type="integer" format="fraction">100</item>)"));
    746 }
    747 
    748 // An <item> without a format specifier accepts all types of values.
    749 TEST_F(ResourceParserTest, ParseItemElementWithoutFormat) {
    750   ASSERT_TRUE(TestParse(R"(<item name="foo" type="integer">100%p</item>)"));
    751 
    752   BinaryPrimitive* val = test::GetValue<BinaryPrimitive>(&table_, "integer/foo");
    753   ASSERT_THAT(val, NotNull());
    754   EXPECT_THAT(val->value.dataType, Eq(Res_value::TYPE_FRACTION));
    755 }
    756 
    757 TEST_F(ResourceParserTest, ParseConfigVaryingItem) {
    758   ASSERT_TRUE(TestParse(R"(<item name="foo" type="configVarying">Hey</item>)"));
    759   ASSERT_THAT(test::GetValue<String>(&table_, "configVarying/foo"), NotNull());
    760 }
    761 
    762 TEST_F(ResourceParserTest, ParseBagElement) {
    763   std::string input = R"(
    764       <bag name="bag" type="configVarying">
    765         <item name="test">Hello!</item>
    766       </bag>)";
    767   ASSERT_TRUE(TestParse(input));
    768 
    769   Style* val = test::GetValue<Style>(&table_, "configVarying/bag");
    770   ASSERT_THAT(val, NotNull());
    771   ASSERT_THAT(val->entries, SizeIs(1));
    772 
    773   EXPECT_THAT(val->entries[0].key, Eq(Reference(test::ParseNameOrDie("attr/test"))));
    774   EXPECT_THAT(ValueCast<RawString>(val->entries[0].value.get()), NotNull());
    775 }
    776 
    777 TEST_F(ResourceParserTest, ParseElementWithNoValue) {
    778   std::string input = R"(
    779       <item type="drawable" format="reference" name="foo" />
    780       <string name="foo" />)";
    781   ASSERT_TRUE(TestParse(input));
    782   ASSERT_THAT(test::GetValue(&table_, "drawable/foo"), Pointee(ValueEq(Reference())));
    783 
    784   String* str = test::GetValue<String>(&table_, "string/foo");
    785   ASSERT_THAT(str, NotNull());
    786   EXPECT_THAT(*str, StrValueEq(""));
    787 }
    788 
    789 TEST_F(ResourceParserTest, ParsePlatformIndependentNewline) {
    790   ASSERT_TRUE(TestParse(R"(<string name="foo">%1$s %n %2$s</string>)"));
    791 }
    792 
    793 }  // namespace aapt
    794