JavaClassGenerator_test.cpp revision 58a20a6482a56a262fd83a617482641e3a981db1
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#include "test/Test.h"
19#include "util/Util.h"
20
21#include <sstream>
22#include <string>
23
24namespace aapt {
25
26TEST(JavaClassGeneratorTest, FailWhenEntryIsJavaKeyword) {
27    std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
28            .setPackageId("android", 0x01)
29            .addSimple("android:id/class", ResourceId(0x01020000))
30            .build();
31
32    std::unique_ptr<IAaptContext> context = test::ContextBuilder()
33            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
34            .setNameManglerPolicy(NameManglerPolicy{ "android" })
35            .build();
36    JavaClassGenerator generator(context.get(), table.get(), {});
37
38    std::stringstream out;
39    EXPECT_FALSE(generator.generate("android", &out));
40}
41
42TEST(JavaClassGeneratorTest, TransformInvalidJavaIdentifierCharacter) {
43    std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
44            .setPackageId("android", 0x01)
45            .addSimple("android:id/hey-man", ResourceId(0x01020000))
46            .addValue("android:attr/cool.attr", ResourceId(0x01010000),
47                      test::AttributeBuilder(false).build())
48            .addValue("android:styleable/hey.dude", ResourceId(0x01030000),
49                      test::StyleableBuilder()
50                              .addItem("android:attr/cool.attr", ResourceId(0x01010000))
51                              .build())
52            .build();
53
54    std::unique_ptr<IAaptContext> context = test::ContextBuilder()
55            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
56            .setNameManglerPolicy(NameManglerPolicy{ "android" })
57            .build();
58    JavaClassGenerator generator(context.get(), table.get(), {});
59
60    std::stringstream out;
61    EXPECT_TRUE(generator.generate("android", &out));
62
63    std::string output = out.str();
64
65    EXPECT_NE(std::string::npos,
66              output.find("public static final int hey_man=0x01020000;"));
67
68    EXPECT_NE(std::string::npos,
69              output.find("public static final int[] hey_dude={"));
70
71    EXPECT_NE(std::string::npos,
72              output.find("public static final int hey_dude_cool_attr=0;"));
73}
74
75TEST(JavaClassGeneratorTest, CorrectPackageNameIsUsed) {
76    std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
77            .setPackageId("android", 0x01)
78            .addSimple("android:id/one", ResourceId(0x01020000))
79            .addSimple("android:id/com.foo$two", ResourceId(0x01020001))
80            .build();
81
82    std::unique_ptr<IAaptContext> context = test::ContextBuilder()
83            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
84            .setNameManglerPolicy(NameManglerPolicy{ "android" })
85            .build();
86    JavaClassGenerator generator(context.get(), table.get(), {});
87    std::stringstream out;
88    ASSERT_TRUE(generator.generate("android", "com.android.internal", &out));
89
90    std::string output = out.str();
91    EXPECT_NE(std::string::npos, output.find("package com.android.internal;"));
92    EXPECT_NE(std::string::npos, output.find("public static final int one=0x01020000;"));
93    EXPECT_EQ(std::string::npos, output.find("two"));
94    EXPECT_EQ(std::string::npos, output.find("com_foo$two"));
95}
96
97TEST(JavaClassGeneratorTest, AttrPrivateIsWrittenAsAttr) {
98    std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
99            .setPackageId("android", 0x01)
100            .addSimple("android:attr/two", ResourceId(0x01010001))
101            .addSimple("android:^attr-private/one", ResourceId(0x01010000))
102            .build();
103
104    std::unique_ptr<IAaptContext> context = test::ContextBuilder()
105            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
106            .setNameManglerPolicy(NameManglerPolicy{ "android" })
107            .build();
108    JavaClassGenerator generator(context.get(), table.get(), {});
109    std::stringstream out;
110    ASSERT_TRUE(generator.generate("android", &out));
111
112    std::string output = out.str();
113    EXPECT_NE(std::string::npos, output.find("public static final class attr"));
114    EXPECT_EQ(std::string::npos, output.find("public static final class ^attr-private"));
115}
116
117TEST(JavaClassGeneratorTest, OnlyWritePublicResources) {
118    StdErrDiagnostics diag;
119    std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
120            .setPackageId("android", 0x01)
121            .addSimple("android:id/one", ResourceId(0x01020000))
122            .addSimple("android:id/two", ResourceId(0x01020001))
123            .addSimple("android:id/three", ResourceId(0x01020002))
124            .setSymbolState("android:id/one", ResourceId(0x01020000), SymbolState::kPublic)
125            .setSymbolState("android:id/two", ResourceId(0x01020001), SymbolState::kPrivate)
126            .build();
127
128    std::unique_ptr<IAaptContext> context = test::ContextBuilder()
129            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
130            .setNameManglerPolicy(NameManglerPolicy{ "android" })
131            .build();
132
133    JavaClassGeneratorOptions options;
134    options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
135    {
136        JavaClassGenerator generator(context.get(), table.get(), options);
137        std::stringstream out;
138        ASSERT_TRUE(generator.generate("android", &out));
139        std::string output = out.str();
140        EXPECT_NE(std::string::npos, output.find("public static final int one=0x01020000;"));
141        EXPECT_EQ(std::string::npos, output.find("two"));
142        EXPECT_EQ(std::string::npos, output.find("three"));
143    }
144
145    options.types = JavaClassGeneratorOptions::SymbolTypes::kPublicPrivate;
146    {
147        JavaClassGenerator generator(context.get(), table.get(), options);
148        std::stringstream out;
149        ASSERT_TRUE(generator.generate("android", &out));
150        std::string output = out.str();
151        EXPECT_NE(std::string::npos, output.find("public static final int one=0x01020000;"));
152        EXPECT_NE(std::string::npos, output.find("public static final int two=0x01020001;"));
153        EXPECT_EQ(std::string::npos, output.find("three"));
154    }
155
156    options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
157    {
158        JavaClassGenerator generator(context.get(), table.get(), options);
159        std::stringstream out;
160        ASSERT_TRUE(generator.generate("android", &out));
161        std::string output = out.str();
162        EXPECT_NE(std::string::npos, output.find("public static final int one=0x01020000;"));
163        EXPECT_NE(std::string::npos, output.find("public static final int two=0x01020001;"));
164        EXPECT_NE(std::string::npos, output.find("public static final int three=0x01020002;"));
165    }
166}
167
168/*
169 * TODO(adamlesinski): Re-enable this once we get merging working again.
170 * TEST(JavaClassGeneratorTest, EmitPackageMangledSymbols) {
171    ASSERT_TRUE(addResource(ResourceName{ {}, ResourceType::kId, u"foo" },
172                            ResourceId{ 0x01, 0x02, 0x0000 }));
173    ResourceTable table;
174    table.setPackage(u"com.lib");
175    ASSERT_TRUE(table.addResource(ResourceName{ {}, ResourceType::kId, u"test" }, {},
176                                  Source{ "lib.xml", 33 }, util::make_unique<Id>()));
177    ASSERT_TRUE(mTable->merge(std::move(table)));
178
179    Linker linker(mTable,
180                  std::make_shared<MockResolver>(mTable, std::map<ResourceName, ResourceId>()),
181                  {});
182    ASSERT_TRUE(linker.linkAndValidate());
183
184    JavaClassGenerator generator(mTable, {});
185
186    std::stringstream out;
187    EXPECT_TRUE(generator.generate(mTable->getPackage(), out));
188    std::string output = out.str();
189    EXPECT_NE(std::string::npos, output.find("int foo ="));
190    EXPECT_EQ(std::string::npos, output.find("int test ="));
191
192    out.str("");
193    EXPECT_TRUE(generator.generate(u"com.lib", out));
194    output = out.str();
195    EXPECT_NE(std::string::npos, output.find("int test ="));
196    EXPECT_EQ(std::string::npos, output.find("int foo ="));
197}*/
198
199TEST(JavaClassGeneratorTest, EmitOtherPackagesAttributesInStyleable) {
200    std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
201                .setPackageId("android", 0x01)
202                .setPackageId("com.lib", 0x02)
203                .addValue("android:attr/bar", ResourceId(0x01010000),
204                          test::AttributeBuilder(false).build())
205                .addValue("com.lib:attr/bar", ResourceId(0x02010000),
206                           test::AttributeBuilder(false).build())
207                .addValue("android:styleable/foo", ResourceId(0x01030000),
208                          test::StyleableBuilder()
209                                  .addItem("android:attr/bar", ResourceId(0x01010000))
210                                  .addItem("com.lib:attr/bar", ResourceId(0x02010000))
211                                  .build())
212                .build();
213
214    std::unique_ptr<IAaptContext> context = test::ContextBuilder()
215            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
216            .setNameManglerPolicy(NameManglerPolicy{ "android" })
217            .build();
218    JavaClassGenerator generator(context.get(), table.get(), {});
219
220    std::stringstream out;
221    EXPECT_TRUE(generator.generate("android", &out));
222
223    std::string output = out.str();
224    EXPECT_NE(std::string::npos, output.find("int foo_bar="));
225    EXPECT_NE(std::string::npos, output.find("int foo_com_lib_bar="));
226}
227
228TEST(JavaClassGeneratorTest, CommentsForSimpleResourcesArePresent) {
229    std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
230            .setPackageId("android", 0x01)
231            .addSimple("android:id/foo", ResourceId(0x01010000))
232            .build();
233    test::getValue<Id>(table.get(), "android:id/foo")
234            ->setComment(std::string("This is a comment\n@deprecated"));
235
236    std::unique_ptr<IAaptContext> context = test::ContextBuilder()
237            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
238            .setNameManglerPolicy(NameManglerPolicy{ "android" })
239            .build();
240    JavaClassGenerator generator(context.get(), table.get(), {});
241    std::stringstream out;
242    ASSERT_TRUE(generator.generate("android", &out));
243    std::string actual = out.str();
244
245    const char* expectedText =
246R"EOF(/**
247     * This is a comment
248     * @deprecated
249     */
250    @Deprecated
251    public static final int foo=0x01010000;)EOF";
252
253    EXPECT_NE(std::string::npos, actual.find(expectedText));
254}
255
256TEST(JavaClassGeneratorTest, CommentsForEnumAndFlagAttributesArePresent) {
257
258}
259
260TEST(JavaClassGeneratorTest, CommentsForStyleablesAndNestedAttributesArePresent) {
261    Attribute attr(false);
262    attr.setComment(StringPiece("This is an attribute"));
263
264    Styleable styleable;
265    styleable.entries.push_back(Reference(test::parseNameOrDie("android:attr/one")));
266    styleable.setComment(StringPiece("This is a styleable"));
267
268    std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
269            .setPackageId("android", 0x01)
270            .addValue("android:attr/one", util::make_unique<Attribute>(attr))
271            .addValue("android:styleable/Container",
272                      std::unique_ptr<Styleable>(styleable.clone(nullptr)))
273            .build();
274
275    std::unique_ptr<IAaptContext> context = test::ContextBuilder()
276            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
277            .setNameManglerPolicy(NameManglerPolicy{ "android" })
278            .build();
279    JavaClassGeneratorOptions options;
280    options.useFinal = false;
281    JavaClassGenerator generator(context.get(), table.get(), options);
282    std::stringstream out;
283    ASSERT_TRUE(generator.generate("android", &out));
284    std::string actual = out.str();
285
286    EXPECT_NE(std::string::npos, actual.find("attr name android:one"));
287    EXPECT_NE(std::string::npos, actual.find("attr description"));
288    EXPECT_NE(std::string::npos, actual.find(attr.getComment().data()));
289    EXPECT_NE(std::string::npos, actual.find(styleable.getComment().data()));
290}
291
292TEST(JavaClassGeneratorTest, CommentsForRemovedAttributesAreNotPresentInClass) {
293    Attribute attr(false);
294    attr.setComment(StringPiece("removed"));
295
296    std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
297            .setPackageId("android", 0x01)
298            .addValue("android:attr/one", util::make_unique<Attribute>(attr))
299            .build();
300
301    std::unique_ptr<IAaptContext> context = test::ContextBuilder()
302            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
303            .setNameManglerPolicy(NameManglerPolicy{ "android" })
304            .build();
305    JavaClassGeneratorOptions options;
306    options.useFinal = false;
307    JavaClassGenerator generator(context.get(), table.get(), options);
308    std::stringstream out;
309    ASSERT_TRUE(generator.generate("android", &out));
310    std::string actual = out.str();
311
312    EXPECT_EQ(std::string::npos, actual.find("@attr name android:one"));
313    EXPECT_EQ(std::string::npos, actual.find("@attr description"));
314
315    // We should find @removed only in the attribute javadoc and not anywhere else (i.e. the class
316    // javadoc).
317    const size_t pos = actual.find("removed");
318    EXPECT_NE(std::string::npos, pos);
319    EXPECT_EQ(std::string::npos, actual.find("removed", pos + 1));
320}
321
322} // namespace aapt
323