diff options
author | TreeHugger Robot <treehugger-gerrit@google.com> | 2018-04-26 20:38:08 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2018-04-26 20:38:08 +0000 |
commit | 4afbedf988425e25b74e3d246cbefaff9e10c1bb (patch) | |
tree | dd674bf673b8fee38265d4b4382a7e379db549ca /libs/protoutil | |
parent | 317f7de44ce4441e64cbc3bfc65d34b90a5dab0d (diff) | |
parent | c3d4b28a760da3ff48d8dc0b8d0b4a4f20c61ffe (diff) |
Merge "Add unit tests to libprotoutil."
Diffstat (limited to 'libs/protoutil')
-rw-r--r-- | libs/protoutil/Android.bp | 10 | ||||
-rw-r--r-- | libs/protoutil/tests/EncodedBuffer_test.cpp | 133 | ||||
-rw-r--r-- | libs/protoutil/tests/ProtoOutputStream_test.cpp | 170 | ||||
-rw-r--r-- | libs/protoutil/tests/protobuf_test.cpp | 51 | ||||
-rw-r--r-- | libs/protoutil/tests/test.proto | 42 |
5 files changed, 401 insertions, 5 deletions
diff --git a/libs/protoutil/Android.bp b/libs/protoutil/Android.bp index a36bf802cf79..14b2e4131acb 100644 --- a/libs/protoutil/Android.bp +++ b/libs/protoutil/Android.bp @@ -42,16 +42,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", + } } diff --git a/libs/protoutil/tests/EncodedBuffer_test.cpp b/libs/protoutil/tests/EncodedBuffer_test.cpp index 615ab4ab29ed..964fc8ec9ee0 100644 --- a/libs/protoutil/tests/EncodedBuffer_test.cpp +++ b/libs/protoutil/tests/EncodedBuffer_test.cpp @@ -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); } diff --git a/libs/protoutil/tests/ProtoOutputStream_test.cpp b/libs/protoutil/tests/ProtoOutputStream_test.cpp new file mode 100644 index 000000000000..e8e155779829 --- /dev/null +++ b/libs/protoutil/tests/ProtoOutputStream_test.cpp @@ -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()); +} diff --git a/libs/protoutil/tests/protobuf_test.cpp b/libs/protoutil/tests/protobuf_test.cpp new file mode 100644 index 000000000000..5ca3e6477c01 --- /dev/null +++ b/libs/protoutil/tests/protobuf_test.cpp @@ -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); +}
\ No newline at end of file diff --git a/libs/protoutil/tests/test.proto b/libs/protoutil/tests/test.proto new file mode 100644 index 000000000000..52c55f39f326 --- /dev/null +++ b/libs/protoutil/tests/test.proto @@ -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; +} |