blob: 2c9388b7d711be28677d2036caf5b7b7c8695bfe [file] [log] [blame]
Ryan Mitchell479fa392019-01-02 17:15:39 -08001/*
2 * Copyright (C) 2018 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 "Convert.h"
18
19#include "LoadedApk.h"
Iurii Makhno054e4332022-10-12 16:03:03 +000020#include "test/Common.h"
Ryan Mitchell479fa392019-01-02 17:15:39 -080021#include "test/Test.h"
Winsonf54c9a12019-01-23 12:39:40 -080022#include "ziparchive/zip_archive.h"
Ryan Mitchell479fa392019-01-02 17:15:39 -080023
Iurii Makhno054e4332022-10-12 16:03:03 +000024using testing::AnyOfArray;
Ryan Mitchell479fa392019-01-02 17:15:39 -080025using testing::Eq;
26using testing::Ne;
Iurii Makhno054e4332022-10-12 16:03:03 +000027using testing::Not;
28using testing::SizeIs;
Ryan Mitchell479fa392019-01-02 17:15:39 -080029
30namespace aapt {
Iurii Makhno054e4332022-10-12 16:03:03 +000031using namespace aapt::test;
Ryan Mitchell479fa392019-01-02 17:15:39 -080032
33using ConvertTest = CommandTestFixture;
34
35TEST_F(ConvertTest, RemoveRawXmlStrings) {
36 StdErrDiagnostics diag;
37 const std::string compiled_files_dir = GetTestPath("compiled");
38 ASSERT_TRUE(CompileFile(GetTestPath("res/xml/test.xml"), R"(<Item AgentCode="007"/>)",
39 compiled_files_dir, &diag));
40
41 const std::string out_apk = GetTestPath("out.apk");
42 std::vector<std::string> link_args = {
43 "--manifest", GetDefaultManifest(),
44 "-o", out_apk,
45 "--keep-raw-values",
46 "--proto-format"
47 };
48
49 ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag));
50
51 const std::string out_convert_apk = GetTestPath("out_convert.apk");
52 std::vector<android::StringPiece> convert_args = {
53 "-o", out_convert_apk,
54 "--output-format", "binary",
55 out_apk,
56 };
57 ASSERT_THAT(ConvertCommand().Execute(convert_args, &std::cerr), Eq(0));
58
59 // Load the binary xml tree
60 android::ResXMLTree tree;
61 std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(out_convert_apk, &diag);
Winsonb7be7932019-01-23 11:10:52 -080062
63 std::unique_ptr<io::IData> data = OpenFileAsData(apk.get(), "res/xml/test.xml");
64 ASSERT_THAT(data, Ne(nullptr));
65
66 AssertLoadXml(apk.get(), data.get(), &tree);
Ryan Mitchell479fa392019-01-02 17:15:39 -080067
68 // Check that the raw string index has not been assigned
69 EXPECT_THAT(tree.getAttributeValueStringID(0), Eq(-1));
70}
71
72TEST_F(ConvertTest, KeepRawXmlStrings) {
73 StdErrDiagnostics diag;
74 const std::string compiled_files_dir = GetTestPath("compiled");
75 ASSERT_TRUE(CompileFile(GetTestPath("res/xml/test.xml"), R"(<Item AgentCode="007"/>)",
76 compiled_files_dir, &diag));
77
78 const std::string out_apk = GetTestPath("out.apk");
79 std::vector<std::string> link_args = {
80 "--manifest", GetDefaultManifest(),
81 "-o", out_apk,
82 "--keep-raw-values",
83 "--proto-format"
84 };
85
86 ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag));
87
88 const std::string out_convert_apk = GetTestPath("out_convert.apk");
89 std::vector<android::StringPiece> convert_args = {
90 "-o", out_convert_apk,
91 "--output-format", "binary",
92 "--keep-raw-values",
93 out_apk,
94 };
95 ASSERT_THAT(ConvertCommand().Execute(convert_args, &std::cerr), Eq(0));
96
97 // Load the binary xml tree
98 android::ResXMLTree tree;
99 std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(out_convert_apk, &diag);
Winsonb7be7932019-01-23 11:10:52 -0800100
101 std::unique_ptr<io::IData> data = OpenFileAsData(apk.get(), "res/xml/test.xml");
102 ASSERT_THAT(data, Ne(nullptr));
103
104 AssertLoadXml(apk.get(), data.get(), &tree);
Ryan Mitchell479fa392019-01-02 17:15:39 -0800105
106 // Check that the raw string index has been set to the correct string pool entry
107 int32_t raw_index = tree.getAttributeValueStringID(0);
108 ASSERT_THAT(raw_index, Ne(-1));
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000109 EXPECT_THAT(android::util::GetString(tree.getStrings(), static_cast<size_t>(raw_index)),
110 Eq("007"));
Ryan Mitchell479fa392019-01-02 17:15:39 -0800111}
112
Winsonf54c9a12019-01-23 12:39:40 -0800113TEST_F(ConvertTest, DuplicateEntriesWrittenOnce) {
114 StdErrDiagnostics diag;
115 const std::string apk_path =
116 file::BuildPath({android::base::GetExecutableDirectory(),
117 "integration-tests", "ConvertTest", "duplicate_entries.apk"});
118
119 const std::string out_convert_apk = GetTestPath("out_convert.apk");
120 std::vector<android::StringPiece> convert_args = {
121 "-o", out_convert_apk,
122 "--output-format", "proto",
123 apk_path
124 };
125 ASSERT_THAT(ConvertCommand().Execute(convert_args, &std::cerr), Eq(0));
126
127 ZipArchiveHandle handle;
128 ASSERT_THAT(OpenArchive(out_convert_apk.c_str(), &handle), Eq(0));
129
130 void* cookie = nullptr;
131
Elliott Hughes65c8b862019-05-10 17:11:36 -0700132 int32_t result = StartIteration(handle, &cookie, "res/theme/10", "");
Winsonf54c9a12019-01-23 12:39:40 -0800133
134 // If this is -5, that means we've found a duplicate entry and this test has failed
135 EXPECT_THAT(result, Eq(0));
136
137 // But if read succeeds, verify only one res/theme/10 entry
138 int count = 0;
139
140 // Can't pass nullptrs into Next()
Elliott Hughes78de4f92019-06-14 15:28:38 -0700141 std::string zip_name;
Winsonf54c9a12019-01-23 12:39:40 -0800142 ZipEntry zip_data;
143
144 while ((result = Next(cookie, &zip_data, &zip_name)) == 0) {
145 count++;
146 }
147
148 EndIteration(cookie);
149
150 EXPECT_THAT(count, Eq(1));
151}
152
Iurii Makhno054e4332022-10-12 16:03:03 +0000153TEST_F(ConvertTest, ConvertWithResourceNameCollapsing) {
154 StdErrDiagnostics diag;
155 const std::string compiled_files_dir = GetTestPath("compiled");
156 ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"),
157 R"(<resources>
158 <string name="first">string</string>
159 <string name="second">string</string>
160 <string name="third">another string</string>
161
162 <bool name="bool1">true</bool>
163 <bool name="bool2">true</bool>
164 <bool name="bool3">true</bool>
165
166 <integer name="int1">10</integer>
167 <integer name="int2">10</integer>
168 </resources>)",
169 compiled_files_dir, &diag));
170 std::string resource_config_path = GetTestPath("resource-config");
171 WriteFile(resource_config_path, "integer/int1#no_collapse\ninteger/int2#no_collapse");
172
173 const std::string proto_apk = GetTestPath("proto.apk");
174 std::vector<std::string> link_args = {
175 "--proto-format", "--manifest", GetDefaultManifest(kDefaultPackageName), "-o", proto_apk,
176 };
177 ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag));
178
179 const std::string binary_apk = GetTestPath("binary.apk");
180 std::vector<android::StringPiece> convert_args = {"-o",
181 binary_apk,
182 "--output-format",
183 "binary",
184 "--collapse-resource-names",
185 "--deduplicate-entry-values",
186 "--resources-config-path",
187 resource_config_path,
188 proto_apk};
189 ASSERT_THAT(ConvertCommand().Execute(convert_args, &std::cerr), Eq(0));
190
191 std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(binary_apk, &diag);
192 for (const auto& package : apk->GetResourceTable()->packages) {
193 for (const auto& type : package->types) {
194 switch (type->named_type.type) {
195 case ResourceType::kBool:
196 EXPECT_THAT(type->entries, SizeIs(3));
197 for (const auto& entry : type->entries) {
198 auto value = ValueCast<BinaryPrimitive>(entry->FindValue({})->value.get())->value;
199 EXPECT_THAT(value.data, Eq(0xffffffffu));
200 }
201 break;
202 case ResourceType::kString:
203 EXPECT_THAT(type->entries, SizeIs(3));
204 for (const auto& entry : type->entries) {
205 auto value = ValueCast<String>(entry->FindValue({})->value.get())->value;
206 EXPECT_THAT(entry->name, Not(AnyOfArray({"first", "second", "third"})));
207 EXPECT_THAT(*value, AnyOfArray({"string", "another string"}));
208 }
209 break;
210 case ResourceType::kInteger:
211 EXPECT_THAT(type->entries, SizeIs(2));
212 for (const auto& entry : type->entries) {
213 auto value = ValueCast<BinaryPrimitive>(entry->FindValue({})->value.get())->value;
214 EXPECT_THAT(entry->name, AnyOfArray({"int1", "int2"}));
215 EXPECT_THAT(value.data, Eq(10));
216 }
217 break;
218 default:
219 break;
220 }
221 }
222 }
223}
224
Elliott Hughes65c8b862019-05-10 17:11:36 -0700225} // namespace aapt