1 /*
2  * Copyright (C) 2014 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 "androidfw/ResourceTypes.h"
18 
19 #include "utils/String16.h"
20 #include "utils/String8.h"
21 
22 #include "TestHelpers.h"
23 #include "data/basic/R.h"
24 
25 using com::android::basic::R;
26 
27 namespace android {
28 
makeConfigFrench(ResTable_config * config)29 static void makeConfigFrench(ResTable_config* config) {
30   memset(config, 0, sizeof(*config));
31   config->language[0] = 'f';
32   config->language[1] = 'r';
33 }
34 
35 class SplitTest : public ::testing::Test {
36  public:
SetUp()37   void SetUp() override {
38     ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk",
39                                         "resources.arsc", &basic_contents_));
40     ASSERT_TRUE(
41         ReadFileFromZipToString(GetTestDataPath() + "/basic/basic_de_fr.apk",
42                                 "resources.arsc", &basic_de_fr_contents_));
43     ASSERT_TRUE(
44         ReadFileFromZipToString(GetTestDataPath() + "/basic/basic_hdpi-v4.apk",
45                                 "resources.arsc", &basic_hdpi_contents_));
46     ASSERT_TRUE(
47         ReadFileFromZipToString(GetTestDataPath() + "/basic/basic_xhdpi-v4.apk",
48                                 "resources.arsc", &basic_xhdpi_contents_));
49     ASSERT_TRUE(ReadFileFromZipToString(
50         GetTestDataPath() + "/basic/basic_xxhdpi-v4.apk", "resources.arsc",
51         &basic_xxhdpi_contents_));
52     ASSERT_TRUE(
53         ReadFileFromZipToString(GetTestDataPath() + "/feature/feature.apk",
54                                 "resources.arsc", &feature_contents_));
55   }
56 
57  protected:
58   std::string basic_contents_;
59   std::string basic_de_fr_contents_;
60   std::string basic_hdpi_contents_;
61   std::string basic_xhdpi_contents_;
62   std::string basic_xxhdpi_contents_;
63   std::string feature_contents_;
64 };
65 
TEST_F(SplitTest,TestLoadBase)66 TEST_F(SplitTest, TestLoadBase) {
67   ResTable table;
68   ASSERT_EQ(NO_ERROR,
69             table.add(basic_contents_.data(), basic_contents_.size()));
70 }
71 
TEST_F(SplitTest,TestGetResourceFromBase)72 TEST_F(SplitTest, TestGetResourceFromBase) {
73   ResTable_config frenchConfig;
74   makeConfigFrench(&frenchConfig);
75 
76   ResTable table;
77   table.setParameters(&frenchConfig);
78 
79   ASSERT_EQ(NO_ERROR,
80             table.add(basic_contents_.data(), basic_contents_.size()));
81 
82   ResTable_config expectedConfig;
83   memset(&expectedConfig, 0, sizeof(expectedConfig));
84 
85   Res_value val;
86   ResTable_config config;
87   ssize_t block = table.getResource(R::string::test1, &val, MAY_NOT_BE_BAG, 0,
88                                     NULL, &config);
89 
90   // The returned block should tell us which string pool to get the value, if it
91   // is a string.
92   EXPECT_GE(block, 0);
93 
94   // We expect the default resource to be selected since it is the only resource
95   // configuration.
96   EXPECT_EQ(0, expectedConfig.compare(config));
97 
98   EXPECT_EQ(Res_value::TYPE_STRING, val.dataType);
99 }
100 
TEST_F(SplitTest,TestGetResourceFromSplit)101 TEST_F(SplitTest, TestGetResourceFromSplit) {
102   ResTable_config expectedConfig;
103   makeConfigFrench(&expectedConfig);
104 
105   ResTable table;
106   table.setParameters(&expectedConfig);
107 
108   ASSERT_EQ(NO_ERROR,
109             table.add(basic_contents_.data(), basic_contents_.size()));
110   ASSERT_EQ(NO_ERROR, table.add(basic_de_fr_contents_.data(),
111                                 basic_de_fr_contents_.size()));
112 
113   Res_value val;
114   ResTable_config config;
115   ssize_t block = table.getResource(R::string::test1, &val, MAY_NOT_BE_BAG, 0,
116                                     NULL, &config);
117 
118   EXPECT_GE(block, 0);
119 
120   EXPECT_EQ(0, expectedConfig.compare(config));
121 
122   EXPECT_EQ(Res_value::TYPE_STRING, val.dataType);
123 }
124 
TEST_F(SplitTest,ResourcesFromBaseAndSplitHaveSameNames)125 TEST_F(SplitTest, ResourcesFromBaseAndSplitHaveSameNames) {
126   ResTable_config expectedConfig;
127   makeConfigFrench(&expectedConfig);
128 
129   ResTable table;
130   table.setParameters(&expectedConfig);
131 
132   ASSERT_EQ(NO_ERROR,
133             table.add(basic_contents_.data(), basic_contents_.size()));
134 
135   ResTable::resource_name baseName;
136   EXPECT_TRUE(table.getResourceName(R::string::test1, false, &baseName));
137 
138   ASSERT_EQ(NO_ERROR, table.add(basic_de_fr_contents_.data(),
139                                 basic_de_fr_contents_.size()));
140 
141   ResTable::resource_name frName;
142   EXPECT_TRUE(table.getResourceName(R::string::test1, false, &frName));
143 
144   EXPECT_EQ(String16(baseName.package, baseName.packageLen),
145             String16(frName.package, frName.packageLen));
146 
147   EXPECT_EQ(String16(baseName.type, baseName.typeLen),
148             String16(frName.type, frName.typeLen));
149 
150   EXPECT_EQ(String16(baseName.name, baseName.nameLen),
151             String16(frName.name, frName.nameLen));
152 }
153 
TEST_F(SplitTest,TypeEntrySpecFlagsAreUpdated)154 TEST_F(SplitTest, TypeEntrySpecFlagsAreUpdated) {
155   ResTable_config defaultConfig;
156   memset(&defaultConfig, 0, sizeof(defaultConfig));
157 
158   ResTable table;
159   ASSERT_EQ(NO_ERROR,
160             table.add(basic_contents_.data(), basic_contents_.size()));
161 
162   Res_value val;
163   uint32_t specFlags = 0;
164   ssize_t block = table.getResource(R::string::test1, &val, MAY_NOT_BE_BAG, 0,
165                                     &specFlags, NULL);
166   EXPECT_GE(block, 0);
167 
168   EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), specFlags);
169 
170   ASSERT_EQ(NO_ERROR, table.add(basic_de_fr_contents_.data(),
171                                 basic_de_fr_contents_.size()));
172 
173   uint32_t frSpecFlags = 0;
174   block = table.getResource(R::string::test1, &val, MAY_NOT_BE_BAG, 0,
175                             &frSpecFlags, NULL);
176   ASSERT_GE(block, 0);
177 
178   EXPECT_EQ(static_cast<uint32_t>(ResTable_config::CONFIG_LOCALE | ResTable_typeSpec::SPEC_PUBLIC),
179             frSpecFlags);
180 }
181 
TEST_F(SplitTest,SelectBestDensity)182 TEST_F(SplitTest, SelectBestDensity) {
183   ResTable_config baseConfig;
184   memset(&baseConfig, 0, sizeof(baseConfig));
185   baseConfig.density = ResTable_config::DENSITY_XHIGH;
186   baseConfig.sdkVersion = 21;
187 
188   ResTable table;
189   table.setParameters(&baseConfig);
190   ASSERT_EQ(NO_ERROR,
191             table.add(basic_contents_.data(), basic_contents_.size()));
192   ASSERT_EQ(NO_ERROR, table.add(basic_hdpi_contents_.data(),
193                                 basic_hdpi_contents_.size()));
194 
195   EXPECT_TRUE(IsStringEqual(table, R::string::density, "hdpi"));
196 
197   ASSERT_EQ(NO_ERROR, table.add(basic_xhdpi_contents_.data(),
198                                 basic_xhdpi_contents_.size()));
199 
200   EXPECT_TRUE(IsStringEqual(table, R::string::density, "xhdpi"));
201 
202   ASSERT_EQ(NO_ERROR, table.add(basic_xxhdpi_contents_.data(),
203                                 basic_xxhdpi_contents_.size()));
204 
205   EXPECT_TRUE(IsStringEqual(table, R::string::density, "xhdpi"));
206 
207   baseConfig.density = ResTable_config::DENSITY_XXHIGH;
208   table.setParameters(&baseConfig);
209 
210   EXPECT_TRUE(IsStringEqual(table, R::string::density, "xxhdpi"));
211 }
212 
TEST_F(SplitTest,TestNewResourceIsAccessible)213 TEST_F(SplitTest, TestNewResourceIsAccessible) {
214   ResTable table;
215   ASSERT_EQ(NO_ERROR,
216             table.add(basic_contents_.data(), basic_contents_.size()));
217 
218   Res_value val;
219   ssize_t block = table.getResource(R::string::test3, &val, MAY_NOT_BE_BAG);
220   EXPECT_LT(block, 0);
221 
222   ASSERT_EQ(NO_ERROR,
223             table.add(feature_contents_.data(), feature_contents_.size()));
224 
225   block = table.getResource(R::string::test3, &val, MAY_NOT_BE_BAG);
226   ASSERT_GE(block, 0);
227 
228   EXPECT_EQ(Res_value::TYPE_STRING, val.dataType);
229 }
230 
TEST_F(SplitTest,TestNewResourceNameHasCorrectName)231 TEST_F(SplitTest, TestNewResourceNameHasCorrectName) {
232   ResTable table;
233   ASSERT_EQ(NO_ERROR,
234             table.add(basic_contents_.data(), basic_contents_.size()));
235 
236   ResTable::resource_name name;
237   EXPECT_FALSE(table.getResourceName(R::string::test3, false, &name));
238 
239   ASSERT_EQ(NO_ERROR,
240             table.add(feature_contents_.data(), feature_contents_.size()));
241 
242   ASSERT_TRUE(table.getResourceName(R::string::test3, false, &name));
243 
244   EXPECT_EQ(String16("com.android.basic"),
245             String16(name.package, name.packageLen));
246 
247   EXPECT_EQ(String16("string"), String16(name.type, name.typeLen));
248 
249   EXPECT_EQ(String16("test3"), String16(name.name, name.nameLen));
250 }
251 
TEST_F(SplitTest,TestNewResourceIsAccessibleByName)252 TEST_F(SplitTest, TestNewResourceIsAccessibleByName) {
253   ResTable table;
254   ASSERT_EQ(NO_ERROR,
255             table.add(basic_contents_.data(), basic_contents_.size()));
256   ASSERT_EQ(NO_ERROR,
257             table.add(feature_contents_.data(), feature_contents_.size()));
258 
259   const String16 name("test3");
260   const String16 type("string");
261   const String16 package("com.android.basic");
262   ASSERT_EQ(
263       R::string::test3,
264       table.identifierForName(name.string(), name.size(), type.string(),
265                               type.size(), package.string(), package.size()));
266 }
267 
268 }  // namespace
269