TableProtoSerializer_test.cpp revision 58a20a6482a56a262fd83a617482641e3a981db1
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 "ResourceTable.h"
18#include "proto/ProtoSerialize.h"
19#include "test/Test.h"
20
21namespace aapt {
22
23TEST(TableProtoSerializer, SerializeSinglePackage) {
24    std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
25    std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
26            .setPackageId("com.app.a", 0x7f)
27            .addFileReference("com.app.a:layout/main", ResourceId(0x7f020000),
28                              "res/layout/main.xml")
29            .addReference("com.app.a:layout/other", ResourceId(0x7f020001),
30                          "com.app.a:layout/main")
31            .addString("com.app.a:string/text", {}, "hi")
32            .addValue("com.app.a:id/foo", {}, util::make_unique<Id>())
33            .build();
34
35    Symbol publicSymbol;
36    publicSymbol.state = SymbolState::kPublic;
37    ASSERT_TRUE(table->setSymbolState(test::parseNameOrDie("com.app.a:layout/main"),
38                                      ResourceId(0x7f020000),
39                                      publicSymbol, context->getDiagnostics()));
40
41    Id* id = test::getValue<Id>(table.get(), "com.app.a:id/foo");
42    ASSERT_NE(nullptr, id);
43
44    // Make a plural.
45    std::unique_ptr<Plural> plural = util::make_unique<Plural>();
46    plural->values[Plural::One] = util::make_unique<String>(table->stringPool.makeRef("one"));
47    ASSERT_TRUE(table->addResource(test::parseNameOrDie("com.app.a:plurals/hey"),
48                                   ConfigDescription{}, {}, std::move(plural),
49                                   context->getDiagnostics()));
50
51    // Make a resource with different products.
52    ASSERT_TRUE(table->addResource(test::parseNameOrDie("com.app.a:integer/one"),
53                                   test::parseConfigOrDie("land"), {},
54                                   test::buildPrimitive(android::Res_value::TYPE_INT_DEC, 123u),
55                                   context->getDiagnostics()));
56    ASSERT_TRUE(table->addResource(test::parseNameOrDie("com.app.a:integer/one"),
57                                       test::parseConfigOrDie("land"), "tablet",
58                                       test::buildPrimitive(android::Res_value::TYPE_INT_DEC, 321u),
59                                       context->getDiagnostics()));
60
61    // Make a reference with both resource name and resource ID.
62    // The reference should point to a resource outside of this table to test that both
63    // name and id get serialized.
64    Reference expectedRef;
65    expectedRef.name = test::parseNameOrDie("android:layout/main");
66    expectedRef.id = ResourceId(0x01020000);
67    ASSERT_TRUE(table->addResource(test::parseNameOrDie("com.app.a:layout/abc"),
68                                   ConfigDescription::defaultConfig(), {},
69                                   util::make_unique<Reference>(expectedRef),
70                                   context->getDiagnostics()));
71
72    std::unique_ptr<pb::ResourceTable> pbTable = serializeTableToPb(table.get());
73    ASSERT_NE(nullptr, pbTable);
74
75    std::unique_ptr<ResourceTable> newTable = deserializeTableFromPb(*pbTable,
76                                                                     Source{ "test" },
77                                                                     context->getDiagnostics());
78    ASSERT_NE(nullptr, newTable);
79
80    Id* newId = test::getValue<Id>(newTable.get(), "com.app.a:id/foo");
81    ASSERT_NE(nullptr, newId);
82    EXPECT_EQ(id->isWeak(), newId->isWeak());
83
84    Maybe<ResourceTable::SearchResult> result = newTable->findResource(
85            test::parseNameOrDie("com.app.a:layout/main"));
86    AAPT_ASSERT_TRUE(result);
87    EXPECT_EQ(SymbolState::kPublic, result.value().type->symbolStatus.state);
88    EXPECT_EQ(SymbolState::kPublic, result.value().entry->symbolStatus.state);
89
90    // Find the product-dependent values
91    BinaryPrimitive* prim = test::getValueForConfigAndProduct<BinaryPrimitive>(
92            newTable.get(), "com.app.a:integer/one", test::parseConfigOrDie("land"), "");
93    ASSERT_NE(nullptr, prim);
94    EXPECT_EQ(123u, prim->value.data);
95
96    prim = test::getValueForConfigAndProduct<BinaryPrimitive>(
97            newTable.get(), "com.app.a:integer/one", test::parseConfigOrDie("land"), "tablet");
98    ASSERT_NE(nullptr, prim);
99    EXPECT_EQ(321u, prim->value.data);
100
101    Reference* actualRef = test::getValue<Reference>(newTable.get(), "com.app.a:layout/abc");
102    ASSERT_NE(nullptr, actualRef);
103    AAPT_ASSERT_TRUE(actualRef->name);
104    AAPT_ASSERT_TRUE(actualRef->id);
105    EXPECT_EQ(expectedRef.name.value(), actualRef->name.value());
106    EXPECT_EQ(expectedRef.id.value(), actualRef->id.value());
107}
108
109TEST(TableProtoSerializer, SerializeFileHeader) {
110    std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
111
112    ResourceFile f;
113    f.config = test::parseConfigOrDie("hdpi-v9");
114    f.name = test::parseNameOrDie("com.app.a:layout/main");
115    f.source.path = "res/layout-hdpi-v9/main.xml";
116    f.exportedSymbols.push_back(SourcedResourceName{ test::parseNameOrDie("id/unchecked"), 23u });
117
118    const std::string expectedData = "1234";
119
120    std::unique_ptr<pb::CompiledFile> pbFile = serializeCompiledFileToPb(f);
121
122    std::string outputStr;
123    {
124        google::protobuf::io::StringOutputStream outStream(&outputStr);
125        CompiledFileOutputStream outFileStream(&outStream, pbFile.get());
126
127        ASSERT_TRUE(outFileStream.Write(expectedData.data(), expectedData.size()));
128        ASSERT_TRUE(outFileStream.Finish());
129    }
130
131    CompiledFileInputStream inFileStream(outputStr.data(), outputStr.size());
132    const pb::CompiledFile* newPbFile = inFileStream.CompiledFile();
133    ASSERT_NE(nullptr, newPbFile);
134
135    std::unique_ptr<ResourceFile> file = deserializeCompiledFileFromPb(*newPbFile, Source("test"),
136                                                                       context->getDiagnostics());
137    ASSERT_NE(nullptr, file);
138
139    std::string actualData((const char*)inFileStream.data(), inFileStream.size());
140    EXPECT_EQ(expectedData, actualData);
141    EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(inFileStream.data()) & 0x03);
142
143    ASSERT_EQ(1u, file->exportedSymbols.size());
144    EXPECT_EQ(test::parseNameOrDie("id/unchecked"), file->exportedSymbols[0].name);
145}
146
147TEST(TableProtoSerializer, DeserializeCorruptHeaderSafely) {
148    ResourceFile f;
149    std::unique_ptr<pb::CompiledFile> pbFile = serializeCompiledFileToPb(f);
150
151    const std::string expectedData = "1234";
152
153    std::string outputStr;
154    {
155        google::protobuf::io::StringOutputStream outStream(&outputStr);
156        CompiledFileOutputStream outFileStream(&outStream, pbFile.get());
157
158        ASSERT_TRUE(outFileStream.Write(expectedData.data(), expectedData.size()));
159        ASSERT_TRUE(outFileStream.Finish());
160    }
161
162    outputStr[0] = 0xff;
163
164    CompiledFileInputStream inFileStream(outputStr.data(), outputStr.size());
165    EXPECT_EQ(nullptr, inFileStream.CompiledFile());
166    EXPECT_EQ(nullptr, inFileStream.data());
167    EXPECT_EQ(0u, inFileStream.size());
168}
169
170} // namespace aapt
171