• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 #include "proto/ProtoSerialize.h"
18 
19 #include "ResourceTable.h"
20 #include "test/Test.h"
21 
22 using ::google::protobuf::io::StringOutputStream;
23 
24 namespace aapt {
25 
TEST(TableProtoSerializer,SerializeSinglePackage)26 TEST(TableProtoSerializer, SerializeSinglePackage) {
27   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), "res/layout/main.xml")
32           .AddReference("com.app.a:layout/other", ResourceId(0x7f020001), "com.app.a:layout/main")
33           .AddString("com.app.a:string/text", {}, "hi")
34           .AddValue("com.app.a:id/foo", {}, util::make_unique<Id>())
35           .SetSymbolState("com.app.a:bool/foo", {}, SymbolState::kUndefined, true /*allow_new*/)
36           .Build();
37 
38   Symbol public_symbol;
39   public_symbol.state = SymbolState::kPublic;
40   ASSERT_TRUE(table->SetSymbolState(
41       test::ParseNameOrDie("com.app.a:layout/main"), ResourceId(0x7f020000),
42       public_symbol, context->GetDiagnostics()));
43 
44   Id* id = test::GetValue<Id>(table.get(), "com.app.a:id/foo");
45   ASSERT_NE(nullptr, id);
46 
47   // Make a plural.
48   std::unique_ptr<Plural> plural = util::make_unique<Plural>();
49   plural->values[Plural::One] =
50       util::make_unique<String>(table->string_pool.MakeRef("one"));
51   ASSERT_TRUE(table->AddResource(test::ParseNameOrDie("com.app.a:plurals/hey"),
52                                  ConfigDescription{}, {}, std::move(plural),
53                                  context->GetDiagnostics()));
54 
55   // Make a resource with different products.
56   ASSERT_TRUE(table->AddResource(
57       test::ParseNameOrDie("com.app.a:integer/one"),
58       test::ParseConfigOrDie("land"), {},
59       test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 123u),
60       context->GetDiagnostics()));
61   ASSERT_TRUE(table->AddResource(
62       test::ParseNameOrDie("com.app.a:integer/one"),
63       test::ParseConfigOrDie("land"), "tablet",
64       test::BuildPrimitive(android::Res_value::TYPE_INT_DEC, 321u),
65       context->GetDiagnostics()));
66 
67   // Make a reference with both resource name and resource ID.
68   // The reference should point to a resource outside of this table to test that
69   // both
70   // name and id get serialized.
71   Reference expected_ref;
72   expected_ref.name = test::ParseNameOrDie("android:layout/main");
73   expected_ref.id = ResourceId(0x01020000);
74   ASSERT_TRUE(table->AddResource(test::ParseNameOrDie("com.app.a:layout/abc"),
75                                  ConfigDescription::DefaultConfig(), {},
76                                  util::make_unique<Reference>(expected_ref),
77                                  context->GetDiagnostics()));
78 
79   std::unique_ptr<pb::ResourceTable> pb_table = SerializeTableToPb(table.get());
80   ASSERT_NE(nullptr, pb_table);
81 
82   std::unique_ptr<ResourceTable> new_table = DeserializeTableFromPb(
83       *pb_table, Source{"test"}, context->GetDiagnostics());
84   ASSERT_NE(nullptr, new_table);
85 
86   Id* new_id = test::GetValue<Id>(new_table.get(), "com.app.a:id/foo");
87   ASSERT_NE(nullptr, new_id);
88   EXPECT_EQ(id->IsWeak(), new_id->IsWeak());
89 
90   Maybe<ResourceTable::SearchResult> result =
91       new_table->FindResource(test::ParseNameOrDie("com.app.a:layout/main"));
92   AAPT_ASSERT_TRUE(result);
93   EXPECT_EQ(SymbolState::kPublic, result.value().type->symbol_status.state);
94   EXPECT_EQ(SymbolState::kPublic, result.value().entry->symbol_status.state);
95 
96   result = new_table->FindResource(test::ParseNameOrDie("com.app.a:bool/foo"));
97   ASSERT_TRUE(result);
98   EXPECT_EQ(SymbolState::kUndefined, result.value().entry->symbol_status.state);
99   EXPECT_TRUE(result.value().entry->symbol_status.allow_new);
100 
101   // Find the product-dependent values
102   BinaryPrimitive* prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
103       new_table.get(), "com.app.a:integer/one", test::ParseConfigOrDie("land"), "");
104   ASSERT_NE(nullptr, prim);
105   EXPECT_EQ(123u, prim->value.data);
106 
107   prim = test::GetValueForConfigAndProduct<BinaryPrimitive>(
108       new_table.get(), "com.app.a:integer/one", test::ParseConfigOrDie("land"), "tablet");
109   ASSERT_NE(nullptr, prim);
110   EXPECT_EQ(321u, prim->value.data);
111 
112   Reference* actual_ref = test::GetValue<Reference>(new_table.get(), "com.app.a:layout/abc");
113   ASSERT_NE(nullptr, actual_ref);
114   AAPT_ASSERT_TRUE(actual_ref->name);
115   AAPT_ASSERT_TRUE(actual_ref->id);
116   EXPECT_EQ(expected_ref.name.value(), actual_ref->name.value());
117   EXPECT_EQ(expected_ref.id.value(), actual_ref->id.value());
118 }
119 
TEST(TableProtoSerializer,SerializeFileHeader)120 TEST(TableProtoSerializer, SerializeFileHeader) {
121   std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
122 
123   ResourceFile f;
124   f.config = test::ParseConfigOrDie("hdpi-v9");
125   f.name = test::ParseNameOrDie("com.app.a:layout/main");
126   f.source.path = "res/layout-hdpi-v9/main.xml";
127   f.exported_symbols.push_back(
128       SourcedResourceName{test::ParseNameOrDie("id/unchecked"), 23u});
129 
130   const std::string expected_data1 = "123";
131   const std::string expected_data2 = "1234";
132 
133   std::string output_str;
134   {
135     std::unique_ptr<pb::CompiledFile> pb_file1 = SerializeCompiledFileToPb(f);
136 
137     f.name.entry = "__" + f.name.entry + "$0";
138     std::unique_ptr<pb::CompiledFile> pb_file2 = SerializeCompiledFileToPb(f);
139 
140     StringOutputStream out_stream(&output_str);
141     CompiledFileOutputStream out_file_stream(&out_stream);
142     out_file_stream.WriteLittleEndian32(2);
143     out_file_stream.WriteCompiledFile(pb_file1.get());
144     out_file_stream.WriteData(expected_data1.data(), expected_data1.size());
145     out_file_stream.WriteCompiledFile(pb_file2.get());
146     out_file_stream.WriteData(expected_data2.data(), expected_data2.size());
147     ASSERT_FALSE(out_file_stream.HadError());
148   }
149 
150   CompiledFileInputStream in_file_stream(output_str.data(), output_str.size());
151   uint32_t num_files = 0;
152   ASSERT_TRUE(in_file_stream.ReadLittleEndian32(&num_files));
153   ASSERT_EQ(2u, num_files);
154 
155   // Read the first compiled file.
156 
157   pb::CompiledFile new_pb_file;
158   ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_file));
159 
160   std::unique_ptr<ResourceFile> file = DeserializeCompiledFileFromPb(
161       new_pb_file, Source("test"), context->GetDiagnostics());
162   ASSERT_NE(nullptr, file);
163 
164   uint64_t offset, len;
165   ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len));
166 
167   std::string actual_data(output_str.data() + offset, len);
168   EXPECT_EQ(expected_data1, actual_data);
169 
170   // Expect the data to be aligned.
171   EXPECT_EQ(0u, offset & 0x03);
172 
173   ASSERT_EQ(1u, file->exported_symbols.size());
174   EXPECT_EQ(test::ParseNameOrDie("id/unchecked"),
175             file->exported_symbols[0].name);
176 
177   // Read the second compiled file.
178 
179   ASSERT_TRUE(in_file_stream.ReadCompiledFile(&new_pb_file));
180 
181   file = DeserializeCompiledFileFromPb(new_pb_file, Source("test"),
182                                        context->GetDiagnostics());
183   ASSERT_NE(nullptr, file);
184 
185   ASSERT_TRUE(in_file_stream.ReadDataMetaData(&offset, &len));
186 
187   actual_data = std::string(output_str.data() + offset, len);
188   EXPECT_EQ(expected_data2, actual_data);
189 
190   // Expect the data to be aligned.
191   EXPECT_EQ(0u, offset & 0x03);
192 }
193 
TEST(TableProtoSerializer,DeserializeCorruptHeaderSafely)194 TEST(TableProtoSerializer, DeserializeCorruptHeaderSafely) {
195   ResourceFile f;
196   std::unique_ptr<pb::CompiledFile> pb_file = SerializeCompiledFileToPb(f);
197 
198   const std::string expected_data = "1234";
199 
200   std::string output_str;
201   {
202     StringOutputStream out_stream(&output_str);
203     CompiledFileOutputStream out_file_stream(&out_stream);
204     out_file_stream.WriteLittleEndian32(1);
205     out_file_stream.WriteCompiledFile(pb_file.get());
206     out_file_stream.WriteData(expected_data.data(), expected_data.size());
207     ASSERT_FALSE(out_file_stream.HadError());
208   }
209 
210   output_str[4] = 0xff;
211 
212   CompiledFileInputStream in_file_stream(output_str.data(), output_str.size());
213 
214   uint32_t num_files = 0;
215   EXPECT_TRUE(in_file_stream.ReadLittleEndian32(&num_files));
216   EXPECT_EQ(1u, num_files);
217 
218   pb::CompiledFile new_pb_file;
219   EXPECT_FALSE(in_file_stream.ReadCompiledFile(&new_pb_file));
220 
221   uint64_t offset, len;
222   EXPECT_FALSE(in_file_stream.ReadDataMetaData(&offset, &len));
223 }
224 
225 }  // namespace aapt
226