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