C++程序  |  359行  |  16.96 KB

// Copyright (C) 2018 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <android-base/file.h>
#include <android-base/test_utils.h>
#include <android/util/protobuf.h>
#include <android/util/ProtoOutputStream.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include "frameworks/base/libs/protoutil/tests/test.pb.h"

using android::sp;
using namespace android::base;
using namespace android::util;
using ::testing::StrEq;

static std::string flushToString(ProtoOutputStream* proto) {
    TemporaryFile tf;
    std::string content;

    EXPECT_NE(tf.fd, -1);
    EXPECT_TRUE(proto->flush(tf.fd));
    EXPECT_TRUE(ReadFileToString(tf.path, &content));
    return content;
}

static std::string iterateToString(ProtoOutputStream* proto) {
    std::string content;
    content.reserve(proto->size());
    sp<ProtoReader> reader = proto->data();
    while (reader->hasNext()) {
        content.push_back(reader->next());
    }
    return content;
}

TEST(ProtoOutputStreamTest, Primitives) {
    std::string s = "hello";
    const char b[5] = { 'a', 'p', 'p', 'l', 'e' };

    ProtoOutputStream proto;
    EXPECT_TRUE(proto.write(FIELD_TYPE_INT32 | PrimitiveProto::kValInt32FieldNumber, 123));
    EXPECT_TRUE(proto.write(FIELD_TYPE_INT64 | PrimitiveProto::kValInt64FieldNumber, -1LL));
    EXPECT_TRUE(proto.write(FIELD_TYPE_FLOAT | PrimitiveProto::kValFloatFieldNumber, -23.5f));
    EXPECT_TRUE(proto.write(FIELD_TYPE_DOUBLE | PrimitiveProto::kValDoubleFieldNumber, 324.5));
    EXPECT_TRUE(proto.write(FIELD_TYPE_UINT32 | PrimitiveProto::kValUint32FieldNumber, 3424));
    EXPECT_TRUE(proto.write(FIELD_TYPE_UINT64 | PrimitiveProto::kValUint64FieldNumber, 57LL));
    EXPECT_TRUE(proto.write(FIELD_TYPE_FIXED32 | PrimitiveProto::kValFixed32FieldNumber, -20));
    EXPECT_TRUE(proto.write(FIELD_TYPE_FIXED64 | PrimitiveProto::kValFixed64FieldNumber, -37LL));
    EXPECT_TRUE(proto.write(FIELD_TYPE_BOOL | PrimitiveProto::kValBoolFieldNumber, true));
    EXPECT_TRUE(proto.write(FIELD_TYPE_STRING | PrimitiveProto::kValStringFieldNumber, s));
    EXPECT_TRUE(proto.write(FIELD_TYPE_BYTES | PrimitiveProto::kValBytesFieldNumber, b, 5));
    EXPECT_TRUE(proto.write(FIELD_TYPE_SFIXED32 | PrimitiveProto::kValSfixed32FieldNumber, 63));
    EXPECT_TRUE(proto.write(FIELD_TYPE_SFIXED64 | PrimitiveProto::kValSfixed64FieldNumber, -54));
    EXPECT_TRUE(proto.write(FIELD_TYPE_SINT32 | PrimitiveProto::kValSint32FieldNumber, -533));
    EXPECT_TRUE(proto.write(FIELD_TYPE_SINT64 | PrimitiveProto::kValSint64FieldNumber, -61224762453LL));
    EXPECT_TRUE(proto.write(FIELD_TYPE_ENUM | PrimitiveProto::kValEnumFieldNumber, 2));

    PrimitiveProto primitives;
    ASSERT_TRUE(primitives.ParseFromString(flushToString(&proto)));
    EXPECT_EQ(primitives.val_int32(), 123);
    EXPECT_EQ(primitives.val_int64(), -1);
    EXPECT_EQ(primitives.val_float(), -23.5f);
    EXPECT_EQ(primitives.val_double(), 324.5f);
    EXPECT_EQ(primitives.val_uint32(), 3424);
    EXPECT_EQ(primitives.val_uint64(), 57);
    EXPECT_EQ(primitives.val_fixed32(), -20);
    EXPECT_EQ(primitives.val_fixed64(), -37);
    EXPECT_EQ(primitives.val_bool(), true);
    EXPECT_THAT(primitives.val_string(), StrEq(s.c_str()));
    EXPECT_THAT(primitives.val_bytes(), StrEq("apple"));
    EXPECT_EQ(primitives.val_sfixed32(), 63);
    EXPECT_EQ(primitives.val_sfixed64(), -54);
    EXPECT_EQ(primitives.val_sint32(), -533);
    EXPECT_EQ(primitives.val_sint64(), -61224762453LL);
    EXPECT_EQ(primitives.val_enum(), PrimitiveProto_Count_TWO);
}

TEST(ProtoOutputStreamTest, SerializeToStringPrimitives) {
    std::string s = "hello";
    const char b[5] = { 'a', 'p', 'p', 'l', 'e' };

    ProtoOutputStream proto;
    EXPECT_TRUE(proto.write(FIELD_TYPE_INT32 | PrimitiveProto::kValInt32FieldNumber, 123));
    EXPECT_TRUE(proto.write(FIELD_TYPE_INT64 | PrimitiveProto::kValInt64FieldNumber, -1LL));
    EXPECT_TRUE(proto.write(FIELD_TYPE_FLOAT | PrimitiveProto::kValFloatFieldNumber, -23.5f));
    EXPECT_TRUE(proto.write(FIELD_TYPE_DOUBLE | PrimitiveProto::kValDoubleFieldNumber, 324.5));
    EXPECT_TRUE(proto.write(FIELD_TYPE_UINT32 | PrimitiveProto::kValUint32FieldNumber, 3424));
    EXPECT_TRUE(proto.write(FIELD_TYPE_UINT64 | PrimitiveProto::kValUint64FieldNumber, 57LL));
    EXPECT_TRUE(proto.write(FIELD_TYPE_FIXED32 | PrimitiveProto::kValFixed32FieldNumber, -20));
    EXPECT_TRUE(proto.write(FIELD_TYPE_FIXED64 | PrimitiveProto::kValFixed64FieldNumber, -37LL));
    EXPECT_TRUE(proto.write(FIELD_TYPE_BOOL | PrimitiveProto::kValBoolFieldNumber, true));
    EXPECT_TRUE(proto.write(FIELD_TYPE_STRING | PrimitiveProto::kValStringFieldNumber, s));
    EXPECT_TRUE(proto.write(FIELD_TYPE_BYTES | PrimitiveProto::kValBytesFieldNumber, b, 5));
    EXPECT_TRUE(proto.write(FIELD_TYPE_SFIXED32 | PrimitiveProto::kValSfixed32FieldNumber, 63));
    EXPECT_TRUE(proto.write(FIELD_TYPE_SFIXED64 | PrimitiveProto::kValSfixed64FieldNumber, -54));
    EXPECT_TRUE(proto.write(FIELD_TYPE_SINT32 | PrimitiveProto::kValSint32FieldNumber, -533));
    EXPECT_TRUE(proto.write(FIELD_TYPE_SINT64 | PrimitiveProto::kValSint64FieldNumber, -61224762453LL));
    EXPECT_TRUE(proto.write(FIELD_TYPE_ENUM | PrimitiveProto::kValEnumFieldNumber, 2));

    PrimitiveProto primitives;
    std::string serialized;
    ASSERT_TRUE(proto.serializeToString(&serialized));
    ASSERT_TRUE(primitives.ParseFromString(serialized));
    EXPECT_EQ(primitives.val_int32(), 123);
    EXPECT_EQ(primitives.val_int64(), -1);
    EXPECT_EQ(primitives.val_float(), -23.5f);
    EXPECT_EQ(primitives.val_double(), 324.5f);
    EXPECT_EQ(primitives.val_uint32(), 3424);
    EXPECT_EQ(primitives.val_uint64(), 57);
    EXPECT_EQ(primitives.val_fixed32(), -20);
    EXPECT_EQ(primitives.val_fixed64(), -37);
    EXPECT_EQ(primitives.val_bool(), true);
    EXPECT_THAT(primitives.val_string(), StrEq(s.c_str()));
    EXPECT_THAT(primitives.val_bytes(), StrEq("apple"));
    EXPECT_EQ(primitives.val_sfixed32(), 63);
    EXPECT_EQ(primitives.val_sfixed64(), -54);
    EXPECT_EQ(primitives.val_sint32(), -533);
    EXPECT_EQ(primitives.val_sint64(), -61224762453LL);
    EXPECT_EQ(primitives.val_enum(), PrimitiveProto_Count_TWO);
}

TEST(ProtoOutputStreamTest, SerializeToVectorPrimitives) {
    std::string s = "hello";
    const char b[5] = { 'a', 'p', 'p', 'l', 'e' };

    ProtoOutputStream proto;
    EXPECT_TRUE(proto.write(FIELD_TYPE_INT32 | PrimitiveProto::kValInt32FieldNumber, 123));
    EXPECT_TRUE(proto.write(FIELD_TYPE_INT64 | PrimitiveProto::kValInt64FieldNumber, -1LL));
    EXPECT_TRUE(proto.write(FIELD_TYPE_FLOAT | PrimitiveProto::kValFloatFieldNumber, -23.5f));
    EXPECT_TRUE(proto.write(FIELD_TYPE_DOUBLE | PrimitiveProto::kValDoubleFieldNumber, 324.5));
    EXPECT_TRUE(proto.write(FIELD_TYPE_UINT32 | PrimitiveProto::kValUint32FieldNumber, 3424));
    EXPECT_TRUE(proto.write(FIELD_TYPE_UINT64 | PrimitiveProto::kValUint64FieldNumber, 57LL));
    EXPECT_TRUE(proto.write(FIELD_TYPE_FIXED32 | PrimitiveProto::kValFixed32FieldNumber, -20));
    EXPECT_TRUE(proto.write(FIELD_TYPE_FIXED64 | PrimitiveProto::kValFixed64FieldNumber, -37LL));
    EXPECT_TRUE(proto.write(FIELD_TYPE_BOOL | PrimitiveProto::kValBoolFieldNumber, true));
    EXPECT_TRUE(proto.write(FIELD_TYPE_STRING | PrimitiveProto::kValStringFieldNumber, s));
    EXPECT_TRUE(proto.write(FIELD_TYPE_BYTES | PrimitiveProto::kValBytesFieldNumber, b, 5));
    EXPECT_TRUE(proto.write(FIELD_TYPE_SFIXED32 | PrimitiveProto::kValSfixed32FieldNumber, 63));
    EXPECT_TRUE(proto.write(FIELD_TYPE_SFIXED64 | PrimitiveProto::kValSfixed64FieldNumber, -54));
    EXPECT_TRUE(proto.write(FIELD_TYPE_SINT32 | PrimitiveProto::kValSint32FieldNumber, -533));
    EXPECT_TRUE(proto.write(FIELD_TYPE_SINT64 | PrimitiveProto::kValSint64FieldNumber, -61224762453LL));
    EXPECT_TRUE(proto.write(FIELD_TYPE_ENUM | PrimitiveProto::kValEnumFieldNumber, 2));

    PrimitiveProto primitives;
    std::vector<uint8_t> vec;
    ASSERT_TRUE(proto.serializeToVector(&vec));

    std::string serialized(vec.data(), vec.data() + vec.size());
    ASSERT_TRUE(primitives.ParseFromString(serialized));

    EXPECT_EQ(primitives.val_int32(), 123);
    EXPECT_EQ(primitives.val_int64(), -1);
    EXPECT_EQ(primitives.val_float(), -23.5f);
    EXPECT_EQ(primitives.val_double(), 324.5f);
    EXPECT_EQ(primitives.val_uint32(), 3424);
    EXPECT_EQ(primitives.val_uint64(), 57);
    EXPECT_EQ(primitives.val_fixed32(), -20);
    EXPECT_EQ(primitives.val_fixed64(), -37);
    EXPECT_EQ(primitives.val_bool(), true);
    EXPECT_THAT(primitives.val_string(), StrEq(s.c_str()));
    EXPECT_THAT(primitives.val_bytes(), StrEq("apple"));
    EXPECT_EQ(primitives.val_sfixed32(), 63);
    EXPECT_EQ(primitives.val_sfixed64(), -54);
    EXPECT_EQ(primitives.val_sint32(), -533);
    EXPECT_EQ(primitives.val_sint64(), -61224762453LL);
    EXPECT_EQ(primitives.val_enum(), PrimitiveProto_Count_TWO);
}

TEST(ProtoOutputStreamTest, Complex) {
    std::string name1 = "cat";
    std::string name2 = "dog";
    const char data1[6] = { 'f', 'u', 'n', 'n', 'y', '!' };
    const char data2[4] = { 'f', 'o', 'o', 'd' };

    ProtoOutputStream proto;
    EXPECT_TRUE(proto.write(FIELD_TYPE_INT32 | ComplexProto::kIntsFieldNumber, 23));
    EXPECT_TRUE(proto.write(FIELD_TYPE_INT32 | ComplexProto::kIntsFieldNumber, 101));
    EXPECT_TRUE(proto.write(FIELD_TYPE_INT32 | ComplexProto::kIntsFieldNumber, -72));
    uint64_t token1 = proto.start(FIELD_TYPE_MESSAGE | ComplexProto::kLogsFieldNumber);
    EXPECT_TRUE(proto.write(FIELD_TYPE_INT32 | ComplexProto::Log::kIdFieldNumber, 12));
    EXPECT_TRUE(proto.write(FIELD_TYPE_STRING | ComplexProto::Log::kNameFieldNumber, name1));
    // specify the length to test the write(id, bytes, length) function.
    EXPECT_TRUE(proto.write(FIELD_TYPE_BYTES | ComplexProto::Log::kDataFieldNumber, data1, 5));
    proto.end(token1);
    uint64_t token2 = proto.start(FIELD_TYPE_MESSAGE | ComplexProto::kLogsFieldNumber);
    EXPECT_TRUE(proto.write(FIELD_TYPE_INT32 | ComplexProto::Log::kIdFieldNumber, 98));
    EXPECT_TRUE(proto.write(FIELD_TYPE_STRING | ComplexProto::Log::kNameFieldNumber, name2));
    EXPECT_TRUE(proto.write(FIELD_TYPE_BYTES | ComplexProto::Log::kDataFieldNumber, data2, 4));
    proto.end(token2);

    ComplexProto complex;
    ASSERT_TRUE(complex.ParseFromString(iterateToString(&proto)));
    EXPECT_EQ(complex.ints_size(), 3);
    EXPECT_EQ(complex.ints(0), 23);
    EXPECT_EQ(complex.ints(1), 101);
    EXPECT_EQ(complex.ints(2), -72);
    EXPECT_EQ(complex.logs_size(), 2);
    ComplexProto::Log log1 = complex.logs(0);
    EXPECT_EQ(log1.id(), 12);
    EXPECT_THAT(log1.name(), StrEq(name1.c_str()));
    EXPECT_THAT(log1.data(), StrEq("funny")); // should not contain '!'
    ComplexProto::Log log2 = complex.logs(1);
    EXPECT_EQ(log2.id(), 98);
    EXPECT_THAT(log2.name(), StrEq(name2.c_str()));
    EXPECT_THAT(log2.data(), StrEq("food"));
}

TEST(ProtoOutputStreamTest, SerializeToStringComplex) {
    std::string name1 = "cat";
    std::string name2 = "dog";
    const char data1[6] = { 'f', 'u', 'n', 'n', 'y', '!' };
    const char data2[4] = { 'f', 'o', 'o', 'd' };

    ProtoOutputStream proto;
    EXPECT_TRUE(proto.write(FIELD_TYPE_INT32 | ComplexProto::kIntsFieldNumber, 23));
    EXPECT_TRUE(proto.write(FIELD_TYPE_INT32 | ComplexProto::kIntsFieldNumber, 101));
    EXPECT_TRUE(proto.write(FIELD_TYPE_INT32 | ComplexProto::kIntsFieldNumber, -72));
    uint64_t token1 = proto.start(FIELD_TYPE_MESSAGE | ComplexProto::kLogsFieldNumber);
    EXPECT_TRUE(proto.write(FIELD_TYPE_INT32 | ComplexProto::Log::kIdFieldNumber, 12));
    EXPECT_TRUE(proto.write(FIELD_TYPE_STRING | ComplexProto::Log::kNameFieldNumber, name1));
    // specify the length to test the write(id, bytes, length) function.
    EXPECT_TRUE(proto.write(FIELD_TYPE_BYTES | ComplexProto::Log::kDataFieldNumber, data1, 5));
    proto.end(token1);
    uint64_t token2 = proto.start(FIELD_TYPE_MESSAGE | ComplexProto::kLogsFieldNumber);
    EXPECT_TRUE(proto.write(FIELD_TYPE_INT32 | ComplexProto::Log::kIdFieldNumber, 98));
    EXPECT_TRUE(proto.write(FIELD_TYPE_STRING | ComplexProto::Log::kNameFieldNumber, name2));
    EXPECT_TRUE(proto.write(FIELD_TYPE_BYTES | ComplexProto::Log::kDataFieldNumber, data2, 4));
    proto.end(token2);

    ComplexProto complex;
    std::string serialized;
    ASSERT_TRUE(proto.serializeToString(&serialized));
    ASSERT_TRUE(complex.ParseFromString(serialized));
    EXPECT_EQ(complex.ints_size(), 3);
    EXPECT_EQ(complex.ints(0), 23);
    EXPECT_EQ(complex.ints(1), 101);
    EXPECT_EQ(complex.ints(2), -72);
    EXPECT_EQ(complex.logs_size(), 2);
    ComplexProto::Log log1 = complex.logs(0);
    EXPECT_EQ(log1.id(), 12);
    EXPECT_THAT(log1.name(), StrEq(name1.c_str()));
    EXPECT_THAT(log1.data(), StrEq("funny")); // should not contain '!'
    ComplexProto::Log log2 = complex.logs(1);
    EXPECT_EQ(log2.id(), 98);
    EXPECT_THAT(log2.name(), StrEq(name2.c_str()));
    EXPECT_THAT(log2.data(), StrEq("food"));
}

TEST(ProtoOutputStreamTest, Reusability) {
    ProtoOutputStream proto;
    EXPECT_TRUE(proto.write(FIELD_TYPE_INT32 | ComplexProto::kIntsFieldNumber, 32));
    EXPECT_TRUE(proto.write(FIELD_TYPE_INT32 | ComplexProto::kIntsFieldNumber, 15));
    EXPECT_EQ(proto.bytesWritten(), 4);
    EXPECT_EQ(proto.size(), 4);
    // Can't write to proto after compact
    EXPECT_FALSE(proto.write(FIELD_TYPE_INT32 | ComplexProto::kIntsFieldNumber, 94));

    ComplexProto beforeClear;
    ASSERT_TRUE(beforeClear.ParseFromString(flushToString(&proto)));
    EXPECT_EQ(beforeClear.ints_size(), 2);
    EXPECT_EQ(beforeClear.ints(0), 32);
    EXPECT_EQ(beforeClear.ints(1), 15);

    proto.clear();
    EXPECT_EQ(proto.bytesWritten(), 0);
    EXPECT_TRUE(proto.write(FIELD_TYPE_INT32 | ComplexProto::kIntsFieldNumber, 1076));

    ComplexProto afterClear;
    ASSERT_TRUE(afterClear.ParseFromString(flushToString(&proto)));
    EXPECT_EQ(afterClear.ints_size(), 1);
    EXPECT_EQ(afterClear.ints(0), 1076);
}

TEST(ProtoOutputStreamTest, AdvancedEncoding) {
    ProtoOutputStream proto;
    proto.writeRawVarint((ComplexProto::kIntsFieldNumber << FIELD_ID_SHIFT) + WIRE_TYPE_VARINT);
    proto.writeRawVarint(UINT64_C(-123809234));
    proto.writeLengthDelimitedHeader(ComplexProto::kLogsFieldNumber, 8);
    proto.writeRawByte((ComplexProto::Log::kDataFieldNumber << FIELD_ID_SHIFT) + WIRE_TYPE_LENGTH_DELIMITED);
    proto.writeRawByte(6);
    proto.writeRawByte('b');
    proto.writeRawByte('a');
    proto.writeRawByte('n');
    proto.writeRawByte('a');
    proto.writeRawByte('n');
    proto.writeRawByte('a');
    uint64_t token = proto.start(FIELD_TYPE_MESSAGE | ComplexProto::kLogsFieldNumber);
    proto.write(FIELD_TYPE_INT32 | ComplexProto::Log::kIdFieldNumber, 14);
    proto.end(token);

    ComplexProto complex;
    ASSERT_TRUE(complex.ParseFromString(flushToString(&proto)));
    EXPECT_EQ(complex.ints_size(), 1);
    EXPECT_EQ(complex.ints(0), UINT64_C(-123809234));
    EXPECT_EQ(complex.logs_size(), 2);
    ComplexProto::Log log1 = complex.logs(0);
    EXPECT_FALSE(log1.has_id());
    EXPECT_FALSE(log1.has_name());
    EXPECT_THAT(log1.data(), StrEq("banana"));
    ComplexProto::Log log2 = complex.logs(1);
    EXPECT_EQ(log2.id(), 14);
    EXPECT_FALSE(log2.has_name());
    EXPECT_FALSE(log2.has_data());
}

TEST(ProtoOutputStreamTest, InvalidTypes) {
    ProtoOutputStream proto;
    EXPECT_FALSE(proto.write(FIELD_TYPE_UNKNOWN | PrimitiveProto::kValInt32FieldNumber, 790));
    EXPECT_FALSE(proto.write(FIELD_TYPE_ENUM | PrimitiveProto::kValEnumFieldNumber, 234.34));
    EXPECT_FALSE(proto.write(FIELD_TYPE_BOOL | PrimitiveProto::kValBoolFieldNumber, 18.73f));
    EXPECT_EQ(proto.size(), 0);
}

TEST(ProtoOutputStreamTest, NoEndCalled) {
    ProtoOutputStream proto;
    proto.start(FIELD_TYPE_MESSAGE | ComplexProto::kLogsFieldNumber);
    proto.write(FIELD_TYPE_INT32 | ComplexProto::Log::kIdFieldNumber, 53);
    // no proto.end called
    EXPECT_NE(proto.bytesWritten(), 0);
    EXPECT_EQ(proto.size(), 0);
    EXPECT_FALSE(proto.flush(STDOUT_FILENO));
}


TEST(ProtoOutputStreamTest, TwoEndCalled) {
    ProtoOutputStream proto;
    uint64_t token = proto.start(FIELD_TYPE_MESSAGE | ComplexProto::kLogsFieldNumber);
    proto.write(FIELD_TYPE_INT32 | ComplexProto::Log::kIdFieldNumber, 53);
    proto.end(token);
    proto.end(token);
    EXPECT_NE(proto.bytesWritten(), 0);
    EXPECT_EQ(proto.size(), 0);
    EXPECT_FALSE(proto.flush(STDOUT_FILENO));
}

TEST(ProtoOutputStreamTest, NoStartCalled) {
    ProtoOutputStream proto;
    uint64_t wrongToken = UINT64_C(324536345);
    // no proto.start called
    proto.write(FIELD_TYPE_INT32 | ComplexProto::Log::kIdFieldNumber, 53);
    proto.end(wrongToken);
    EXPECT_NE(proto.bytesWritten(), 0);
    EXPECT_EQ(proto.size(), 0);
    EXPECT_FALSE(proto.flush(STDOUT_FILENO));
}