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:
SetUp()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
Flatten(xml::XmlResource * doc,android::ResXMLTree * out_tree,const XmlFlattenerOptions & options={})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
TEST_F(XmlFlattenerTest,FlattenXmlWithNoCompiledAttributes)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
TEST_F(XmlFlattenerTest,FlattenCompiledXmlAndStripOnlyTools)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
TEST_F(XmlFlattenerTest,AssignSpecialAttributeIndices)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
TEST_F(XmlFlattenerTest,ProcessQuotes)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
TEST_F(XmlFlattenerTest,ProcessWhitepspace)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
TEST_F(XmlFlattenerTest,FlattenRawValueOnlyMakesCompiledValueToo)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
TEST_F(XmlFlattenerTest,FlattenCompiledStringValuePreservesRawValue)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
TEST_F(XmlFlattenerTest,FlattenCompiledValueExcludesRawValueWithKeepRawOptionFalse)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
TEST_F(XmlFlattenerTest,FlattenCompiledValueExcludesRawValueWithKeepRawOptionTrue)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