1 /*
2  * Copyright (C) 2015 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/ManifestClassGenerator.h"
18 
19 #include "io/StringStream.h"
20 #include "test/Test.h"
21 
22 using ::aapt::io::StringOutputStream;
23 using ::testing::HasSubstr;
24 using ::testing::Not;
25 
26 namespace aapt {
27 
28 static ::testing::AssertionResult GetManifestClassText(IAaptContext* context, xml::XmlResource* res,
29                                                        bool strip_api_annotations,
30                                                        std::string* out_str);
31 
TEST(ManifestClassGeneratorTest,NameIsProperlyGeneratedFromSymbol)32 TEST(ManifestClassGeneratorTest, NameIsProperlyGeneratedFromSymbol) {
33   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
34   std::unique_ptr<xml::XmlResource> manifest = test::BuildXmlDom(R"(
35       <manifest xmlns:android="http://schemas.android.com/apk/res/android">
36         <permission android:name="android.permission.ACCESS_INTERNET" />
37         <permission android:name="android.DO_DANGEROUS_THINGS" />
38         <permission android:name="com.test.sample.permission.HUH" />
39         <permission-group android:name="foo.bar.PERMISSION" />
40       </manifest>)");
41 
42   std::string actual;
43   ASSERT_TRUE(GetManifestClassText(context.get(), manifest.get(),
44                                    false /* strip_api_annotations */, &actual));
45 
46   ASSERT_THAT(actual, HasSubstr("public static final class permission {"));
47   ASSERT_THAT(actual, HasSubstr("public static final class permission_group {"));
48 
49   const size_t permission_start_pos = actual.find("public static final class permission {");
50   const size_t permission_group_start_pos =
51       actual.find("public static final class permission_group {");
52 
53   //
54   // Make sure these permissions are in the permission class.
55   //
56   const std::string permission_class =
57       actual.substr(permission_start_pos, permission_group_start_pos - permission_start_pos);
58 
59   EXPECT_THAT(
60       permission_class,
61       HasSubstr(
62           "public static final String ACCESS_INTERNET=\"android.permission.ACCESS_INTERNET\";"));
63   EXPECT_THAT(
64       permission_class,
65       HasSubstr("public static final String DO_DANGEROUS_THINGS=\"android.DO_DANGEROUS_THINGS\";"));
66   EXPECT_THAT(permission_class,
67               HasSubstr("public static final String HUH=\"com.test.sample.permission.HUH\";"));
68 
69   //
70   // Make sure these permissions are in the permission_group class
71   //
72   const std::string permission_group_class = actual.substr(permission_group_start_pos);
73 
74   EXPECT_THAT(permission_group_class,
75               HasSubstr("public static final String PERMISSION=\"foo.bar.PERMISSION\";"));
76 }
77 
78 TEST(ManifestClassGeneratorTest, CommentsAndAnnotationsArePresent) {
79   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
80   std::unique_ptr<xml::XmlResource> manifest = test::BuildXmlDom(R"(
81       <manifest xmlns:android="http://schemas.android.com/apk/res/android">
82         <!-- Required to access the internet.
83              Added in API 1. -->
84         <permission android:name="android.permission.ACCESS_INTERNET" />
85         <!-- @deprecated This permission is for playing outside. -->
86         <permission android:name="android.permission.PLAY_OUTSIDE" />
87         <!-- This is a private permission for system only!
88              @hide
89              @SystemApi -->
90         <permission android:name="android.permission.SECRET" />
91         <!-- @TestApi This is a test only permission. -->
92         <permission android:name="android.permission.TEST_ONLY" />
93       </manifest>)");
94 
95   std::string actual;
96   ASSERT_TRUE(GetManifestClassText(context.get(), manifest.get(),
97                                    false /* strip_api_annotations */, &actual));
98 
99   const char* expected_access_internet = R"(    /**
100      * Required to access the internet.
101      * Added in API 1.
102      */
103     public static final String ACCESS_INTERNET="android.permission.ACCESS_INTERNET";)";
104   EXPECT_THAT(actual, HasSubstr(expected_access_internet));
105 
106   const char* expected_play_outside = R"(    /**
107      * @deprecated This permission is for playing outside.
108      */
109     @Deprecated
110     public static final String PLAY_OUTSIDE="android.permission.PLAY_OUTSIDE";)";
111   EXPECT_THAT(actual, HasSubstr(expected_play_outside));
112 
113   const char* expected_secret = R"(    /**
114      * This is a private permission for system only!
115      * @hide
116      */
117     @android.annotation.SystemApi
118     public static final String SECRET="android.permission.SECRET";)";
119   EXPECT_THAT(actual, HasSubstr(expected_secret));
120 
121   const char* expected_test = R"(    /**
122      * This is a test only permission.
123      */
124     @android.annotation.TestApi
125     public static final String TEST_ONLY="android.permission.TEST_ONLY";)";
126   EXPECT_THAT(actual, HasSubstr(expected_test));
127 }
128 
129 TEST(ManifestClassGeneratorTest, CommentsAndAnnotationsArePresentButNoApiAnnotations) {
130   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
131   std::unique_ptr<xml::XmlResource> manifest = test::BuildXmlDom(R"(
132       <manifest xmlns:android="http://schemas.android.com/apk/res/android">
133         <!-- Required to access the internet.
134              Added in API 1. -->
135         <permission android:name="android.permission.ACCESS_INTERNET" />
136         <!-- @deprecated This permission is for playing outside. -->
137         <permission android:name="android.permission.PLAY_OUTSIDE" />
138         <!-- This is a private permission for system only!
139              @hide
140              @SystemApi -->
141         <permission android:name="android.permission.SECRET" />
142         <!-- @TestApi This is a test only permission. -->
143         <permission android:name="android.permission.TEST_ONLY" />
144       </manifest>)");
145 
146   std::string actual;
147   ASSERT_TRUE(GetManifestClassText(context.get(), manifest.get(),
148                                    true /* strip_api_annotations */, &actual));
149 
150   const char* expected_access_internet = R"(    /**
151      * Required to access the internet.
152      * Added in API 1.
153      */
154     public static final String ACCESS_INTERNET="android.permission.ACCESS_INTERNET";)";
155   EXPECT_THAT(actual, HasSubstr(expected_access_internet));
156 
157   const char* expected_play_outside = R"(    /**
158      * @deprecated This permission is for playing outside.
159      */
160     @Deprecated
161     public static final String PLAY_OUTSIDE="android.permission.PLAY_OUTSIDE";)";
162   EXPECT_THAT(actual, HasSubstr(expected_play_outside));
163 
164   const char* expected_secret = R"(    /**
165      * This is a private permission for system only!
166      * @hide
167      */
168     public static final String SECRET="android.permission.SECRET";)";
169   EXPECT_THAT(actual, HasSubstr(expected_secret));
170 
171   const char* expected_test = R"(    /**
172      * This is a test only permission.
173      */
174     public static final String TEST_ONLY="android.permission.TEST_ONLY";)";
175   EXPECT_THAT(actual, HasSubstr(expected_test));
176 }
177 
178 // This is bad but part of public API behaviour so we need to preserve it.
179 TEST(ManifestClassGeneratorTest, LastSeenPermissionWithSameLeafNameTakesPrecedence) {
180   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
181   std::unique_ptr<xml::XmlResource> manifest = test::BuildXmlDom(R"(
182       <manifest xmlns:android="http://schemas.android.com/apk/res/android">
183         <permission android:name="android.permission.ACCESS_INTERNET" />
184         <permission android:name="com.android.sample.ACCESS_INTERNET" />
185         <permission android:name="com.android.permission.UNRELATED_PERMISSION" />
186         <permission android:name="com.android.aapt.test.ACCESS_INTERNET" /> -->
187       </manifest>)");
188 
189   std::string actual;
190   ASSERT_TRUE(GetManifestClassText(context.get(), manifest.get(),
191                                    false  /* strip_api_annotations */, &actual));
192   EXPECT_THAT(actual, HasSubstr("ACCESS_INTERNET=\"com.android.aapt.test.ACCESS_INTERNET\";"));
193   EXPECT_THAT(actual, Not(HasSubstr("ACCESS_INTERNET=\"android.permission.ACCESS_INTERNET\";")));
194   EXPECT_THAT(actual, Not(HasSubstr("ACCESS_INTERNET=\"com.android.sample.ACCESS_INTERNET\";")));
195 }
196 
197 TEST(ManifestClassGeneratorTest, NormalizePermissionNames) {
198   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
199   std::unique_ptr<xml::XmlResource> manifest = test::BuildXmlDom(R"(
200         <manifest xmlns:android="http://schemas.android.com/apk/res/android">
201           <permission android:name="android.permission.access-internet" />
202         </manifest>)");
203 
204   std::string actual;
205   ASSERT_TRUE(GetManifestClassText(context.get(), manifest.get(),
206                                    false  /* strip_api_annotations */, &actual));
207   EXPECT_THAT(actual, HasSubstr("access_internet=\"android.permission.access-internet\";"));
208 }
209 
210 static ::testing::AssertionResult GetManifestClassText(IAaptContext* context, xml::XmlResource* res,
211                                                        bool strip_api_annotations,
212                                                        std::string* out_str) {
213   std::unique_ptr<ClassDefinition> manifest_class =
214       GenerateManifestClass(context->GetDiagnostics(), res);
215   if (!manifest_class) {
216     return ::testing::AssertionFailure() << "manifest_class == nullptr";
217   }
218 
219   StringOutputStream out(out_str);
220   manifest_class->WriteJavaFile(manifest_class.get(), "android", true, strip_api_annotations, &out);
221   out.Flush();
222   return ::testing::AssertionSuccess();
223 }
224 
225 }  // namespace aapt
226