• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,AttrPrivateIsWrittenAsAttr)110 TEST(JavaClassGeneratorTest, AttrPrivateIsWrittenAsAttr) {
111   std::unique_ptr<ResourceTable> table =
112       test::ResourceTableBuilder()
113           .SetPackageId("android", 0x01)
114           .AddSimple("android:attr/two", ResourceId(0x01010001))
115           .AddSimple("android:^attr-private/one", ResourceId(0x01010000))
116           .Build();
117 
118   std::unique_ptr<IAaptContext> context =
119       test::ContextBuilder()
120           .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
121           .SetNameManglerPolicy(NameManglerPolicy{"android"})
122           .Build();
123   JavaClassGenerator generator(context.get(), table.get(), {});
124 
125   std::string output;
126   StringOutputStream out(&output);
127   ASSERT_TRUE(generator.Generate("android", &out));
128   out.Flush();
129 
130   EXPECT_THAT(output, HasSubstr("public static final class attr"));
131   EXPECT_THAT(output, Not(HasSubstr("public static final class ^attr-private")));
132 }
133 
TEST(JavaClassGeneratorTest,OnlyWritePublicResources)134 TEST(JavaClassGeneratorTest, OnlyWritePublicResources) {
135   StdErrDiagnostics diag;
136   std::unique_ptr<ResourceTable> table =
137       test::ResourceTableBuilder()
138           .SetPackageId("android", 0x01)
139           .AddSimple("android:id/one", ResourceId(0x01020000))
140           .AddSimple("android:id/two", ResourceId(0x01020001))
141           .AddSimple("android:id/three", ResourceId(0x01020002))
142           .SetSymbolState("android:id/one", ResourceId(0x01020000), Visibility::Level::kPublic)
143           .SetSymbolState("android:id/two", ResourceId(0x01020001), Visibility::Level::kPrivate)
144           .Build();
145 
146   std::unique_ptr<IAaptContext> context =
147       test::ContextBuilder()
148           .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
149           .SetNameManglerPolicy(NameManglerPolicy{"android"})
150           .Build();
151 
152   JavaClassGeneratorOptions options;
153   options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
154   {
155     JavaClassGenerator generator(context.get(), table.get(), options);
156     std::string output;
157     StringOutputStream out(&output);
158     ASSERT_TRUE(generator.Generate("android", &out));
159     out.Flush();
160 
161     EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;"));
162     EXPECT_THAT(output, Not(HasSubstr("two")));
163     EXPECT_THAT(output, Not(HasSubstr("three")));
164   }
165 
166   options.types = JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate;
167   {
168     JavaClassGenerator generator(context.get(), table.get(), options);
169     std::string output;
170     StringOutputStream out(&output);
171     ASSERT_TRUE(generator.Generate("android", &out));
172     out.Flush();
173 
174     EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;"));
175     EXPECT_THAT(output, HasSubstr("public static final int two=0x01020001;"));
176     EXPECT_THAT(output, Not(HasSubstr("three")));
177   }
178 
179   options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
180   {
181     JavaClassGenerator generator(context.get(), table.get(), options);
182     std::string output;
183     StringOutputStream out(&output);
184     ASSERT_TRUE(generator.Generate("android", &out));
185     out.Flush();
186 
187     EXPECT_THAT(output, HasSubstr("public static final int one=0x01020000;"));
188     EXPECT_THAT(output, HasSubstr("public static final int two=0x01020001;"));
189     EXPECT_THAT(output, HasSubstr("public static final int three=0x01020002;"));
190   }
191 }
192 
193 /*
194  * TODO(adamlesinski): Re-enable this once we get merging working again.
195  * TEST(JavaClassGeneratorTest, EmitPackageMangledSymbols) {
196     ASSERT_TRUE(addResource(ResourceName{ {}, ResourceType::kId, u"foo" },
197                             ResourceId{ 0x01, 0x02, 0x0000 }));
198     ResourceTable table;
199     table.setPackage(u"com.lib");
200     ASSERT_TRUE(table.addResource(ResourceName{ {}, ResourceType::kId, u"test"
201 }, {},
202                                   Source{ "lib.xml", 33 },
203 util::make_unique<Id>()));
204     ASSERT_TRUE(mTable->merge(std::move(table)));
205 
206     Linker linker(mTable,
207                   std::make_shared<MockResolver>(mTable, std::map<ResourceName,
208 ResourceId>()),
209                   {});
210     ASSERT_TRUE(linker.linkAndValidate());
211 
212     JavaClassGenerator generator(mTable, {});
213 
214     std::stringstream out;
215     EXPECT_TRUE(generator.generate(mTable->getPackage(), out));
216     std::string output = out.str();
217     EXPECT_NE(std::string::npos, output.find("int foo ="));
218     EXPECT_EQ(std::string::npos, output.find("int test ="));
219 
220     out.str("");
221     EXPECT_TRUE(generator.generate(u"com.lib", out));
222     output = out.str();
223     EXPECT_NE(std::string::npos, output.find("int test ="));
224     EXPECT_EQ(std::string::npos, output.find("int foo ="));
225 }*/
226 
TEST(JavaClassGeneratorTest,EmitOtherPackagesAttributesInStyleable)227 TEST(JavaClassGeneratorTest, EmitOtherPackagesAttributesInStyleable) {
228   std::unique_ptr<ResourceTable> table =
229       test::ResourceTableBuilder()
230           .SetPackageId("android", 0x01)
231           .SetPackageId("com.lib", 0x02)
232           .AddValue("android:attr/bar", ResourceId(0x01010000), test::AttributeBuilder().Build())
233           .AddValue("com.lib:attr/bar", ResourceId(0x02010000), test::AttributeBuilder().Build())
234           .AddValue("android:styleable/foo", ResourceId(0x01030000),
235                     test::StyleableBuilder()
236                         .AddItem("android:attr/bar", ResourceId(0x01010000))
237                         .AddItem("com.lib:attr/bar", ResourceId(0x02010000))
238                         .Build())
239           .Build();
240 
241   std::unique_ptr<IAaptContext> context =
242       test::ContextBuilder()
243           .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
244           .SetNameManglerPolicy(NameManglerPolicy{"android"})
245           .Build();
246   JavaClassGenerator generator(context.get(), table.get(), {});
247 
248   std::string output;
249   StringOutputStream out(&output);
250   EXPECT_TRUE(generator.Generate("android", &out));
251   out.Flush();
252 
253   EXPECT_THAT(output, HasSubstr("int foo_bar="));
254   EXPECT_THAT(output, HasSubstr("int foo_com_lib_bar="));
255 }
256 
TEST(JavaClassGeneratorTest,CommentsForSimpleResourcesArePresent)257 TEST(JavaClassGeneratorTest, CommentsForSimpleResourcesArePresent) {
258   std::unique_ptr<ResourceTable> table =
259       test::ResourceTableBuilder()
260           .SetPackageId("android", 0x01)
261           .AddSimple("android:id/foo", ResourceId(0x01010000))
262           .Build();
263   test::GetValue<Id>(table.get(), "android:id/foo")
264       ->SetComment(std::string("This is a comment\n@deprecated"));
265 
266   std::unique_ptr<IAaptContext> context =
267       test::ContextBuilder()
268           .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
269           .SetNameManglerPolicy(NameManglerPolicy{"android"})
270           .Build();
271   JavaClassGenerator generator(context.get(), table.get(), {});
272 
273   std::string output;
274   StringOutputStream out(&output);
275   ASSERT_TRUE(generator.Generate("android", &out));
276   out.Flush();
277 
278   const char* expected_text =
279       R"EOF(/**
280      * This is a comment
281      * @deprecated
282      */
283     @Deprecated
284     public static final int foo=0x01010000;)EOF";
285   EXPECT_THAT(output, HasSubstr(expected_text));
286 }
287 
TEST(JavaClassGeneratorTest,CommentsForEnumAndFlagAttributesArePresent)288 TEST(JavaClassGeneratorTest, CommentsForEnumAndFlagAttributesArePresent) {}
289 
TEST(JavaClassGeneratorTest,CommentsForStyleablesAndNestedAttributesArePresent)290 TEST(JavaClassGeneratorTest, CommentsForStyleablesAndNestedAttributesArePresent) {
291   Attribute attr;
292   attr.SetComment(StringPiece("This is an attribute"));
293 
294   Styleable styleable;
295   styleable.entries.push_back(Reference(test::ParseNameOrDie("android:attr/one")));
296   styleable.SetComment(StringPiece("This is a styleable"));
297 
298   std::unique_ptr<ResourceTable> table =
299       test::ResourceTableBuilder()
300           .SetPackageId("android", 0x01)
301           .AddValue("android:attr/one", util::make_unique<Attribute>(attr))
302           .AddValue("android:styleable/Container",
303                     std::unique_ptr<Styleable>(styleable.Clone(nullptr)))
304           .Build();
305 
306   std::unique_ptr<IAaptContext> context =
307       test::ContextBuilder()
308           .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
309           .SetNameManglerPolicy(NameManglerPolicy{"android"})
310           .Build();
311   JavaClassGeneratorOptions options;
312   options.use_final = false;
313   JavaClassGenerator generator(context.get(), table.get(), options);
314 
315   std::string output;
316   StringOutputStream out(&output);
317   ASSERT_TRUE(generator.Generate("android", &out));
318   out.Flush();
319 
320   EXPECT_THAT(output, HasSubstr("attr name android:one"));
321   EXPECT_THAT(output, HasSubstr("attr description"));
322   EXPECT_THAT(output, HasSubstr(attr.GetComment()));
323   EXPECT_THAT(output, HasSubstr(styleable.GetComment()));
324 }
325 
TEST(JavaClassGeneratorTest,StyleableAndIndicesAreColocated)326 TEST(JavaClassGeneratorTest, StyleableAndIndicesAreColocated) {
327   std::unique_ptr<ResourceTable> table =
328       test::ResourceTableBuilder()
329           .SetPackageId("android", 0x01)
330           .AddValue("android:attr/layout_gravity", util::make_unique<Attribute>())
331           .AddValue("android:attr/background", util::make_unique<Attribute>())
332           .AddValue("android:styleable/ActionBar",
333                     test::StyleableBuilder()
334                         .AddItem("android:attr/background", ResourceId(0x01010000))
335                         .Build())
336           .AddValue("android:styleable/ActionBar.LayoutParams",
337                     test::StyleableBuilder()
338                         .AddItem("android:attr/layout_gravity", ResourceId(0x01010001))
339                         .Build())
340           .Build();
341 
342   std::unique_ptr<IAaptContext> context =
343       test::ContextBuilder()
344           .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
345           .SetNameManglerPolicy(NameManglerPolicy{"android"})
346           .Build();
347 
348   JavaClassGeneratorOptions options;
349   JavaClassGenerator generator(context.get(), table.get(), {});
350 
351   std::string output;
352   StringOutputStream out(&output);
353   ASSERT_TRUE(generator.Generate("android", &out));
354   out.Flush();
355 
356   std::string::size_type actionbar_pos = output.find("int[] ActionBar");
357   ASSERT_THAT(actionbar_pos, Ne(std::string::npos));
358 
359   std::string::size_type actionbar_background_pos = output.find("int ActionBar_background");
360   ASSERT_THAT(actionbar_background_pos, Ne(std::string::npos));
361 
362   std::string::size_type actionbar_layout_params_pos = output.find("int[] ActionBar_LayoutParams");
363   ASSERT_THAT(actionbar_layout_params_pos, Ne(std::string::npos));
364 
365   std::string::size_type actionbar_layout_params_layout_gravity_pos =
366       output.find("int ActionBar_LayoutParams_layout_gravity");
367   ASSERT_THAT(actionbar_layout_params_layout_gravity_pos, Ne(std::string::npos));
368 
369   EXPECT_THAT(actionbar_pos, Lt(actionbar_background_pos));
370   EXPECT_THAT(actionbar_pos, Lt(actionbar_layout_params_pos));
371   EXPECT_THAT(actionbar_background_pos, Lt(actionbar_layout_params_pos));
372   EXPECT_THAT(actionbar_layout_params_pos, Lt(actionbar_layout_params_layout_gravity_pos));
373 }
374 
TEST(JavaClassGeneratorTest,CommentsForRemovedAttributesAreNotPresentInClass)375 TEST(JavaClassGeneratorTest, CommentsForRemovedAttributesAreNotPresentInClass) {
376   Attribute attr;
377   attr.SetComment(StringPiece("removed"));
378 
379   std::unique_ptr<ResourceTable> table =
380       test::ResourceTableBuilder()
381           .SetPackageId("android", 0x01)
382           .AddValue("android:attr/one", util::make_unique<Attribute>(attr))
383           .Build();
384 
385   std::unique_ptr<IAaptContext> context =
386       test::ContextBuilder()
387           .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
388           .SetNameManglerPolicy(NameManglerPolicy{"android"})
389           .Build();
390   JavaClassGeneratorOptions options;
391   options.use_final = false;
392   JavaClassGenerator generator(context.get(), table.get(), options);
393 
394   std::string output;
395   StringOutputStream out(&output);
396   ASSERT_TRUE(generator.Generate("android", &out));
397   out.Flush();
398 
399   EXPECT_THAT(output, Not(HasSubstr("@attr name android:one")));
400   EXPECT_THAT(output, Not(HasSubstr("@attr description")));
401 
402   // We should find @removed only in the attribute javadoc and not anywhere else
403   // (i.e. the class javadoc).
404   const std::string kRemoved("removed");
405   ASSERT_THAT(output, HasSubstr(kRemoved));
406   std::string after_first_match = output.substr(output.find(kRemoved) + kRemoved.size());
407   EXPECT_THAT(after_first_match, Not(HasSubstr(kRemoved)));
408 }
409 
TEST(JavaClassGeneratorTest,GenerateOnResourcesLoadedCallbackForSharedLibrary)410 TEST(JavaClassGeneratorTest, GenerateOnResourcesLoadedCallbackForSharedLibrary) {
411   std::unique_ptr<ResourceTable> table =
412       test::ResourceTableBuilder()
413           .SetPackageId("android", 0x00)
414           .AddValue("android:attr/foo", ResourceId(0x00010000), util::make_unique<Attribute>())
415           .AddValue("android:id/foo", ResourceId(0x00020000), util::make_unique<Id>())
416           .AddValue(
417               "android:style/foo", ResourceId(0x00030000),
418               test::StyleBuilder()
419                   .AddItem("android:attr/foo", ResourceId(0x00010000), util::make_unique<Id>())
420                   .Build())
421           .Build();
422 
423   std::unique_ptr<IAaptContext> context =
424       test::ContextBuilder().SetPackageId(0x00).SetCompilationPackage("android").Build();
425 
426   JavaClassGeneratorOptions options;
427   options.use_final = false;
428   options.rewrite_callback_options = OnResourcesLoadedCallbackOptions{{"com.foo", "com.boo"}};
429   JavaClassGenerator generator(context.get(), table.get(), options);
430 
431   std::string output;
432   StringOutputStream out(&output);
433   ASSERT_TRUE(generator.Generate("android", &out));
434   out.Flush();
435 
436   EXPECT_THAT(output, HasSubstr("void onResourcesLoaded"));
437   EXPECT_THAT(output, HasSubstr("com.foo.R.onResourcesLoaded"));
438   EXPECT_THAT(output, HasSubstr("com.boo.R.onResourcesLoaded"));
439 }
440 
441 }  // namespace aapt
442