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=""">\\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