1f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski/*
2f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski * Copyright (C) 2017 The Android Open Source Project
3f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski *
4f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
5f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski * you may not use this file except in compliance with the License.
6f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski * You may obtain a copy of the License at
7f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski *
8f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
9f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski *
10f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski * Unless required by applicable law or agreed to in writing, software
11f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
12f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski * See the License for the specific language governing permissions and
14f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski * limitations under the License.
15f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski */
16f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
17f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski#include "java/ProguardRules.h"
18dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski#include "link/Linkers.h"
19f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
20a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski#include "io/StringStream.h"
21f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski#include "test/Test.h"
22f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
23a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinskiusing ::aapt::io::StringOutputStream;
24f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinskiusing ::testing::HasSubstr;
25f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinskiusing ::testing::Not;
26f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
27f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinskinamespace aapt {
28f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
29a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinskistd::string GetKeepSetString(const proguard::KeepSet& set) {
30a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski  std::string out;
31a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski  StringOutputStream sout(&out);
32a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski  proguard::WriteKeepSet(set, &sout);
33a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski  sout.Flush();
34a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski  return out;
35a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski}
36a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski
37f762df257574231ffd08679a69e9cf62fe143dcdAdam LesinskiTEST(ProguardRulesTest, FragmentNameRuleIsEmitted) {
38f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
39f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
40f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski      <fragment xmlns:android="http://schemas.android.com/apk/res/android"
41f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski          android:name="com.foo.Bar"/>)");
42f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  layout->file.name = test::ParseNameOrDie("layout/foo");
43f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
44f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  proguard::KeepSet set;
45dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
46f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
47a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski  std::string actual = GetKeepSetString(set);
48f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
49f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
50f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski}
51f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
52f762df257574231ffd08679a69e9cf62fe143dcdAdam LesinskiTEST(ProguardRulesTest, FragmentClassRuleIsEmitted) {
53f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
54f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  std::unique_ptr<xml::XmlResource> layout =
55f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski      test::BuildXmlDom(R"(<fragment class="com.foo.Bar"/>)");
56f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  layout->file.name = test::ParseNameOrDie("layout/foo");
57f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
58f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  proguard::KeepSet set;
59dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
60f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
61a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski  std::string actual = GetKeepSetString(set);
62f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
63f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
64f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski}
65f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
66f762df257574231ffd08679a69e9cf62fe143dcdAdam LesinskiTEST(ProguardRulesTest, FragmentNameAndClassRulesAreEmitted) {
67f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
68f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
69f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski      <fragment xmlns:android="http://schemas.android.com/apk/res/android"
70f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski          android:name="com.foo.Baz"
71f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski          class="com.foo.Bar"/>)");
72f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  layout->file.name = test::ParseNameOrDie("layout/foo");
73f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
74f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  proguard::KeepSet set;
75dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
76f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
77a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski  std::string actual = GetKeepSetString(set);
78f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
79f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
80f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  EXPECT_THAT(actual, HasSubstr("com.foo.Baz"));
81f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski}
82f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
83dc21dea9b8b1157a4a9347b68301da4307c51168Adam KoskiTEST(ProguardRulesTest, CustomViewRulesAreEmitted) {
84dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
85dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
86dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski      <View xmlns:android="http://schemas.android.com/apk/res/android">
87dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski        <com.foo.Bar />
88dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski      </View>)");
89dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  layout->file.name = test::ParseNameOrDie("layout/foo");
90dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski
91dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  proguard::KeepSet set;
92dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
93dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski
94a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski  std::string actual = GetKeepSetString(set);
95dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski
96dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
97dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski}
98dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski
99dc21dea9b8b1157a4a9347b68301da4307c51168Adam KoskiTEST(ProguardRulesTest, IncludedLayoutRulesAreConditional) {
100dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  std::unique_ptr<xml::XmlResource> bar_layout = test::BuildXmlDom(R"(
101dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski      <View xmlns:android="http://schemas.android.com/apk/res/android">
102dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski        <com.foo.Bar />
103dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski      </View>)");
104dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  bar_layout->file.name = test::ParseNameOrDie("com.foo:layout/bar");
105dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski
106dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  ResourceTable table;
107dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  StdErrDiagnostics errDiagnostics;
108dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  table.AddResource(bar_layout->file.name, ConfigDescription::DefaultConfig(), "",
109dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski                    util::make_unique<FileReference>(), &errDiagnostics);
110dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski
111dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  std::unique_ptr<IAaptContext> context =
112dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski      test::ContextBuilder()
113dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski          .SetCompilationPackage("com.foo")
114dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski          .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(&table))
115dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski          .Build();
116dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski
117dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  std::unique_ptr<xml::XmlResource> foo_layout = test::BuildXmlDom(R"(
118dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski      <View xmlns:android="http://schemas.android.com/apk/res/android">
119dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski        <include layout="@layout/bar" />
120dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski      </View>)");
121dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  foo_layout->file.name = test::ParseNameOrDie("com.foo:layout/foo");
122dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski
123dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  XmlReferenceLinker xml_linker;
124dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  ASSERT_TRUE(xml_linker.Consume(context.get(), bar_layout.get()));
125dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  ASSERT_TRUE(xml_linker.Consume(context.get(), foo_layout.get()));
126dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski
127dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  proguard::KeepSet set = proguard::KeepSet(true);
128dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  ASSERT_TRUE(proguard::CollectProguardRules(bar_layout.get(), &set));
129dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  ASSERT_TRUE(proguard::CollectProguardRules(foo_layout.get(), &set));
130dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski
131a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski  std::string actual = GetKeepSetString(set);
132dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski
13309ef94e918870a55907b20f35348cc7b77bdc148Adam Koski  EXPECT_THAT(actual, HasSubstr("-if class **.R$layout"));
134a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski  EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
135dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  EXPECT_THAT(actual, HasSubstr("int foo"));
136dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  EXPECT_THAT(actual, HasSubstr("int bar"));
137dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
138dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski}
139dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski
140dc21dea9b8b1157a4a9347b68301da4307c51168Adam KoskiTEST(ProguardRulesTest, AliasedLayoutRulesAreConditional) {
141dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
142dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
143dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski      <View xmlns:android="http://schemas.android.com/apk/res/android">
144dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski        <com.foo.Bar />
145dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski      </View>)");
146dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  layout->file.name = test::ParseNameOrDie("layout/foo");
147dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski
148dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  proguard::KeepSet set = proguard::KeepSet(true);
149dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  set.AddReference({test::ParseNameOrDie("layout/bar"), {}}, layout->file.name);
150dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
151dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski
152a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski  std::string actual = GetKeepSetString(set);
153dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski
154a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski  EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
15509ef94e918870a55907b20f35348cc7b77bdc148Adam Koski  EXPECT_THAT(actual, HasSubstr("-if class **.R$layout"));
156dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  EXPECT_THAT(actual, HasSubstr("int foo"));
157dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  EXPECT_THAT(actual, HasSubstr("int bar"));
158dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
159dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski}
160dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski
161dc21dea9b8b1157a4a9347b68301da4307c51168Adam KoskiTEST(ProguardRulesTest, NonLayoutReferencesAreUnconditional) {
162dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
163dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
164dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski      <View xmlns:android="http://schemas.android.com/apk/res/android">
165dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski        <com.foo.Bar />
166dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski      </View>)");
167dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  layout->file.name = test::ParseNameOrDie("layout/foo");
168dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski
169dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  proguard::KeepSet set = proguard::KeepSet(true);
170dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  set.AddReference({test::ParseNameOrDie("style/MyStyle"), {}}, layout->file.name);
171dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
172dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski
173a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski  std::string actual = GetKeepSetString(set);
174dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski
17509ef94e918870a55907b20f35348cc7b77bdc148Adam Koski  EXPECT_THAT(actual, Not(HasSubstr("-if")));
176a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski  EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }"));
177dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski}
178dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski
179f762df257574231ffd08679a69e9cf62fe143dcdAdam LesinskiTEST(ProguardRulesTest, ViewOnClickRuleIsEmitted) {
180f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
181f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"(
182f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski      <View xmlns:android="http://schemas.android.com/apk/res/android"
183f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski          android:onClick="bar_method" />)");
184f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  layout->file.name = test::ParseNameOrDie("layout/foo");
185f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
186f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  proguard::KeepSet set;
187dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set));
188f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
189a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski  std::string actual = GetKeepSetString(set);
190f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
191f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  EXPECT_THAT(actual, HasSubstr("bar_method"));
192f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski}
193f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
194f762df257574231ffd08679a69e9cf62fe143dcdAdam LesinskiTEST(ProguardRulesTest, MenuRulesAreEmitted) {
195f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
196f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  std::unique_ptr<xml::XmlResource> menu = test::BuildXmlDom(R"(
197f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski      <menu xmlns:android="http://schemas.android.com/apk/res/android">
198f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski        <item android:onClick="on_click"
199f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski            android:actionViewClass="com.foo.Bar"
200f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski            android:actionProviderClass="com.foo.Baz"
201f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski            android:name="com.foo.Bat" />
202f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski      </menu>)");
203f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  menu->file.name = test::ParseNameOrDie("menu/foo");
204f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
205f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  proguard::KeepSet set;
206dc21dea9b8b1157a4a9347b68301da4307c51168Adam Koski  ASSERT_TRUE(proguard::CollectProguardRules(menu.get(), &set));
207f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
208a693c4a32ebed4e96dcc1cf6a706e8ebbb004db2Adam Lesinski  std::string actual = GetKeepSetString(set);
209f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
210f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  EXPECT_THAT(actual, HasSubstr("on_click"));
211f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  EXPECT_THAT(actual, HasSubstr("com.foo.Bar"));
212f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  EXPECT_THAT(actual, HasSubstr("com.foo.Baz"));
213f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski  EXPECT_THAT(actual, Not(HasSubstr("com.foo.Bat")));
214f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski}
215f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski
216f762df257574231ffd08679a69e9cf62fe143dcdAdam Lesinski}  // namespace aapt
217