Home | History | Annotate | Download | only in binary
      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 "format/binary/XmlFlattener.h"
     18 
     19 #include "androidfw/ResourceTypes.h"
     20 
     21 #include "link/Linkers.h"
     22 #include "test/Test.h"
     23 #include "util/BigBuffer.h"
     24 #include "util/Util.h"
     25 
     26 using ::aapt::test::StrEq;
     27 using ::android::StringPiece16;
     28 using ::testing::Eq;
     29 using ::testing::Ge;
     30 using ::testing::IsNull;
     31 using ::testing::Ne;
     32 using ::testing::NotNull;
     33 
     34 namespace aapt {
     35 
     36 class XmlFlattenerTest : public ::testing::Test {
     37  public:
     38   void SetUp() override {
     39     context_ = test::ContextBuilder()
     40                    .SetCompilationPackage("com.app.test")
     41                    .SetNameManglerPolicy(NameManglerPolicy{"com.app.test"})
     42                    .AddSymbolSource(
     43                        test::StaticSymbolSourceBuilder()
     44                            .AddPublicSymbol("android:attr/id", ResourceId(0x010100d0),
     45                                             test::AttributeBuilder().Build())
     46                            .AddSymbol("com.app.test:id/id", ResourceId(0x7f020000))
     47                            .AddPublicSymbol("android:attr/paddingStart", ResourceId(0x010103b3),
     48                                             test::AttributeBuilder().Build())
     49                            .AddPublicSymbol("android:attr/colorAccent", ResourceId(0x01010435),
     50                                             test::AttributeBuilder().Build())
     51                            .AddSymbol("com.app.test.feature:id/foo", ResourceId(0x80020000))
     52                            .AddSymbol("com.app.test.feature:attr/foo", ResourceId(0x80010000),
     53                                       test::AttributeBuilder().Build())
     54                            .Build())
     55                    .Build();
     56   }
     57 
     58   ::testing::AssertionResult Flatten(xml::XmlResource* doc, android::ResXMLTree* out_tree,
     59                                      const XmlFlattenerOptions& options = {}) {
     60     using namespace android;  // For NO_ERROR on windows because it is a macro.
     61 
     62     BigBuffer buffer(1024);
     63     XmlFlattener flattener(&buffer, options);
     64     if (!flattener.Consume(context_.get(), doc)) {
     65       return ::testing::AssertionFailure() << "failed to flatten XML Tree";
     66     }
     67 
     68     std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
     69     if (out_tree->setTo(data.get(), buffer.size(), true) != NO_ERROR) {
     70       return ::testing::AssertionFailure() << "flattened XML is corrupt";
     71     }
     72     return ::testing::AssertionSuccess();
     73   }
     74 
     75  protected:
     76   std::unique_ptr<test::Context> context_;
     77 };
     78 
     79 TEST_F(XmlFlattenerTest, FlattenXmlWithNoCompiledAttributes) {
     80   std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(
     81       <View xmlns:test="http://com.test" attr="hey">
     82           <Layout test:hello="hi" />
     83           <Layout>Some text\\</Layout>
     84       </View>)");
     85 
     86   android::ResXMLTree tree;
     87   ASSERT_TRUE(Flatten(doc.get(), &tree));
     88   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_NAMESPACE));
     89 
     90   size_t len;
     91   EXPECT_THAT(tree.getNamespacePrefix(&len), StrEq(u"test"));
     92   EXPECT_THAT(tree.getNamespaceUri(&len), StrEq(u"http://com.test"));
     93 
     94   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
     95   EXPECT_THAT(tree.getElementNamespace(&len), IsNull());
     96   EXPECT_THAT(tree.getElementName(&len), StrEq(u"View"));
     97 
     98   ASSERT_THAT(tree.getAttributeCount(), Eq(1u));
     99   EXPECT_THAT(tree.getAttributeNamespace(0, &len), IsNull());
    100   EXPECT_THAT(tree.getAttributeName(0, &len), StrEq(u"attr"));
    101 
    102   const StringPiece16 kAttr(u"attr");
    103   EXPECT_THAT(tree.indexOfAttribute(nullptr, 0, kAttr.data(), kAttr.size()), Eq(0));
    104 
    105   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
    106   EXPECT_THAT(tree.getElementNamespace(&len), IsNull());
    107   EXPECT_THAT(tree.getElementName(&len), StrEq(u"Layout"));
    108 
    109   ASSERT_THAT(tree.getAttributeCount(), Eq(1u));
    110   EXPECT_THAT(tree.getAttributeNamespace(0, &len), StrEq(u"http://com.test"));
    111   EXPECT_THAT(tree.getAttributeName(0, &len), StrEq(u"hello"));
    112 
    113   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
    114   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
    115 
    116   EXPECT_THAT(tree.getElementNamespace(&len), IsNull());
    117   EXPECT_THAT(tree.getElementName(&len), StrEq(u"Layout"));
    118   ASSERT_THAT(tree.getAttributeCount(), Eq(0u));
    119 
    120   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
    121   EXPECT_THAT(tree.getText(&len), StrEq(u"Some text\\\\"));
    122 
    123   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
    124   EXPECT_THAT(tree.getElementNamespace(&len), IsNull());
    125   EXPECT_THAT(tree.getElementName(&len), StrEq(u"Layout"));
    126 
    127   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
    128   EXPECT_THAT(tree.getElementNamespace(&len), IsNull());
    129   EXPECT_THAT(tree.getElementName(&len), StrEq(u"View"));
    130 
    131   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_NAMESPACE));
    132   EXPECT_THAT(tree.getNamespacePrefix(&len), StrEq(u"test"));
    133   EXPECT_THAT(tree.getNamespaceUri(&len), StrEq(u"http://com.test"));
    134 
    135   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_DOCUMENT));
    136 }
    137 
    138 TEST_F(XmlFlattenerTest, FlattenCompiledXmlAndStripOnlyTools) {
    139   std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(
    140       <View xmlns:tools="http://schemas.android.com/tools"
    141           xmlns:foo="http://schemas.android.com/foo"
    142           foo:bar="Foo"
    143           tools:ignore="MissingTranslation"/>)");
    144 
    145   android::ResXMLTree tree;
    146   ASSERT_TRUE(Flatten(doc.get(), &tree));
    147   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_NAMESPACE));
    148 
    149   size_t len;
    150   EXPECT_THAT(tree.getNamespacePrefix(&len), StrEq(u"foo"));
    151   EXPECT_THAT(tree.getNamespaceUri(&len), StrEq(u"http://schemas.android.com/foo"));
    152   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
    153 
    154   EXPECT_THAT(tree.indexOfAttribute("http://schemas.android.com/tools", "ignore"),
    155               Eq(android::NAME_NOT_FOUND));
    156   EXPECT_THAT(tree.indexOfAttribute("http://schemas.android.com/foo", "bar"), Ge(0));
    157 }
    158 
    159 TEST_F(XmlFlattenerTest, AssignSpecialAttributeIndices) {
    160   std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(
    161       <View xmlns:android="http://schemas.android.com/apk/res/android"
    162           android:id="@id/id"
    163           class="str"
    164           style="@id/id"/>)");
    165 
    166   android::ResXMLTree tree;
    167   ASSERT_TRUE(Flatten(doc.get(), &tree));
    168 
    169   while (tree.next() != android::ResXMLTree::START_TAG) {
    170     ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT));
    171     ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT));
    172   }
    173 
    174   EXPECT_THAT(tree.indexOfClass(), Eq(0));
    175   EXPECT_THAT(tree.indexOfStyle(), Eq(1));
    176 }
    177 
    178 // The device ResXMLParser in libandroidfw differentiates between empty namespace and null
    179 // namespace.
    180 TEST_F(XmlFlattenerTest, NoNamespaceIsNotTheSameAsEmptyNamespace) {
    181   std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(<View package="android"/>)");
    182 
    183   android::ResXMLTree tree;
    184   ASSERT_TRUE(Flatten(doc.get(), &tree));
    185 
    186   while (tree.next() != android::ResXMLTree::START_TAG) {
    187     ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT));
    188     ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT));
    189   }
    190 
    191   const StringPiece16 kPackage = u"package";
    192   EXPECT_THAT(tree.indexOfAttribute(nullptr, 0, kPackage.data(), kPackage.size()), Ge(0));
    193 }
    194 
    195 TEST_F(XmlFlattenerTest, EmptyStringValueInAttributeIsNotNull) {
    196   std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(<View package=""/>)");
    197 
    198   android::ResXMLTree tree;
    199   ASSERT_TRUE(Flatten(doc.get(), &tree));
    200 
    201   while (tree.next() != android::ResXMLTree::START_TAG) {
    202     ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT));
    203     ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT));
    204   }
    205 
    206   const StringPiece16 kPackage = u"package";
    207   ssize_t idx = tree.indexOfAttribute(nullptr, 0, kPackage.data(), kPackage.size());
    208   ASSERT_THAT(idx, Ge(0));
    209 
    210   size_t len;
    211   EXPECT_THAT(tree.getAttributeStringValue(idx, &len), NotNull());
    212 }
    213 
    214 TEST_F(XmlFlattenerTest, FlattenNonStandardPackageId) {
    215   context_->SetCompilationPackage("com.app.test.feature");
    216   context_->SetPackageId(0x80);
    217   context_->SetNameManglerPolicy({"com.app.test.feature"});
    218 
    219   std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDomForPackageName(context_.get(), R"(
    220       <View xmlns:android="http://schemas.android.com/apk/res/android"
    221             xmlns:app="http://schemas.android.com/apk/res-auto"
    222             android:id="@id/foo"
    223             app:foo="@id/foo" />)");
    224 
    225   XmlReferenceLinker linker;
    226   ASSERT_TRUE(linker.Consume(context_.get(), doc.get()));
    227 
    228   // The tree needs a custom DynamicRefTable since it is not using a standard app ID (0x7f).
    229   android::DynamicRefTable dynamic_ref_table;
    230   dynamic_ref_table.addMapping(0x80, 0x80);
    231 
    232   android::ResXMLTree tree(&dynamic_ref_table);
    233   ASSERT_TRUE(Flatten(doc.get(), &tree));
    234 
    235   while (tree.next() != android::ResXMLTree::START_TAG) {
    236     ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT));
    237     ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT));
    238   }
    239 
    240   ssize_t idx;
    241 
    242   idx = tree.indexOfAttribute(xml::kSchemaAndroid, "id");
    243   ASSERT_THAT(idx, Ge(0));
    244   EXPECT_THAT(tree.indexOfID(), Eq(idx));
    245   EXPECT_THAT(tree.getAttributeNameResID(idx), Eq(0x010100d0u));
    246 
    247   idx = tree.indexOfAttribute(xml::kSchemaAuto, "foo");
    248   ASSERT_THAT(idx, Ge(0));
    249   EXPECT_THAT(tree.getAttributeNameResID(idx), Eq(0x80010000u));
    250   EXPECT_THAT(tree.getAttributeDataType(idx), Eq(android::Res_value::TYPE_REFERENCE));
    251   EXPECT_THAT(tree.getAttributeData(idx), Eq(int32_t(0x80020000)));
    252 }
    253 
    254 TEST_F(XmlFlattenerTest, ProcessEscapedStrings) {
    255   std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(
    256       R"(<element value="\?hello" pattern="\\d{5}" other="&quot;">\\d{5}</element>)");
    257 
    258   android::ResXMLTree tree;
    259   ASSERT_TRUE(Flatten(doc.get(), &tree));
    260 
    261   while (tree.next() != android::ResXMLTree::START_TAG) {
    262     ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT));
    263     ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT));
    264   }
    265 
    266   const StringPiece16 kValue = u"value";
    267   const StringPiece16 kPattern = u"pattern";
    268   const StringPiece16 kOther = u"other";
    269 
    270   size_t len;
    271   ssize_t idx;
    272 
    273   idx = tree.indexOfAttribute(nullptr, 0, kValue.data(), kValue.size());
    274   ASSERT_THAT(idx, Ge(0));
    275   EXPECT_THAT(tree.getAttributeStringValue(idx, &len), StrEq(u"?hello"));
    276 
    277   idx = tree.indexOfAttribute(nullptr, 0, kPattern.data(), kPattern.size());
    278   ASSERT_THAT(idx, Ge(0));
    279   EXPECT_THAT(tree.getAttributeStringValue(idx, &len), StrEq(u"\\d{5}"));
    280 
    281   idx = tree.indexOfAttribute(nullptr, 0, kOther.data(), kOther.size());
    282   ASSERT_THAT(idx, Ge(0));
    283   EXPECT_THAT(tree.getAttributeStringValue(idx, &len), StrEq(u"\""));
    284 
    285   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
    286   EXPECT_THAT(tree.getText(&len), StrEq(u"\\\\d{5}"));
    287 }
    288 
    289 TEST_F(XmlFlattenerTest, ProcessQuotes) {
    290   std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(
    291       R"(<root>
    292           <item>Regular text</item>
    293           <item>"Text in double quotes"</item>
    294           <item>'Text in single quotes'</item>
    295           <item>Text containing "double quotes"</item>
    296           <item>Text containing 'single quotes'</item>
    297       </root>)");
    298 
    299   size_t len;
    300   android::ResXMLTree tree;
    301 
    302   XmlFlattenerOptions options;
    303   ASSERT_TRUE(Flatten(doc.get(), &tree, options));
    304 
    305   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
    306   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
    307   EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
    308   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
    309   EXPECT_THAT(tree.getText(&len), StrEq(u"Regular text"));
    310   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
    311 
    312   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
    313   EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
    314   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
    315   EXPECT_THAT(tree.getText(&len), StrEq(u"\"Text in double quotes\""));
    316   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
    317 
    318   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
    319   EXPECT_THAT(tree.getElementNamespace(&len), IsNull());
    320   EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
    321   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
    322   EXPECT_THAT(tree.getText(&len), StrEq(u"'Text in single quotes'"));
    323   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
    324 
    325   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
    326   EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
    327   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
    328   EXPECT_THAT(tree.getText(&len), StrEq(u"Text containing \"double quotes\""));
    329   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
    330 
    331   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
    332   EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
    333   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
    334   EXPECT_THAT(tree.getText(&len), StrEq(u"Text containing 'single quotes'"));
    335   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
    336   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
    337 
    338   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_DOCUMENT));
    339 }
    340 
    341 TEST_F(XmlFlattenerTest, ProcessWhitepspace) {
    342   std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(
    343       R"(<root>
    344           <item>   Compact   Spaces   </item>
    345           <item>
    346                  A
    347           </item>
    348           <item>B   </item>
    349           <item>C </item>
    350           <item> D  </item>
    351           <item>   E</item>
    352           <item> F</item>
    353           <item>  G </item>
    354           <item> H </item>
    355 <item>
    356 I
    357 </item>
    358 <item>
    359 
    360    J
    361 
    362 </item>
    363           <item>\t K \n </item>
    364           <item>
    365           </item>
    366       </root>)");
    367 
    368   size_t len;
    369   android::ResXMLTree tree;
    370 
    371   XmlFlattenerOptions options;
    372   ASSERT_TRUE(Flatten(doc.get(), &tree, options));
    373 
    374   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
    375   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
    376   EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
    377   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
    378   EXPECT_THAT(tree.getText(&len), StrEq(u" Compact   Spaces "));
    379   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
    380 
    381   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
    382   EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
    383   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
    384   EXPECT_THAT(tree.getText(&len), StrEq(u" A "));
    385   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
    386 
    387   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
    388   EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
    389   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
    390   EXPECT_THAT(tree.getText(&len), StrEq(u"B "));
    391   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
    392 
    393   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
    394   EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
    395   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
    396   EXPECT_THAT(tree.getText(&len), StrEq(u"C "));
    397   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
    398 
    399   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
    400   EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
    401   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
    402   EXPECT_THAT(tree.getText(&len), StrEq(u" D "));
    403   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
    404 
    405   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
    406   EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
    407   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
    408   EXPECT_THAT(tree.getText(&len), StrEq(u" E"));
    409   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
    410 
    411   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
    412   EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
    413   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
    414   EXPECT_THAT(tree.getText(&len), StrEq(u" F"));
    415   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
    416 
    417   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
    418   EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
    419   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
    420   EXPECT_THAT(tree.getText(&len), StrEq(u" G "));
    421   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
    422 
    423   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
    424   EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
    425   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
    426   EXPECT_THAT(tree.getText(&len), StrEq(u" H "));
    427   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
    428 
    429   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
    430   EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
    431   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
    432   EXPECT_THAT(tree.getText(&len), StrEq(u" I "));
    433   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
    434 
    435   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
    436   EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
    437   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
    438   EXPECT_THAT(tree.getText(&len), StrEq(u" J "));
    439   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
    440 
    441   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
    442   EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
    443   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT));
    444   EXPECT_THAT(tree.getText(&len), StrEq(u"\\t K \\n "));
    445   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
    446 
    447   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG));
    448   EXPECT_THAT(tree.getElementName(&len), StrEq(u"item"));
    449   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
    450   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG));
    451 
    452   ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_DOCUMENT));
    453 }
    454 
    455 TEST_F(XmlFlattenerTest, FlattenRawValueOnlyMakesCompiledValueToo) {
    456   std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(<element foo="bar" />)");
    457 
    458   // Raw values are kept when encoding an attribute with no compiled value, regardless of option.
    459   XmlFlattenerOptions options;
    460   options.keep_raw_values = false;
    461 
    462   android::ResXMLTree tree;
    463   ASSERT_TRUE(Flatten(doc.get(), &tree, options));
    464 
    465   while (tree.next() != android::ResXMLTree::START_TAG) {
    466     ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT));
    467     ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT));
    468   }
    469 
    470   ASSERT_THAT(tree.getAttributeCount(), Eq(1u));
    471   EXPECT_THAT(tree.getAttributeValueStringID(0), Ge(0));
    472   EXPECT_THAT(tree.getAttributeDataType(0), Eq(android::Res_value::TYPE_STRING));
    473   EXPECT_THAT(tree.getAttributeValueStringID(0), Eq(tree.getAttributeData(0)));
    474 }
    475 
    476 TEST_F(XmlFlattenerTest, FlattenCompiledStringValuePreservesRawValue) {
    477   std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(<element foo="bar" />)");
    478   doc->root->attributes[0].compiled_value =
    479       util::make_unique<String>(doc->string_pool.MakeRef("bar"));
    480 
    481   // Raw values are kept when encoding a string anyways.
    482   XmlFlattenerOptions options;
    483   options.keep_raw_values = false;
    484 
    485   android::ResXMLTree tree;
    486   ASSERT_TRUE(Flatten(doc.get(), &tree, options));
    487 
    488   while (tree.next() != android::ResXMLTree::START_TAG) {
    489     ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT));
    490     ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT));
    491   }
    492 
    493   ASSERT_THAT(tree.getAttributeCount(), Eq(1u));
    494   EXPECT_THAT(tree.getAttributeValueStringID(0), Ge(0));
    495   EXPECT_THAT(tree.getAttributeDataType(0), Eq(android::Res_value::TYPE_STRING));
    496   EXPECT_THAT(tree.getAttributeValueStringID(0), Eq(tree.getAttributeData(0)));
    497 }
    498 
    499 TEST_F(XmlFlattenerTest, FlattenCompiledValueExcludesRawValueWithKeepRawOptionFalse) {
    500   std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(<element foo="true" />)");
    501   doc->root->attributes[0].compiled_value = ResourceUtils::MakeBool(true);
    502 
    503   XmlFlattenerOptions options;
    504   options.keep_raw_values = false;
    505 
    506   android::ResXMLTree tree;
    507   ASSERT_TRUE(Flatten(doc.get(), &tree, options));
    508 
    509   while (tree.next() != android::ResXMLTree::START_TAG) {
    510     ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT));
    511     ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT));
    512   }
    513 
    514   ASSERT_THAT(tree.getAttributeCount(), Eq(1u));
    515   EXPECT_THAT(tree.getAttributeValueStringID(0), Eq(-1));
    516   EXPECT_THAT(tree.getAttributeDataType(0), Eq(android::Res_value::TYPE_INT_BOOLEAN));
    517 }
    518 
    519 TEST_F(XmlFlattenerTest, FlattenCompiledValueExcludesRawValueWithKeepRawOptionTrue) {
    520   std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(<element foo="true" />)");
    521   doc->root->attributes[0].compiled_value = ResourceUtils::MakeBool(true);
    522 
    523   XmlFlattenerOptions options;
    524   options.keep_raw_values = true;
    525 
    526   android::ResXMLTree tree;
    527   ASSERT_TRUE(Flatten(doc.get(), &tree, options));
    528 
    529   while (tree.next() != android::ResXMLTree::START_TAG) {
    530     ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT));
    531     ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT));
    532   }
    533 
    534   ASSERT_THAT(tree.getAttributeCount(), Eq(1u));
    535   EXPECT_THAT(tree.getAttributeValueStringID(0), Ge(0));
    536 
    537   size_t len;
    538   EXPECT_THAT(tree.getAttributeStringValue(0, &len), StrEq(u"true"));
    539 
    540   EXPECT_THAT(tree.getAttributeDataType(0), Eq(android::Res_value::TYPE_INT_BOOLEAN));
    541 }
    542 
    543 }  // namespace aapt
    544