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 "JavaClassGenerator.h"
18 #include "Linker.h"
19 #include "MockResolver.h"
20 #include "ResourceTable.h"
21 #include "ResourceTableResolver.h"
22 #include "ResourceValues.h"
23 #include "Util.h"
24 
25 #include <gtest/gtest.h>
26 #include <sstream>
27 #include <string>
28 
29 namespace aapt {
30 
31 struct JavaClassGeneratorTest : public ::testing::Test {
SetUpaapt::JavaClassGeneratorTest32     virtual void SetUp() override {
33         mTable = std::make_shared<ResourceTable>();
34         mTable->setPackage(u"android");
35         mTable->setPackageId(0x01);
36     }
37 
addResourceaapt::JavaClassGeneratorTest38     bool addResource(const ResourceNameRef& name, ResourceId id) {
39         return mTable->addResource(name, id, {}, SourceLine{ "test.xml", 21 },
40                                    util::make_unique<Id>());
41     }
42 
43     std::shared_ptr<ResourceTable> mTable;
44 };
45 
TEST_F(JavaClassGeneratorTest,FailWhenEntryIsJavaKeyword)46 TEST_F(JavaClassGeneratorTest, FailWhenEntryIsJavaKeyword) {
47     ASSERT_TRUE(addResource(ResourceName{ {}, ResourceType::kId, u"class" },
48                             ResourceId{ 0x01, 0x02, 0x0000 }));
49 
50     JavaClassGenerator generator(mTable, {});
51 
52     std::stringstream out;
53     EXPECT_FALSE(generator.generate(mTable->getPackage(), out));
54 }
55 
TEST_F(JavaClassGeneratorTest,TransformInvalidJavaIdentifierCharacter)56 TEST_F(JavaClassGeneratorTest, TransformInvalidJavaIdentifierCharacter) {
57     ASSERT_TRUE(addResource(ResourceName{ {}, ResourceType::kId, u"hey-man" },
58                             ResourceId{ 0x01, 0x02, 0x0000 }));
59 
60     ASSERT_TRUE(addResource(ResourceName{ {}, ResourceType::kAttr, u"cool.attr" },
61                             ResourceId{ 0x01, 0x01, 0x0000 }));
62 
63     std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
64     Reference ref(ResourceName{ u"android", ResourceType::kAttr, u"cool.attr"});
65     ref.id = ResourceId{ 0x01, 0x01, 0x0000 };
66     styleable->entries.emplace_back(ref);
67 
68     ASSERT_TRUE(mTable->addResource(ResourceName{ {}, ResourceType::kStyleable, u"hey.dude" },
69                                     ResourceId{ 0x01, 0x03, 0x0000 }, {},
70                                     SourceLine{ "test.xml", 21 }, std::move(styleable)));
71 
72     JavaClassGenerator generator(mTable, {});
73 
74     std::stringstream out;
75     EXPECT_TRUE(generator.generate(mTable->getPackage(), out));
76     std::string output = out.str();
77 
78     EXPECT_NE(std::string::npos,
79               output.find("public static final int hey_man = 0x01020000;"));
80 
81     EXPECT_NE(std::string::npos,
82               output.find("public static final int[] hey_dude = {"));
83 
84     EXPECT_NE(std::string::npos,
85               output.find("public static final int hey_dude_cool_attr = 0;"));
86 }
87 
88 
TEST_F(JavaClassGeneratorTest,EmitPackageMangledSymbols)89 TEST_F(JavaClassGeneratorTest, EmitPackageMangledSymbols) {
90     ASSERT_TRUE(addResource(ResourceName{ {}, ResourceType::kId, u"foo" },
91                             ResourceId{ 0x01, 0x02, 0x0000 }));
92     ResourceTable table;
93     table.setPackage(u"com.lib");
94     ASSERT_TRUE(table.addResource(ResourceName{ {}, ResourceType::kId, u"test" }, {},
95                                   SourceLine{ "lib.xml", 33 }, util::make_unique<Id>()));
96     ASSERT_TRUE(mTable->merge(std::move(table)));
97 
98     Linker linker(mTable,
99                   std::make_shared<MockResolver>(mTable, std::map<ResourceName, ResourceId>()),
100                   {});
101     ASSERT_TRUE(linker.linkAndValidate());
102 
103     JavaClassGenerator generator(mTable, {});
104 
105     std::stringstream out;
106     EXPECT_TRUE(generator.generate(mTable->getPackage(), out));
107     std::string output = out.str();
108     EXPECT_NE(std::string::npos, output.find("int foo ="));
109     EXPECT_EQ(std::string::npos, output.find("int test ="));
110 
111     out.str("");
112     EXPECT_TRUE(generator.generate(u"com.lib", out));
113     output = out.str();
114     EXPECT_NE(std::string::npos, output.find("int test ="));
115     EXPECT_EQ(std::string::npos, output.find("int foo ="));
116 }
117 
TEST_F(JavaClassGeneratorTest,EmitOtherPackagesAttributesInStyleable)118 TEST_F(JavaClassGeneratorTest, EmitOtherPackagesAttributesInStyleable) {
119     std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
120     styleable->entries.emplace_back(ResourceNameRef{ mTable->getPackage(),
121                                                      ResourceType::kAttr,
122                                                      u"bar" });
123     styleable->entries.emplace_back(ResourceNameRef{ u"com.lib", ResourceType::kAttr, u"bar" });
124     ASSERT_TRUE(mTable->addResource(ResourceName{ {}, ResourceType::kStyleable, u"Foo" }, {}, {},
125                                     std::move(styleable)));
126 
127     std::shared_ptr<IResolver> resolver = std::make_shared<MockResolver>(mTable,
128             std::map<ResourceName, ResourceId>({
129                     { ResourceName{ u"android", ResourceType::kAttr, u"bar" },
130                       ResourceId{ 0x01, 0x01, 0x0000 } },
131                     { ResourceName{ u"com.lib", ResourceType::kAttr, u"bar" },
132                       ResourceId{ 0x02, 0x01, 0x0000 } }}));
133 
134     Linker linker(mTable, resolver, {});
135     ASSERT_TRUE(linker.linkAndValidate());
136 
137     JavaClassGenerator generator(mTable, {});
138 
139     std::stringstream out;
140     EXPECT_TRUE(generator.generate(mTable->getPackage(), out));
141     std::string output = out.str();
142     EXPECT_NE(std::string::npos, output.find("int Foo_bar ="));
143     EXPECT_NE(std::string::npos, output.find("int Foo_com_lib_bar ="));
144 }
145 
146 } // namespace aapt
147