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