blob: 80608b3d9c05e4b359c05099ba01ed5577f65930 [file] [log] [blame]
Adam Lesinski59e04c62016-02-04 15:59:23 -08001/*
2 * Copyright (C) 2016 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
Adam Lesinski59e04c62016-02-04 15:59:23 -080017#include "proto/ProtoSerialize.h"
Adam Lesinskice5e56e2016-10-21 17:56:45 -070018
19#include "ResourceTable.h"
Adam Lesinskid0f116b2016-07-08 15:00:32 -070020#include "test/Test.h"
Adam Lesinski59e04c62016-02-04 15:59:23 -080021
Adam Lesinskice5e56e2016-10-21 17:56:45 -070022using ::google::protobuf::io::StringOutputStream;
Adam Lesinski08535002017-08-04 16:15:17 -070023using ::testing::Eq;
Adam Lesinskia45893a2017-05-30 15:19:02 -070024using ::testing::NotNull;
Adam Lesinski08535002017-08-04 16:15:17 -070025using ::testing::SizeIs;
Adam Lesinski5eeaadd2016-08-25 12:26:56 -070026
Adam Lesinski59e04c62016-02-04 15:59:23 -080027namespace aapt {
28
29TEST(TableProtoSerializer, SerializeSinglePackage) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070030 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
31 std::unique_ptr<ResourceTable> table =
32 test::ResourceTableBuilder()
33 .SetPackageId("com.app.a", 0x7f)
Adam Lesinski4488f1c2017-05-26 17:33:38 -070034 .AddFileReference("com.app.a:layout/main", ResourceId(0x7f020000), "res/layout/main.xml")
35 .AddReference("com.app.a:layout/other", ResourceId(0x7f020001), "com.app.a:layout/main")
Adam Lesinskice5e56e2016-10-21 17:56:45 -070036 .AddString("com.app.a:string/text", {}, "hi")
37 .AddValue("com.app.a:id/foo", {}, util::make_unique<Id>())
Adam Lesinski4488f1c2017-05-26 17:33:38 -070038 .SetSymbolState("com.app.a:bool/foo", {}, SymbolState::kUndefined, true /*allow_new*/)
Adam Lesinskice5e56e2016-10-21 17:56:45 -070039 .Build();
Adam Lesinski59e04c62016-02-04 15:59:23 -080040
Adam Lesinskice5e56e2016-10-21 17:56:45 -070041 Symbol public_symbol;
42 public_symbol.state = SymbolState::kPublic;
Adam Lesinski08535002017-08-04 16:15:17 -070043 ASSERT_TRUE(table->SetSymbolState(test::ParseNameOrDie("com.app.a:layout/main"),
44 ResourceId(0x7f020000), public_symbol,
45 context->GetDiagnostics()));
Adam Lesinski59e04c62016-02-04 15:59:23 -080046
Adam Lesinskice5e56e2016-10-21 17:56:45 -070047 Id* id = test::GetValue<Id>(table.get(), "com.app.a:id/foo");
Adam Lesinski08535002017-08-04 16:15:17 -070048 ASSERT_THAT(id, NotNull());
Adam Lesinski59e04c62016-02-04 15:59:23 -080049
Adam Lesinskice5e56e2016-10-21 17:56:45 -070050 // Make a plural.
51 std::unique_ptr<Plural> plural = util::make_unique<Plural>();
Adam Lesinskia45893a2017-05-30 15:19:02 -070052 plural->values[Plural::One] = util::make_unique<String>(table->string_pool.MakeRef("one"));
Adam Lesinskice5e56e2016-10-21 17:56:45 -070053 ASSERT_TRUE(table->AddResource(test::ParseNameOrDie("com.app.a:plurals/hey"),
54 ConfigDescription{}, {}, std::move(plural),
55 context->GetDiagnostics()));
Adam Lesinski59e04c62016-02-04 15:59:23 -080056
Adam Lesinski08535002017-08-04 16:15:17 -070057 // Make a styled string.
58 StyleString style_string;
59 style_string.str = "hello";
60 style_string.spans.push_back(Span{"b", 0u, 4u});
61 ASSERT_TRUE(
62 table->AddResource(test::ParseNameOrDie("com.app.a:string/styled"), ConfigDescription{}, {},
63 util::make_unique<StyledString>(table->string_pool.MakeRef(style_string)),
64 context->GetDiagnostics()));
65
Adam Lesinskice5e56e2016-10-21 17:56:45 -070066 // Make a resource with different products.
67 ASSERT_TRUE(table->AddResource(
68 test::ParseNameOrDie("com.app.a:integer/one"),
69 test::ParseConfigOrDie("land"), {},
70 test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 123u),
71 context->GetDiagnostics()));
72 ASSERT_TRUE(table->AddResource(
73 test::ParseNameOrDie("com.app.a:integer/one"),
74 test::ParseConfigOrDie("land"), "tablet",
75 test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 321u),
76 context->GetDiagnostics()));
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -080077
Adam Lesinskice5e56e2016-10-21 17:56:45 -070078 // Make a reference with both resource name and resource ID.
Adam Lesinski08535002017-08-04 16:15:17 -070079 // The reference should point to a resource outside of this table to test that both name and id
80 // get serialized.
Adam Lesinskice5e56e2016-10-21 17:56:45 -070081 Reference expected_ref;
82 expected_ref.name = test::ParseNameOrDie("android:layout/main");
83 expected_ref.id = ResourceId(0x01020000);
84 ASSERT_TRUE(table->AddResource(test::ParseNameOrDie("com.app.a:layout/abc"),
85 ConfigDescription::DefaultConfig(), {},
86 util::make_unique<Reference>(expected_ref),
87 context->GetDiagnostics()));
Adam Lesinski64587af2016-02-18 18:33:06 -080088
Adam Lesinskice5e56e2016-10-21 17:56:45 -070089 std::unique_ptr<pb::ResourceTable> pb_table = SerializeTableToPb(table.get());
Adam Lesinskia45893a2017-05-30 15:19:02 -070090 ASSERT_THAT(pb_table, NotNull());
Adam Lesinski59e04c62016-02-04 15:59:23 -080091
Adam Lesinskice5e56e2016-10-21 17:56:45 -070092 std::unique_ptr<ResourceTable> new_table = DeserializeTableFromPb(
93 *pb_table, Source{"test"}, context->GetDiagnostics());
Adam Lesinskia45893a2017-05-30 15:19:02 -070094 ASSERT_THAT(new_table, NotNull());
Adam Lesinski59e04c62016-02-04 15:59:23 -080095
Adam Lesinskice5e56e2016-10-21 17:56:45 -070096 Id* new_id = test::GetValue<Id>(new_table.get(), "com.app.a:id/foo");
Adam Lesinskia45893a2017-05-30 15:19:02 -070097 ASSERT_THAT(new_id, NotNull());
Adam Lesinski08535002017-08-04 16:15:17 -070098 EXPECT_THAT(new_id->IsWeak(), Eq(id->IsWeak()));
Adam Lesinski59e04c62016-02-04 15:59:23 -080099
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700100 Maybe<ResourceTable::SearchResult> result =
101 new_table->FindResource(test::ParseNameOrDie("com.app.a:layout/main"));
Adam Lesinskia45893a2017-05-30 15:19:02 -0700102 ASSERT_TRUE(result);
Adam Lesinski08535002017-08-04 16:15:17 -0700103
104 EXPECT_THAT(result.value().type->symbol_status.state, Eq(SymbolState::kPublic));
105 EXPECT_THAT(result.value().entry->symbol_status.state, Eq(SymbolState::kPublic));
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800106
Adam Lesinski4488f1c2017-05-26 17:33:38 -0700107 result = new_table->FindResource(test::ParseNameOrDie("com.app.a:bool/foo"));
108 ASSERT_TRUE(result);
Adam Lesinski08535002017-08-04 16:15:17 -0700109 EXPECT_THAT(result.value().entry->symbol_status.state, Eq(SymbolState::kUndefined));
Adam Lesinski4488f1c2017-05-26 17:33:38 -0700110 EXPECT_TRUE(result.value().entry->symbol_status.allow_new);
111
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700112 // Find the product-dependent values
113 BinaryPrimitive* prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
Adam Lesinski4488f1c2017-05-26 17:33:38 -0700114 new_table.get(), "com.app.a:integer/one", test::ParseConfigOrDie("land"), "");
Adam Lesinskia45893a2017-05-30 15:19:02 -0700115 ASSERT_THAT(prim, NotNull());
Adam Lesinski08535002017-08-04 16:15:17 -0700116 EXPECT_THAT(prim->value.data, Eq(123u));
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800117
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700118 prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
Adam Lesinski4488f1c2017-05-26 17:33:38 -0700119 new_table.get(), "com.app.a:integer/one", test::ParseConfigOrDie("land"), "tablet");
Adam Lesinskia45893a2017-05-30 15:19:02 -0700120 ASSERT_THAT(prim, NotNull());
Adam Lesinski08535002017-08-04 16:15:17 -0700121 EXPECT_THAT(prim->value.data, Eq(321u));
Adam Lesinski64587af2016-02-18 18:33:06 -0800122
Adam Lesinski4488f1c2017-05-26 17:33:38 -0700123 Reference* actual_ref = test::GetValue<Reference>(new_table.get(), "com.app.a:layout/abc");
Adam Lesinskia45893a2017-05-30 15:19:02 -0700124 ASSERT_THAT(actual_ref, NotNull());
125 ASSERT_TRUE(actual_ref->name);
126 ASSERT_TRUE(actual_ref->id);
Adam Lesinski08535002017-08-04 16:15:17 -0700127 EXPECT_THAT(*actual_ref, Eq(expected_ref));
128
129 StyledString* actual_styled_str =
130 test::GetValue<StyledString>(new_table.get(), "com.app.a:string/styled");
131 ASSERT_THAT(actual_styled_str, NotNull());
132 EXPECT_THAT(actual_styled_str->value->value, Eq("hello"));
133 ASSERT_THAT(actual_styled_str->value->spans, SizeIs(1u));
134 EXPECT_THAT(*actual_styled_str->value->spans[0].name, Eq("b"));
135 EXPECT_THAT(actual_styled_str->value->spans[0].first_char, Eq(0u));
136 EXPECT_THAT(actual_styled_str->value->spans[0].last_char, Eq(4u));
Adam Lesinski59e04c62016-02-04 15:59:23 -0800137}
138
139TEST(TableProtoSerializer, SerializeFileHeader) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700140 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
Adam Lesinski59e04c62016-02-04 15:59:23 -0800141
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700142 ResourceFile f;
143 f.config = test::ParseConfigOrDie("hdpi-v9");
144 f.name = test::ParseNameOrDie("com.app.a:layout/main");
145 f.source.path = "res/layout-hdpi-v9/main.xml";
146 f.exported_symbols.push_back(
147 SourcedResourceName{test::ParseNameOrDie("id/unchecked"), 23u});
Adam Lesinski59e04c62016-02-04 15:59:23 -0800148
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700149 const std::string expected_data1 = "123";
150 const std::string expected_data2 = "1234";
Adam Lesinski59e04c62016-02-04 15:59:23 -0800151
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700152 std::string output_str;
153 {
Adam Lesinski4ffea042017-08-10 15:37:28 -0700154 std::unique_ptr<pb::internal::CompiledFile> pb_file1 = SerializeCompiledFileToPb(f);
Adam Lesinski59e04c62016-02-04 15:59:23 -0800155
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700156 f.name.entry = "__" + f.name.entry + "$0";
Adam Lesinski4ffea042017-08-10 15:37:28 -0700157 std::unique_ptr<pb::internal::CompiledFile> pb_file2 = SerializeCompiledFileToPb(f);
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700158
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700159 StringOutputStream out_stream(&output_str);
160 CompiledFileOutputStream out_file_stream(&out_stream);
161 out_file_stream.WriteLittleEndian32(2);
162 out_file_stream.WriteCompiledFile(pb_file1.get());
163 out_file_stream.WriteData(expected_data1.data(), expected_data1.size());
164 out_file_stream.WriteCompiledFile(pb_file2.get());
165 out_file_stream.WriteData(expected_data2.data(), expected_data2.size());
166 ASSERT_FALSE(out_file_stream.HadError());
167 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800168
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700169 CompiledFileInputStream in_file_stream(output_str.data(), output_str.size());
170 uint32_t num_files = 0;
171 ASSERT_TRUE(in_file_stream.ReadLittleEndian32(&num_files));
172 ASSERT_EQ(2u, num_files);
Adam Lesinski59e04c62016-02-04 15:59:23 -0800173
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700174 // Read the first compiled file.
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700175
Adam Lesinski4ffea042017-08-10 15:37:28 -0700176 pb::internal::CompiledFile new_pb_file;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700177 ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_file));
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700178
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700179 std::unique_ptr<ResourceFile> file = DeserializeCompiledFileFromPb(
180 new_pb_file, Source("test"), context->GetDiagnostics());
Adam Lesinskia45893a2017-05-30 15:19:02 -0700181 ASSERT_THAT(file, NotNull());
Adam Lesinski59e04c62016-02-04 15:59:23 -0800182
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700183 uint64_t offset, len;
184 ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len));
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700185
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700186 std::string actual_data(output_str.data() + offset, len);
187 EXPECT_EQ(expected_data1, actual_data);
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700188
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700189 // Expect the data to be aligned.
190 EXPECT_EQ(0u, offset & 0x03);
Adam Lesinski59e04c62016-02-04 15:59:23 -0800191
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700192 ASSERT_EQ(1u, file->exported_symbols.size());
Adam Lesinskia45893a2017-05-30 15:19:02 -0700193 EXPECT_EQ(test::ParseNameOrDie("id/unchecked"), file->exported_symbols[0].name);
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700194
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700195 // Read the second compiled file.
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700196
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700197 ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_file));
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700198
Adam Lesinskia45893a2017-05-30 15:19:02 -0700199 file = DeserializeCompiledFileFromPb(new_pb_file, Source("test"), context->GetDiagnostics());
200 ASSERT_THAT(file, NotNull());
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700201
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700202 ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len));
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700203
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700204 actual_data = std::string(output_str.data() + offset, len);
205 EXPECT_EQ(expected_data2, actual_data);
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700206
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700207 // Expect the data to be aligned.
208 EXPECT_EQ(0u, offset & 0x03);
Adam Lesinski59e04c62016-02-04 15:59:23 -0800209}
210
Adam Lesinski64587af2016-02-18 18:33:06 -0800211TEST(TableProtoSerializer, DeserializeCorruptHeaderSafely) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700212 ResourceFile f;
Adam Lesinski4ffea042017-08-10 15:37:28 -0700213 std::unique_ptr<pb::internal::CompiledFile> pb_file = SerializeCompiledFileToPb(f);
Adam Lesinski64587af2016-02-18 18:33:06 -0800214
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700215 const std::string expected_data = "1234";
Adam Lesinski64587af2016-02-18 18:33:06 -0800216
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700217 std::string output_str;
218 {
219 StringOutputStream out_stream(&output_str);
220 CompiledFileOutputStream out_file_stream(&out_stream);
221 out_file_stream.WriteLittleEndian32(1);
222 out_file_stream.WriteCompiledFile(pb_file.get());
223 out_file_stream.WriteData(expected_data.data(), expected_data.size());
224 ASSERT_FALSE(out_file_stream.HadError());
225 }
Adam Lesinski64587af2016-02-18 18:33:06 -0800226
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700227 output_str[4] = 0xff;
Adam Lesinski64587af2016-02-18 18:33:06 -0800228
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700229 CompiledFileInputStream in_file_stream(output_str.data(), output_str.size());
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700230
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700231 uint32_t num_files = 0;
232 EXPECT_TRUE(in_file_stream.ReadLittleEndian32(&num_files));
233 EXPECT_EQ(1u, num_files);
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700234
Adam Lesinski4ffea042017-08-10 15:37:28 -0700235 pb::internal::CompiledFile new_pb_file;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700236 EXPECT_FALSE(in_file_stream.ReadCompiledFile(&new_pb_file));
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700237
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700238 uint64_t offset, len;
239 EXPECT_FALSE(in_file_stream.ReadDataMetaData(&offset, &len));
Adam Lesinski64587af2016-02-18 18:33:06 -0800240}
241
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700242} // namespace aapt