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 23using ::aapt::io::StringOutputStream; 24using ::testing::HasSubstr; 25using ::testing::Not; 26 27namespace aapt { 28 29std::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 37TEST(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; 45 ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set)); 46 47 std::string actual = GetKeepSetString(set); 48 49 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; 59 ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set)); 60 61 std::string actual = GetKeepSetString(set); 62 63 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; 75 ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set)); 76 77 std::string actual = GetKeepSetString(set); 78 79 EXPECT_THAT(actual, HasSubstr("com.foo.Bar")); 80 EXPECT_THAT(actual, HasSubstr("com.foo.Baz")); 81} 82 83TEST(ProguardRulesTest, CustomViewRulesAreEmitted) { 84 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); 85 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"( 86 <View xmlns:android="http://schemas.android.com/apk/res/android"> 87 <com.foo.Bar /> 88 </View>)"); 89 layout->file.name = test::ParseNameOrDie("layout/foo"); 90 91 proguard::KeepSet set; 92 ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set)); 93 94 std::string actual = GetKeepSetString(set); 95 96 EXPECT_THAT(actual, HasSubstr("com.foo.Bar")); 97} 98 99TEST(ProguardRulesTest, IncludedLayoutRulesAreConditional) { 100 std::unique_ptr<xml::XmlResource> bar_layout = test::BuildXmlDom(R"( 101 <View xmlns:android="http://schemas.android.com/apk/res/android"> 102 <com.foo.Bar /> 103 </View>)"); 104 bar_layout->file.name = test::ParseNameOrDie("com.foo:layout/bar"); 105 106 ResourceTable table; 107 StdErrDiagnostics errDiagnostics; 108 table.AddResource(bar_layout->file.name, ConfigDescription::DefaultConfig(), "", 109 util::make_unique<FileReference>(), &errDiagnostics); 110 111 std::unique_ptr<IAaptContext> context = 112 test::ContextBuilder() 113 .SetCompilationPackage("com.foo") 114 .AddSymbolSource(util::make_unique<ResourceTableSymbolSource>(&table)) 115 .Build(); 116 117 std::unique_ptr<xml::XmlResource> foo_layout = test::BuildXmlDom(R"( 118 <View xmlns:android="http://schemas.android.com/apk/res/android"> 119 <include layout="@layout/bar" /> 120 </View>)"); 121 foo_layout->file.name = test::ParseNameOrDie("com.foo:layout/foo"); 122 123 XmlReferenceLinker xml_linker; 124 ASSERT_TRUE(xml_linker.Consume(context.get(), bar_layout.get())); 125 ASSERT_TRUE(xml_linker.Consume(context.get(), foo_layout.get())); 126 127 proguard::KeepSet set = proguard::KeepSet(true); 128 ASSERT_TRUE(proguard::CollectProguardRules(bar_layout.get(), &set)); 129 ASSERT_TRUE(proguard::CollectProguardRules(foo_layout.get(), &set)); 130 131 std::string actual = GetKeepSetString(set); 132 133 EXPECT_THAT(actual, HasSubstr("-if class **.R$layout")); 134 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }")); 135 EXPECT_THAT(actual, HasSubstr("int foo")); 136 EXPECT_THAT(actual, HasSubstr("int bar")); 137 EXPECT_THAT(actual, HasSubstr("com.foo.Bar")); 138} 139 140TEST(ProguardRulesTest, AliasedLayoutRulesAreConditional) { 141 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); 142 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"( 143 <View xmlns:android="http://schemas.android.com/apk/res/android"> 144 <com.foo.Bar /> 145 </View>)"); 146 layout->file.name = test::ParseNameOrDie("layout/foo"); 147 148 proguard::KeepSet set = proguard::KeepSet(true); 149 set.AddReference({test::ParseNameOrDie("layout/bar"), {}}, layout->file.name); 150 ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set)); 151 152 std::string actual = GetKeepSetString(set); 153 154 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }")); 155 EXPECT_THAT(actual, HasSubstr("-if class **.R$layout")); 156 EXPECT_THAT(actual, HasSubstr("int foo")); 157 EXPECT_THAT(actual, HasSubstr("int bar")); 158 EXPECT_THAT(actual, HasSubstr("com.foo.Bar")); 159} 160 161TEST(ProguardRulesTest, NonLayoutReferencesAreUnconditional) { 162 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); 163 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"( 164 <View xmlns:android="http://schemas.android.com/apk/res/android"> 165 <com.foo.Bar /> 166 </View>)"); 167 layout->file.name = test::ParseNameOrDie("layout/foo"); 168 169 proguard::KeepSet set = proguard::KeepSet(true); 170 set.AddReference({test::ParseNameOrDie("style/MyStyle"), {}}, layout->file.name); 171 ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set)); 172 173 std::string actual = GetKeepSetString(set); 174 175 EXPECT_THAT(actual, Not(HasSubstr("-if"))); 176 EXPECT_THAT(actual, HasSubstr("-keep class com.foo.Bar { <init>(...); }")); 177} 178 179TEST(ProguardRulesTest, ViewOnClickRuleIsEmitted) { 180 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); 181 std::unique_ptr<xml::XmlResource> layout = test::BuildXmlDom(R"( 182 <View xmlns:android="http://schemas.android.com/apk/res/android" 183 android:onClick="bar_method" />)"); 184 layout->file.name = test::ParseNameOrDie("layout/foo"); 185 186 proguard::KeepSet set; 187 ASSERT_TRUE(proguard::CollectProguardRules(layout.get(), &set)); 188 189 std::string actual = GetKeepSetString(set); 190 191 EXPECT_THAT(actual, HasSubstr("bar_method")); 192} 193 194TEST(ProguardRulesTest, MenuRulesAreEmitted) { 195 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); 196 std::unique_ptr<xml::XmlResource> menu = test::BuildXmlDom(R"( 197 <menu xmlns:android="http://schemas.android.com/apk/res/android"> 198 <item android:onClick="on_click" 199 android:actionViewClass="com.foo.Bar" 200 android:actionProviderClass="com.foo.Baz" 201 android:name="com.foo.Bat" /> 202 </menu>)"); 203 menu->file.name = test::ParseNameOrDie("menu/foo"); 204 205 proguard::KeepSet set; 206 ASSERT_TRUE(proguard::CollectProguardRules(menu.get(), &set)); 207 208 std::string actual = GetKeepSetString(set); 209 210 EXPECT_THAT(actual, HasSubstr("on_click")); 211 EXPECT_THAT(actual, HasSubstr("com.foo.Bar")); 212 EXPECT_THAT(actual, HasSubstr("com.foo.Baz")); 213 EXPECT_THAT(actual, Not(HasSubstr("com.foo.Bat"))); 214} 215 216} // namespace aapt 217