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 std::unique_ptr<Attribute> flagAttr =
329 test::AttributeBuilder()
330 .SetTypeMask(android::ResTable_map::TYPE_FLAGS)
331 .SetComment("Flag attribute")
332 .AddItemWithComment("flagOne", 0x01, "Flag comment 1")
333 .AddItemWithComment("flagTwo", 0x02, "@deprecated Flag comment 2")
334 .Build();
335 std::unique_ptr<Attribute> enumAttr =
336 test::AttributeBuilder()
337 .SetTypeMask(android::ResTable_map::TYPE_ENUM)
338 .SetComment("Enum attribute")
339 .AddItemWithComment("enumOne", 0x01, "@TestApi Enum comment 1")
340 .AddItemWithComment("enumTwo", 0x02, "Enum comment 2")
341 .Build();
342
343 std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
344 .AddValue("android:attr/one", std::move(flagAttr))
345 .AddValue("android:attr/two", std::move(enumAttr))
346 .Build();
347
348 std::unique_ptr<IAaptContext> context =
349 test::ContextBuilder()
350 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
351 .SetNameManglerPolicy(NameManglerPolicy{"android"})
352 .Build();
353 JavaClassGeneratorOptions options;
354 options.use_final = false;
355 JavaClassGenerator generator(context.get(), table.get(), options);
356
357 std::string output;
358 StringOutputStream out(&output);
359 ASSERT_TRUE(generator.Generate("android", &out));
360 out.Flush();
361
362 // Special annotations from the enum/flag values should NOT generate
363 // annotations for the attribute value.
364 EXPECT_THAT(output, Not(HasSubstr("@Deprecated")));
365 EXPECT_THAT(output, Not(HasSubstr("@android.annotation.TestApi")));
366
367 EXPECT_THAT(output, HasSubstr("Flag attribute"));
368 EXPECT_THAT(output, HasSubstr("flagOne"));
369 EXPECT_THAT(output, HasSubstr("Flag comment 1"));
370 EXPECT_THAT(output, HasSubstr("flagTwo"));
371 EXPECT_THAT(output, HasSubstr("@deprecated Flag comment 2"));
372
373 EXPECT_THAT(output, HasSubstr("Enum attribute"));
374 EXPECT_THAT(output, HasSubstr("enumOne"));
375 EXPECT_THAT(output, HasSubstr("@TestApi Enum comment 1"));
376 EXPECT_THAT(output, HasSubstr("enumTwo"));
377 EXPECT_THAT(output, HasSubstr("Enum comment 2"));
378 }
379
TEST(JavaClassGeneratorTest,CommentsForStyleablesAndNestedAttributesArePresent)380 TEST(JavaClassGeneratorTest, CommentsForStyleablesAndNestedAttributesArePresent) {
381 Attribute attr;
382 attr.SetComment(StringPiece("This is an attribute"));
383
384 Styleable styleable;
385 styleable.entries.push_back(Reference(test::ParseNameOrDie("android:attr/one")));
386 styleable.SetComment(StringPiece("This is a styleable"));
387
388 CloningValueTransformer cloner(nullptr);
389 std::unique_ptr<ResourceTable> table =
390 test::ResourceTableBuilder()
391 .AddValue("android:attr/one", util::make_unique<Attribute>(attr))
392 .AddValue("android:styleable/Container",
393 std::unique_ptr<Styleable>(styleable.Transform(cloner)))
394 .Build();
395
396 std::unique_ptr<IAaptContext> context =
397 test::ContextBuilder()
398 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
399 .SetNameManglerPolicy(NameManglerPolicy{"android"})
400 .Build();
401 JavaClassGeneratorOptions options;
402 options.use_final = false;
403 JavaClassGenerator generator(context.get(), table.get(), options);
404
405 std::string output;
406 StringOutputStream out(&output);
407 ASSERT_TRUE(generator.Generate("android", &out));
408 out.Flush();
409
410 EXPECT_THAT(output, HasSubstr("#Container_one android:one"));
411 EXPECT_THAT(output, HasSubstr("@see #Container_one"));
412 EXPECT_THAT(output, HasSubstr("attr name android:one"));
413 EXPECT_THAT(output, HasSubstr("attr description"));
414 EXPECT_THAT(output, HasSubstr(attr.GetComment()));
415 EXPECT_THAT(output, HasSubstr(styleable.GetComment()));
416 }
417
TEST(JavaClassGeneratorTest,CommentsForStyleableHiddenAttributesAreNotPresent)418 TEST(JavaClassGeneratorTest, CommentsForStyleableHiddenAttributesAreNotPresent) {
419 Attribute attr;
420 attr.SetComment(StringPiece("This is an attribute @hide"));
421
422 Styleable styleable;
423 styleable.entries.push_back(Reference(test::ParseNameOrDie("android:attr/one")));
424 styleable.SetComment(StringPiece("This is a styleable"));
425
426 CloningValueTransformer cloner(nullptr);
427 std::unique_ptr<ResourceTable> table =
428 test::ResourceTableBuilder()
429 .AddValue("android:attr/one", util::make_unique<Attribute>(attr))
430 .AddValue("android:styleable/Container",
431 std::unique_ptr<Styleable>(styleable.Transform(cloner)))
432 .Build();
433
434 std::unique_ptr<IAaptContext> context =
435 test::ContextBuilder()
436 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
437 .SetNameManglerPolicy(NameManglerPolicy{"android"})
438 .Build();
439 JavaClassGeneratorOptions options;
440 options.use_final = false;
441 JavaClassGenerator generator(context.get(), table.get(), options);
442
443 std::string output;
444 StringOutputStream out(&output);
445 ASSERT_TRUE(generator.Generate("android", &out));
446 out.Flush();
447
448 EXPECT_THAT(output, Not(HasSubstr("#Container_one android:one")));
449 EXPECT_THAT(output, Not(HasSubstr("@see #Container_one")));
450 EXPECT_THAT(output, HasSubstr("attr name android:one"));
451 EXPECT_THAT(output, HasSubstr("attr description"));
452 EXPECT_THAT(output, HasSubstr(attr.GetComment()));
453 EXPECT_THAT(output, HasSubstr(styleable.GetComment()));
454 }
455
TEST(JavaClassGeneratorTest,StyleableAndIndicesAreColocated)456 TEST(JavaClassGeneratorTest, StyleableAndIndicesAreColocated) {
457 std::unique_ptr<ResourceTable> table =
458 test::ResourceTableBuilder()
459 .AddValue("android:attr/layout_gravity", util::make_unique<Attribute>())
460 .AddValue("android:attr/background", util::make_unique<Attribute>())
461 .AddValue("android:styleable/ActionBar",
462 test::StyleableBuilder()
463 .AddItem("android:attr/background", ResourceId(0x01010000))
464 .Build())
465 .AddValue("android:styleable/ActionBar.LayoutParams",
466 test::StyleableBuilder()
467 .AddItem("android:attr/layout_gravity", ResourceId(0x01010001))
468 .Build())
469 .Build();
470
471 std::unique_ptr<IAaptContext> context =
472 test::ContextBuilder()
473 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
474 .SetNameManglerPolicy(NameManglerPolicy{"android"})
475 .Build();
476
477 JavaClassGeneratorOptions options;
478 JavaClassGenerator generator(context.get(), table.get(), {});
479
480 std::string output;
481 StringOutputStream out(&output);
482 ASSERT_TRUE(generator.Generate("android", &out));
483 out.Flush();
484
485 std::string::size_type actionbar_pos = output.find("int[] ActionBar");
486 ASSERT_THAT(actionbar_pos, Ne(std::string::npos));
487
488 std::string::size_type actionbar_background_pos = output.find("int ActionBar_background");
489 ASSERT_THAT(actionbar_background_pos, Ne(std::string::npos));
490
491 std::string::size_type actionbar_layout_params_pos = output.find("int[] ActionBar_LayoutParams");
492 ASSERT_THAT(actionbar_layout_params_pos, Ne(std::string::npos));
493
494 std::string::size_type actionbar_layout_params_layout_gravity_pos =
495 output.find("int ActionBar_LayoutParams_layout_gravity");
496 ASSERT_THAT(actionbar_layout_params_layout_gravity_pos, Ne(std::string::npos));
497
498 EXPECT_THAT(actionbar_pos, Lt(actionbar_background_pos));
499 EXPECT_THAT(actionbar_pos, Lt(actionbar_layout_params_pos));
500 EXPECT_THAT(actionbar_background_pos, Lt(actionbar_layout_params_pos));
501 EXPECT_THAT(actionbar_layout_params_pos, Lt(actionbar_layout_params_layout_gravity_pos));
502 }
503
TEST(JavaClassGeneratorTest,CommentsForRemovedAttributesAreNotPresentInClass)504 TEST(JavaClassGeneratorTest, CommentsForRemovedAttributesAreNotPresentInClass) {
505 Attribute attr;
506 attr.SetComment(StringPiece("removed"));
507
508 std::unique_ptr<ResourceTable> table =
509 test::ResourceTableBuilder()
510 .AddValue("android:attr/one", util::make_unique<Attribute>(attr))
511 .Build();
512
513 std::unique_ptr<IAaptContext> context =
514 test::ContextBuilder()
515 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
516 .SetNameManglerPolicy(NameManglerPolicy{"android"})
517 .Build();
518 JavaClassGeneratorOptions options;
519 options.use_final = false;
520 JavaClassGenerator generator(context.get(), table.get(), options);
521
522 std::string output;
523 StringOutputStream out(&output);
524 ASSERT_TRUE(generator.Generate("android", &out));
525 out.Flush();
526
527 EXPECT_THAT(output, Not(HasSubstr("@attr name android:one")));
528 EXPECT_THAT(output, Not(HasSubstr("@attr description")));
529
530 // We should find @removed only in the attribute javadoc and not anywhere else
531 // (i.e. the class javadoc).
532 const std::string kRemoved("removed");
533 ASSERT_THAT(output, HasSubstr(kRemoved));
534 std::string after_first_match = output.substr(output.find(kRemoved) + kRemoved.size());
535 EXPECT_THAT(after_first_match, Not(HasSubstr(kRemoved)));
536 }
537
TEST(JavaClassGeneratorTest,GenerateOnResourcesLoadedCallbackForSharedLibrary)538 TEST(JavaClassGeneratorTest, GenerateOnResourcesLoadedCallbackForSharedLibrary) {
539 std::unique_ptr<ResourceTable> table =
540 test::ResourceTableBuilder()
541 .AddValue("android:attr/foo", ResourceId(0x00010000), util::make_unique<Attribute>())
542 .AddValue("android:id/foo", ResourceId(0x00020000), util::make_unique<Id>())
543 .AddValue(
544 "android:style/foo", ResourceId(0x00030000),
545 test::StyleBuilder()
546 .AddItem("android:attr/foo", ResourceId(0x00010000), util::make_unique<Id>())
547 .Build())
548 .Build();
549
550 std::unique_ptr<IAaptContext> context =
551 test::ContextBuilder().SetPackageId(0x00).SetCompilationPackage("android").Build();
552
553 JavaClassGeneratorOptions options;
554 options.use_final = false;
555 options.rewrite_callback_options = OnResourcesLoadedCallbackOptions{{"com.foo", "com.boo"}};
556 JavaClassGenerator generator(context.get(), table.get(), options);
557
558 std::string output;
559 StringOutputStream out(&output);
560 ASSERT_TRUE(generator.Generate("android", &out));
561 out.Flush();
562
563 EXPECT_THAT(output, HasSubstr(
564 R"( public static void onResourcesLoaded(int p) {
565 com.foo.R.onResourcesLoaded(p);
566 com.boo.R.onResourcesLoaded(p);
567 final int packageIdBits = p << 24;
568 attr.foo = (attr.foo & 0x00ffffff) | packageIdBits;
569 id.foo = (id.foo & 0x00ffffff) | packageIdBits;
570 style.foo = (style.foo & 0x00ffffff) | packageIdBits;
571 })"));
572 }
573
TEST(JavaClassGeneratorTest,OnlyGenerateRText)574 TEST(JavaClassGeneratorTest, OnlyGenerateRText) {
575 std::unique_ptr<ResourceTable> table =
576 test::ResourceTableBuilder()
577 .AddValue("android:attr/foo", ResourceId(0x01010000), util::make_unique<Attribute>())
578 .AddValue("android:styleable/hey.dude", ResourceId(0x01020000),
579 test::StyleableBuilder()
580 .AddItem("android:attr/foo", ResourceId(0x01010000))
581 .Build())
582 .Build();
583
584 std::unique_ptr<IAaptContext> context =
585 test::ContextBuilder().SetPackageId(0x01).SetCompilationPackage("android").Build();
586 JavaClassGenerator generator(context.get(), table.get(), {});
587
588 ASSERT_TRUE(generator.Generate("android", nullptr));
589 }
590
TEST(JavaClassGeneratorTest,SortsDynamicAttributesAfterFrameworkAttributes)591 TEST(JavaClassGeneratorTest, SortsDynamicAttributesAfterFrameworkAttributes) {
592 std::unique_ptr<ResourceTable> table =
593 test::ResourceTableBuilder()
594 .AddValue("android:attr/framework_attr", ResourceId(0x01010000),
595 test::AttributeBuilder().Build())
596 .AddValue("lib:attr/dynamic_attr", ResourceId(0x00010000),
597 test::AttributeBuilder().Build())
598 .AddValue("lib:styleable/MyStyleable", ResourceId(0x00030000),
599 test::StyleableBuilder()
600 .AddItem("android:attr/framework_attr", ResourceId(0x01010000))
601 .AddItem("lib:attr/dynamic_attr", ResourceId(0x00010000))
602 .Build())
603 .Build();
604
605 std::unique_ptr<IAaptContext> context =
606 test::ContextBuilder()
607 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
608 .SetNameManglerPolicy(NameManglerPolicy{"custom"})
609 .SetCompilationPackage("custom")
610 .Build();
611 JavaClassGenerator generator(context.get(), table.get(), {});
612
613 std::string output;
614 StringOutputStream out(&output);
615 EXPECT_TRUE(generator.Generate("lib", &out));
616 out.Flush();
617
618 EXPECT_THAT(output, HasSubstr("public static final int[] MyStyleable={"));
619 EXPECT_THAT(output, HasSubstr("0x01010000, lib.R.attr.dynamic_attr"));
620 EXPECT_THAT(output, HasSubstr("public static final int MyStyleable_android_framework_attr=0;"));
621 EXPECT_THAT(output, HasSubstr("public static final int MyStyleable_dynamic_attr=1;"));
622 }
623
TEST(JavaClassGeneratorTest,SkipMacros)624 TEST(JavaClassGeneratorTest, SkipMacros) {
625 std::unique_ptr<ResourceTable> table =
626 test::ResourceTableBuilder()
627 .AddValue("android:macro/bar", ResourceId(0x01010000), test::AttributeBuilder().Build())
628 .Build();
629
630 std::unique_ptr<IAaptContext> context =
631 test::ContextBuilder()
632 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
633 .SetNameManglerPolicy(NameManglerPolicy{"android"})
634 .Build();
635 JavaClassGenerator generator(context.get(), table.get(), {});
636
637 std::string output;
638 StringOutputStream out(&output);
639 EXPECT_TRUE(generator.Generate("android", &out));
640 out.Flush();
641
642 EXPECT_THAT(output, Not(HasSubstr("bar")));
643 }
644
645 } // namespace aapt
646