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 "java/JavaClassGenerator.h"
18
19 #include <string>
20
21 #include "io/StringStream.h"
22 #include "test/Test.h"
23 #include "util/Util.h"
24
25 using ::aapt::io::StringOutputStream;
26 using ::android::StringPiece;
27 using ::testing::HasSubstr;
28 using ::testing::Lt;
29 using ::testing::Ne;
30 using ::testing::Not;
31
32 namespace aapt {
33
TEST(JavaClassGeneratorTest,FailWhenEntryIsJavaKeyword)34 TEST(JavaClassGeneratorTest, FailWhenEntryIsJavaKeyword) {
35 std::unique_ptr<ResourceTable> table =
36 test::ResourceTableBuilder()
37 .AddSimple("android:id/class", ResourceId(0x01020000))
38 .Build();
39
40 std::unique_ptr<IAaptContext> context =
41 test::ContextBuilder()
42 .AddSymbolSource(
43 util::make_unique<ResourceTableSymbolSource>(table.get()))
44 .SetNameManglerPolicy(NameManglerPolicy{"android"})
45 .Build();
46 JavaClassGenerator generator(context.get(), table.get(), {});
47
48 std::string result;
49 StringOutputStream out(&result);
50 EXPECT_FALSE(generator.Generate("android", &out));
51 }
52
TEST(JavaClassGeneratorTest,TransformInvalidJavaIdentifierCharacter)53 TEST(JavaClassGeneratorTest, TransformInvalidJavaIdentifierCharacter) {
54 std::unique_ptr<ResourceTable> table =
55 test::ResourceTableBuilder()
56 .AddSimple("android:id/hey-man", ResourceId(0x01020000))
57 .AddValue("android:attr/cool.attr", ResourceId(0x01010000),
58 test::AttributeBuilder().Build())
59 .AddValue("android:styleable/hey.dude", ResourceId(0x01030000),
60 test::StyleableBuilder()
61 .AddItem("android:attr/cool.attr", ResourceId(0x01010000))
62 .Build())
63 .Build();
64
65 std::unique_ptr<IAaptContext> context =
66 test::ContextBuilder()
67 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
68 .SetNameManglerPolicy(NameManglerPolicy{"android"})
69 .Build();
70 JavaClassGenerator generator(context.get(), table.get(), {});
71
72 std::string output;
73 StringOutputStream out(&output);
74 EXPECT_TRUE(generator.Generate("android", &out));
75 out.Flush();
76
77 EXPECT_THAT(output, HasSubstr("public static final int hey_man=0x01020000;"));
78 EXPECT_THAT(output, HasSubstr("public static final int[] hey_dude={"));
79 EXPECT_THAT(output, HasSubstr("public static final int hey_dude_cool_attr=0;"));
80 }
81
TEST(JavaClassGeneratorTest,CorrectPackageNameIsUsed)82 TEST(JavaClassGeneratorTest, CorrectPackageNameIsUsed) {
83 std::unique_ptr<ResourceTable> table =
84 test::ResourceTableBuilder()
85 .AddSimple("android:id/one", ResourceId(0x01020000))
86 .AddSimple("android:id/com.foo$two", ResourceId(0x01020001))
87 .Build();
88
89 std::unique_ptr<IAaptContext> context =
90 test::ContextBuilder()
91 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
92 .SetNameManglerPolicy(NameManglerPolicy{"android"})
93 .Build();
94 JavaClassGenerator generator(context.get(), table.get(), {});
95
96 std::string output;
97 StringOutputStream out(&output);
98 ASSERT_TRUE(generator.Generate("android", "com.android.internal", &out));
99 out.Flush();
100
101 EXPECT_THAT(output, HasSubstr("package com.android.internal;"));
102 EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;"));
103 EXPECT_THAT(output, Not(HasSubstr("two")));
104 EXPECT_THAT(output, Not(HasSubstr("com_foo$two")));
105 }
106
TEST(JavaClassGeneratorTest,StyleableAttributesWithDifferentPackageName)107 TEST(JavaClassGeneratorTest, StyleableAttributesWithDifferentPackageName) {
108 std::unique_ptr<ResourceTable> table =
109 test::ResourceTableBuilder()
110 .AddValue("app:attr/foo", ResourceId(0x7f010000),
111 test::AttributeBuilder().Build())
112 .AddValue("app:attr/bar", ResourceId(0x7f010001),
113 test::AttributeBuilder().Build())
114 .AddValue("android:attr/baz", ResourceId(0x01010000),
115 test::AttributeBuilder().Build())
116 .AddValue("app:styleable/MyStyleable", ResourceId(0x7f030000),
117 test::StyleableBuilder()
118 .AddItem("app:attr/foo", ResourceId(0x7f010000))
119 .AddItem("attr/bar", ResourceId(0x7f010001))
120 .AddItem("android:attr/baz", ResourceId(0x01010000))
121 .Build())
122 .Build();
123
124 std::unique_ptr<IAaptContext> context =
125 test::ContextBuilder()
126 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
127 .SetNameManglerPolicy(NameManglerPolicy{"custom"})
128 .SetCompilationPackage("custom")
129 .Build();
130 JavaClassGenerator generator(context.get(), table.get(), {});
131
132 std::string output;
133 StringOutputStream out(&output);
134 EXPECT_TRUE(generator.Generate("app", &out));
135 out.Flush();
136
137 EXPECT_THAT(output, Not(HasSubstr("public static final int baz=0x01010000;")));
138 EXPECT_THAT(output, HasSubstr("public static final int foo=0x7f010000;"));
139 EXPECT_THAT(output, HasSubstr("public static final int bar=0x7f010001;"));
140
141 EXPECT_THAT(output, HasSubstr("public static final int MyStyleable_android_baz=0;"));
142 EXPECT_THAT(output, HasSubstr("public static final int MyStyleable_foo=1;"));
143 EXPECT_THAT(output, HasSubstr("public static final int MyStyleable_bar=2;"));
144
145 EXPECT_THAT(output, HasSubstr("@link #MyStyleable_android_baz android:baz"));
146 EXPECT_THAT(output, HasSubstr("@link #MyStyleable_foo app:foo"));
147 EXPECT_THAT(output, HasSubstr("@link #MyStyleable_bar app:bar"));
148
149 EXPECT_THAT(output, HasSubstr("@link android.R.attr#baz"));
150 EXPECT_THAT(output, HasSubstr("@link app.R.attr#foo"));
151 EXPECT_THAT(output, HasSubstr("@link app.R.attr#bar"));
152 }
153
TEST(JavaClassGeneratorTest,AttrPrivateIsWrittenAsAttr)154 TEST(JavaClassGeneratorTest, AttrPrivateIsWrittenAsAttr) {
155 std::unique_ptr<ResourceTable> table =
156 test::ResourceTableBuilder()
157 .AddSimple("android:attr/two", ResourceId(0x01010001))
158 .AddSimple("android:^attr-private/one", ResourceId(0x01010000))
159 .Build();
160
161 std::unique_ptr<IAaptContext> context =
162 test::ContextBuilder()
163 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
164 .SetNameManglerPolicy(NameManglerPolicy{"android"})
165 .Build();
166 JavaClassGenerator generator(context.get(), table.get(), {});
167
168 std::string output;
169 StringOutputStream out(&output);
170 ASSERT_TRUE(generator.Generate("android", &out));
171 out.Flush();
172
173 EXPECT_THAT(output, HasSubstr("public static final class attr"));
174 EXPECT_THAT(output, Not(HasSubstr("public static final class ^attr-private")));
175 }
176
TEST(JavaClassGeneratorTest,OnlyWritePublicResources)177 TEST(JavaClassGeneratorTest, OnlyWritePublicResources) {
178 StdErrDiagnostics diag;
179 std::unique_ptr<ResourceTable> table =
180 test::ResourceTableBuilder()
181 .AddSimple("android:id/one", ResourceId(0x01020000))
182 .AddSimple("android:id/two", ResourceId(0x01020001))
183 .AddSimple("android:id/three", ResourceId(0x01020002))
184 .SetSymbolState("android:id/one", ResourceId(0x01020000), Visibility::Level::kPublic)
185 .SetSymbolState("android:id/two", ResourceId(0x01020001), Visibility::Level::kPrivate)
186 .Build();
187
188 std::unique_ptr<IAaptContext> context =
189 test::ContextBuilder()
190 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
191 .SetNameManglerPolicy(NameManglerPolicy{"android"})
192 .Build();
193
194 JavaClassGeneratorOptions options;
195 options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
196 {
197 JavaClassGenerator generator(context.get(), table.get(), options);
198 std::string output;
199 StringOutputStream out(&output);
200 ASSERT_TRUE(generator.Generate("android", &out));
201 out.Flush();
202
203 EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;"));
204 EXPECT_THAT(output, Not(HasSubstr("two")));
205 EXPECT_THAT(output, Not(HasSubstr("three")));
206 }
207
208 options.types = JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate;
209 {
210 JavaClassGenerator generator(context.get(), table.get(), options);
211 std::string output;
212 StringOutputStream out(&output);
213 ASSERT_TRUE(generator.Generate("android", &out));
214 out.Flush();
215
216 EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;"));
217 EXPECT_THAT(output, HasSubstr("public static final int two=0x01020001;"));
218 EXPECT_THAT(output, Not(HasSubstr("three")));
219 }
220
221 options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
222 {
223 JavaClassGenerator generator(context.get(), table.get(), options);
224 std::string output;
225 StringOutputStream out(&output);
226 ASSERT_TRUE(generator.Generate("android", &out));
227 out.Flush();
228
229 EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;"));
230 EXPECT_THAT(output, HasSubstr("public static final int two=0x01020001;"));
231 EXPECT_THAT(output, HasSubstr("public static final int three=0x01020002;"));
232 }
233 }
234
235 /*
236 * TODO(adamlesinski): Re-enable this once we get merging working again.
237 * TEST(JavaClassGeneratorTest, EmitPackageMangledSymbols) {
238 ASSERT_TRUE(addResource(ResourceName{ {}, ResourceType::kId, u"foo" },
239 ResourceId{ 0x01, 0x02, 0x0000 }));
240 ResourceTable table;
241 table.setPackage(u"com.lib");
242 ASSERT_TRUE(table.addResource(ResourceName{ {}, ResourceType::kId, u"test"
243 }, {},
244 Source{ "lib.xml", 33 },
245 util::make_unique<Id>()));
246 ASSERT_TRUE(mTable->merge(std::move(table)));
247
248 Linker linker(mTable,
249 std::make_shared<MockResolver>(mTable, std::map<ResourceName,
250 ResourceId>()),
251 {});
252 ASSERT_TRUE(linker.linkAndValidate());
253
254 JavaClassGenerator generator(mTable, {});
255
256 std::stringstream out;
257 EXPECT_TRUE(generator.generate(mTable->getPackage(), out));
258 std::string output = out.str();
259 EXPECT_NE(std::string::npos, output.find("int foo ="));
260 EXPECT_EQ(std::string::npos, output.find("int test ="));
261
262 out.str("");
263 EXPECT_TRUE(generator.generate(u"com.lib", out));
264 output = out.str();
265 EXPECT_NE(std::string::npos, output.find("int test ="));
266 EXPECT_EQ(std::string::npos, output.find("int foo ="));
267 }*/
268
TEST(JavaClassGeneratorTest,EmitOtherPackagesAttributesInStyleable)269 TEST(JavaClassGeneratorTest, EmitOtherPackagesAttributesInStyleable) {
270 std::unique_ptr<ResourceTable> table =
271 test::ResourceTableBuilder()
272 .AddValue("android:attr/bar", ResourceId(0x01010000), test::AttributeBuilder().Build())
273 .AddValue("com.lib:attr/bar", ResourceId(0x02010000), test::AttributeBuilder().Build())
274 .AddValue("android:styleable/foo", ResourceId(0x01030000),
275 test::StyleableBuilder()
276 .AddItem("android:attr/bar", ResourceId(0x01010000))
277 .AddItem("com.lib:attr/bar", ResourceId(0x02010000))
278 .Build())
279 .Build();
280
281 std::unique_ptr<IAaptContext> context =
282 test::ContextBuilder()
283 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
284 .SetNameManglerPolicy(NameManglerPolicy{"android"})
285 .Build();
286 JavaClassGenerator generator(context.get(), table.get(), {});
287
288 std::string output;
289 StringOutputStream out(&output);
290 EXPECT_TRUE(generator.Generate("android", &out));
291 out.Flush();
292
293 EXPECT_THAT(output, HasSubstr("int foo_bar="));
294 EXPECT_THAT(output, HasSubstr("int foo_com_lib_bar="));
295 }
296
TEST(JavaClassGeneratorTest,CommentsForSimpleResourcesArePresent)297 TEST(JavaClassGeneratorTest, CommentsForSimpleResourcesArePresent) {
298 std::unique_ptr<ResourceTable> table =
299 test::ResourceTableBuilder()
300 .AddSimple("android:id/foo", ResourceId(0x01010000))
301 .Build();
302 test::GetValue<Id>(table.get(), "android:id/foo")
303 ->SetComment(std::string("This is a comment\n@deprecated"));
304
305 std::unique_ptr<IAaptContext> context =
306 test::ContextBuilder()
307 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
308 .SetNameManglerPolicy(NameManglerPolicy{"android"})
309 .Build();
310 JavaClassGenerator generator(context.get(), table.get(), {});
311
312 std::string output;
313 StringOutputStream out(&output);
314 ASSERT_TRUE(generator.Generate("android", &out));
315 out.Flush();
316
317 const char* expected_text =
318 R"EOF(/**
319 * This is a comment
320 * @deprecated
321 */
322 @Deprecated
323 public static final int foo=0x01010000;)EOF";
324 EXPECT_THAT(output, HasSubstr(expected_text));
325 }
326
TEST(JavaClassGeneratorTest,CommentsForEnumAndFlagAttributesArePresent)327 TEST(JavaClassGeneratorTest, CommentsForEnumAndFlagAttributesArePresent) {}
328
TEST(JavaClassGeneratorTest,CommentsForStyleablesAndNestedAttributesArePresent)329 TEST(JavaClassGeneratorTest, CommentsForStyleablesAndNestedAttributesArePresent) {
330 Attribute attr;
331 attr.SetComment(StringPiece("This is an attribute"));
332
333 Styleable styleable;
334 styleable.entries.push_back(Reference(test::ParseNameOrDie("android:attr/one")));
335 styleable.SetComment(StringPiece("This is a styleable"));
336
337 CloningValueTransformer cloner(nullptr);
338 std::unique_ptr<ResourceTable> table =
339 test::ResourceTableBuilder()
340 .AddValue("android:attr/one", util::make_unique<Attribute>(attr))
341 .AddValue("android:styleable/Container",
342 std::unique_ptr<Styleable>(styleable.Transform(cloner)))
343 .Build();
344
345 std::unique_ptr<IAaptContext> context =
346 test::ContextBuilder()
347 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
348 .SetNameManglerPolicy(NameManglerPolicy{"android"})
349 .Build();
350 JavaClassGeneratorOptions options;
351 options.use_final = false;
352 JavaClassGenerator generator(context.get(), table.get(), options);
353
354 std::string output;
355 StringOutputStream out(&output);
356 ASSERT_TRUE(generator.Generate("android", &out));
357 out.Flush();
358
359 EXPECT_THAT(output, HasSubstr("#Container_one android:one"));
360 EXPECT_THAT(output, HasSubstr("@see #Container_one"));
361 EXPECT_THAT(output, HasSubstr("attr name android:one"));
362 EXPECT_THAT(output, HasSubstr("attr description"));
363 EXPECT_THAT(output, HasSubstr(attr.GetComment()));
364 EXPECT_THAT(output, HasSubstr(styleable.GetComment()));
365 }
366
TEST(JavaClassGeneratorTest,CommentsForStyleableHiddenAttributesAreNotPresent)367 TEST(JavaClassGeneratorTest, CommentsForStyleableHiddenAttributesAreNotPresent) {
368 Attribute attr;
369 attr.SetComment(StringPiece("This is an attribute @hide"));
370
371 Styleable styleable;
372 styleable.entries.push_back(Reference(test::ParseNameOrDie("android:attr/one")));
373 styleable.SetComment(StringPiece("This is a styleable"));
374
375 CloningValueTransformer cloner(nullptr);
376 std::unique_ptr<ResourceTable> table =
377 test::ResourceTableBuilder()
378 .AddValue("android:attr/one", util::make_unique<Attribute>(attr))
379 .AddValue("android:styleable/Container",
380 std::unique_ptr<Styleable>(styleable.Transform(cloner)))
381 .Build();
382
383 std::unique_ptr<IAaptContext> context =
384 test::ContextBuilder()
385 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
386 .SetNameManglerPolicy(NameManglerPolicy{"android"})
387 .Build();
388 JavaClassGeneratorOptions options;
389 options.use_final = false;
390 JavaClassGenerator generator(context.get(), table.get(), options);
391
392 std::string output;
393 StringOutputStream out(&output);
394 ASSERT_TRUE(generator.Generate("android", &out));
395 out.Flush();
396
397 EXPECT_THAT(output, Not(HasSubstr("#Container_one android:one")));
398 EXPECT_THAT(output, Not(HasSubstr("@see #Container_one")));
399 EXPECT_THAT(output, HasSubstr("attr name android:one"));
400 EXPECT_THAT(output, HasSubstr("attr description"));
401 EXPECT_THAT(output, HasSubstr(attr.GetComment()));
402 EXPECT_THAT(output, HasSubstr(styleable.GetComment()));
403 }
404
TEST(JavaClassGeneratorTest,StyleableAndIndicesAreColocated)405 TEST(JavaClassGeneratorTest, StyleableAndIndicesAreColocated) {
406 std::unique_ptr<ResourceTable> table =
407 test::ResourceTableBuilder()
408 .AddValue("android:attr/layout_gravity", util::make_unique<Attribute>())
409 .AddValue("android:attr/background", util::make_unique<Attribute>())
410 .AddValue("android:styleable/ActionBar",
411 test::StyleableBuilder()
412 .AddItem("android:attr/background", ResourceId(0x01010000))
413 .Build())
414 .AddValue("android:styleable/ActionBar.LayoutParams",
415 test::StyleableBuilder()
416 .AddItem("android:attr/layout_gravity", ResourceId(0x01010001))
417 .Build())
418 .Build();
419
420 std::unique_ptr<IAaptContext> context =
421 test::ContextBuilder()
422 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
423 .SetNameManglerPolicy(NameManglerPolicy{"android"})
424 .Build();
425
426 JavaClassGeneratorOptions options;
427 JavaClassGenerator generator(context.get(), table.get(), {});
428
429 std::string output;
430 StringOutputStream out(&output);
431 ASSERT_TRUE(generator.Generate("android", &out));
432 out.Flush();
433
434 std::string::size_type actionbar_pos = output.find("int[] ActionBar");
435 ASSERT_THAT(actionbar_pos, Ne(std::string::npos));
436
437 std::string::size_type actionbar_background_pos = output.find("int ActionBar_background");
438 ASSERT_THAT(actionbar_background_pos, Ne(std::string::npos));
439
440 std::string::size_type actionbar_layout_params_pos = output.find("int[] ActionBar_LayoutParams");
441 ASSERT_THAT(actionbar_layout_params_pos, Ne(std::string::npos));
442
443 std::string::size_type actionbar_layout_params_layout_gravity_pos =
444 output.find("int ActionBar_LayoutParams_layout_gravity");
445 ASSERT_THAT(actionbar_layout_params_layout_gravity_pos, Ne(std::string::npos));
446
447 EXPECT_THAT(actionbar_pos, Lt(actionbar_background_pos));
448 EXPECT_THAT(actionbar_pos, Lt(actionbar_layout_params_pos));
449 EXPECT_THAT(actionbar_background_pos, Lt(actionbar_layout_params_pos));
450 EXPECT_THAT(actionbar_layout_params_pos, Lt(actionbar_layout_params_layout_gravity_pos));
451 }
452
TEST(JavaClassGeneratorTest,CommentsForRemovedAttributesAreNotPresentInClass)453 TEST(JavaClassGeneratorTest, CommentsForRemovedAttributesAreNotPresentInClass) {
454 Attribute attr;
455 attr.SetComment(StringPiece("removed"));
456
457 std::unique_ptr<ResourceTable> table =
458 test::ResourceTableBuilder()
459 .AddValue("android:attr/one", util::make_unique<Attribute>(attr))
460 .Build();
461
462 std::unique_ptr<IAaptContext> context =
463 test::ContextBuilder()
464 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
465 .SetNameManglerPolicy(NameManglerPolicy{"android"})
466 .Build();
467 JavaClassGeneratorOptions options;
468 options.use_final = false;
469 JavaClassGenerator generator(context.get(), table.get(), options);
470
471 std::string output;
472 StringOutputStream out(&output);
473 ASSERT_TRUE(generator.Generate("android", &out));
474 out.Flush();
475
476 EXPECT_THAT(output, Not(HasSubstr("@attr name android:one")));
477 EXPECT_THAT(output, Not(HasSubstr("@attr description")));
478
479 // We should find @removed only in the attribute javadoc and not anywhere else
480 // (i.e. the class javadoc).
481 const std::string kRemoved("removed");
482 ASSERT_THAT(output, HasSubstr(kRemoved));
483 std::string after_first_match = output.substr(output.find(kRemoved) + kRemoved.size());
484 EXPECT_THAT(after_first_match, Not(HasSubstr(kRemoved)));
485 }
486
TEST(JavaClassGeneratorTest,GenerateOnResourcesLoadedCallbackForSharedLibrary)487 TEST(JavaClassGeneratorTest, GenerateOnResourcesLoadedCallbackForSharedLibrary) {
488 std::unique_ptr<ResourceTable> table =
489 test::ResourceTableBuilder()
490 .AddValue("android:attr/foo", ResourceId(0x00010000), util::make_unique<Attribute>())
491 .AddValue("android:id/foo", ResourceId(0x00020000), util::make_unique<Id>())
492 .AddValue(
493 "android:style/foo", ResourceId(0x00030000),
494 test::StyleBuilder()
495 .AddItem("android:attr/foo", ResourceId(0x00010000), util::make_unique<Id>())
496 .Build())
497 .Build();
498
499 std::unique_ptr<IAaptContext> context =
500 test::ContextBuilder().SetPackageId(0x00).SetCompilationPackage("android").Build();
501
502 JavaClassGeneratorOptions options;
503 options.use_final = false;
504 options.rewrite_callback_options = OnResourcesLoadedCallbackOptions{{"com.foo", "com.boo"}};
505 JavaClassGenerator generator(context.get(), table.get(), options);
506
507 std::string output;
508 StringOutputStream out(&output);
509 ASSERT_TRUE(generator.Generate("android", &out));
510 out.Flush();
511
512 EXPECT_THAT(output, HasSubstr(
513 R"( public static void onResourcesLoaded(int p) {
514 com.foo.R.onResourcesLoaded(p);
515 com.boo.R.onResourcesLoaded(p);
516 final int packageIdBits = p << 24;
517 attr.foo = (attr.foo & 0x00ffffff) | packageIdBits;
518 id.foo = (id.foo & 0x00ffffff) | packageIdBits;
519 style.foo = (style.foo & 0x00ffffff) | packageIdBits;
520 })"));
521 }
522
TEST(JavaClassGeneratorTest,OnlyGenerateRText)523 TEST(JavaClassGeneratorTest, OnlyGenerateRText) {
524 std::unique_ptr<ResourceTable> table =
525 test::ResourceTableBuilder()
526 .AddValue("android:attr/foo", ResourceId(0x01010000), util::make_unique<Attribute>())
527 .AddValue("android:styleable/hey.dude", ResourceId(0x01020000),
528 test::StyleableBuilder()
529 .AddItem("android:attr/foo", ResourceId(0x01010000))
530 .Build())
531 .Build();
532
533 std::unique_ptr<IAaptContext> context =
534 test::ContextBuilder().SetPackageId(0x01).SetCompilationPackage("android").Build();
535 JavaClassGenerator generator(context.get(), table.get(), {});
536
537 ASSERT_TRUE(generator.Generate("android", nullptr));
538 }
539
TEST(JavaClassGeneratorTest,SortsDynamicAttributesAfterFrameworkAttributes)540 TEST(JavaClassGeneratorTest, SortsDynamicAttributesAfterFrameworkAttributes) {
541 std::unique_ptr<ResourceTable> table =
542 test::ResourceTableBuilder()
543 .AddValue("android:attr/framework_attr", ResourceId(0x01010000),
544 test::AttributeBuilder().Build())
545 .AddValue("lib:attr/dynamic_attr", ResourceId(0x00010000),
546 test::AttributeBuilder().Build())
547 .AddValue("lib:styleable/MyStyleable", ResourceId(0x00030000),
548 test::StyleableBuilder()
549 .AddItem("android:attr/framework_attr", ResourceId(0x01010000))
550 .AddItem("lib:attr/dynamic_attr", ResourceId(0x00010000))
551 .Build())
552 .Build();
553
554 std::unique_ptr<IAaptContext> context =
555 test::ContextBuilder()
556 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
557 .SetNameManglerPolicy(NameManglerPolicy{"custom"})
558 .SetCompilationPackage("custom")
559 .Build();
560 JavaClassGenerator generator(context.get(), table.get(), {});
561
562 std::string output;
563 StringOutputStream out(&output);
564 EXPECT_TRUE(generator.Generate("lib", &out));
565 out.Flush();
566
567 EXPECT_THAT(output, HasSubstr("public static final int[] MyStyleable={"));
568 EXPECT_THAT(output, HasSubstr("0x01010000, lib.R.attr.dynamic_attr"));
569 EXPECT_THAT(output, HasSubstr("public static final int MyStyleable_android_framework_attr=0;"));
570 EXPECT_THAT(output, HasSubstr("public static final int MyStyleable_dynamic_attr=1;"));
571 }
572
TEST(JavaClassGeneratorTest,SkipMacros)573 TEST(JavaClassGeneratorTest, SkipMacros) {
574 std::unique_ptr<ResourceTable> table =
575 test::ResourceTableBuilder()
576 .AddValue("android:macro/bar", ResourceId(0x01010000), test::AttributeBuilder().Build())
577 .Build();
578
579 std::unique_ptr<IAaptContext> context =
580 test::ContextBuilder()
581 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
582 .SetNameManglerPolicy(NameManglerPolicy{"android"})
583 .Build();
584 JavaClassGenerator generator(context.get(), table.get(), {});
585
586 std::string output;
587 StringOutputStream out(&output);
588 EXPECT_TRUE(generator.Generate("android", &out));
589 out.Flush();
590
591 EXPECT_THAT(output, Not(HasSubstr("bar")));
592 }
593
594 } // namespace aapt
595