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