blob: 876c7a76d3f58cf88d911923b3207d50f1ff6f59 [file] [log] [blame]
Adam Lesinskif762df22017-06-26 16:39:03 -07001/*
2 * Copyright (C) 2017 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/ProguardRules.h"
Adam Koskidc21dea2017-07-21 10:55:27 -070018#include "link/Linkers.h"
Adam Lesinskif762df22017-06-26 16:39:03 -070019
Adam Lesinskia693c4a2017-11-09 11:29:39 -080020#include "io/StringStream.h"
Adam Lesinskif762df22017-06-26 16:39:03 -070021#include "test/Test.h"
22
Adam Lesinskia693c4a2017-11-09 11:29:39 -080023using ::aapt::io::StringOutputStream;
Adam Lesinskif762df22017-06-26 16:39:03 -070024using ::testing::HasSubstr;
25using ::testing::Not;
26
27namespace aapt {
28
Adam Lesinskia693c4a2017-11-09 11:29:39 -080029std::string GetKeepSetString(const proguard::KeepSet& set) {
30 std::string out;
31 StringOutputStream sout(&out);
32 proguard::WriteKeepSet(set, &sout);
33 sout.Flush();
34 return out;
35}
36
Adam Lesinskif762df22017-06-26 16:39:03 -070037TEST(ProguardRulesTest, FragmentNameRuleIsEmitted) {
38 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
39 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
40 <fragment xmlns:android="http://schemas.android.com/apk/res/android"
41 android:name="com.foo.Bar"/>)");
42 layout->file.name = test::ParseNameOrDie("layout/foo");
43
44 proguard::KeepSet set;
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -070045 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
Adam Lesinskif762df22017-06-26 16:39:03 -070046
Adam Lesinskia693c4a2017-11-09 11:29:39 -080047 std::string actual = GetKeepSetString(set);
Adam Lesinskif762df22017-06-26 16:39:03 -070048
Adam Lesinskif762df22017-06-26 16:39:03 -070049 EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
50}
51
52TEST(ProguardRulesTest, FragmentClassRuleIsEmitted) {
53 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
54 std::unique_ptr<xml::XmlResource> layout =
55 test::BuildXmlDom(R"(<fragment class="com.foo.Bar"/>)");
56 layout->file.name = test::ParseNameOrDie("layout/foo");
57
58 proguard::KeepSet set;
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -070059 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
Adam Lesinskif762df22017-06-26 16:39:03 -070060
Adam Lesinskia693c4a2017-11-09 11:29:39 -080061 std::string actual = GetKeepSetString(set);
Adam Lesinskif762df22017-06-26 16:39:03 -070062
Adam Lesinskif762df22017-06-26 16:39:03 -070063 EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
64}
65
66TEST(ProguardRulesTest, FragmentNameAndClassRulesAreEmitted) {
67 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
68 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
69 <fragment xmlns:android="http://schemas.android.com/apk/res/android"
70 android:name="com.foo.Baz"
71 class="com.foo.Bar"/>)");
72 layout->file.name = test::ParseNameOrDie("layout/foo");
73
74 proguard::KeepSet set;
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -070075 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
Adam Lesinskif762df22017-06-26 16:39:03 -070076
Adam Lesinskia693c4a2017-11-09 11:29:39 -080077 std::string actual = GetKeepSetString(set);
Adam Lesinskif762df22017-06-26 16:39:03 -070078
Adam Lesinskif762df22017-06-26 16:39:03 -070079 EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
80 EXPECT_THAT(actual, HasSubstr("com.foo.Baz"));
81}
82
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -070083TEST(ProguardRulesTest, NavigationFragmentNameAndClassRulesAreEmitted) {
84 std::unique_ptr<IAaptContext> context = test::ContextBuilder()
85 .SetCompilationPackage("com.base").Build();
86 std::unique_ptr<xml::XmlResource> navigation = test::BuildXmlDom(R"(
87 <navigation
88 xmlns:android="http://schemas.android.com/apk/res/android"
89 xmlns:app="http://schemas.android.com/apk/res-auto">
90 <custom android:id="@id/foo"
91 android:name="com.package.Foo"/>
92 <fragment android:id="@id/bar"
93 android:name="com.package.Bar">
94 <nested android:id="@id/nested"
95 android:name=".Nested"/>
96 </fragment>
97 </navigation>
98 )");
99
100 navigation->file.name = test::ParseNameOrDie("navigation/graph.xml");
101
102 proguard::KeepSet set;
103 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), navigation.get(), &set));
104
105 std::string actual = GetKeepSetString(set);
106 EXPECT_THAT(actual, HasSubstr("com.package.Foo"));
107 EXPECT_THAT(actual, HasSubstr("com.package.Bar"));
108 EXPECT_THAT(actual, HasSubstr("com.base.Nested"));
109}
110
Adam Koskidc21dea2017-07-21 10:55:27 -0700111TEST(ProguardRulesTest, CustomViewRulesAreEmitted) {
112 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
113 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
114 <View xmlns:android="http://schemas.android.com/apk/res/android">
115 <com.foo.Bar />
116 </View>)");
117 layout->file.name = test::ParseNameOrDie("layout/foo");
118
119 proguard::KeepSet set;
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700120 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
Adam Koskidc21dea2017-07-21 10:55:27 -0700121
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800122 std::string actual = GetKeepSetString(set);
Adam Koskidc21dea2017-07-21 10:55:27 -0700123
Adam Koskidc21dea2017-07-21 10:55:27 -0700124 EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
125}
126
127TEST(ProguardRulesTest, IncludedLayoutRulesAreConditional) {
128 std::unique_ptr<xml::XmlResource> bar_layout = test::BuildXmlDom(R"(
129 <View xmlns:android="http://schemas.android.com/apk/res/android">
130 <com.foo.Bar />
131 </View>)");
132 bar_layout->file.name = test::ParseNameOrDie("com.foo:layout/bar");
133
134 ResourceTable table;
135 StdErrDiagnostics errDiagnostics;
136 table.AddResource(bar_layout->file.name, ConfigDescription::DefaultConfig(), "",
137 util::make_unique<FileReference>(), &errDiagnostics);
138
139 std::unique_ptr<IAaptContext> context =
140 test::ContextBuilder()
141 .SetCompilationPackage("com.foo")
142 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(&table))
143 .Build();
144
145 std::unique_ptr<xml::XmlResource> foo_layout = test::BuildXmlDom(R"(
146 <View xmlns:android="http://schemas.android.com/apk/res/android">
147 <include layout="@layout/bar" />
148 </View>)");
149 foo_layout->file.name = test::ParseNameOrDie("com.foo:layout/foo");
150
151 XmlReferenceLinker xml_linker;
152 ASSERT_TRUE(xml_linker.Consume(context.get(), bar_layout.get()));
153 ASSERT_TRUE(xml_linker.Consume(context.get(), foo_layout.get()));
154
155 proguard::KeepSet set = proguard::KeepSet(true);
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700156 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), bar_layout.get(), &set));
157 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), foo_layout.get(), &set));
Adam Koskidc21dea2017-07-21 10:55:27 -0700158
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800159 std::string actual = GetKeepSetString(set);
Adam Koskidc21dea2017-07-21 10:55:27 -0700160
Adam Koski09ef94e2017-11-10 11:15:55 -0800161 EXPECT_THAT(actual, HasSubstr("-if class **.R$layout"));
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800162 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
Adam Koskidc21dea2017-07-21 10:55:27 -0700163 EXPECT_THAT(actual, HasSubstr("int foo"));
164 EXPECT_THAT(actual, HasSubstr("int bar"));
165 EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
166}
167
168TEST(ProguardRulesTest, AliasedLayoutRulesAreConditional) {
169 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
170 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
171 <View xmlns:android="http://schemas.android.com/apk/res/android">
172 <com.foo.Bar />
173 </View>)");
174 layout->file.name = test::ParseNameOrDie("layout/foo");
175
176 proguard::KeepSet set = proguard::KeepSet(true);
177 set.AddReference({test::ParseNameOrDie("layout/bar"), {}}, layout->file.name);
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700178 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
Adam Koskidc21dea2017-07-21 10:55:27 -0700179
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800180 std::string actual = GetKeepSetString(set);
Adam Koskidc21dea2017-07-21 10:55:27 -0700181
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800182 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
Adam Koski09ef94e2017-11-10 11:15:55 -0800183 EXPECT_THAT(actual, HasSubstr("-if class **.R$layout"));
Adam Koskidc21dea2017-07-21 10:55:27 -0700184 EXPECT_THAT(actual, HasSubstr("int foo"));
185 EXPECT_THAT(actual, HasSubstr("int bar"));
186 EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
187}
188
189TEST(ProguardRulesTest, NonLayoutReferencesAreUnconditional) {
190 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
191 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
192 <View xmlns:android="http://schemas.android.com/apk/res/android">
193 <com.foo.Bar />
194 </View>)");
195 layout->file.name = test::ParseNameOrDie("layout/foo");
196
197 proguard::KeepSet set = proguard::KeepSet(true);
198 set.AddReference({test::ParseNameOrDie("style/MyStyle"), {}}, layout->file.name);
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700199 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
Adam Koskidc21dea2017-07-21 10:55:27 -0700200
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800201 std::string actual = GetKeepSetString(set);
Adam Koskidc21dea2017-07-21 10:55:27 -0700202
Adam Koski09ef94e2017-11-10 11:15:55 -0800203 EXPECT_THAT(actual, Not(HasSubstr("-if")));
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800204 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
Adam Koskidc21dea2017-07-21 10:55:27 -0700205}
206
Adam Lesinskif762df22017-06-26 16:39:03 -0700207TEST(ProguardRulesTest, ViewOnClickRuleIsEmitted) {
208 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
209 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
210 <View xmlns:android="http://schemas.android.com/apk/res/android"
211 android:onClick="bar_method" />)");
212 layout->file.name = test::ParseNameOrDie("layout/foo");
213
214 proguard::KeepSet set;
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700215 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
Adam Lesinskif762df22017-06-26 16:39:03 -0700216
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800217 std::string actual = GetKeepSetString(set);
Adam Lesinskif762df22017-06-26 16:39:03 -0700218
Adam Lesinskif762df22017-06-26 16:39:03 -0700219 EXPECT_THAT(actual, HasSubstr("bar_method"));
220}
221
222TEST(ProguardRulesTest, MenuRulesAreEmitted) {
223 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
224 std::unique_ptr<xml::XmlResource> menu = test::BuildXmlDom(R"(
225 <menu xmlns:android="http://schemas.android.com/apk/res/android">
226 <item android:onClick="on_click"
227 android:actionViewClass="com.foo.Bar"
228 android:actionProviderClass="com.foo.Baz"
229 android:name="com.foo.Bat" />
230 </menu>)");
231 menu->file.name = test::ParseNameOrDie("menu/foo");
232
233 proguard::KeepSet set;
Ryan Mitchell9a2f6e62018-05-23 14:23:18 -0700234 ASSERT_TRUE(proguard::CollectProguardRules(context.get(), menu.get(), &set));
Adam Lesinskif762df22017-06-26 16:39:03 -0700235
Adam Lesinskia693c4a2017-11-09 11:29:39 -0800236 std::string actual = GetKeepSetString(set);
Adam Lesinskif762df22017-06-26 16:39:03 -0700237
Adam Lesinskif762df22017-06-26 16:39:03 -0700238 EXPECT_THAT(actual, HasSubstr("on_click"));
239 EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
240 EXPECT_THAT(actual, HasSubstr("com.foo.Baz"));
241 EXPECT_THAT(actual, Not(HasSubstr("com.foo.Bat")));
242}
243
244} // namespace aapt