Add unit tests to libprotoutil.

Bug: 77342154
Test: atest libprotoutil_test
Change-Id: I57f31f5cf83b635b200a93cbc655fac7f5edfbd5
This commit is contained in:
Yi Jin
2018-04-23 16:02:20 -07:00
parent 63b534768e
commit c3d4b28a76
5 changed files with 401 additions and 5 deletions

View File

@@ -41,16 +41,20 @@ cc_library {
cc_test {
name: "libprotoutil_test",
srcs: [
"tests/EncodedBuffer_test.cpp",
],
srcs: ["tests/*"],
shared_libs: [
"libbase",
"libcutils",
"libprotoutil",
"libprotobuf-cpp-full",
],
static_libs: [
"libgmock",
],
proto: {
type: "full",
}
}

View File

@@ -17,9 +17,138 @@
using namespace android::util;
constexpr size_t TEST_CHUNK_SIZE = 16UL;
constexpr size_t TEST_CHUNK_HALF_SIZE = TEST_CHUNK_SIZE / 2;
constexpr size_t TEST_CHUNK_3X_SIZE = 3 * TEST_CHUNK_SIZE;
static void expectPointer(EncodedBuffer::Pointer* p, size_t pos) {
EXPECT_EQ(p->pos(), pos);
EXPECT_EQ(p->index(), pos / TEST_CHUNK_SIZE);
EXPECT_EQ(p->offset(), pos % TEST_CHUNK_SIZE);
}
TEST(EncodedBufferTest, WriteSimple) {
EncodedBuffer buffer(TEST_CHUNK_SIZE);
EXPECT_EQ(buffer.size(), 0UL);
expectPointer(buffer.wp(), 0);
EXPECT_EQ(buffer.currentToWrite(), TEST_CHUNK_SIZE);
for (size_t i = 0; i < TEST_CHUNK_HALF_SIZE; i++) {
buffer.writeRawByte(50 + i);
}
EXPECT_EQ(buffer.size(), TEST_CHUNK_HALF_SIZE);
expectPointer(buffer.wp(), TEST_CHUNK_HALF_SIZE);
EXPECT_EQ(buffer.currentToWrite(), TEST_CHUNK_HALF_SIZE);
for (size_t i = 0; i < TEST_CHUNK_SIZE; i++) {
buffer.writeRawByte(80 + i);
}
EXPECT_EQ(buffer.size(), TEST_CHUNK_SIZE + TEST_CHUNK_HALF_SIZE);
expectPointer(buffer.wp(), TEST_CHUNK_SIZE + TEST_CHUNK_HALF_SIZE);
EXPECT_EQ(buffer.currentToWrite(), TEST_CHUNK_HALF_SIZE);
// verifies the buffer's data
expectPointer(buffer.ep(), 0);
for (size_t i = 0; i < TEST_CHUNK_HALF_SIZE; i++) {
EXPECT_EQ(buffer.readRawByte(), 50 + i);
}
for (size_t i = 0; i < TEST_CHUNK_SIZE; i++) {
EXPECT_EQ(buffer.readRawByte(), 80 + i);
}
// clears the buffer
buffer.clear();
EXPECT_EQ(buffer.size(), 0UL);
expectPointer(buffer.wp(), 0);
}
TEST(EncodedBufferTest, WriteVarint) {
EncodedBuffer buffer(TEST_CHUNK_SIZE);
size_t expected_buffer_size = 0;
EXPECT_EQ(buffer.writeRawVarint32(13), 1);
expected_buffer_size += 1;
EXPECT_EQ(buffer.size(), expected_buffer_size);
EXPECT_EQ(buffer.writeRawVarint32(UINT32_C(-1)), 5);
expected_buffer_size += 5;
EXPECT_EQ(buffer.size(), expected_buffer_size);
EXPECT_EQ(buffer.writeRawVarint64(200), 2);
expected_buffer_size += 2;
EXPECT_EQ(buffer.size(), expected_buffer_size);
EXPECT_EQ(buffer.writeRawVarint64(UINT64_C(-1)), 10);
expected_buffer_size += 10;
EXPECT_EQ(buffer.size(), expected_buffer_size);
buffer.writeRawFixed32(UINT32_C(-1));
expected_buffer_size += 4;
EXPECT_EQ(buffer.size(), expected_buffer_size);
buffer.writeRawFixed64(UINT64_C(-1));
expected_buffer_size += 8;
EXPECT_EQ(buffer.size(), expected_buffer_size);
EXPECT_EQ(buffer.writeHeader(32, 2), 2);
expected_buffer_size += 2;
EXPECT_EQ(buffer.size(), expected_buffer_size);
// verify data are correctly written to the buffer.
expectPointer(buffer.ep(), 0);
EXPECT_EQ(buffer.readRawVarint(), UINT32_C(13));
EXPECT_EQ(buffer.readRawVarint(), UINT32_C(-1));
EXPECT_EQ(buffer.readRawVarint(), UINT64_C(200));
EXPECT_EQ(buffer.readRawVarint(), UINT64_C(-1));
EXPECT_EQ(buffer.readRawFixed32(), UINT32_C(-1));
EXPECT_EQ(buffer.readRawFixed64(), UINT64_C(-1));
EXPECT_EQ(buffer.readRawVarint(), UINT64_C((32 << 3) + 2));
expectPointer(buffer.ep(), expected_buffer_size);
}
TEST(EncodedBufferTest, Edit) {
EncodedBuffer buffer(TEST_CHUNK_SIZE);
buffer.writeRawFixed64(0xdeadbeefdeadbeef);
EXPECT_EQ(buffer.readRawFixed64(), UINT64_C(0xdeadbeefdeadbeef));
buffer.editRawFixed32(4, 0x12345678);
// fixed 64 is little endian order.
buffer.ep()->rewind(); // rewind ep for readRawFixed64 from 0
EXPECT_EQ(buffer.readRawFixed64(), UINT64_C(0x12345678deadbeef));
buffer.wp()->rewind();
expectPointer(buffer.wp(), 0);
buffer.copy(4, 3);
buffer.ep()->rewind(); // rewind ep for readRawFixed64 from 0
EXPECT_EQ(buffer.readRawFixed64(), UINT64_C(0x12345678de345678));
}
TEST(EncodedBufferTest, ReadSimple) {
EncodedBuffer buffer(TEST_CHUNK_SIZE);
for (size_t i = 0; i < TEST_CHUNK_3X_SIZE; i++) {
buffer.writeRawByte(i);
}
auto iter = buffer.begin();
EXPECT_EQ(iter.size(), TEST_CHUNK_3X_SIZE);
EXPECT_EQ(iter.bytesRead(), 0);
expectPointer(iter.rp(), 0);
while (iter.readBuffer() != NULL) {
iter.rp()->move(iter.currentToRead());
}
EXPECT_EQ(iter.bytesRead(), TEST_CHUNK_3X_SIZE);
expectPointer(iter.rp(), TEST_CHUNK_3X_SIZE);
iter.rp()->rewind();
expectPointer(iter.rp(), 0);
uint8_t val = 0;
while (iter.hasNext()) {
EXPECT_EQ(iter.next(), val);
val++;
}
EXPECT_EQ(iter.bytesRead(), TEST_CHUNK_3X_SIZE);
expectPointer(iter.rp(), TEST_CHUNK_3X_SIZE);
}
TEST(EncodedBufferTest, ReadVarint) {
EncodedBuffer buffer;
uint64_t val = UINT64_C(1522865904593);
buffer.writeRawVarint64(val);
EXPECT_EQ(val, buffer.begin().readRawVarint());
size_t len = buffer.writeRawVarint64(val);
auto iter = buffer.begin();
EXPECT_EQ(iter.size(), len);
EXPECT_EQ(iter.readRawVarint(), val);
}

View File

@@ -0,0 +1,170 @@
// 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 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());
auto iter = proto->data();
while (iter.hasNext()) {
content.push_back(iter.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, 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, 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);
proto.clear();
EXPECT_EQ(proto.bytesWritten(), 0);
EXPECT_EQ(proto.size(), 0);
}
TEST(ProtoOutputStreamTest, AdvancedEncoding) {
ProtoOutputStream proto;
proto.writeRawVarint(ComplexProto::kIntsFieldNumber << FIELD_ID_SHIFT);
proto.writeRawVarint(UINT64_C(-123809234));
proto.writeLengthDelimitedHeader(ComplexProto::kLogsFieldNumber, 8);
proto.writeRawByte((ComplexProto::Log::kDataFieldNumber << FIELD_ID_SHIFT) + 2);
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());
}

View File

@@ -0,0 +1,51 @@
// 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/util/protobuf.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using namespace android::util;
TEST(ProtobufTest, All) {
EXPECT_EQ(read_wire_type(UINT32_C(17)), 1);
EXPECT_EQ(read_field_id(UINT32_C(17)), 2);
EXPECT_EQ(get_varint_size(UINT64_C(234134)), 3);
EXPECT_EQ(get_varint_size(UINT64_C(-1)), 10);
constexpr uint8_t UNSET_BYTE = 0xAB;
uint8_t buf[11];
memset(buf, UNSET_BYTE, sizeof(buf));
EXPECT_EQ(write_raw_varint(buf, UINT64_C(150)) - buf, 2);
EXPECT_EQ(buf[0], 0x96);
EXPECT_EQ(buf[1], 0x01);
EXPECT_EQ(buf[2], UNSET_BYTE);
memset(buf, UNSET_BYTE, sizeof(buf));
EXPECT_EQ(write_raw_varint(buf, UINT64_C(-2)) - buf, 10);
EXPECT_EQ(buf[0], 0xfe);
for (int i = 1; i < 9; i++) {
EXPECT_EQ(buf[i], 0xff);
}
EXPECT_EQ(buf[9], 0x01);
EXPECT_EQ(buf[10], UNSET_BYTE);
uint8_t header[20];
memset(header, UNSET_BYTE, sizeof(header));
EXPECT_EQ(write_length_delimited_tag_header(header, 3, 150) - header, 3);
EXPECT_EQ(header[0], 26);
EXPECT_EQ(header[1], 0x96);
EXPECT_EQ(header[2], 0x01);
EXPECT_EQ(header[3], UNSET_BYTE);
}

View File

@@ -0,0 +1,42 @@
// This proto file is only used for testing purpose.
syntax = "proto2";
package android.util;
message PrimitiveProto {
optional int32 val_int32 = 1;
optional int64 val_int64 = 2;
optional float val_float = 3;
optional double val_double = 4;
optional uint32 val_uint32 = 5;
optional uint64 val_uint64 = 6;
optional fixed32 val_fixed32 = 7;
optional fixed64 val_fixed64 = 8;
optional bool val_bool = 9;
optional string val_string = 10;
optional bytes val_bytes = 11;
optional sfixed32 val_sfixed32 = 12;
optional sfixed64 val_sfixed64 = 13;
optional sint32 val_sint32 = 14;
optional sint64 val_sint64 = 15;
enum Count {
ZERO = 0;
ONE = 1;
TWO = 2;
};
optional Count val_enum = 16;
}
message ComplexProto {
repeated int32 ints = 1;
message Log {
optional int32 id = 1;
optional string name = 2;
optional bytes data = 3;
}
repeated Log logs = 2;
}