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
29namespace aapt {
30
31struct JavaClassGeneratorTest : public ::testing::Test {
32    virtual void SetUp() override {
33        mTable = std::make_shared<ResourceTable>();
34        mTable->setPackage(u"android");
35        mTable->setPackageId(0x01);
36    }
37
38    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
46TEST_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
56TEST_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
89TEST_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
118TEST_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