Merge "Add unit tests to libprotoutil."
diff --git a/libs/protoutil/Android.bp b/libs/protoutil/Android.bp
index a36bf80..14b2e41 100644
--- a/libs/protoutil/Android.bp
+++ b/libs/protoutil/Android.bp
@@ -42,16 +42,20 @@
 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 615ab4a..964fc8e 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 0000000..e8e1557
--- /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 0000000..5ca3e64
--- /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 0000000..52c55f3
--- /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;
+}