1 /*
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"
18 #include "link/Linkers.h"
19 
20 #include "io/StringStream.h"
21 #include "test/Test.h"
22 
23 using ::aapt::io::StringOutputStream;
24 using ::android::ConfigDescription;
25 using ::testing::HasSubstr;
26 using ::testing::Not;
27 
28 namespace aapt {
29 
GetKeepSetString(const proguard::KeepSet & set,bool minimal_rules)30 std::string GetKeepSetString(const proguard::KeepSet& set, bool minimal_rules) {
31   std::string out;
32   StringOutputStream sout(&out);
33   proguard::WriteKeepSet(set, &sout, minimal_rules, false);
34   sout.Flush();
35   return out;
36 }
37 
TEST(ProguardRulesTest,ManifestRuleDefaultConstructorOnly)38 TEST(ProguardRulesTest, ManifestRuleDefaultConstructorOnly) {
39   std::unique_ptr<xml::XmlResource> manifest = test::BuildXmlDom(R"(
40       <manifest xmlns:android="http://schemas.android.com/apk/res/android">
41         <application
42             android:appComponentFactory="com.foo.BarAppComponentFactory"
43             android:backupAgent="com.foo.BarBackupAgent"
44             android:name="com.foo.BarApplication"
45             android:zygotePreloadName="com.foo.BarZygotePreload"
46             >
47           <activity android:name="com.foo.BarActivity"/>
48           <service android:name="com.foo.BarService"/>
49           <receiver android:name="com.foo.BarReceiver"/>
50           <provider android:name="com.foo.BarProvider"/>
51         </application>
52         <instrumentation android:name="com.foo.BarInstrumentation"/>
53       </manifest>)");
54 
55   proguard::KeepSet set;
56   ASSERT_TRUE(proguard::CollectProguardRulesForManifest(manifest.get(), &set, false));
57 
58   std::string actual = GetKeepSetString(set, /** minimal_rules */ false);
59   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarAppComponentFactory { <init>(); }"));
60   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarBackupAgent { <init>(); }"));
61   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarApplication { <init>(); }"));
62   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarActivity { <init>(); }"));
63   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarService { <init>(); }"));
64   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarReceiver { <init>(); }"));
65   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarProvider { <init>(); }"));
66   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarInstrumentation { <init>(); }"));
67   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarZygotePreload { <init>(); }"));
68 
69   actual = GetKeepSetString(set, /** minimal_rules */ true);
70   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarAppComponentFactory { <init>(); }"));
71   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarBackupAgent { <init>(); }"));
72   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarApplication { <init>(); }"));
73   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarActivity { <init>(); }"));
74   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarService { <init>(); }"));
75   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarReceiver { <init>(); }"));
76   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarProvider { <init>(); }"));
77   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarInstrumentation { <init>(); }"));
78   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.BarZygotePreload { <init>(); }"));
79 }
80 
81 TEST(ProguardRulesTest, FragmentNameRuleIsEmitted) {
82   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
83   std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
84       <fragment xmlns:android="http://schemas.android.com/apk/res/android"
85           android:name="com.foo.Bar"/>)");
86   layout->file.name = test::ParseNameOrDie("layout/foo");
87 
88   proguard::KeepSet set;
89   ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
90 
91   std::string actual = GetKeepSetString(set, /** minimal_rules */ false);
92   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
93 
94   actual = GetKeepSetString(set, /** minimal_rules */ true);
95   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(); }"));
96 }
97 
98 TEST(ProguardRulesTest, FragmentClassRuleIsEmitted) {
99   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
100   std::unique_ptr<xml::XmlResource> layout =
101       test::BuildXmlDom(R"(<fragment class="com.foo.Bar"/>)");
102   layout->file.name = test::ParseNameOrDie("layout/foo");
103 
104   proguard::KeepSet set;
105   ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
106 
107   std::string actual = GetKeepSetString(set, /** minimal_rules */ false);
108   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
109 
110   actual = GetKeepSetString(set, /** minimal_rules */ true);
111   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(); }"));
112 }
113 
114 TEST(ProguardRulesTest, FragmentNameAndClassRulesAreEmitted) {
115   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
116   std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
117       <fragment xmlns:android="http://schemas.android.com/apk/res/android"
118           android:name="com.foo.Baz"
119           class="com.foo.Bar"/>)");
120   layout->file.name = test::ParseNameOrDie("layout/foo");
121 
122   proguard::KeepSet set;
123   ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
124 
125   std::string actual = GetKeepSetString(set, /** minimal_rules */ false);
126   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
127   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Baz { <init>(...); }"));
128 
129   actual = GetKeepSetString(set, /** minimal_rules */ true);
130   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(); }"));
131   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Baz { <init>(); }"));
132 }
133 
134 TEST(ProguardRulesTest, FragmentContainerViewNameRuleIsEmitted) {
135   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
136   std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
137       <androidx.fragment.app.FragmentContainerView
138           xmlns:android="http://schemas.android.com/apk/res/android"
139           android:name="com.foo.Bar"/>)");
140   layout->file.name = test::ParseNameOrDie("layout/foo");
141 
142   proguard::KeepSet set;
143   ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
144 
145   std::string actual = GetKeepSetString(set, /** minimal_rules */ false);
146   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
147 
148   actual = GetKeepSetString(set, /** minimal_rules */ true);
149   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(); }"));
150 }
151 
152 TEST(ProguardRulesTest, FragmentContainerViewClassRuleIsEmitted) {
153   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
154   std::unique_ptr<xml::XmlResource> layout =
155       test::BuildXmlDom(R"(<androidx.fragment.app.FragmentContainerView class="com.foo.Bar"/>)");
156   layout->file.name = test::ParseNameOrDie("layout/foo");
157 
158   proguard::KeepSet set;
159   ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
160 
161   std::string actual = GetKeepSetString(set, /** minimal_rules */ false);
162   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
163 
164   actual = GetKeepSetString(set, /** minimal_rules */ true);
165   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(); }"));
166 }
167 
168 TEST(ProguardRulesTest, FragmentContainerViewNameAndClassRulesAreEmitted) {
169   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
170   std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
171       <androidx.fragment.app.FragmentContainerView
172           xmlns:android="http://schemas.android.com/apk/res/android"
173           android:name="com.foo.Baz"
174           class="com.foo.Bar"/>)");
175   layout->file.name = test::ParseNameOrDie("layout/foo");
176 
177   proguard::KeepSet set;
178   ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
179 
180   std::string actual = GetKeepSetString(set, /** minimal_rules */ false);
181   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
182   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Baz { <init>(...); }"));
183 
184   actual = GetKeepSetString(set, /** minimal_rules */ true);
185   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(); }"));
186   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Baz { <init>(); }"));
187 }
188 
189 TEST(ProguardRulesTest, NavigationFragmentNameAndClassRulesAreEmitted) {
190   std::unique_ptr<IAaptContext> context = test::ContextBuilder()
191       .SetCompilationPackage("com.base").Build();
192   std::unique_ptr<xml::XmlResource> navigation = test::BuildXmlDom(R"(
193       <navigation
194           xmlns:android="http://schemas.android.com/apk/res/android"
195           xmlns:app="http://schemas.android.com/apk/res-auto">
196           <custom android:id="@id/foo"
197               android:name="com.package.Foo"/>
198           <fragment android:id="@id/bar"
199               android:name="com.package.Bar">
200               <nested android:id="@id/nested"
201                   android:name=".Nested"/>
202           </fragment>
203       </navigation>
204   )");
205 
206   navigation->file.name = test::ParseNameOrDie("navigation/graph.xml");
207 
208   proguard::KeepSet set;
209   ASSERT_TRUE(proguard::CollectProguardRules(context.get(), navigation.get(), &set));
210 
211   std::string actual = GetKeepSetString(set, /** minimal_rules */ false);
212   EXPECT_THAT(actual, HasSubstr("-keep class com.package.Foo { <init>(...); }"));
213   EXPECT_THAT(actual, HasSubstr("-keep class com.package.Bar { <init>(...); }"));
214   EXPECT_THAT(actual, HasSubstr("-keep class com.base.Nested { <init>(...); }"));
215 
216   actual = GetKeepSetString(set, /** minimal_rules */ true);
217   EXPECT_THAT(actual, HasSubstr("-keep class com.package.Foo { <init>(...); }"));
218   EXPECT_THAT(actual, HasSubstr("-keep class com.package.Bar { <init>(...); }"));
219   EXPECT_THAT(actual, HasSubstr("-keep class com.base.Nested { <init>(...); }"));
220 }
221 
222 TEST(ProguardRulesTest, CustomViewRulesAreEmitted) {
223   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
224   std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
225       <View xmlns:android="http://schemas.android.com/apk/res/android">
226         <com.foo.Bar />
227       </View>)");
228   layout->file.name = test::ParseNameOrDie("layout/foo");
229 
230   proguard::KeepSet set;
231   ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
232 
233   std::string actual = GetKeepSetString(set, /** minimal_rules */ false);
234   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
235 
236   actual = GetKeepSetString(set, /** minimal_rules */ true);
237   EXPECT_THAT(actual, HasSubstr(
238       "-keep class com.foo.Bar { <init>(android.content.Context, android.util.AttributeSet); }"));
239 }
240 
241 TEST(ProguardRulesTest, IncludedLayoutRulesAreConditional) {
242   std::unique_ptr<xml::XmlResource> bar_layout = test::BuildXmlDom(R"(
243       <View xmlns:android="http://schemas.android.com/apk/res/android">
244         <com.foo.Bar />
245       </View>)");
246   bar_layout->file.name = test::ParseNameOrDie("com.foo:layout/bar");
247 
248   ResourceTable table;
249   StdErrDiagnostics errDiagnostics;
250   table.AddResource(NewResourceBuilder(bar_layout->file.name)
251                         .SetValue(util::make_unique<FileReference>())
252                         .Build(),
253                     &errDiagnostics);
254 
255   std::unique_ptr<IAaptContext> context =
256       test::ContextBuilder()
257           .SetCompilationPackage("com.foo")
258           .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(&table))
259           .Build();
260 
261   std::unique_ptr<xml::XmlResource> foo_layout = test::BuildXmlDom(R"(
262       <View xmlns:android="http://schemas.android.com/apk/res/android">
263         <include layout="@layout/bar" />
264       </View>)");
265   foo_layout->file.name = test::ParseNameOrDie("com.foo:layout/foo");
266 
267   XmlReferenceLinker xml_linker(nullptr);
268   ASSERT_TRUE(xml_linker.Consume(context.get(), bar_layout.get()));
269   ASSERT_TRUE(xml_linker.Consume(context.get(), foo_layout.get()));
270 
271   proguard::KeepSet set = proguard::KeepSet(true);
272   ASSERT_TRUE(proguard::CollectProguardRules(context.get(), bar_layout.get(), &set));
273   ASSERT_TRUE(proguard::CollectProguardRules(context.get(), foo_layout.get(), &set));
274 
275   std::string actual = GetKeepSetString(set, /** minimal_rules */ false);
276   EXPECT_THAT(actual, HasSubstr("-if class **.R$layout"));
277   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
278   EXPECT_THAT(actual, HasSubstr("int foo"));
279   EXPECT_THAT(actual, HasSubstr("int bar"));
280 
281   actual = GetKeepSetString(set, /** minimal_rules */ true);
282   EXPECT_THAT(actual, HasSubstr("-if class **.R$layout"));
283   EXPECT_THAT(actual, HasSubstr(
284     "-keep class com.foo.Bar { <init>(android.content.Context, android.util.AttributeSet); }"));
285   EXPECT_THAT(actual, HasSubstr("int foo"));
286   EXPECT_THAT(actual, HasSubstr("int bar"));
287 }
288 
289 TEST(ProguardRulesTest, AliasedLayoutRulesAreConditional) {
290   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
291   std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
292       <View xmlns:android="http://schemas.android.com/apk/res/android">
293         <com.foo.Bar />
294       </View>)");
295   layout->file.name = test::ParseNameOrDie("layout/foo");
296 
297   proguard::KeepSet set = proguard::KeepSet(true);
298   set.AddReference({test::ParseNameOrDie("layout/bar"), {}}, layout->file.name);
299   ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
300 
301   std::string actual = GetKeepSetString(set, /** minimal_rules */ false);
302   EXPECT_THAT(actual, HasSubstr(
303       "-keep class com.foo.Bar { <init>(...); }"));
304   EXPECT_THAT(actual, HasSubstr("-if class **.R$layout"));
305   EXPECT_THAT(actual, HasSubstr("int foo"));
306   EXPECT_THAT(actual, HasSubstr("int bar"));
307 
308   actual = GetKeepSetString(set, /** minimal_rules */ true);
309   EXPECT_THAT(actual, HasSubstr(
310     "-keep class com.foo.Bar { <init>(android.content.Context, android.util.AttributeSet); }"));
311   EXPECT_THAT(actual, HasSubstr("-if class **.R$layout"));
312   EXPECT_THAT(actual, HasSubstr("int foo"));
313   EXPECT_THAT(actual, HasSubstr("int bar"));
314 }
315 
316 TEST(ProguardRulesTest, NonLayoutReferencesAreUnconditional) {
317   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
318   std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
319       <View xmlns:android="http://schemas.android.com/apk/res/android">
320         <com.foo.Bar />
321       </View>)");
322   layout->file.name = test::ParseNameOrDie("layout/foo");
323 
324   proguard::KeepSet set = proguard::KeepSet(true);
325   set.AddReference({test::ParseNameOrDie("style/MyStyle"), {}}, layout->file.name);
326   ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
327 
328   std::string actual = GetKeepSetString(set, /** minimal_rules */ false);
329   EXPECT_THAT(actual, Not(HasSubstr("-if")));
330   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
331 
332   actual = GetKeepSetString(set, /** minimal_rules */ true);
333   EXPECT_THAT(actual, Not(HasSubstr("-if")));
334   EXPECT_THAT(actual, HasSubstr(
335     "-keep class com.foo.Bar { <init>(android.content.Context, android.util.AttributeSet); }"));
336 }
337 
338 TEST(ProguardRulesTest, ViewOnClickRuleIsEmitted) {
339   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
340   std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
341       <View xmlns:android="http://schemas.android.com/apk/res/android"
342           android:onClick="bar_method" />)");
343   layout->file.name = test::ParseNameOrDie("layout/foo");
344 
345   proguard::KeepSet set;
346   ASSERT_TRUE(proguard::CollectProguardRules(context.get(), layout.get(), &set));
347 
348   std::string actual = GetKeepSetString(set,  /** minimal_rules */ false);
349   EXPECT_THAT(actual, HasSubstr(
350       "-keepclassmembers class * { *** bar_method(android.view.View); }"));
351 
352   actual = GetKeepSetString(set,  /** minimal_rules */ true);
353   EXPECT_THAT(actual, HasSubstr(
354     "-keepclassmembers class * { *** bar_method(android.view.View); }"));
355 }
356 
357 TEST(ProguardRulesTest, MenuRulesAreEmitted) {
358   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
359   std::unique_ptr<xml::XmlResource> menu = test::BuildXmlDom(R"(
360       <menu xmlns:android="http://schemas.android.com/apk/res/android">
361         <item android:onClick="on_click"
362             android:actionViewClass="com.foo.Bar"
363             android:actionProviderClass="com.foo.Baz"
364             android:name="com.foo.Bat" />
365       </menu>)");
366   menu->file.name = test::ParseNameOrDie("menu/foo");
367 
368   proguard::KeepSet set;
369   ASSERT_TRUE(proguard::CollectProguardRules(context.get(), menu.get(), &set));
370 
371   std::string actual = GetKeepSetString(set,  /** minimal_rules */ false);
372   EXPECT_THAT(actual, HasSubstr(
373     "-keepclassmembers class * { *** on_click(android.view.MenuItem); }"));
374   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
375   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Baz { <init>(...); }"));
376   EXPECT_THAT(actual, Not(HasSubstr("com.foo.Bat")));
377 
378   actual = GetKeepSetString(set,  /** minimal_rules */ true);
379   EXPECT_THAT(actual, HasSubstr(
380     "-keepclassmembers class * { *** on_click(android.view.MenuItem); }"));
381   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(android.content.Context); }"));
382   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Baz { <init>(android.content.Context); }"));
383   EXPECT_THAT(actual, Not(HasSubstr("com.foo.Bat")));
384 }
385 
386 TEST(ProguardRulesTest, MenuRulesAreEmittedForActionClasses) {
387   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
388   std::unique_ptr<xml::XmlResource> menu = test::BuildXmlDom(R"(
389       <menu xmlns:android="http://schemas.android.com/apk/res/android"
390             xmlns:app="http://schemas.android.com/apk/res-auto">
391         <item android:id="@+id/my_item"
392             app:actionViewClass="com.foo.Bar"
393             app:actionProviderClass="com.foo.Baz" />
394       </menu>)");
395   menu->file.name = test::ParseNameOrDie("menu/foo");
396 
397   proguard::KeepSet set;
398   ASSERT_TRUE(proguard::CollectProguardRules(context.get(), menu.get(), &set));
399 
400   std::string actual = GetKeepSetString(set, /** minimal_rules */ false);
401   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar"));
402   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Baz"));
403 }
404 
405 TEST(ProguardRulesTest, TransitionPathMotionRulesAreEmitted) {
406   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
407   std::unique_ptr<xml::XmlResource> transition = test::BuildXmlDom(R"(
408       <changeBounds>
409         <pathMotion class="com.foo.Bar"/>
410       </changeBounds>)");
411   transition->file.name = test::ParseNameOrDie("transition/foo");
412 
413   proguard::KeepSet set;
414   ASSERT_TRUE(proguard::CollectProguardRules(context.get(), transition.get(), &set));
415 
416   std::string actual = GetKeepSetString(set, /** minimal_rules */ false);
417   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
418 
419   actual = GetKeepSetString(set, /** minimal_rules */ true);
420   EXPECT_THAT(actual, HasSubstr(
421     "-keep class com.foo.Bar { <init>(android.content.Context, android.util.AttributeSet); }"));
422 }
423 
424 TEST(ProguardRulesTest, TransitionRulesAreEmitted) {
425   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
426   std::unique_ptr<xml::XmlResource> transitionSet = test::BuildXmlDom(R"(
427       <transitionSet>
428         <transition class="com.foo.Bar"/>
429       </transitionSet>)");
430   transitionSet->file.name = test::ParseNameOrDie("transition/foo");
431 
432   proguard::KeepSet set;
433   ASSERT_TRUE(proguard::CollectProguardRules(context.get(), transitionSet.get(), &set));
434 
435   std::string actual = GetKeepSetString(set, /** minimal_rules */ false);
436   EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
437 
438   actual = GetKeepSetString(set, /** minimal_rules */ true);
439   EXPECT_THAT(actual, HasSubstr(
440     "-keep class com.foo.Bar { <init>(android.content.Context, android.util.AttributeSet); }"));
441 }
442 
443 TEST(ProguardRulesTest, UsageLocationComparator) {
444   proguard::UsageLocation location1 = {{"pkg", ResourceType::kAttr, "x"}};
445   proguard::UsageLocation location2 = {{"pkg", ResourceType::kAttr, "y"}};
446 
447   EXPECT_EQ(location1 < location2, true);
448   EXPECT_EQ(location2 < location1, false);
449 }
450 
451 }  // namespace aapt
452