// 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)); }