blob: fdd5197167efd14f13a3b534bcd26b8d22dfa79d [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 Lesinski5eeaadd2016-08-25 12:26:56 -070023
Adam Lesinski59e04c62016-02-04 15:59:23 -080024namespace aapt {
25
26TEST(TableProtoSerializer, SerializeSinglePackage) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070027 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
28 std::unique_ptr<ResourceTable> table =
29 test::ResourceTableBuilder()
30 .SetPackageId("com.app.a", 0x7f)
31 .AddFileReference("com.app.a:layout/main", ResourceId(0x7f020000),
32 "res/layout/main.xml")
33 .AddReference("com.app.a:layout/other", ResourceId(0x7f020001),
34 "com.app.a:layout/main")
35 .AddString("com.app.a:string/text", {}, "hi")
36 .AddValue("com.app.a:id/foo", {}, util::make_unique<Id>())
37 .Build();
Adam Lesinski59e04c62016-02-04 15:59:23 -080038
Adam Lesinskice5e56e2016-10-21 17:56:45 -070039 Symbol public_symbol;
40 public_symbol.state = SymbolState::kPublic;
41 ASSERT_TRUE(table->SetSymbolState(
42 test::ParseNameOrDie("com.app.a:layout/main"), ResourceId(0x7f020000),
43 public_symbol, context->GetDiagnostics()));
Adam Lesinski59e04c62016-02-04 15:59:23 -080044
Adam Lesinskice5e56e2016-10-21 17:56:45 -070045 Id* id = test::GetValue<Id>(table.get(), "com.app.a:id/foo");
46 ASSERT_NE(nullptr, id);
Adam Lesinski59e04c62016-02-04 15:59:23 -080047
Adam Lesinskice5e56e2016-10-21 17:56:45 -070048 // Make a plural.
49 std::unique_ptr<Plural> plural = util::make_unique<Plural>();
50 plural->values[Plural::One] =
51 util::make_unique<String>(table->string_pool.MakeRef("one"));
52 ASSERT_TRUE(table->AddResource(test::ParseNameOrDie("com.app.a:plurals/hey"),
53 ConfigDescription{}, {}, std::move(plural),
54 context->GetDiagnostics()));
Adam Lesinski59e04c62016-02-04 15:59:23 -080055
Adam Lesinskice5e56e2016-10-21 17:56:45 -070056 // Make a resource with different products.
57 ASSERT_TRUE(table->AddResource(
58 test::ParseNameOrDie("com.app.a:integer/one"),
59 test::ParseConfigOrDie("land"), {},
60 test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 123u),
61 context->GetDiagnostics()));
62 ASSERT_TRUE(table->AddResource(
63 test::ParseNameOrDie("com.app.a:integer/one"),
64 test::ParseConfigOrDie("land"), "tablet",
65 test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 321u),
66 context->GetDiagnostics()));
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -080067
Adam Lesinskice5e56e2016-10-21 17:56:45 -070068 // Make a reference with both resource name and resource ID.
69 // The reference should point to a resource outside of this table to test that
70 // both
71 // name and id get serialized.
72 Reference expected_ref;
73 expected_ref.name = test::ParseNameOrDie("android:layout/main");
74 expected_ref.id = ResourceId(0x01020000);
75 ASSERT_TRUE(table->AddResource(test::ParseNameOrDie("com.app.a:layout/abc"),
76 ConfigDescription::DefaultConfig(), {},
77 util::make_unique<Reference>(expected_ref),
78 context->GetDiagnostics()));
Adam Lesinski64587af2016-02-18 18:33:06 -080079
Adam Lesinskice5e56e2016-10-21 17:56:45 -070080 std::unique_ptr<pb::ResourceTable> pb_table = SerializeTableToPb(table.get());
81 ASSERT_NE(nullptr, pb_table);
Adam Lesinski59e04c62016-02-04 15:59:23 -080082
Adam Lesinskice5e56e2016-10-21 17:56:45 -070083 std::unique_ptr<ResourceTable> new_table = DeserializeTableFromPb(
84 *pb_table, Source{"test"}, context->GetDiagnostics());
85 ASSERT_NE(nullptr, new_table);
Adam Lesinski59e04c62016-02-04 15:59:23 -080086
Adam Lesinskice5e56e2016-10-21 17:56:45 -070087 Id* new_id = test::GetValue<Id>(new_table.get(), "com.app.a:id/foo");
88 ASSERT_NE(nullptr, new_id);
89 EXPECT_EQ(id->IsWeak(), new_id->IsWeak());
Adam Lesinski59e04c62016-02-04 15:59:23 -080090
Adam Lesinskice5e56e2016-10-21 17:56:45 -070091 Maybe<ResourceTable::SearchResult> result =
92 new_table->FindResource(test::ParseNameOrDie("com.app.a:layout/main"));
93 AAPT_ASSERT_TRUE(result);
94 EXPECT_EQ(SymbolState::kPublic, result.value().type->symbol_status.state);
95 EXPECT_EQ(SymbolState::kPublic, result.value().entry->symbol_status.state);
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -080096
Adam Lesinskice5e56e2016-10-21 17:56:45 -070097 // Find the product-dependent values
98 BinaryPrimitive* prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
99 new_table.get(), "com.app.a:integer/one", test::ParseConfigOrDie("land"),
100 "");
101 ASSERT_NE(nullptr, prim);
102 EXPECT_EQ(123u, prim->value.data);
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800103
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700104 prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
105 new_table.get(), "com.app.a:integer/one", test::ParseConfigOrDie("land"),
106 "tablet");
107 ASSERT_NE(nullptr, prim);
108 EXPECT_EQ(321u, prim->value.data);
Adam Lesinski64587af2016-02-18 18:33:06 -0800109
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700110 Reference* actual_ref =
111 test::GetValue<Reference>(new_table.get(), "com.app.a:layout/abc");
112 ASSERT_NE(nullptr, actual_ref);
113 AAPT_ASSERT_TRUE(actual_ref->name);
114 AAPT_ASSERT_TRUE(actual_ref->id);
115 EXPECT_EQ(expected_ref.name.value(), actual_ref->name.value());
116 EXPECT_EQ(expected_ref.id.value(), actual_ref->id.value());
Adam Lesinski59e04c62016-02-04 15:59:23 -0800117}
118
119TEST(TableProtoSerializer, SerializeFileHeader) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700120 std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
Adam Lesinski59e04c62016-02-04 15:59:23 -0800121
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700122 ResourceFile f;
123 f.config = test::ParseConfigOrDie("hdpi-v9");
124 f.name = test::ParseNameOrDie("com.app.a:layout/main");
125 f.source.path = "res/layout-hdpi-v9/main.xml";
126 f.exported_symbols.push_back(
127 SourcedResourceName{test::ParseNameOrDie("id/unchecked"), 23u});
Adam Lesinski59e04c62016-02-04 15:59:23 -0800128
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700129 const std::string expected_data1 = "123";
130 const std::string expected_data2 = "1234";
Adam Lesinski59e04c62016-02-04 15:59:23 -0800131
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700132 std::string output_str;
133 {
134 std::unique_ptr<pb::CompiledFile> pb_file1 = SerializeCompiledFileToPb(f);
Adam Lesinski59e04c62016-02-04 15:59:23 -0800135
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700136 f.name.entry = "__" + f.name.entry + "$0";
137 std::unique_ptr<pb::CompiledFile> pb_file2 = SerializeCompiledFileToPb(f);
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700138
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700139 StringOutputStream out_stream(&output_str);
140 CompiledFileOutputStream out_file_stream(&out_stream);
141 out_file_stream.WriteLittleEndian32(2);
142 out_file_stream.WriteCompiledFile(pb_file1.get());
143 out_file_stream.WriteData(expected_data1.data(), expected_data1.size());
144 out_file_stream.WriteCompiledFile(pb_file2.get());
145 out_file_stream.WriteData(expected_data2.data(), expected_data2.size());
146 ASSERT_FALSE(out_file_stream.HadError());
147 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800148
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700149 CompiledFileInputStream in_file_stream(output_str.data(), output_str.size());
150 uint32_t num_files = 0;
151 ASSERT_TRUE(in_file_stream.ReadLittleEndian32(&num_files));
152 ASSERT_EQ(2u, num_files);
Adam Lesinski59e04c62016-02-04 15:59:23 -0800153
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700154 // Read the first compiled file.
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700155
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700156 pb::CompiledFile new_pb_file;
157 ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_file));
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700158
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700159 std::unique_ptr<ResourceFile> file = DeserializeCompiledFileFromPb(
160 new_pb_file, Source("test"), context->GetDiagnostics());
161 ASSERT_NE(nullptr, file);
Adam Lesinski59e04c62016-02-04 15:59:23 -0800162
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700163 uint64_t offset, len;
164 ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len));
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700165
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700166 std::string actual_data(output_str.data() + offset, len);
167 EXPECT_EQ(expected_data1, actual_data);
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700168
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700169 // Expect the data to be aligned.
170 EXPECT_EQ(0u, offset & 0x03);
Adam Lesinski59e04c62016-02-04 15:59:23 -0800171
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700172 ASSERT_EQ(1u, file->exported_symbols.size());
173 EXPECT_EQ(test::ParseNameOrDie("id/unchecked"),
174 file->exported_symbols[0].name);
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700175
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700176 // Read the second compiled file.
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700177
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700178 ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_file));
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700179
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700180 file = DeserializeCompiledFileFromPb(new_pb_file, Source("test"),
181 context->GetDiagnostics());
182 ASSERT_NE(nullptr, file);
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700183
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700184 ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len));
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700185
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700186 actual_data = std::string(output_str.data() + offset, len);
187 EXPECT_EQ(expected_data2, 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}
192
Adam Lesinski64587af2016-02-18 18:33:06 -0800193TEST(TableProtoSerializer, DeserializeCorruptHeaderSafely) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700194 ResourceFile f;
195 std::unique_ptr<pb::CompiledFile> pb_file = SerializeCompiledFileToPb(f);
Adam Lesinski64587af2016-02-18 18:33:06 -0800196
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700197 const std::string expected_data = "1234";
Adam Lesinski64587af2016-02-18 18:33:06 -0800198
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700199 std::string output_str;
200 {
201 StringOutputStream out_stream(&output_str);
202 CompiledFileOutputStream out_file_stream(&out_stream);
203 out_file_stream.WriteLittleEndian32(1);
204 out_file_stream.WriteCompiledFile(pb_file.get());
205 out_file_stream.WriteData(expected_data.data(), expected_data.size());
206 ASSERT_FALSE(out_file_stream.HadError());
207 }
Adam Lesinski64587af2016-02-18 18:33:06 -0800208
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700209 output_str[4] = 0xff;
Adam Lesinski64587af2016-02-18 18:33:06 -0800210
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700211 CompiledFileInputStream in_file_stream(output_str.data(), output_str.size());
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700212
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700213 uint32_t num_files = 0;
214 EXPECT_TRUE(in_file_stream.ReadLittleEndian32(&num_files));
215 EXPECT_EQ(1u, num_files);
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700216
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700217 pb::CompiledFile new_pb_file;
218 EXPECT_FALSE(in_file_stream.ReadCompiledFile(&new_pb_file));
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700219
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700220 uint64_t offset, len;
221 EXPECT_FALSE(in_file_stream.ReadDataMetaData(&offset, &len));
Adam Lesinski64587af2016-02-18 18:33:06 -0800222}
223
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700224} // namespace aapt