1 /*
2  * Copyright (C) 2021 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 <android-base/file.h>
18 #include <gtest/gtest.h>
19 #include <idmap2/FabricatedOverlay.h>
20 #include "TestHelpers.h"
21 
22 #include <fstream>
23 #include <utility>
24 
25 namespace android::idmap2 {
26 
TEST(FabricatedOverlayTests,OverlayInfo)27 TEST(FabricatedOverlayTests, OverlayInfo) {
28   auto overlay =
29       FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "com.example.target")
30           .SetOverlayable("TestResources")
31           .Build();
32 
33   ASSERT_TRUE(overlay);
34   auto container = FabricatedOverlayContainer::FromOverlay(std::move(*overlay));
35   auto info = container->FindOverlayInfo("SandTheme");
36   ASSERT_TRUE(info);
37   EXPECT_EQ("SandTheme", (*info).name);
38   EXPECT_EQ("TestResources", (*info).target_name);
39 
40   info = container->FindOverlayInfo("OceanTheme");
41   ASSERT_FALSE(info);
42 }
43 
TEST(FabricatedOverlayTests,SetResourceValue)44 TEST(FabricatedOverlayTests, SetResourceValue) {
45   auto path = GetTestDataPath() + "/overlay/res/drawable/android.png";
46   auto fd = android::base::unique_fd(::open(path.c_str(), O_RDONLY | O_CLOEXEC));
47   ASSERT_TRUE(fd > 0) << "errno " << errno << " for path " << path;
48 
49   auto overlay =
50       FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "com.example.target")
51           .SetResourceValue(
52               "com.example.target:integer/int1", Res_value::TYPE_INT_DEC, 1U, "port")
53           .SetResourceValue(
54               "com.example.target.split:integer/int2", Res_value::TYPE_INT_DEC, 2U, "land")
55           .SetResourceValue(
56               "string/int3", Res_value::TYPE_REFERENCE, 0x7f010000, "xxhdpi-v7")
57           .SetResourceValue(
58               "com.example.target:string/string1",
59               Res_value::TYPE_STRING,
60               "foobar",
61               "en-rUS-normal-xxhdpi-v21")
62           .SetResourceValue("com.example.target:drawable/dr1", fd, "port-xxhdpi-v7")
63           .setFrroPath("/foo/bar/biz.frro")
64           .Build();
65   ASSERT_TRUE(overlay);
66   auto container = FabricatedOverlayContainer::FromOverlay(std::move(*overlay));
67   auto info = container->FindOverlayInfo("SandTheme");
68   ASSERT_TRUE(info);
69   ASSERT_TRUE((*info).target_name.empty());
70 
71   auto crc = (*container).GetCrc();
72   ASSERT_TRUE(crc) << crc.GetErrorMessage();
73   EXPECT_NE(0U, *crc);
74 
75   auto pairs = container->GetOverlayData(*info);
76   ASSERT_TRUE(pairs);
77   ASSERT_EQ(5U, pairs->pairs.size());
78   auto string_pool = ResStringPool(pairs->string_pool_data->data.get(),
79                                         pairs->string_pool_data->data_length, false);
80 
81   auto& it = pairs->pairs[0];
82   ASSERT_EQ("com.example.target:drawable/dr1", it.resource_name);
83   auto entry = std::get_if<TargetValueWithConfig>(&it.value);
84   ASSERT_NE(nullptr, entry);
85   ASSERT_EQ(std::string("frro://foo/bar/biz.frro?offset=16&size=8341"),
86       string_pool.string8At(entry->value.data_value).value_or(""));
87   ASSERT_EQ(Res_value::TYPE_STRING, entry->value.data_type);
88   ASSERT_EQ("port-xxhdpi-v7", entry->config);
89 
90   it = pairs->pairs[1];
91   ASSERT_EQ("com.example.target:integer/int1", it.resource_name);
92   entry = std::get_if<TargetValueWithConfig>(&it.value);
93   ASSERT_NE(nullptr, entry);
94   ASSERT_EQ(1U, entry->value.data_value);
95   ASSERT_EQ(Res_value::TYPE_INT_DEC, entry->value.data_type);
96   ASSERT_EQ("port", entry->config);
97 
98   it = pairs->pairs[2];
99   ASSERT_EQ("com.example.target:string/int3", it.resource_name);
100   entry = std::get_if<TargetValueWithConfig>(&it.value);
101   ASSERT_NE(nullptr, entry);
102   ASSERT_EQ(0x7f010000, entry->value.data_value);
103   ASSERT_EQ(Res_value::TYPE_REFERENCE, entry->value.data_type);
104   ASSERT_EQ("xxhdpi-v7", entry->config);
105 
106   it = pairs->pairs[3];
107   ASSERT_EQ("com.example.target:string/string1", it.resource_name);
108   entry = std::get_if<TargetValueWithConfig>(&it.value);
109   ASSERT_NE(nullptr, entry);
110   ASSERT_EQ(Res_value::TYPE_STRING, entry->value.data_type);
111   ASSERT_EQ(std::string("foobar"), string_pool.string8At(entry->value.data_value).value_or(""));
112   ASSERT_EQ("en-rUS-normal-xxhdpi-v21", entry->config);
113 
114   it = pairs->pairs[4];
115   ASSERT_EQ("com.example.target.split:integer/int2", it.resource_name);
116   entry = std::get_if<TargetValueWithConfig>(&it.value);
117   ASSERT_NE(nullptr, entry);
118   ASSERT_EQ(2U, entry->value.data_value);
119   ASSERT_EQ(Res_value::TYPE_INT_DEC, entry->value.data_type);
120   ASSERT_EQ("land", entry->config);
121 }
122 
TEST(FabricatedOverlayTests,SetResourceValueBadArgs)123 TEST(FabricatedOverlayTests, SetResourceValueBadArgs) {
124   {
125     auto builder =
126         FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "com.example.target")
127             .SetResourceValue("int1", Res_value::TYPE_INT_DEC, 1U, "");
128     ASSERT_FALSE(builder.Build());
129   }
130   {
131     auto builder =
132         FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "com.example.target")
133             .SetResourceValue("com.example.target:int2", Res_value::TYPE_INT_DEC, 1U, "");
134     ASSERT_FALSE(builder.Build());
135   }
136 }
137 
TEST(FabricatedOverlayTests,SerializeAndDeserialize)138 TEST(FabricatedOverlayTests, SerializeAndDeserialize) {
139   auto overlay =
140       FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "com.example.target")
141           .SetOverlayable("TestResources")
142           .SetResourceValue("com.example.target:integer/int1", Res_value::TYPE_INT_DEC, 1U, "")
143           .SetResourceValue(
144               "com.example.target:string/string1", Res_value::TYPE_STRING, "foobar", "")
145           .Build();
146   ASSERT_TRUE(overlay);
147   TemporaryFile tf;
148   std::ofstream out(tf.path);
149   ASSERT_TRUE((*overlay).ToBinaryStream(out));
150   out.close();
151 
152   auto container = OverlayResourceContainer::FromPath(tf.path);
153   ASSERT_TRUE(container) << container.GetErrorMessage();
154   EXPECT_EQ(tf.path, (*container)->GetPath());
155 
156   auto crc = (*container)->GetCrc();
157   ASSERT_TRUE(crc) << crc.GetErrorMessage();
158   EXPECT_NE(0U, *crc);
159 
160   auto info = (*container)->FindOverlayInfo("SandTheme");
161   ASSERT_TRUE(info) << info.GetErrorMessage();
162   EXPECT_EQ("SandTheme", (*info).name);
163   EXPECT_EQ("TestResources", (*info).target_name);
164 
165   auto pairs = (*container)->GetOverlayData(*info);
166   ASSERT_TRUE(pairs) << pairs.GetErrorMessage();
167   EXPECT_EQ(2U, pairs->pairs.size());
168   auto string_pool = ResStringPool(pairs->string_pool_data->data.get(),
169                                         pairs->string_pool_data->data_length, false);
170 
171   auto& it = pairs->pairs[0];
172   ASSERT_EQ("com.example.target:integer/int1", it.resource_name);
173   auto entry = std::get_if<TargetValueWithConfig>(&it.value);
174   ASSERT_NE(nullptr, entry);
175   EXPECT_EQ(1U, entry->value.data_value);
176   EXPECT_EQ(Res_value::TYPE_INT_DEC, entry->value.data_type);
177 
178   it = pairs->pairs[1];
179   ASSERT_EQ("com.example.target:string/string1", it.resource_name);
180   entry = std::get_if<TargetValueWithConfig>(&it.value);
181   ASSERT_NE(nullptr, entry);
182   ASSERT_EQ(Res_value::TYPE_STRING, entry->value.data_type);
183   ASSERT_EQ(std::string("foobar"), string_pool.string8At(entry->value.data_value).value_or(""));
184 }
185 
186 }  // namespace android::idmap2
187