blob: 2bd976796f53120cb5d244638789140d20ca0120 [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
17#include "ResourceTable.h"
18#include "proto/ProtoSerialize.h"
Adam Lesinskid0f116b2016-07-08 15:00:32 -070019#include "test/Test.h"
Adam Lesinski59e04c62016-02-04 15:59:23 -080020
Adam Lesinski5eeaadd2016-08-25 12:26:56 -070021using namespace google::protobuf::io;
22
Adam Lesinski59e04c62016-02-04 15:59:23 -080023namespace aapt {
24
25TEST(TableProtoSerializer, SerializeSinglePackage) {
26 std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
27 std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
Adam Lesinskid0f116b2016-07-08 15:00:32 -070028 .setPackageId("com.app.a", 0x7f)
Adam Lesinski58a20a62016-07-25 17:56:58 -070029 .addFileReference("com.app.a:layout/main", ResourceId(0x7f020000),
Adam Lesinskid0f116b2016-07-08 15:00:32 -070030 "res/layout/main.xml")
Adam Lesinski58a20a62016-07-25 17:56:58 -070031 .addReference("com.app.a:layout/other", ResourceId(0x7f020001),
32 "com.app.a:layout/main")
33 .addString("com.app.a:string/text", {}, "hi")
34 .addValue("com.app.a:id/foo", {}, util::make_unique<Id>())
Adam Lesinski59e04c62016-02-04 15:59:23 -080035 .build();
36
37 Symbol publicSymbol;
38 publicSymbol.state = SymbolState::kPublic;
Adam Lesinski58a20a62016-07-25 17:56:58 -070039 ASSERT_TRUE(table->setSymbolState(test::parseNameOrDie("com.app.a:layout/main"),
Adam Lesinski59e04c62016-02-04 15:59:23 -080040 ResourceId(0x7f020000),
41 publicSymbol, context->getDiagnostics()));
42
Adam Lesinski58a20a62016-07-25 17:56:58 -070043 Id* id = test::getValue<Id>(table.get(), "com.app.a:id/foo");
Adam Lesinski59e04c62016-02-04 15:59:23 -080044 ASSERT_NE(nullptr, id);
45
46 // Make a plural.
47 std::unique_ptr<Plural> plural = util::make_unique<Plural>();
Adam Lesinskid0f116b2016-07-08 15:00:32 -070048 plural->values[Plural::One] = util::make_unique<String>(table->stringPool.makeRef("one"));
Adam Lesinski58a20a62016-07-25 17:56:58 -070049 ASSERT_TRUE(table->addResource(test::parseNameOrDie("com.app.a:plurals/hey"),
Adam Lesinskid0f116b2016-07-08 15:00:32 -070050 ConfigDescription{}, {}, std::move(plural),
Adam Lesinski59e04c62016-02-04 15:59:23 -080051 context->getDiagnostics()));
52
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -080053 // Make a resource with different products.
Adam Lesinski58a20a62016-07-25 17:56:58 -070054 ASSERT_TRUE(table->addResource(test::parseNameOrDie("com.app.a:integer/one"),
Adam Lesinskid0f116b2016-07-08 15:00:32 -070055 test::parseConfigOrDie("land"), {},
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -080056 test::buildPrimitive(android::Res_value::TYPE_INT_DEC, 123u),
57 context->getDiagnostics()));
Adam Lesinski58a20a62016-07-25 17:56:58 -070058 ASSERT_TRUE(table->addResource(test::parseNameOrDie("com.app.a:integer/one"),
Adam Lesinskid0f116b2016-07-08 15:00:32 -070059 test::parseConfigOrDie("land"), "tablet",
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -080060 test::buildPrimitive(android::Res_value::TYPE_INT_DEC, 321u),
61 context->getDiagnostics()));
62
Adam Lesinski64587af2016-02-18 18:33:06 -080063 // Make a reference with both resource name and resource ID.
64 // The reference should point to a resource outside of this table to test that both
65 // name and id get serialized.
66 Reference expectedRef;
Adam Lesinski58a20a62016-07-25 17:56:58 -070067 expectedRef.name = test::parseNameOrDie("android:layout/main");
Adam Lesinski64587af2016-02-18 18:33:06 -080068 expectedRef.id = ResourceId(0x01020000);
Adam Lesinski58a20a62016-07-25 17:56:58 -070069 ASSERT_TRUE(table->addResource(test::parseNameOrDie("com.app.a:layout/abc"),
Adam Lesinskid0f116b2016-07-08 15:00:32 -070070 ConfigDescription::defaultConfig(), {},
Adam Lesinski64587af2016-02-18 18:33:06 -080071 util::make_unique<Reference>(expectedRef),
72 context->getDiagnostics()));
73
Adam Lesinski59e04c62016-02-04 15:59:23 -080074 std::unique_ptr<pb::ResourceTable> pbTable = serializeTableToPb(table.get());
75 ASSERT_NE(nullptr, pbTable);
76
77 std::unique_ptr<ResourceTable> newTable = deserializeTableFromPb(*pbTable,
78 Source{ "test" },
79 context->getDiagnostics());
80 ASSERT_NE(nullptr, newTable);
81
Adam Lesinski58a20a62016-07-25 17:56:58 -070082 Id* newId = test::getValue<Id>(newTable.get(), "com.app.a:id/foo");
Adam Lesinski59e04c62016-02-04 15:59:23 -080083 ASSERT_NE(nullptr, newId);
84 EXPECT_EQ(id->isWeak(), newId->isWeak());
85
86 Maybe<ResourceTable::SearchResult> result = newTable->findResource(
Adam Lesinski58a20a62016-07-25 17:56:58 -070087 test::parseNameOrDie("com.app.a:layout/main"));
Adam Lesinski59e04c62016-02-04 15:59:23 -080088 AAPT_ASSERT_TRUE(result);
89 EXPECT_EQ(SymbolState::kPublic, result.value().type->symbolStatus.state);
90 EXPECT_EQ(SymbolState::kPublic, result.value().entry->symbolStatus.state);
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -080091
92 // Find the product-dependent values
93 BinaryPrimitive* prim = test::getValueForConfigAndProduct<BinaryPrimitive>(
Adam Lesinski58a20a62016-07-25 17:56:58 -070094 newTable.get(), "com.app.a:integer/one", test::parseConfigOrDie("land"), "");
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -080095 ASSERT_NE(nullptr, prim);
96 EXPECT_EQ(123u, prim->value.data);
97
98 prim = test::getValueForConfigAndProduct<BinaryPrimitive>(
Adam Lesinski58a20a62016-07-25 17:56:58 -070099 newTable.get(), "com.app.a:integer/one", test::parseConfigOrDie("land"), "tablet");
Adam Lesinskie4bb9eb2016-02-12 22:18:51 -0800100 ASSERT_NE(nullptr, prim);
101 EXPECT_EQ(321u, prim->value.data);
Adam Lesinski64587af2016-02-18 18:33:06 -0800102
Adam Lesinski58a20a62016-07-25 17:56:58 -0700103 Reference* actualRef = test::getValue<Reference>(newTable.get(), "com.app.a:layout/abc");
Adam Lesinski64587af2016-02-18 18:33:06 -0800104 ASSERT_NE(nullptr, actualRef);
105 AAPT_ASSERT_TRUE(actualRef->name);
106 AAPT_ASSERT_TRUE(actualRef->id);
107 EXPECT_EQ(expectedRef.name.value(), actualRef->name.value());
108 EXPECT_EQ(expectedRef.id.value(), actualRef->id.value());
Adam Lesinski59e04c62016-02-04 15:59:23 -0800109}
110
111TEST(TableProtoSerializer, SerializeFileHeader) {
112 std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
113
114 ResourceFile f;
115 f.config = test::parseConfigOrDie("hdpi-v9");
Adam Lesinski58a20a62016-07-25 17:56:58 -0700116 f.name = test::parseNameOrDie("com.app.a:layout/main");
Adam Lesinski59e04c62016-02-04 15:59:23 -0800117 f.source.path = "res/layout-hdpi-v9/main.xml";
Adam Lesinski58a20a62016-07-25 17:56:58 -0700118 f.exportedSymbols.push_back(SourcedResourceName{ test::parseNameOrDie("id/unchecked"), 23u });
Adam Lesinski59e04c62016-02-04 15:59:23 -0800119
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700120 const std::string expectedData1 = "123";
121 const std::string expectedData2 = "1234";
Adam Lesinski59e04c62016-02-04 15:59:23 -0800122
123 std::string outputStr;
124 {
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700125 std::unique_ptr<pb::CompiledFile> pbFile1 = serializeCompiledFileToPb(f);
Adam Lesinski59e04c62016-02-04 15:59:23 -0800126
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700127 f.name.entry = "__" + f.name.entry + "$0";
128 std::unique_ptr<pb::CompiledFile> pbFile2 = serializeCompiledFileToPb(f);
129
130 StringOutputStream outStream(&outputStr);
131 CompiledFileOutputStream outFileStream(&outStream);
132 outFileStream.WriteLittleEndian32(2);
133 outFileStream.WriteCompiledFile(pbFile1.get());
134 outFileStream.WriteData(expectedData1.data(), expectedData1.size());
135 outFileStream.WriteCompiledFile(pbFile2.get());
136 outFileStream.WriteData(expectedData2.data(), expectedData2.size());
137 ASSERT_FALSE(outFileStream.HadError());
Adam Lesinski59e04c62016-02-04 15:59:23 -0800138 }
139
140 CompiledFileInputStream inFileStream(outputStr.data(), outputStr.size());
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700141 uint32_t numFiles = 0;
142 ASSERT_TRUE(inFileStream.ReadLittleEndian32(&numFiles));
143 ASSERT_EQ(2u, numFiles);
Adam Lesinski59e04c62016-02-04 15:59:23 -0800144
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700145 // Read the first compiled file.
146
147 pb::CompiledFile newPbFile;
148 ASSERT_TRUE(inFileStream.ReadCompiledFile(&newPbFile));
149
150 std::unique_ptr<ResourceFile> file = deserializeCompiledFileFromPb(newPbFile, Source("test"),
Adam Lesinski59e04c62016-02-04 15:59:23 -0800151 context->getDiagnostics());
152 ASSERT_NE(nullptr, file);
153
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700154 uint64_t offset, len;
155 ASSERT_TRUE(inFileStream.ReadDataMetaData(&offset, &len));
156
157 std::string actualData(outputStr.data() + offset, len);
158 EXPECT_EQ(expectedData1, actualData);
159
160 // Expect the data to be aligned.
161 EXPECT_EQ(0u, offset & 0x03);
Adam Lesinski59e04c62016-02-04 15:59:23 -0800162
163 ASSERT_EQ(1u, file->exportedSymbols.size());
Adam Lesinski58a20a62016-07-25 17:56:58 -0700164 EXPECT_EQ(test::parseNameOrDie("id/unchecked"), file->exportedSymbols[0].name);
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700165
166 // Read the second compiled file.
167
168 ASSERT_TRUE(inFileStream.ReadCompiledFile(&newPbFile));
169
170 file = deserializeCompiledFileFromPb(newPbFile, Source("test"), context->getDiagnostics());
171 ASSERT_NE(nullptr, file);
172
173 ASSERT_TRUE(inFileStream.ReadDataMetaData(&offset, &len));
174
175 actualData = std::string(outputStr.data() + offset, len);
176 EXPECT_EQ(expectedData2, actualData);
177
178 // Expect the data to be aligned.
179 EXPECT_EQ(0u, offset & 0x03);
Adam Lesinski59e04c62016-02-04 15:59:23 -0800180}
181
Adam Lesinski64587af2016-02-18 18:33:06 -0800182TEST(TableProtoSerializer, DeserializeCorruptHeaderSafely) {
183 ResourceFile f;
184 std::unique_ptr<pb::CompiledFile> pbFile = serializeCompiledFileToPb(f);
185
186 const std::string expectedData = "1234";
187
188 std::string outputStr;
189 {
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700190 StringOutputStream outStream(&outputStr);
191 CompiledFileOutputStream outFileStream(&outStream);
192 outFileStream.WriteLittleEndian32(1);
193 outFileStream.WriteCompiledFile(pbFile.get());
194 outFileStream.WriteData(expectedData.data(), expectedData.size());
195 ASSERT_FALSE(outFileStream.HadError());
Adam Lesinski64587af2016-02-18 18:33:06 -0800196 }
197
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700198 outputStr[4] = 0xff;
Adam Lesinski64587af2016-02-18 18:33:06 -0800199
200 CompiledFileInputStream inFileStream(outputStr.data(), outputStr.size());
Adam Lesinski5eeaadd2016-08-25 12:26:56 -0700201
202 uint32_t numFiles = 0;
203 EXPECT_TRUE(inFileStream.ReadLittleEndian32(&numFiles));
204 EXPECT_EQ(1u, numFiles);
205
206 pb::CompiledFile newPbFile;
207 EXPECT_FALSE(inFileStream.ReadCompiledFile(&newPbFile));
208
209 uint64_t offset, len;
210 EXPECT_FALSE(inFileStream.ReadDataMetaData(&offset, &len));
Adam Lesinski64587af2016-02-18 18:33:06 -0800211}
212
Adam Lesinski59e04c62016-02-04 15:59:23 -0800213} // namespace aapt