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 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 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 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 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 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 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 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 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 337 TEST(JavaClassGeneratorTest, CommentsForEnumAndFlagAttributesArePresent) {} 338 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 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 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 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 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("void onResourcesLoaded")); 526 EXPECT_THAT(output, HasSubstr("com.foo.R.onResourcesLoaded")); 527 EXPECT_THAT(output, HasSubstr("com.boo.R.onResourcesLoaded")); 528 } 529 530 TEST(JavaClassGeneratorTest, OnlyGenerateRText) { 531 std::unique_ptr<ResourceTable> table = 532 test::ResourceTableBuilder() 533 .SetPackageId("android", 0x01) 534 .AddValue("android:attr/foo", ResourceId(0x01010000), util::make_unique<Attribute>()) 535 .AddValue("android:styleable/hey.dude", ResourceId(0x01020000), 536 test::StyleableBuilder() 537 .AddItem("android:attr/foo", ResourceId(0x01010000)) 538 .Build()) 539 .Build(); 540 541 std::unique_ptr<IAaptContext> context = 542 test::ContextBuilder().SetPackageId(0x01).SetCompilationPackage("android").Build(); 543 JavaClassGenerator generator(context.get(), table.get(), {}); 544 545 ASSERT_TRUE(generator.Generate("android", nullptr)); 546 } 547 548 } // namespace aapt 549