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