XmlFlattener_test.cpp revision 0dcb20c72742a1de30b4984c4b8996d76cb7a428
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 26using ::aapt::test::StrEq; 27using ::android::StringPiece16; 28using ::testing::Eq; 29using ::testing::Ge; 30using ::testing::IsNull; 31using ::testing::Ne; 32using ::testing::NotNull; 33 34namespace aapt { 35 36class 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 79TEST_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 138TEST_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 159TEST_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. 180TEST_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 195TEST_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 214TEST_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 254TEST_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 289TEST_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 341TEST_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> 356I 357</item> 358<item> 359 360 J 361 362</item> 363 <item> 364 </item> 365 </root>)"); 366 367 size_t len; 368 android::ResXMLTree tree; 369 370 XmlFlattenerOptions options; 371 ASSERT_TRUE(Flatten(doc.get(), &tree, options)); 372 373 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); 374 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); 375 EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); 376 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); 377 EXPECT_THAT(tree.getText(&len), StrEq(u" Compact Spaces ")); 378 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); 379 380 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); 381 EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); 382 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); 383 EXPECT_THAT(tree.getText(&len), StrEq(u" A ")); 384 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); 385 386 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); 387 EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); 388 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); 389 EXPECT_THAT(tree.getText(&len), StrEq(u"B ")); 390 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); 391 392 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); 393 EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); 394 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); 395 EXPECT_THAT(tree.getText(&len), StrEq(u"C ")); 396 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); 397 398 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); 399 EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); 400 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); 401 EXPECT_THAT(tree.getText(&len), StrEq(u" D ")); 402 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); 403 404 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); 405 EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); 406 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); 407 EXPECT_THAT(tree.getText(&len), StrEq(u" E")); 408 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); 409 410 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); 411 EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); 412 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); 413 EXPECT_THAT(tree.getText(&len), StrEq(u" F")); 414 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); 415 416 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); 417 EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); 418 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); 419 EXPECT_THAT(tree.getText(&len), StrEq(u" G ")); 420 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); 421 422 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); 423 EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); 424 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); 425 EXPECT_THAT(tree.getText(&len), StrEq(u" H ")); 426 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); 427 428 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); 429 EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); 430 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); 431 EXPECT_THAT(tree.getText(&len), StrEq(u" I ")); 432 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); 433 434 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); 435 EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); 436 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::TEXT)); 437 EXPECT_THAT(tree.getText(&len), StrEq(u" J ")); 438 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); 439 440 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::START_TAG)); 441 EXPECT_THAT(tree.getElementName(&len), StrEq(u"item")); 442 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); 443 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_TAG)); 444 445 ASSERT_THAT(tree.next(), Eq(android::ResXMLTree::END_DOCUMENT)); 446} 447 448TEST_F(XmlFlattenerTest, FlattenRawValueOnlyMakesCompiledValueToo) { 449 std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(<element foo="bar" />)"); 450 451 // Raw values are kept when encoding an attribute with no compiled value, regardless of option. 452 XmlFlattenerOptions options; 453 options.keep_raw_values = false; 454 455 android::ResXMLTree tree; 456 ASSERT_TRUE(Flatten(doc.get(), &tree, options)); 457 458 while (tree.next() != android::ResXMLTree::START_TAG) { 459 ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); 460 ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); 461 } 462 463 ASSERT_THAT(tree.getAttributeCount(), Eq(1u)); 464 EXPECT_THAT(tree.getAttributeValueStringID(0), Ge(0)); 465 EXPECT_THAT(tree.getAttributeDataType(0), Eq(android::Res_value::TYPE_STRING)); 466 EXPECT_THAT(tree.getAttributeValueStringID(0), Eq(tree.getAttributeData(0))); 467} 468 469TEST_F(XmlFlattenerTest, FlattenCompiledStringValuePreservesRawValue) { 470 std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(<element foo="bar" />)"); 471 doc->root->attributes[0].compiled_value = 472 util::make_unique<String>(doc->string_pool.MakeRef("bar")); 473 474 // Raw values are kept when encoding a string anyways. 475 XmlFlattenerOptions options; 476 options.keep_raw_values = false; 477 478 android::ResXMLTree tree; 479 ASSERT_TRUE(Flatten(doc.get(), &tree, options)); 480 481 while (tree.next() != android::ResXMLTree::START_TAG) { 482 ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); 483 ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); 484 } 485 486 ASSERT_THAT(tree.getAttributeCount(), Eq(1u)); 487 EXPECT_THAT(tree.getAttributeValueStringID(0), Ge(0)); 488 EXPECT_THAT(tree.getAttributeDataType(0), Eq(android::Res_value::TYPE_STRING)); 489 EXPECT_THAT(tree.getAttributeValueStringID(0), Eq(tree.getAttributeData(0))); 490} 491 492TEST_F(XmlFlattenerTest, FlattenCompiledValueExcludesRawValueWithKeepRawOptionFalse) { 493 std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(<element foo="true" />)"); 494 doc->root->attributes[0].compiled_value = ResourceUtils::MakeBool(true); 495 496 XmlFlattenerOptions options; 497 options.keep_raw_values = false; 498 499 android::ResXMLTree tree; 500 ASSERT_TRUE(Flatten(doc.get(), &tree, options)); 501 502 while (tree.next() != android::ResXMLTree::START_TAG) { 503 ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); 504 ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); 505 } 506 507 ASSERT_THAT(tree.getAttributeCount(), Eq(1u)); 508 EXPECT_THAT(tree.getAttributeValueStringID(0), Eq(-1)); 509 EXPECT_THAT(tree.getAttributeDataType(0), Eq(android::Res_value::TYPE_INT_BOOLEAN)); 510} 511 512TEST_F(XmlFlattenerTest, FlattenCompiledValueExcludesRawValueWithKeepRawOptionTrue) { 513 std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(R"(<element foo="true" />)"); 514 doc->root->attributes[0].compiled_value = ResourceUtils::MakeBool(true); 515 516 XmlFlattenerOptions options; 517 options.keep_raw_values = true; 518 519 android::ResXMLTree tree; 520 ASSERT_TRUE(Flatten(doc.get(), &tree, options)); 521 522 while (tree.next() != android::ResXMLTree::START_TAG) { 523 ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); 524 ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); 525 } 526 527 ASSERT_THAT(tree.getAttributeCount(), Eq(1u)); 528 EXPECT_THAT(tree.getAttributeValueStringID(0), Ge(0)); 529 530 size_t len; 531 EXPECT_THAT(tree.getAttributeStringValue(0, &len), StrEq(u"true")); 532 533 EXPECT_THAT(tree.getAttributeDataType(0), Eq(android::Res_value::TYPE_INT_BOOLEAN)); 534} 535 536} // namespace aapt 537