mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
1166 lines
35 KiB
C++
1166 lines
35 KiB
C++
// Protocol Buffers - Google's data interchange format
|
|
// Copyright 2008 Google Inc. All rights reserved.
|
|
// https://developers.google.com/protocol-buffers/
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above
|
|
// copyright notice, this list of conditions and the following disclaimer
|
|
// in the documentation and/or other materials provided with the
|
|
// distribution.
|
|
// * Neither the name of Google Inc. nor the names of its
|
|
// contributors may be used to endorse or promote products derived from
|
|
// this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
#include <thirdparty/protobuf/util/internal/protostream_objectsource.h>
|
|
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <sstream>
|
|
|
|
#include <thirdparty/protobuf/any.pb.h>
|
|
#include <thirdparty/protobuf/io/coded_stream.h>
|
|
#include <thirdparty/protobuf/io/zero_copy_stream_impl_lite.h>
|
|
#include <thirdparty/protobuf/descriptor.h>
|
|
#include <thirdparty/protobuf/util/internal/expecting_objectwriter.h>
|
|
#include <thirdparty/protobuf/util/internal/testdata/anys.pb.h>
|
|
#include <thirdparty/protobuf/util/internal/testdata/books.pb.h>
|
|
#include <thirdparty/protobuf/util/internal/testdata/field_mask.pb.h>
|
|
#include <thirdparty/protobuf/util/internal/testdata/maps.pb.h>
|
|
#include <thirdparty/protobuf/util/internal/testdata/proto3.pb.h>
|
|
#include <thirdparty/protobuf/util/internal/testdata/struct.pb.h>
|
|
#include <thirdparty/protobuf/util/internal/testdata/timestamp_duration.pb.h>
|
|
#include <gtest/gtest.h>
|
|
#include <thirdparty/protobuf/stubs/casts.h>
|
|
#include <thirdparty/protobuf/stubs/status.h>
|
|
#include <thirdparty/protobuf/util/internal/constants.h>
|
|
#include <thirdparty/protobuf/util/internal/type_info_test_helper.h>
|
|
|
|
|
|
namespace google {
|
|
namespace protobuf {
|
|
namespace util {
|
|
namespace converter {
|
|
|
|
using ::google::protobuf::Any;
|
|
using io::ArrayInputStream;
|
|
using io::CodedInputStream;
|
|
using proto_util_converter::testing::AnyM;
|
|
using proto_util_converter::testing::AnyOut;
|
|
using proto_util_converter::testing::Author;
|
|
using proto_util_converter::testing::BadAuthor;
|
|
using proto_util_converter::testing::BadNestedBook;
|
|
using proto_util_converter::testing::Book;
|
|
using proto_util_converter::testing::Book_Label;
|
|
using proto_util_converter::testing::Cyclic;
|
|
using proto_util_converter::testing::FieldMaskTest;
|
|
using proto_util_converter::testing::MapOut;
|
|
using proto_util_converter::testing::MapOutWireFormat;
|
|
using proto_util_converter::testing::NestedBook;
|
|
using proto_util_converter::testing::NestedFieldMask;
|
|
using proto_util_converter::testing::PackedPrimitive;
|
|
using proto_util_converter::testing::Primitive;
|
|
using proto_util_converter::testing::Proto3Message;
|
|
using proto_util_converter::testing::StructType;
|
|
using proto_util_converter::testing::TimestampDuration;
|
|
using ::testing::_;
|
|
|
|
|
|
namespace {
|
|
std::string GetTypeUrl(const Descriptor* descriptor) {
|
|
return std::string(kTypeServiceBaseUrl) + "/" + descriptor->full_name();
|
|
}
|
|
} // namespace
|
|
|
|
class ProtostreamObjectSourceTest
|
|
: public ::testing::TestWithParam<testing::TypeInfoSource> {
|
|
protected:
|
|
ProtostreamObjectSourceTest()
|
|
: helper_(GetParam()),
|
|
mock_(),
|
|
ow_(&mock_),
|
|
use_lower_camel_for_enums_(false),
|
|
use_ints_for_enums_(false),
|
|
use_preserve_proto_field_names_(false),
|
|
add_trailing_zeros_(false),
|
|
render_unknown_enum_values_(true) {
|
|
helper_.ResetTypeInfo(Book::descriptor(), Proto3Message::descriptor());
|
|
}
|
|
|
|
~ProtostreamObjectSourceTest() override {}
|
|
|
|
void DoTest(const Message& msg, const Descriptor* descriptor) {
|
|
util::Status status = ExecuteTest(msg, descriptor);
|
|
EXPECT_EQ(util::Status(), status);
|
|
}
|
|
|
|
util::Status ExecuteTest(const Message& msg, const Descriptor* descriptor) {
|
|
std::ostringstream oss;
|
|
msg.SerializePartialToOstream(&oss);
|
|
std::string proto = oss.str();
|
|
ArrayInputStream arr_stream(proto.data(), proto.size());
|
|
CodedInputStream in_stream(&arr_stream);
|
|
|
|
ProtoStreamObjectSource::RenderOptions render_options;
|
|
render_options.use_lower_camel_for_enums = use_lower_camel_for_enums_;
|
|
render_options.use_ints_for_enums = use_ints_for_enums_;
|
|
render_options.preserve_proto_field_names = use_preserve_proto_field_names_;
|
|
std::unique_ptr<ProtoStreamObjectSource> os(helper_.NewProtoSource(
|
|
&in_stream, GetTypeUrl(descriptor), render_options));
|
|
os->set_max_recursion_depth(64);
|
|
return os->WriteTo(&mock_);
|
|
}
|
|
|
|
void PrepareExpectingObjectWriterForRepeatedPrimitive() {
|
|
ow_.StartObject("")
|
|
->StartList("repFix32")
|
|
->RenderUint32("", bit_cast<uint32_t>(3201))
|
|
->RenderUint32("", bit_cast<uint32_t>(0))
|
|
->RenderUint32("", bit_cast<uint32_t>(3202))
|
|
->EndList()
|
|
->StartList("repU32")
|
|
->RenderUint32("", bit_cast<uint32_t>(3203))
|
|
->RenderUint32("", bit_cast<uint32_t>(0))
|
|
->EndList()
|
|
->StartList("repI32")
|
|
->RenderInt32("", 0)
|
|
->RenderInt32("", 3204)
|
|
->RenderInt32("", 3205)
|
|
->EndList()
|
|
->StartList("repSf32")
|
|
->RenderInt32("", 3206)
|
|
->RenderInt32("", 0)
|
|
->EndList()
|
|
->StartList("repS32")
|
|
->RenderInt32("", 0)
|
|
->RenderInt32("", 3207)
|
|
->RenderInt32("", 3208)
|
|
->EndList()
|
|
->StartList("repFix64")
|
|
->RenderUint64("", bit_cast<uint64_t>(int64_t{6401}))
|
|
->RenderUint64("", bit_cast<uint64_t>(int64_t{0}))
|
|
->EndList()
|
|
->StartList("repU64")
|
|
->RenderUint64("", bit_cast<uint64_t>(int64_t{0}))
|
|
->RenderUint64("", bit_cast<uint64_t>(int64_t{6402}))
|
|
->RenderUint64("", bit_cast<uint64_t>(int64_t{6403}))
|
|
->EndList()
|
|
->StartList("repI64")
|
|
->RenderInt64("", 6404L)
|
|
->RenderInt64("", 0L)
|
|
->EndList()
|
|
->StartList("repSf64")
|
|
->RenderInt64("", 0L)
|
|
->RenderInt64("", 6405L)
|
|
->RenderInt64("", 6406L)
|
|
->EndList()
|
|
->StartList("repS64")
|
|
->RenderInt64("", 6407L)
|
|
->RenderInt64("", 0L)
|
|
->EndList()
|
|
->StartList("repFloat")
|
|
->RenderFloat("", 0.0f)
|
|
->RenderFloat("", 32.1f)
|
|
->RenderFloat("", 32.2f)
|
|
->EndList()
|
|
->StartList("repDouble")
|
|
->RenderDouble("", 64.1L)
|
|
->RenderDouble("", 0.0L)
|
|
->EndList()
|
|
->StartList("repBool")
|
|
->RenderBool("", true)
|
|
->RenderBool("", false)
|
|
->EndList()
|
|
->EndObject();
|
|
}
|
|
|
|
Primitive PrepareRepeatedPrimitive() {
|
|
Primitive primitive;
|
|
primitive.add_rep_fix32(3201);
|
|
primitive.add_rep_fix32(0);
|
|
primitive.add_rep_fix32(3202);
|
|
primitive.add_rep_u32(3203);
|
|
primitive.add_rep_u32(0);
|
|
primitive.add_rep_i32(0);
|
|
primitive.add_rep_i32(3204);
|
|
primitive.add_rep_i32(3205);
|
|
primitive.add_rep_sf32(3206);
|
|
primitive.add_rep_sf32(0);
|
|
primitive.add_rep_s32(0);
|
|
primitive.add_rep_s32(3207);
|
|
primitive.add_rep_s32(3208);
|
|
primitive.add_rep_fix64(6401L);
|
|
primitive.add_rep_fix64(0L);
|
|
primitive.add_rep_u64(0L);
|
|
primitive.add_rep_u64(6402L);
|
|
primitive.add_rep_u64(6403L);
|
|
primitive.add_rep_i64(6404L);
|
|
primitive.add_rep_i64(0L);
|
|
primitive.add_rep_sf64(0L);
|
|
primitive.add_rep_sf64(6405L);
|
|
primitive.add_rep_sf64(6406L);
|
|
primitive.add_rep_s64(6407L);
|
|
primitive.add_rep_s64(0L);
|
|
primitive.add_rep_float(0.0f);
|
|
primitive.add_rep_float(32.1f);
|
|
primitive.add_rep_float(32.2f);
|
|
primitive.add_rep_double(64.1L);
|
|
primitive.add_rep_double(0.0);
|
|
primitive.add_rep_bool(true);
|
|
primitive.add_rep_bool(false);
|
|
|
|
PrepareExpectingObjectWriterForRepeatedPrimitive();
|
|
return primitive;
|
|
}
|
|
|
|
PackedPrimitive PreparePackedPrimitive() {
|
|
PackedPrimitive primitive;
|
|
primitive.add_rep_fix32(3201);
|
|
primitive.add_rep_fix32(0);
|
|
primitive.add_rep_fix32(3202);
|
|
primitive.add_rep_u32(3203);
|
|
primitive.add_rep_u32(0);
|
|
primitive.add_rep_i32(0);
|
|
primitive.add_rep_i32(3204);
|
|
primitive.add_rep_i32(3205);
|
|
primitive.add_rep_sf32(3206);
|
|
primitive.add_rep_sf32(0);
|
|
primitive.add_rep_s32(0);
|
|
primitive.add_rep_s32(3207);
|
|
primitive.add_rep_s32(3208);
|
|
primitive.add_rep_fix64(6401L);
|
|
primitive.add_rep_fix64(0L);
|
|
primitive.add_rep_u64(0L);
|
|
primitive.add_rep_u64(6402L);
|
|
primitive.add_rep_u64(6403L);
|
|
primitive.add_rep_i64(6404L);
|
|
primitive.add_rep_i64(0L);
|
|
primitive.add_rep_sf64(0L);
|
|
primitive.add_rep_sf64(6405L);
|
|
primitive.add_rep_sf64(6406L);
|
|
primitive.add_rep_s64(6407L);
|
|
primitive.add_rep_s64(0L);
|
|
primitive.add_rep_float(0.0f);
|
|
primitive.add_rep_float(32.1f);
|
|
primitive.add_rep_float(32.2f);
|
|
primitive.add_rep_double(64.1L);
|
|
primitive.add_rep_double(0.0);
|
|
primitive.add_rep_bool(true);
|
|
primitive.add_rep_bool(false);
|
|
|
|
PrepareExpectingObjectWriterForRepeatedPrimitive();
|
|
return primitive;
|
|
}
|
|
|
|
void UseLowerCamelForEnums() { use_lower_camel_for_enums_ = true; }
|
|
|
|
void UseIntsForEnums() { use_ints_for_enums_ = true; }
|
|
|
|
void UsePreserveProtoFieldNames() { use_preserve_proto_field_names_ = true; }
|
|
|
|
void AddTrailingZeros() { add_trailing_zeros_ = true; }
|
|
|
|
void SetRenderUnknownEnumValues(bool value) {
|
|
render_unknown_enum_values_ = value;
|
|
}
|
|
|
|
testing::TypeInfoTestHelper helper_;
|
|
|
|
::testing::NiceMock<MockObjectWriter> mock_;
|
|
ExpectingObjectWriter ow_;
|
|
bool use_lower_camel_for_enums_;
|
|
bool use_ints_for_enums_;
|
|
bool use_preserve_proto_field_names_;
|
|
bool add_trailing_zeros_;
|
|
bool render_unknown_enum_values_;
|
|
};
|
|
|
|
INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
|
|
ProtostreamObjectSourceTest,
|
|
::testing::Values(
|
|
testing::USE_TYPE_RESOLVER));
|
|
|
|
TEST_P(ProtostreamObjectSourceTest, EmptyMessage) {
|
|
Book empty;
|
|
ow_.StartObject("")->EndObject();
|
|
DoTest(empty, Book::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTest, Primitives) {
|
|
Primitive primitive;
|
|
primitive.set_fix32(3201);
|
|
primitive.set_u32(3202);
|
|
primitive.set_i32(3203);
|
|
primitive.set_sf32(3204);
|
|
primitive.set_s32(3205);
|
|
primitive.set_fix64(6401L);
|
|
primitive.set_u64(6402L);
|
|
primitive.set_i64(6403L);
|
|
primitive.set_sf64(6404L);
|
|
primitive.set_s64(6405L);
|
|
primitive.set_str("String Value");
|
|
primitive.set_bytes("Some Bytes");
|
|
primitive.set_float_(32.1f);
|
|
primitive.set_double_(64.1L);
|
|
primitive.set_bool_(true);
|
|
|
|
ow_.StartObject("")
|
|
->RenderUint32("fix32", bit_cast<uint32_t>(3201))
|
|
->RenderUint32("u32", bit_cast<uint32_t>(3202))
|
|
->RenderInt32("i32", 3203)
|
|
->RenderInt32("sf32", 3204)
|
|
->RenderInt32("s32", 3205)
|
|
->RenderUint64("fix64", bit_cast<uint64_t>(int64_t{6401}))
|
|
->RenderUint64("u64", bit_cast<uint64_t>(int64_t{6402}))
|
|
->RenderInt64("i64", 6403L)
|
|
->RenderInt64("sf64", 6404L)
|
|
->RenderInt64("s64", 6405L)
|
|
->RenderString("str", "String Value")
|
|
->RenderBytes("bytes", "Some Bytes")
|
|
->RenderFloat("float", 32.1f)
|
|
->RenderDouble("double", 64.1L)
|
|
->RenderBool("bool", true)
|
|
->EndObject();
|
|
DoTest(primitive, Primitive::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTest, RepeatingPrimitives) {
|
|
Primitive primitive = PrepareRepeatedPrimitive();
|
|
primitive.add_rep_str("String One");
|
|
primitive.add_rep_str("String Two");
|
|
primitive.add_rep_bytes("Some Bytes");
|
|
|
|
ow_.StartList("repStr")
|
|
->RenderString("", "String One")
|
|
->RenderString("", "String Two")
|
|
->EndList()
|
|
->StartList("repBytes")
|
|
->RenderBytes("", "Some Bytes")
|
|
->EndList();
|
|
DoTest(primitive, Primitive::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTest, CustomJsonName) {
|
|
Author author;
|
|
author.set_id(12345);
|
|
|
|
ow_.StartObject("")->RenderUint64("@id", 12345)->EndObject();
|
|
DoTest(author, Author::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTest, NestedMessage) {
|
|
Author* author = new Author();
|
|
author->set_name("Tolstoy");
|
|
Book book;
|
|
book.set_title("My Book");
|
|
book.set_allocated_author(author);
|
|
|
|
ow_.StartObject("")
|
|
->RenderString("title", "My Book")
|
|
->StartObject("author")
|
|
->RenderString("name", "Tolstoy")
|
|
->EndObject()
|
|
->EndObject();
|
|
DoTest(book, Book::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTest, RepeatingField) {
|
|
Author author;
|
|
author.set_alive(false);
|
|
author.set_name("john");
|
|
author.add_pseudonym("phil");
|
|
author.add_pseudonym("bob");
|
|
|
|
ow_.StartObject("")
|
|
->RenderBool("alive", false)
|
|
->RenderString("name", "john")
|
|
->StartList("pseudonym")
|
|
->RenderString("", "phil")
|
|
->RenderString("", "bob")
|
|
->EndList()
|
|
->EndObject();
|
|
DoTest(author, Author::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTest, PackedRepeatingFields) {
|
|
DoTest(PreparePackedPrimitive(), PackedPrimitive::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTest, NonPackedPackableFieldsActuallyPacked) {
|
|
// Protostream is packed, but parse with non-packed Primitive.
|
|
DoTest(PreparePackedPrimitive(), Primitive::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTest, PackedPackableFieldNotActuallyPacked) {
|
|
// Protostream is not packed, but parse with PackedPrimitive.
|
|
DoTest(PrepareRepeatedPrimitive(), PackedPrimitive::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTest, BadAuthor) {
|
|
Author author;
|
|
author.set_alive(false);
|
|
author.set_name("john");
|
|
author.set_id(1234L);
|
|
author.add_pseudonym("phil");
|
|
author.add_pseudonym("bob");
|
|
|
|
ow_.StartObject("")
|
|
->StartList("alive")
|
|
->RenderBool("", false)
|
|
->EndList()
|
|
->StartList("name")
|
|
->RenderUint64("", static_cast<uint64_t>('j'))
|
|
->RenderUint64("", static_cast<uint64_t>('o'))
|
|
->RenderUint64("", static_cast<uint64_t>('h'))
|
|
->RenderUint64("", static_cast<uint64_t>('n'))
|
|
->EndList()
|
|
->RenderString("pseudonym", "phil")
|
|
->RenderString("pseudonym", "bob")
|
|
->EndObject();
|
|
// Protostream created with Author, but parsed with BadAuthor.
|
|
DoTest(author, BadAuthor::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTest, NestedBookToBadNestedBook) {
|
|
Book* book = new Book();
|
|
book->set_length(250);
|
|
book->set_published(2014L);
|
|
NestedBook nested;
|
|
nested.set_allocated_book(book);
|
|
|
|
ow_.StartObject("")
|
|
->StartList("book")
|
|
->RenderUint32("", 24) // tag for field length (3 << 3)
|
|
->RenderUint32("", 250)
|
|
->RenderUint32("", 32) // tag for field published (4 << 3)
|
|
->RenderUint32("", 2014)
|
|
->EndList()
|
|
->EndObject();
|
|
// Protostream created with NestedBook, but parsed with BadNestedBook.
|
|
DoTest(nested, BadNestedBook::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTest, BadNestedBookToNestedBook) {
|
|
BadNestedBook nested;
|
|
nested.add_book(1);
|
|
nested.add_book(2);
|
|
nested.add_book(3);
|
|
nested.add_book(4);
|
|
nested.add_book(5);
|
|
nested.add_book(6);
|
|
nested.add_book(7);
|
|
|
|
ow_.StartObject("")->StartObject("book")->EndObject()->EndObject();
|
|
// Protostream created with BadNestedBook, but parsed with NestedBook.
|
|
DoTest(nested, NestedBook::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTest,
|
|
LongRepeatedListDoesNotBreakIntoMultipleJsonLists) {
|
|
Book book;
|
|
|
|
int repeat = 10000;
|
|
for (int i = 0; i < repeat; ++i) {
|
|
Book_Label* label = book.add_labels();
|
|
label->set_key(StrCat("i", i));
|
|
label->set_value(StrCat("v", i));
|
|
}
|
|
|
|
// Make sure StartList and EndList are called exactly once (see b/18227499 for
|
|
// problems when this doesn't happen)
|
|
EXPECT_CALL(mock_, StartList(_)).Times(1);
|
|
EXPECT_CALL(mock_, EndList()).Times(1);
|
|
|
|
DoTest(book, Book::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTest, LowerCamelEnumOutputMacroCase) {
|
|
Book book;
|
|
book.set_type(Book::ACTION_AND_ADVENTURE);
|
|
|
|
UseLowerCamelForEnums();
|
|
|
|
ow_.StartObject("")->RenderString("type", "actionAndAdventure")->EndObject();
|
|
DoTest(book, Book::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTest, LowerCamelEnumOutputSnakeCase) {
|
|
Book book;
|
|
book.set_type(Book::arts_and_photography);
|
|
|
|
UseLowerCamelForEnums();
|
|
|
|
ow_.StartObject("")->RenderString("type", "artsAndPhotography")->EndObject();
|
|
DoTest(book, Book::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTest, LowerCamelEnumOutputWithNumber) {
|
|
Book book;
|
|
book.set_type(Book::I18N_Tech);
|
|
|
|
UseLowerCamelForEnums();
|
|
|
|
ow_.StartObject("")->RenderString("type", "i18nTech")->EndObject();
|
|
DoTest(book, Book::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTest, EnumCaseIsUnchangedByDefault) {
|
|
Book book;
|
|
book.set_type(Book::ACTION_AND_ADVENTURE);
|
|
ow_.StartObject("")
|
|
->RenderString("type", "ACTION_AND_ADVENTURE")
|
|
->EndObject();
|
|
DoTest(book, Book::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTest, UseIntsForEnumsTest) {
|
|
Book book;
|
|
book.set_type(Book::ACTION_AND_ADVENTURE);
|
|
|
|
UseIntsForEnums();
|
|
|
|
ow_.StartObject("")->RenderInt32("type", 3)->EndObject();
|
|
DoTest(book, Book::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTest, UsePreserveProtoFieldNames) {
|
|
Book book;
|
|
book.set_snake_field("foo");
|
|
|
|
UsePreserveProtoFieldNames();
|
|
|
|
ow_.StartObject("")->RenderString("snake_field", "foo")->EndObject();
|
|
DoTest(book, Book::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTest,
|
|
UnknownEnumAreDroppedWhenRenderUnknownEnumValuesIsUnset) {
|
|
Proto3Message message;
|
|
message.set_enum_value(static_cast<Proto3Message::NestedEnum>(1234));
|
|
|
|
SetRenderUnknownEnumValues(false);
|
|
|
|
// Unknown enum values are not output.
|
|
ow_.StartObject("")->EndObject();
|
|
DoTest(message, Proto3Message::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTest,
|
|
UnknownEnumAreOutputWhenRenderUnknownEnumValuesIsSet) {
|
|
Proto3Message message;
|
|
message.set_enum_value(static_cast<Proto3Message::NestedEnum>(1234));
|
|
|
|
SetRenderUnknownEnumValues(true);
|
|
|
|
// Unknown enum values are output.
|
|
ow_.StartObject("")->RenderInt32("enumValue", 1234)->EndObject();
|
|
DoTest(message, Proto3Message::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTest, CyclicMessageDepthTest) {
|
|
Cyclic cyclic;
|
|
cyclic.set_m_int(123);
|
|
|
|
Book* book = cyclic.mutable_m_book();
|
|
book->set_title("book title");
|
|
Cyclic* current = cyclic.mutable_m_cyclic();
|
|
Author* current_author = cyclic.add_m_author();
|
|
for (int i = 0; i < 63; ++i) {
|
|
Author* next = current_author->add_friend_();
|
|
next->set_id(i);
|
|
next->set_name(StrCat("author_name_", i));
|
|
next->set_alive(true);
|
|
current_author = next;
|
|
}
|
|
|
|
// Recursive message with depth (65) > max (max is 64).
|
|
for (int i = 0; i < 64; ++i) {
|
|
Cyclic* next = current->mutable_m_cyclic();
|
|
next->set_m_str(StrCat("count_", i));
|
|
current = next;
|
|
}
|
|
|
|
util::Status status = ExecuteTest(cyclic, Cyclic::descriptor());
|
|
EXPECT_TRUE(util::IsInvalidArgument(status));
|
|
}
|
|
|
|
class ProtostreamObjectSourceMapsTest : public ProtostreamObjectSourceTest {
|
|
protected:
|
|
ProtostreamObjectSourceMapsTest() {
|
|
helper_.ResetTypeInfo(MapOut::descriptor());
|
|
}
|
|
};
|
|
|
|
INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
|
|
ProtostreamObjectSourceMapsTest,
|
|
::testing::Values(
|
|
testing::USE_TYPE_RESOLVER));
|
|
|
|
// Tests JSON map.
|
|
//
|
|
// This is the example expected output.
|
|
// {
|
|
// "map1": {
|
|
// "key1": {
|
|
// "foo": "foovalue"
|
|
// },
|
|
// "key2": {
|
|
// "foo": "barvalue"
|
|
// }
|
|
// },
|
|
// "map2": {
|
|
// "nestedself": {
|
|
// "map1": {
|
|
// "nested_key1": {
|
|
// "foo": "nested_foo"
|
|
// }
|
|
// },
|
|
// "bar": "nested_bar_string"
|
|
// }
|
|
// },
|
|
// "map3": {
|
|
// "111": "one one one"
|
|
// },
|
|
// "bar": "top bar"
|
|
// }
|
|
TEST_P(ProtostreamObjectSourceMapsTest, MapsTest) {
|
|
MapOut out;
|
|
(*out.mutable_map1())["key1"].set_foo("foovalue");
|
|
(*out.mutable_map1())["key2"].set_foo("barvalue");
|
|
|
|
MapOut* nested_value = &(*out.mutable_map2())["nestedself"];
|
|
(*nested_value->mutable_map1())["nested_key1"].set_foo("nested_foo");
|
|
nested_value->set_bar("nested_bar_string");
|
|
|
|
(*out.mutable_map3())[111] = "one one one";
|
|
|
|
out.set_bar("top bar");
|
|
|
|
ow_.StartObject("")
|
|
->StartObject("map1")
|
|
->StartObject("key1")
|
|
->RenderString("foo", "foovalue")
|
|
->EndObject()
|
|
->StartObject("key2")
|
|
->RenderString("foo", "barvalue")
|
|
->EndObject()
|
|
->StartObject("map2")
|
|
->StartObject("nestedself")
|
|
->StartObject("map1")
|
|
->StartObject("nested_key1")
|
|
->RenderString("foo", "nested_foo")
|
|
->EndObject()
|
|
->EndObject()
|
|
->RenderString("bar", "nested_bar_string")
|
|
->EndObject()
|
|
->EndObject()
|
|
->StartObject("map3")
|
|
->RenderString("111", "one one one")
|
|
->EndObject()
|
|
->EndObject()
|
|
->RenderString("bar", "top bar")
|
|
->EndObject();
|
|
|
|
DoTest(out, MapOut::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceMapsTest, MissingKeysTest) {
|
|
// MapOutWireFormat has the same wire representation with MapOut but uses
|
|
// repeated message fields to represent map fields so we can intentionally
|
|
// leave out the key field or the value field of a map entry.
|
|
MapOutWireFormat out;
|
|
// Create some map entries without keys. They will be rendered with the
|
|
// default values ("" for strings, "0" for integers, etc.).
|
|
// {
|
|
// "map1": {
|
|
// "": {
|
|
// "foo": "foovalue"
|
|
// }
|
|
// },
|
|
// "map2": {
|
|
// "": {
|
|
// "map1": {
|
|
// "nested_key1": {
|
|
// "foo": "nested_foo"
|
|
// }
|
|
// }
|
|
// }
|
|
// },
|
|
// "map3": {
|
|
// "0": "one one one"
|
|
// },
|
|
// "map4": {
|
|
// "false": "bool"
|
|
// }
|
|
// }
|
|
out.add_map1()->mutable_value()->set_foo("foovalue");
|
|
MapOut* nested = out.add_map2()->mutable_value();
|
|
(*nested->mutable_map1())["nested_key1"].set_foo("nested_foo");
|
|
out.add_map3()->set_value("one one one");
|
|
out.add_map4()->set_value("bool");
|
|
|
|
ow_.StartObject("")
|
|
->StartObject("map1")
|
|
->StartObject("")
|
|
->RenderString("foo", "foovalue")
|
|
->EndObject()
|
|
->EndObject()
|
|
->StartObject("map2")
|
|
->StartObject("")
|
|
->StartObject("map1")
|
|
->StartObject("nested_key1")
|
|
->RenderString("foo", "nested_foo")
|
|
->EndObject()
|
|
->EndObject()
|
|
->EndObject()
|
|
->EndObject()
|
|
->StartObject("map3")
|
|
->RenderString("0", "one one one")
|
|
->EndObject()
|
|
->StartObject("map4")
|
|
->RenderString("false", "bool")
|
|
->EndObject()
|
|
->EndObject();
|
|
|
|
DoTest(out, MapOut::descriptor());
|
|
}
|
|
|
|
class ProtostreamObjectSourceAnysTest : public ProtostreamObjectSourceTest {
|
|
protected:
|
|
ProtostreamObjectSourceAnysTest() {
|
|
helper_.ResetTypeInfo({AnyOut::descriptor(), Book::descriptor(),
|
|
google::protobuf::Any::descriptor()});
|
|
}
|
|
};
|
|
|
|
INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
|
|
ProtostreamObjectSourceAnysTest,
|
|
::testing::Values(
|
|
testing::USE_TYPE_RESOLVER));
|
|
|
|
// Tests JSON any support.
|
|
//
|
|
// This is the example expected output.
|
|
// {
|
|
// "any": {
|
|
// "@type": "type.googleapis.com/google.protobuf.testing.AnyM"
|
|
// "foo": "foovalue"
|
|
// }
|
|
// }
|
|
TEST_P(ProtostreamObjectSourceAnysTest, BasicAny) {
|
|
AnyOut out;
|
|
::google::protobuf::Any* any = out.mutable_any();
|
|
|
|
AnyM m;
|
|
m.set_foo("foovalue");
|
|
any->PackFrom(m);
|
|
|
|
ow_.StartObject("")
|
|
->StartObject("any")
|
|
->RenderString("@type",
|
|
"type.googleapis.com/proto_util_converter.testing.AnyM")
|
|
->RenderString("foo", "foovalue")
|
|
->EndObject()
|
|
->EndObject();
|
|
|
|
DoTest(out, AnyOut::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceAnysTest, LowerCamelEnumOutputSnakeCase) {
|
|
AnyOut out;
|
|
::google::protobuf::Any* any = out.mutable_any();
|
|
|
|
Book book;
|
|
book.set_type(Book::arts_and_photography);
|
|
any->PackFrom(book);
|
|
|
|
UseLowerCamelForEnums();
|
|
|
|
ow_.StartObject("")
|
|
->StartObject("any")
|
|
->RenderString("@type",
|
|
"type.googleapis.com/proto_util_converter.testing.Book")
|
|
->RenderString("type", "artsAndPhotography")
|
|
->EndObject()
|
|
->EndObject();
|
|
|
|
DoTest(out, AnyOut::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceAnysTest, UseIntsForEnumsTest) {
|
|
AnyOut out;
|
|
::google::protobuf::Any* any = out.mutable_any();
|
|
|
|
Book book;
|
|
book.set_type(Book::ACTION_AND_ADVENTURE);
|
|
any->PackFrom(book);
|
|
|
|
UseIntsForEnums();
|
|
|
|
ow_.StartObject("")
|
|
->StartObject("any")
|
|
->RenderString("@type",
|
|
"type.googleapis.com/proto_util_converter.testing.Book")
|
|
->RenderInt32("type", 3)
|
|
->EndObject()
|
|
->EndObject();
|
|
|
|
DoTest(out, AnyOut::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceAnysTest, UsePreserveProtoFieldNames) {
|
|
AnyOut out;
|
|
::google::protobuf::Any* any = out.mutable_any();
|
|
|
|
Book book;
|
|
book.set_snake_field("foo");
|
|
any->PackFrom(book);
|
|
|
|
UsePreserveProtoFieldNames();
|
|
|
|
ow_.StartObject("")
|
|
->StartObject("any")
|
|
->RenderString("@type",
|
|
"type.googleapis.com/proto_util_converter.testing.Book")
|
|
->RenderString("snake_field", "foo")
|
|
->EndObject()
|
|
->EndObject();
|
|
|
|
DoTest(out, AnyOut::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceAnysTest, RecursiveAny) {
|
|
AnyOut out;
|
|
::google::protobuf::Any* any = out.mutable_any();
|
|
any->set_type_url("type.googleapis.com/google.protobuf.Any");
|
|
|
|
::google::protobuf::Any nested_any;
|
|
nested_any.set_type_url(
|
|
"type.googleapis.com/proto_util_converter.testing.AnyM");
|
|
|
|
AnyM m;
|
|
m.set_foo("foovalue");
|
|
nested_any.set_value(m.SerializeAsString());
|
|
|
|
any->set_value(nested_any.SerializeAsString());
|
|
|
|
ow_.StartObject("")
|
|
->StartObject("any")
|
|
->RenderString("@type", "type.googleapis.com/google.protobuf.Any")
|
|
->StartObject("value")
|
|
->RenderString("@type",
|
|
"type.googleapis.com/proto_util_converter.testing.AnyM")
|
|
->RenderString("foo", "foovalue")
|
|
->EndObject()
|
|
->EndObject()
|
|
->EndObject();
|
|
|
|
DoTest(out, AnyOut::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceAnysTest, DoubleRecursiveAny) {
|
|
AnyOut out;
|
|
::google::protobuf::Any* any = out.mutable_any();
|
|
any->set_type_url("type.googleapis.com/google.protobuf.Any");
|
|
|
|
::google::protobuf::Any nested_any;
|
|
nested_any.set_type_url("type.googleapis.com/google.protobuf.Any");
|
|
|
|
::google::protobuf::Any second_nested_any;
|
|
second_nested_any.set_type_url(
|
|
"type.googleapis.com/proto_util_converter.testing.AnyM");
|
|
|
|
AnyM m;
|
|
m.set_foo("foovalue");
|
|
second_nested_any.set_value(m.SerializeAsString());
|
|
nested_any.set_value(second_nested_any.SerializeAsString());
|
|
any->set_value(nested_any.SerializeAsString());
|
|
|
|
ow_.StartObject("")
|
|
->StartObject("any")
|
|
->RenderString("@type", "type.googleapis.com/google.protobuf.Any")
|
|
->StartObject("value")
|
|
->RenderString("@type", "type.googleapis.com/google.protobuf.Any")
|
|
->StartObject("value")
|
|
->RenderString("@type",
|
|
"type.googleapis.com/proto_util_converter.testing.AnyM")
|
|
->RenderString("foo", "foovalue")
|
|
->EndObject()
|
|
->EndObject()
|
|
->EndObject()
|
|
->EndObject();
|
|
|
|
DoTest(out, AnyOut::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceAnysTest, EmptyAnyOutputsEmptyObject) {
|
|
AnyOut out;
|
|
out.mutable_any();
|
|
|
|
ow_.StartObject("")->StartObject("any")->EndObject()->EndObject();
|
|
|
|
DoTest(out, AnyOut::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceAnysTest, EmptyWithTypeAndNoValueOutputsType) {
|
|
AnyOut out;
|
|
out.mutable_any()->set_type_url("foo.googleapis.com/my.Type");
|
|
|
|
ow_.StartObject("")
|
|
->StartObject("any")
|
|
->RenderString("@type", "foo.googleapis.com/my.Type")
|
|
->EndObject()
|
|
->EndObject();
|
|
|
|
DoTest(out, AnyOut::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceAnysTest, MissingTypeUrlError) {
|
|
AnyOut out;
|
|
::google::protobuf::Any* any = out.mutable_any();
|
|
|
|
AnyM m;
|
|
m.set_foo("foovalue");
|
|
any->set_value(m.SerializeAsString());
|
|
|
|
// We start the "AnyOut" part and then fail when we hit the Any object.
|
|
ow_.StartObject("");
|
|
|
|
util::Status status = ExecuteTest(out, AnyOut::descriptor());
|
|
EXPECT_TRUE(util::IsInternal(status));
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceAnysTest, UnknownTypeServiceError) {
|
|
AnyOut out;
|
|
::google::protobuf::Any* any = out.mutable_any();
|
|
any->set_type_url("foo.googleapis.com/my.own.Type");
|
|
|
|
AnyM m;
|
|
m.set_foo("foovalue");
|
|
any->set_value(m.SerializeAsString());
|
|
|
|
// We start the "AnyOut" part and then fail when we hit the Any object.
|
|
ow_.StartObject("");
|
|
|
|
util::Status status = ExecuteTest(out, AnyOut::descriptor());
|
|
EXPECT_TRUE(util::IsInternal(status));
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceAnysTest, UnknownTypeError) {
|
|
AnyOut out;
|
|
::google::protobuf::Any* any = out.mutable_any();
|
|
any->set_type_url("type.googleapis.com/unknown.Type");
|
|
|
|
AnyM m;
|
|
m.set_foo("foovalue");
|
|
any->set_value(m.SerializeAsString());
|
|
|
|
// We start the "AnyOut" part and then fail when we hit the Any object.
|
|
ow_.StartObject("");
|
|
|
|
util::Status status = ExecuteTest(out, AnyOut::descriptor());
|
|
EXPECT_TRUE(util::IsInternal(status));
|
|
}
|
|
|
|
class ProtostreamObjectSourceStructTest : public ProtostreamObjectSourceTest {
|
|
protected:
|
|
ProtostreamObjectSourceStructTest() {
|
|
helper_.ResetTypeInfo(StructType::descriptor(),
|
|
google::protobuf::Struct::descriptor());
|
|
}
|
|
};
|
|
|
|
INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
|
|
ProtostreamObjectSourceStructTest,
|
|
::testing::Values(
|
|
testing::USE_TYPE_RESOLVER));
|
|
|
|
// Tests struct
|
|
//
|
|
// "object": {
|
|
// "k1": 123,
|
|
// "k2": true
|
|
// }
|
|
TEST_P(ProtostreamObjectSourceStructTest, StructRenderSuccess) {
|
|
StructType out;
|
|
google::protobuf::Struct* s = out.mutable_object();
|
|
s->mutable_fields()->operator[]("k1").set_number_value(123);
|
|
s->mutable_fields()->operator[]("k2").set_bool_value(true);
|
|
|
|
ow_.StartObject("")
|
|
->StartObject("object")
|
|
->RenderDouble("k1", 123)
|
|
->RenderBool("k2", true)
|
|
->EndObject()
|
|
->EndObject();
|
|
|
|
DoTest(out, StructType::descriptor());
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceStructTest, MissingValueSkipsField) {
|
|
StructType out;
|
|
google::protobuf::Struct* s = out.mutable_object();
|
|
s->mutable_fields()->operator[]("k1");
|
|
|
|
ow_.StartObject("")->StartObject("object")->EndObject()->EndObject();
|
|
|
|
DoTest(out, StructType::descriptor());
|
|
}
|
|
|
|
class ProtostreamObjectSourceFieldMaskTest
|
|
: public ProtostreamObjectSourceTest {
|
|
protected:
|
|
ProtostreamObjectSourceFieldMaskTest() {
|
|
helper_.ResetTypeInfo(FieldMaskTest::descriptor(),
|
|
google::protobuf::FieldMask::descriptor());
|
|
}
|
|
};
|
|
|
|
INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
|
|
ProtostreamObjectSourceFieldMaskTest,
|
|
::testing::Values(
|
|
testing::USE_TYPE_RESOLVER));
|
|
|
|
TEST_P(ProtostreamObjectSourceFieldMaskTest, FieldMaskRenderSuccess) {
|
|
FieldMaskTest out;
|
|
out.set_id("1");
|
|
out.mutable_single_mask()->add_paths("path1");
|
|
out.mutable_single_mask()->add_paths("snake_case_path2");
|
|
::google::protobuf::FieldMask* mask = out.add_repeated_mask();
|
|
mask->add_paths("path3");
|
|
mask = out.add_repeated_mask();
|
|
mask->add_paths("snake_case_path4");
|
|
mask->add_paths("path5");
|
|
NestedFieldMask* nested = out.add_nested_mask();
|
|
nested->set_data("data");
|
|
nested->mutable_single_mask()->add_paths("nested.path1");
|
|
nested->mutable_single_mask()->add_paths("nested_field.snake_case_path2");
|
|
mask = nested->add_repeated_mask();
|
|
mask->add_paths("nested_field.path3");
|
|
mask->add_paths("nested.snake_case_path4");
|
|
mask = nested->add_repeated_mask();
|
|
mask->add_paths("nested.path5");
|
|
mask = nested->add_repeated_mask();
|
|
mask->add_paths(
|
|
"snake_case.map_field[\"map_key_should_be_ignored\"].nested_snake_case."
|
|
"map_field[\"map_key_sho\\\"uld_be_ignored\"]");
|
|
|
|
ow_.StartObject("")
|
|
->RenderString("id", "1")
|
|
->RenderString("singleMask", "path1,snakeCasePath2")
|
|
->StartList("repeatedMask")
|
|
->RenderString("", "path3")
|
|
->RenderString("", "snakeCasePath4,path5")
|
|
->EndList()
|
|
->StartList("nestedMask")
|
|
->StartObject("")
|
|
->RenderString("data", "data")
|
|
->RenderString("singleMask", "nested.path1,nestedField.snakeCasePath2")
|
|
->StartList("repeatedMask")
|
|
->RenderString("", "nestedField.path3,nested.snakeCasePath4")
|
|
->RenderString("", "nested.path5")
|
|
->RenderString("",
|
|
"snakeCase.mapField[\"map_key_should_be_ignored\"]."
|
|
"nestedSnakeCase.mapField[\"map_key_sho\\\"uld_be_"
|
|
"ignored\"]")
|
|
->EndList()
|
|
->EndObject()
|
|
->EndList()
|
|
->EndObject();
|
|
|
|
DoTest(out, FieldMaskTest::descriptor());
|
|
}
|
|
|
|
class ProtostreamObjectSourceTimestampTest
|
|
: public ProtostreamObjectSourceTest {
|
|
protected:
|
|
ProtostreamObjectSourceTimestampTest() {
|
|
helper_.ResetTypeInfo(TimestampDuration::descriptor());
|
|
}
|
|
};
|
|
|
|
INSTANTIATE_TEST_SUITE_P(DifferentTypeInfoSourceTest,
|
|
ProtostreamObjectSourceTimestampTest,
|
|
::testing::Values(
|
|
testing::USE_TYPE_RESOLVER));
|
|
|
|
TEST_P(ProtostreamObjectSourceTimestampTest, InvalidTimestampBelowMinTest) {
|
|
TimestampDuration out;
|
|
google::protobuf::Timestamp* ts = out.mutable_ts();
|
|
// Min allowed seconds - 1
|
|
ts->set_seconds(kTimestampMinSeconds - 1);
|
|
ow_.StartObject("");
|
|
|
|
util::Status status = ExecuteTest(out, TimestampDuration::descriptor());
|
|
EXPECT_TRUE(util::IsInternal(status));
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTimestampTest, InvalidTimestampAboveMaxTest) {
|
|
TimestampDuration out;
|
|
google::protobuf::Timestamp* ts = out.mutable_ts();
|
|
// Max allowed seconds + 1
|
|
ts->set_seconds(kTimestampMaxSeconds + 1);
|
|
ow_.StartObject("");
|
|
|
|
util::Status status = ExecuteTest(out, TimestampDuration::descriptor());
|
|
EXPECT_TRUE(util::IsInternal(status));
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTimestampTest, InvalidDurationBelowMinTest) {
|
|
TimestampDuration out;
|
|
google::protobuf::Duration* dur = out.mutable_dur();
|
|
// Min allowed seconds - 1
|
|
dur->set_seconds(kDurationMinSeconds - 1);
|
|
ow_.StartObject("");
|
|
|
|
util::Status status = ExecuteTest(out, TimestampDuration::descriptor());
|
|
EXPECT_TRUE(util::IsInternal(status));
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTimestampTest, InvalidDurationAboveMaxTest) {
|
|
TimestampDuration out;
|
|
google::protobuf::Duration* dur = out.mutable_dur();
|
|
// Min allowed seconds + 1
|
|
dur->set_seconds(kDurationMaxSeconds + 1);
|
|
ow_.StartObject("");
|
|
|
|
util::Status status = ExecuteTest(out, TimestampDuration::descriptor());
|
|
EXPECT_TRUE(util::IsInternal(status));
|
|
}
|
|
|
|
TEST_P(ProtostreamObjectSourceTimestampTest, TimestampDurationDefaultValue) {
|
|
TimestampDuration out;
|
|
out.mutable_ts()->set_seconds(0);
|
|
out.mutable_dur()->set_seconds(0);
|
|
|
|
ow_.StartObject("")
|
|
->RenderString("ts", "1970-01-01T00:00:00Z")
|
|
->RenderString("dur", "0s")
|
|
->EndObject();
|
|
|
|
DoTest(out, TimestampDuration::descriptor());
|
|
}
|
|
|
|
|
|
|
|
} // namespace converter
|
|
} // namespace util
|
|
} // namespace protobuf
|
|
} // namespace google
|