Merge pull request #10103 from zhangskz/sync-stage

Integrate from Piper for C++, Java, and Python
pull/10104/head
zhangskz 3 years ago committed by GitHub
commit 4548b4ac0e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 24
      java/core/src/main/java/com/google/protobuf/Message.java
  2. 2
      java/core/src/main/java/com/google/protobuf/MessageLite.java
  3. 1
      java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java
  4. 10
      python/google/protobuf/internal/message_test.py
  5. 19
      src/google/protobuf/message_unittest.inc
  6. 2
      src/google/protobuf/port_def.inc
  7. 1
      src/google/protobuf/port_undef.inc
  8. 16
      src/google/protobuf/repeated_field.h
  9. 14
      src/google/protobuf/stubs/status_macros.h
  10. 64
      src/google/protobuf/stubs/statusor.h
  11. 10
      src/google/protobuf/stubs/statusor_test.cc
  12. 1
      src/google/protobuf/unittest_mset.proto
  13. 734
      src/google/protobuf/util/json_util_test.cc
  14. 2
      third_party/benchmark

@ -39,11 +39,12 @@ import java.util.Map;
*
* <p>See also {@link MessageLite}, which defines most of the methods that typical users care about.
* {@link Message} adds methods that are not available in the "lite" runtime. The biggest added
* features are introspection and reflection; that is, getting descriptors for the message type
* and accessing the field values dynamically.
* features are introspection and reflection; that is, getting descriptors for the message type and
* accessing the field values dynamically.
*
* @author kenton@google.com Kenton Varda
*/
@CheckReturnValue
public interface Message extends MessageLite, MessageOrBuilder {
// (From MessageLite, re-declared here only for return type covariance.)
@ -102,6 +103,7 @@ public interface Message extends MessageLite, MessageOrBuilder {
// (From MessageLite.Builder, re-declared here only for return type
// covariance.)
@Override
@CanIgnoreReturnValue
Builder clear();
/**
@ -121,6 +123,7 @@ public interface Message extends MessageLite, MessageOrBuilder {
*
* <p>This is equivalent to the {@code Message::MergeFrom} method in C++.
*/
@CanIgnoreReturnValue
Builder mergeFrom(Message other);
// (From MessageLite.Builder, re-declared here only for return type
@ -135,9 +138,11 @@ public interface Message extends MessageLite, MessageOrBuilder {
Builder clone();
@Override
@CanIgnoreReturnValue
Builder mergeFrom(CodedInputStream input) throws IOException;
@Override
@CanIgnoreReturnValue
Builder mergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
throws IOException;
@ -190,18 +195,21 @@ public interface Message extends MessageLite, MessageOrBuilder {
* Sets a field to the given value. The value must be of the correct type for this field, that
* is, the same type that {@link Message#getField(Descriptors.FieldDescriptor)} returns.
*/
@CanIgnoreReturnValue
Builder setField(Descriptors.FieldDescriptor field, Object value);
/**
* Clears the field. This is exactly equivalent to calling the generated "clear" accessor method
* corresponding to the field.
*/
@CanIgnoreReturnValue
Builder clearField(Descriptors.FieldDescriptor field);
/**
* Clears the oneof. This is exactly equivalent to calling the generated "clear" accessor method
* corresponding to the oneof.
*/
@CanIgnoreReturnValue
Builder clearOneof(Descriptors.OneofDescriptor oneof);
/**
@ -212,6 +220,7 @@ public interface Message extends MessageLite, MessageOrBuilder {
* @throws IllegalArgumentException if the field is not a repeated field, or {@code
* field.getContainingType() != getDescriptorForType()}.
*/
@CanIgnoreReturnValue
Builder setRepeatedField(Descriptors.FieldDescriptor field, int index, Object value);
/**
@ -220,12 +229,15 @@ public interface Message extends MessageLite, MessageOrBuilder {
* @throws IllegalArgumentException if the field is not a repeated field, or {@code
* field.getContainingType() != getDescriptorForType()}
*/
@CanIgnoreReturnValue
Builder addRepeatedField(Descriptors.FieldDescriptor field, Object value);
/** Set the {@link UnknownFieldSet} for this message. */
@CanIgnoreReturnValue
Builder setUnknownFields(UnknownFieldSet unknownFields);
/** Merge some unknown fields into the {@link UnknownFieldSet} for this message. */
@CanIgnoreReturnValue
Builder mergeUnknownFields(UnknownFieldSet unknownFields);
// ---------------------------------------------------------------
@ -234,30 +246,38 @@ public interface Message extends MessageLite, MessageOrBuilder {
// (From MessageLite.Builder, re-declared here only for return type
// covariance.)
@Override
@CanIgnoreReturnValue
Builder mergeFrom(ByteString data) throws InvalidProtocolBufferException;
@Override
@CanIgnoreReturnValue
Builder mergeFrom(ByteString data, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
@Override
@CanIgnoreReturnValue
Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException;
@Override
@CanIgnoreReturnValue
Builder mergeFrom(byte[] data, int off, int len) throws InvalidProtocolBufferException;
@Override
@CanIgnoreReturnValue
Builder mergeFrom(byte[] data, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
@Override
@CanIgnoreReturnValue
Builder mergeFrom(byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
throws InvalidProtocolBufferException;
@Override
@CanIgnoreReturnValue
Builder mergeFrom(InputStream input) throws IOException;
@Override
@CanIgnoreReturnValue
Builder mergeFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
throws IOException;

@ -344,7 +344,6 @@ public interface MessageLite extends MessageLiteOrBuilder {
* a protobuf in the first place.
* @throws IOException an I/O error reading from the stream
*/
@CanIgnoreReturnValue // TODO(kak): should this be @CheckReturnValue instead?
boolean mergeDelimitedFrom(InputStream input) throws IOException;
/**
@ -357,7 +356,6 @@ public interface MessageLite extends MessageLiteOrBuilder {
* a protobuf in the first place.
* @throws IOException an I/O error reading from the stream
*/
@CanIgnoreReturnValue // TODO(kak): should this be @CheckReturnValue instead?
boolean mergeDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry)
throws IOException;
}

@ -39,6 +39,7 @@ import java.util.Map;
*
* @author jonp@google.com (Jon Perlow)
*/
@CheckReturnValue
public interface MessageOrBuilder extends MessageLiteOrBuilder {
// (From MessageLite, re-declared here only for return type covariance.)

@ -34,10 +34,6 @@
Note that the golden messages exercise every known field type, thus this
test ends up exercising and verifying nearly all of the parsing and
serialization code in the whole library.
TODO(kenton): Merge with wire_format_test? It doesn't make a whole lot of
sense to call this a test of the "message" module, which only declares an
abstract interface.
"""
__author__ = 'gps@google.com (Gregory P. Smith)'
@ -476,6 +472,12 @@ class MessageTest(unittest.TestCase):
'}\n')
self.assertEqual(sub_msg.bb, 1)
def testAssignRepeatedField(self, message_module):
msg = message_module.NestedTestAllTypes()
msg.payload.repeated_int32[:] = [1, 2, 3, 4]
self.assertEqual(4, len(msg.payload.repeated_int32))
self.assertEqual([1, 2, 3, 4], msg.payload.repeated_int32)
def testMergeFromRepeatedField(self, message_module):
msg = message_module.TestAllTypes()
msg.repeated_int32.append(1)

@ -422,6 +422,25 @@ TEST(MESSAGE_TEST_NAME, ParseFailsIfExtensionWireMalformed) {
EXPECT_FALSE(p.ParseFromString(serialized));
}
TEST(MESSAGE_TEST_NAME, ParseFailsIfGroupFieldMalformed) {
UNITTEST::TestMutualRecursionA original, parsed;
original.mutable_bb()
->mutable_a()
->mutable_subgroup()
->mutable_sub_message()
->mutable_b()
->set_optional_int32(-1);
std::string data;
ASSERT_TRUE(original.SerializeToString(&data));
// Should parse correctly.
ASSERT_TRUE(parsed.ParseFromString(data));
// Overwriting the last byte of varint (-1) to 0xFF results in malformed wire.
data[data.size() - 2] = 0xFF;
EXPECT_FALSE(parsed.ParseFromString(data));
}
TEST(MESSAGE_TEST_NAME, UninitializedAndMalformed) {
UNITTEST::TestRequiredForeign o, p1, p2;
o.mutable_optional_message()->set_a(-1);

@ -865,6 +865,8 @@
// Inconvenient macro names from usr/include/sys/syslimits.h in some macOS SDKs.
#pragma push_macro("UID_MAX")
#undef UID_MAX
#pragma push_macro("GID_MAX")
#undef GID_MAX
#endif // __APPLE__
#if defined(__clang__) || PROTOBUF_GNUC_MIN(3, 0) || defined(_MSC_VER)

@ -144,6 +144,7 @@
#pragma pop_macro("TRUE")
#pragma pop_macro("FALSE")
#pragma pop_macro("UID_MAX")
#pragma pop_macro("GID_MAX")
#endif // __APPLE__
#if defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER)

@ -454,8 +454,13 @@ class RepeatedField final {
//
// Typically, due to the fact that adder is a local stack variable, the
// compiler will be successful in mem-to-reg transformation and the machine
// code will be loop: cmp %size, %capacity jae fallback mov dword ptr [%buffer
// + %size * 4], %val inc %size jmp loop
// code will be
// loop:
// cmp %size, %capacity
// jae fallback
// mov dword ptr [%buffer + %size * 4], %val
// inc %size
// jmp loop
//
// The first version executes at 7 cycles per iteration while the second
// version executes at only 1 or 2 cycles.
@ -467,6 +472,8 @@ class RepeatedField final {
capacity_ = repeated_field_->total_size_;
buffer_ = repeated_field_->unsafe_elements();
}
FastAdderImpl(const FastAdderImpl&) = delete;
FastAdderImpl& operator=(const FastAdderImpl&) = delete;
~FastAdderImpl() { repeated_field_->current_size_ = index_; }
void Add(Element val) {
@ -484,8 +491,6 @@ class RepeatedField final {
int index_;
int capacity_;
Element* buffer_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FastAdderImpl);
};
// FastAdder is a wrapper for adding fields. The specialization above handles
@ -494,11 +499,12 @@ class RepeatedField final {
class FastAdderImpl<I, false> {
public:
explicit FastAdderImpl(RepeatedField* rf) : repeated_field_(rf) {}
FastAdderImpl(const FastAdderImpl&) = delete;
FastAdderImpl& operator=(const FastAdderImpl&) = delete;
void Add(const Element& val) { repeated_field_->Add(val); }
private:
RepeatedField* repeated_field_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FastAdderImpl);
};
using FastAdder = FastAdderImpl<>;

@ -37,9 +37,14 @@
#include <google/protobuf/stubs/status.h>
#include <google/protobuf/stubs/statusor.h>
#include <google/protobuf/port_def.inc>
namespace google {
namespace protobuf {
namespace util {
namespace status_macros_internal {
using PROTOBUF_NAMESPACE_ID::util::Status;
} // namespace status_macros_internal
// Run a command that returns a util::Status. If the called code returns an
// error status, return that status up out of this method too.
@ -49,7 +54,8 @@ namespace util {
#define RETURN_IF_ERROR(expr) \
do { \
/* Using _status below to avoid capture problems if expr is "status". */ \
const PROTOBUF_NAMESPACE_ID::util::Status _status = (expr); \
const ::google::protobuf::util::status_macros_internal::Status _status = \
(expr); \
if (PROTOBUF_PREDICT_FALSE(!_status.ok())) return _status; \
} while (0)
@ -57,7 +63,7 @@ namespace util {
#define STATUS_MACROS_CONCAT_NAME_INNER(x, y) x##y
#define STATUS_MACROS_CONCAT_NAME(x, y) STATUS_MACROS_CONCAT_NAME_INNER(x, y)
template<typename T>
template <typename T>
Status DoAssignOrReturn(T& lhs, StatusOr<T> result) {
if (result.ok()) {
lhs = result.value();
@ -79,11 +85,13 @@ Status DoAssignOrReturn(T& lhs, StatusOr<T> result) {
// WARNING: ASSIGN_OR_RETURN expands into multiple statements; it cannot be used
// in a single statement (e.g. as the body of an if statement without {})!
#define ASSIGN_OR_RETURN(lhs, rexpr) \
ASSIGN_OR_RETURN_IMPL( \
ASSIGN_OR_RETURN_IMPL( \
STATUS_MACROS_CONCAT_NAME(_status_or_value, __COUNTER__), lhs, rexpr);
} // namespace util
} // namespace protobuf
} // namespace google
#include <google/protobuf/port_undef.inc>
#endif // GOOGLE_PROTOBUF_STUBS_STATUS_H_

@ -72,12 +72,13 @@
#ifndef GOOGLE_PROTOBUF_STUBS_STATUSOR_H_
#define GOOGLE_PROTOBUF_STUBS_STATUSOR_H_
#include <google/protobuf/stubs/status.h>
#include <new>
#include <string>
#include <utility>
#include <google/protobuf/stubs/status.h>
// Must be included last.
#include <google/protobuf/port_def.inc>
namespace google {
@ -85,9 +86,10 @@ namespace protobuf {
namespace util {
namespace statusor_internal {
template<typename T>
template <typename T>
class StatusOr {
template<typename U> friend class StatusOr;
template <typename U>
friend class StatusOr;
public:
using value_type = T;
@ -125,14 +127,14 @@ class StatusOr {
StatusOr(const StatusOr& other);
// Conversion copy constructor, T must be copy constructible from U
template<typename U>
template <typename U>
StatusOr(const StatusOr<U>& other);
// Assignment operator.
StatusOr& operator=(const StatusOr& other);
// Conversion assignment operator, T must be assignable from U
template<typename U>
template <typename U>
StatusOr& operator=(const StatusOr<U>& other);
// Returns a reference to our status. If this contains a T, then
@ -143,7 +145,14 @@ class StatusOr {
bool ok() const;
// Returns a reference to our current value, or CHECK-fails if !this->ok().
const T& value () const;
const T& value() const;
T& value();
// Returns a reference to our current value; UB if not OK.
const T& operator*() const { return value(); }
T& operator*() { return value(); }
const T* operator->() const { return &value(); }
T* operator->() { return &value(); }
private:
Status status_;
@ -159,17 +168,17 @@ class PROTOBUF_EXPORT StatusOrHelper {
static void Crash(const util::Status& status);
// Customized behavior for StatusOr<T> vs. StatusOr<T*>
template<typename T>
template <typename T>
struct Specialize;
};
template<typename T>
template <typename T>
struct StatusOrHelper::Specialize {
// For non-pointer T, a reference can never be nullptr.
static inline bool IsValueNull(const T& /*t*/) { return false; }
};
template<typename T>
template <typename T>
struct StatusOrHelper::Specialize<T*> {
static inline bool IsValueNull(const T* t) { return t == nullptr; }
};
@ -177,7 +186,7 @@ struct StatusOrHelper::Specialize<T*> {
template <typename T>
inline StatusOr<T>::StatusOr() : status_(util::UnknownError("")) {}
template<typename T>
template <typename T>
inline StatusOr<T>::StatusOr(const Status& status) {
if (status.ok()) {
status_ = util::InternalError("OkStatus() is not a valid argument.");
@ -186,7 +195,7 @@ inline StatusOr<T>::StatusOr(const Status& status) {
}
}
template<typename T>
template <typename T>
inline StatusOr<T>::StatusOr(const T& value) {
if (StatusOrHelper::Specialize<T>::IsValueNull(value)) {
status_ = util::InternalError("nullptr is not a valid argument.");
@ -196,43 +205,41 @@ inline StatusOr<T>::StatusOr(const T& value) {
}
}
template<typename T>
template <typename T>
inline StatusOr<T>::StatusOr(const StatusOr<T>& other)
: status_(other.status_), value_(other.value_) {
}
: status_(other.status_), value_(other.value_) {}
template<typename T>
template <typename T>
inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<T>& other) {
status_ = other.status_;
value_ = other.value_;
return *this;
}
template<typename T>
template<typename U>
template <typename T>
template <typename U>
inline StatusOr<T>::StatusOr(const StatusOr<U>& other)
: status_(other.status_), value_(other.status_.ok() ? other.value_ : T()) {
}
: status_(other.status_), value_(other.status_.ok() ? other.value_ : T()) {}
template<typename T>
template<typename U>
template <typename T>
template <typename U>
inline StatusOr<T>& StatusOr<T>::operator=(const StatusOr<U>& other) {
status_ = other.status_;
if (status_.ok()) value_ = other.value_;
return *this;
}
template<typename T>
template <typename T>
inline const Status& StatusOr<T>::status() const {
return status_;
}
template<typename T>
template <typename T>
inline bool StatusOr<T>::ok() const {
return status().ok();
}
template<typename T>
template <typename T>
inline const T& StatusOr<T>::value() const {
if (!status_.ok()) {
StatusOrHelper::Crash(status_);
@ -240,6 +247,13 @@ inline const T& StatusOr<T>::value() const {
return value_;
}
template <typename T>
inline T& StatusOr<T>::value() {
if (!status_.ok()) {
StatusOrHelper::Crash(status_);
}
return value_;
}
} // namespace statusor_internal
using ::google::protobuf::util::statusor_internal::StatusOr;

@ -87,6 +87,16 @@ TEST(StatusOr, TestValueCtor) {
EXPECT_EQ(kI, thing.value());
}
TEST(StatusOr, TestPtrOps) {
const int kI = 4;
StatusOr<int> thing(kI);
EXPECT_TRUE(thing.ok());
EXPECT_EQ(kI, *thing);
StatusOr<StatusOr<int>> thing2(thing);
EXPECT_EQ(kI, thing2->value());
}
TEST(StatusOr, TestCopyCtorStatusOk) {
const int kI = 4;
StatusOr<int> original(kI);

@ -55,6 +55,7 @@ message NestedTestMessageSetContainer {
message NestedTestInt {
optional fixed32 a = 1;
optional int32 b = 3;
optional NestedTestInt child = 2;
}

@ -30,11 +30,16 @@
#include <google/protobuf/util/json_util.h>
#include <algorithm>
#include <cstdint>
#include <list>
#include <string>
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <google/protobuf/stubs/status.h>
#include <google/protobuf/stubs/statusor.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/descriptor_database.h>
#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/io/zero_copy_stream.h>
@ -42,161 +47,177 @@
#include <google/protobuf/util/internal/testdata/maps.pb.h>
#include <google/protobuf/util/json_format.pb.h>
#include <google/protobuf/util/json_format_proto3.pb.h>
#include <google/protobuf/util/json_format_proto3.pb.h>
#include <google/protobuf/util/type_resolver.h>
#include <google/protobuf/util/type_resolver_util.h>
#include <google/protobuf/stubs/status_macros.h>
// Must be included last.
#include <google/protobuf/port_def.inc>
namespace google {
namespace protobuf {
namespace util {
namespace {
using proto3::BAR;
using proto3::FOO;
using proto3::TestAny;
using proto3::TestEnumValue;
using proto3::TestMap;
using proto3::TestMessage;
using proto3::TestOneof;
using proto_util_converter::testing::MapIn;
using ::proto3::TestAny;
using ::proto3::TestEnumValue;
using ::proto3::TestMap;
using ::proto3::TestMessage;
using ::proto3::TestOneof;
using ::proto_util_converter::testing::MapIn;
// TODO(b/234474291): Use the gtest versions once that's available in OSS.
MATCHER_P(IsOkAndHolds, inner,
StrCat("is OK and holds ", testing::PrintToString(inner))) {
if (!arg.ok()) {
*result_listener << arg.status();
return false;
}
return testing::ExplainMatchResult(inner, *arg, result_listener);
}
util::Status GetStatus(const util::Status& s) { return s; }
template <typename T>
util::Status GetStatus(const util::StatusOr<T>& s) {
return s.status();
}
MATCHER_P(StatusIs, status,
StrCat(".status() is ", testing::PrintToString(status))) {
return GetStatus(arg).code() == status;
}
#define EXPECT_OK(x) EXPECT_THAT(x, StatusIs(util::StatusCode::kOk))
#define ASSERT_OK(x) ASSERT_THAT(x, StatusIs(util::StatusCode::kOk))
// As functions defined in json_util.h are just thin wrappers around the
// JSON conversion code in //net/proto2/util/converter, in this test we
// only cover some very basic cases to make sure the wrappers have forwarded
// parameters to the underlying implementation correctly. More detailed
// tests are contained in the //net/proto2/util/converter directory.
class JsonUtilTest : public ::testing::Test {
protected:
JsonUtilTest() {}
std::string ToJson(const Message& message, const JsonPrintOptions& options) {
std::string result;
GOOGLE_CHECK_OK(MessageToJsonString(message, &result, options));
return result;
}
bool FromJson(const std::string& json, Message* message,
const JsonParseOptions& options) {
return JsonStringToMessage(json, message, options).ok();
}
bool FromJson(const std::string& json, Message* message) {
return FromJson(json, message, JsonParseOptions());
}
util::StatusOr<std::string> ToJson(const Message& message,
const JsonPrintOptions& options = {}) {
std::string result;
RETURN_IF_ERROR(MessageToJsonString(message, &result, options));
return result;
}
std::unique_ptr<TypeResolver> resolver_;
};
util::Status FromJson(StringPiece json, Message* message,
const JsonParseOptions& options = {}) {
return JsonStringToMessage(json, message, options);
}
TEST_F(JsonUtilTest, TestWhitespaces) {
TEST(JsonUtilTest, TestWhitespaces) {
TestMessage m;
m.mutable_message_value();
EXPECT_THAT(ToJson(m), IsOkAndHolds("{\"messageValue\":{}}"));
JsonPrintOptions options;
EXPECT_EQ("{\"messageValue\":{}}", ToJson(m, options));
options.add_whitespace = true;
EXPECT_EQ(
"{\n"
" \"messageValue\": {}\n"
"}\n",
ToJson(m, options));
EXPECT_THAT(ToJson(m, options), IsOkAndHolds("{\n"
" \"messageValue\": {}\n"
"}\n"));
}
TEST_F(JsonUtilTest, TestDefaultValues) {
TEST(JsonUtilTest, TestDefaultValues) {
TestMessage m;
EXPECT_THAT(ToJson(m), IsOkAndHolds("{}"));
JsonPrintOptions options;
EXPECT_EQ("{}", ToJson(m, options));
options.always_print_primitive_fields = true;
EXPECT_EQ(
"{\"boolValue\":false,"
"\"int32Value\":0,"
"\"int64Value\":\"0\","
"\"uint32Value\":0,"
"\"uint64Value\":\"0\","
"\"floatValue\":0,"
"\"doubleValue\":0,"
"\"stringValue\":\"\","
"\"bytesValue\":\"\","
"\"enumValue\":\"FOO\","
"\"repeatedBoolValue\":[],"
"\"repeatedInt32Value\":[],"
"\"repeatedInt64Value\":[],"
"\"repeatedUint32Value\":[],"
"\"repeatedUint64Value\":[],"
"\"repeatedFloatValue\":[],"
"\"repeatedDoubleValue\":[],"
"\"repeatedStringValue\":[],"
"\"repeatedBytesValue\":[],"
"\"repeatedEnumValue\":[],"
"\"repeatedMessageValue\":[]"
"}",
ToJson(m, options));
EXPECT_THAT(ToJson(m, options), IsOkAndHolds("{\"boolValue\":false,"
"\"int32Value\":0,"
"\"int64Value\":\"0\","
"\"uint32Value\":0,"
"\"uint64Value\":\"0\","
"\"floatValue\":0,"
"\"doubleValue\":0,"
"\"stringValue\":\"\","
"\"bytesValue\":\"\","
"\"enumValue\":\"FOO\","
"\"repeatedBoolValue\":[],"
"\"repeatedInt32Value\":[],"
"\"repeatedInt64Value\":[],"
"\"repeatedUint32Value\":[],"
"\"repeatedUint64Value\":[],"
"\"repeatedFloatValue\":[],"
"\"repeatedDoubleValue\":[],"
"\"repeatedStringValue\":[],"
"\"repeatedBytesValue\":[],"
"\"repeatedEnumValue\":[],"
"\"repeatedMessageValue\":[]"
"}"));
options.always_print_primitive_fields = true;
m.set_string_value("i am a test string value");
m.set_bytes_value("i am a test bytes value");
EXPECT_EQ(
"{\"boolValue\":false,"
"\"int32Value\":0,"
"\"int64Value\":\"0\","
"\"uint32Value\":0,"
"\"uint64Value\":\"0\","
"\"floatValue\":0,"
"\"doubleValue\":0,"
"\"stringValue\":\"i am a test string value\","
"\"bytesValue\":\"aSBhbSBhIHRlc3QgYnl0ZXMgdmFsdWU=\","
"\"enumValue\":\"FOO\","
"\"repeatedBoolValue\":[],"
"\"repeatedInt32Value\":[],"
"\"repeatedInt64Value\":[],"
"\"repeatedUint32Value\":[],"
"\"repeatedUint64Value\":[],"
"\"repeatedFloatValue\":[],"
"\"repeatedDoubleValue\":[],"
"\"repeatedStringValue\":[],"
"\"repeatedBytesValue\":[],"
"\"repeatedEnumValue\":[],"
"\"repeatedMessageValue\":[]"
"}",
ToJson(m, options));
EXPECT_THAT(
ToJson(m, options),
IsOkAndHolds("{\"boolValue\":false,"
"\"int32Value\":0,"
"\"int64Value\":\"0\","
"\"uint32Value\":0,"
"\"uint64Value\":\"0\","
"\"floatValue\":0,"
"\"doubleValue\":0,"
"\"stringValue\":\"i am a test string value\","
"\"bytesValue\":\"aSBhbSBhIHRlc3QgYnl0ZXMgdmFsdWU=\","
"\"enumValue\":\"FOO\","
"\"repeatedBoolValue\":[],"
"\"repeatedInt32Value\":[],"
"\"repeatedInt64Value\":[],"
"\"repeatedUint32Value\":[],"
"\"repeatedUint64Value\":[],"
"\"repeatedFloatValue\":[],"
"\"repeatedDoubleValue\":[],"
"\"repeatedStringValue\":[],"
"\"repeatedBytesValue\":[],"
"\"repeatedEnumValue\":[],"
"\"repeatedMessageValue\":[]"
"}"));
options.preserve_proto_field_names = true;
m.set_string_value("i am a test string value");
m.set_bytes_value("i am a test bytes value");
EXPECT_EQ(
"{\"bool_value\":false,"
"\"int32_value\":0,"
"\"int64_value\":\"0\","
"\"uint32_value\":0,"
"\"uint64_value\":\"0\","
"\"float_value\":0,"
"\"double_value\":0,"
"\"string_value\":\"i am a test string value\","
"\"bytes_value\":\"aSBhbSBhIHRlc3QgYnl0ZXMgdmFsdWU=\","
"\"enum_value\":\"FOO\","
"\"repeated_bool_value\":[],"
"\"repeated_int32_value\":[],"
"\"repeated_int64_value\":[],"
"\"repeated_uint32_value\":[],"
"\"repeated_uint64_value\":[],"
"\"repeated_float_value\":[],"
"\"repeated_double_value\":[],"
"\"repeated_string_value\":[],"
"\"repeated_bytes_value\":[],"
"\"repeated_enum_value\":[],"
"\"repeated_message_value\":[]"
"}",
ToJson(m, options));
EXPECT_THAT(
ToJson(m, options),
IsOkAndHolds("{\"bool_value\":false,"
"\"int32_value\":0,"
"\"int64_value\":\"0\","
"\"uint32_value\":0,"
"\"uint64_value\":\"0\","
"\"float_value\":0,"
"\"double_value\":0,"
"\"string_value\":\"i am a test string value\","
"\"bytes_value\":\"aSBhbSBhIHRlc3QgYnl0ZXMgdmFsdWU=\","
"\"enum_value\":\"FOO\","
"\"repeated_bool_value\":[],"
"\"repeated_int32_value\":[],"
"\"repeated_int64_value\":[],"
"\"repeated_uint32_value\":[],"
"\"repeated_uint64_value\":[],"
"\"repeated_float_value\":[],"
"\"repeated_double_value\":[],"
"\"repeated_string_value\":[],"
"\"repeated_bytes_value\":[],"
"\"repeated_enum_value\":[],"
"\"repeated_message_value\":[]"
"}"));
}
TEST_F(JsonUtilTest, TestPreserveProtoFieldNames) {
TEST(JsonUtilTest, TestPreserveProtoFieldNames) {
TestMessage m;
m.mutable_message_value();
JsonPrintOptions options;
options.preserve_proto_field_names = true;
EXPECT_EQ("{\"message_value\":{}}", ToJson(m, options));
EXPECT_THAT(ToJson(m, options), IsOkAndHolds("{\"message_value\":{}}"));
}
TEST_F(JsonUtilTest, TestAlwaysPrintEnumsAsInts) {
TEST(JsonUtilTest, TestAlwaysPrintEnumsAsInts) {
TestMessage orig;
orig.set_enum_value(proto3::BAR);
orig.add_repeated_enum_value(proto3::FOO);
@ -205,20 +226,20 @@ TEST_F(JsonUtilTest, TestAlwaysPrintEnumsAsInts) {
JsonPrintOptions print_options;
print_options.always_print_enums_as_ints = true;
std::string expected_json = "{\"enumValue\":1,\"repeatedEnumValue\":[0,1]}";
EXPECT_EQ(expected_json, ToJson(orig, print_options));
auto printed = ToJson(orig, print_options);
ASSERT_THAT(printed,
IsOkAndHolds("{\"enumValue\":1,\"repeatedEnumValue\":[0,1]}"));
TestMessage parsed;
JsonParseOptions parse_options;
ASSERT_TRUE(FromJson(expected_json, &parsed, parse_options));
ASSERT_OK(FromJson(*printed, &parsed));
EXPECT_EQ(proto3::BAR, parsed.enum_value());
EXPECT_EQ(2, parsed.repeated_enum_value_size());
EXPECT_EQ(proto3::FOO, parsed.repeated_enum_value(0));
EXPECT_EQ(proto3::BAR, parsed.repeated_enum_value(1));
EXPECT_EQ(parsed.enum_value(), proto3::BAR);
EXPECT_EQ(parsed.repeated_enum_value_size(), 2);
EXPECT_EQ(parsed.repeated_enum_value(0), proto3::FOO);
EXPECT_EQ(parsed.repeated_enum_value(1), proto3::BAR);
}
TEST_F(JsonUtilTest, TestPrintEnumsAsIntsWithDefaultValue) {
TEST(JsonUtilTest, TestPrintEnumsAsIntsWithDefaultValue) {
TestEnumValue orig;
// orig.set_enum_value1(proto3::FOO)
orig.set_enum_value2(proto3::FOO);
@ -228,20 +249,20 @@ TEST_F(JsonUtilTest, TestPrintEnumsAsIntsWithDefaultValue) {
print_options.always_print_enums_as_ints = true;
print_options.always_print_primitive_fields = true;
std::string expected_json =
"{\"enumValue1\":0,\"enumValue2\":0,\"enumValue3\":1}";
EXPECT_EQ(expected_json, ToJson(orig, print_options));
auto printed = ToJson(orig, print_options);
ASSERT_THAT(
printed,
IsOkAndHolds("{\"enumValue1\":0,\"enumValue2\":0,\"enumValue3\":1}"));
TestEnumValue parsed;
JsonParseOptions parse_options;
ASSERT_TRUE(FromJson(expected_json, &parsed, parse_options));
ASSERT_OK(FromJson(*printed, &parsed));
EXPECT_EQ(proto3::FOO, parsed.enum_value1());
EXPECT_EQ(proto3::FOO, parsed.enum_value2());
EXPECT_EQ(proto3::BAR, parsed.enum_value3());
EXPECT_EQ(parsed.enum_value1(), proto3::FOO);
EXPECT_EQ(parsed.enum_value2(), proto3::FOO);
EXPECT_EQ(parsed.enum_value3(), proto3::BAR);
}
TEST_F(JsonUtilTest, TestPrintProto2EnumAsIntWithDefaultValue) {
TEST(JsonUtilTest, TestPrintProto2EnumAsIntWithDefaultValue) {
protobuf_unittest::TestDefaultEnumValue orig;
JsonPrintOptions print_options;
@ -250,111 +271,105 @@ TEST_F(JsonUtilTest, TestPrintProto2EnumAsIntWithDefaultValue) {
print_options.always_print_primitive_fields = true;
// result should be int rather than string
std::string expected_json = "{\"enumValue\":2}";
EXPECT_EQ(expected_json, ToJson(orig, print_options));
auto printed = ToJson(orig, print_options);
ASSERT_THAT(printed, IsOkAndHolds("{\"enumValue\":2}"));
protobuf_unittest::TestDefaultEnumValue parsed;
JsonParseOptions parse_options;
ASSERT_TRUE(FromJson(expected_json, &parsed, parse_options));
ASSERT_OK(FromJson(*printed, &parsed));
EXPECT_EQ(protobuf_unittest::DEFAULT, parsed.enum_value());
EXPECT_EQ(parsed.enum_value(), protobuf_unittest::DEFAULT);
}
TEST_F(JsonUtilTest, ParseMessage) {
TEST(JsonUtilTest, ParseMessage) {
// Some random message but good enough to verify that the parsing wrapper
// functions are working properly.
std::string input =
"{\n"
" \"int32Value\": 1234567891,\n"
" \"int64Value\": 5302428716536692736,\n"
" \"floatValue\": 3.4028235e+38,\n"
" \"repeatedInt32Value\": [1, 2],\n"
" \"messageValue\": {\n"
" \"value\": 2048\n"
" },\n"
" \"repeatedMessageValue\": [\n"
" {\"value\": 40}, {\"value\": 96}\n"
" ]\n"
"}\n";
JsonParseOptions options;
TestMessage m;
ASSERT_TRUE(FromJson(input, &m, options));
EXPECT_EQ(1234567891, m.int32_value());
EXPECT_EQ(5302428716536692736, m.int64_value());
EXPECT_EQ(3.402823466e+38f, m.float_value());
ASSERT_EQ(2, m.repeated_int32_value_size());
EXPECT_EQ(1, m.repeated_int32_value(0));
EXPECT_EQ(2, m.repeated_int32_value(1));
EXPECT_EQ(2048, m.message_value().value());
ASSERT_EQ(2, m.repeated_message_value_size());
EXPECT_EQ(40, m.repeated_message_value(0).value());
EXPECT_EQ(96, m.repeated_message_value(1).value());
ASSERT_OK(FromJson(R"json(
{
"int32Value": 1234567891,
"int64Value": 5302428716536692736,
"floatValue": 3.4028235e+38,
"repeatedInt32Value": [1, 2],
"messageValue": {
"value": 2048
},
"repeatedMessageValue": [
{"value": 40},
{"value": 96}
]
}
)json",
&m));
EXPECT_EQ(m.int32_value(), 1234567891);
EXPECT_EQ(m.int64_value(), 5302428716536692736);
EXPECT_EQ(m.float_value(), 3.402823466e+38f);
ASSERT_EQ(m.repeated_int32_value_size(), 2);
EXPECT_EQ(m.repeated_int32_value(0), 1);
EXPECT_EQ(m.repeated_int32_value(1), 2);
EXPECT_EQ(m.message_value().value(), 2048);
ASSERT_EQ(m.repeated_message_value_size(), 2);
EXPECT_EQ(m.repeated_message_value(0).value(), 40);
EXPECT_EQ(m.repeated_message_value(1).value(), 96);
}
TEST_F(JsonUtilTest, ParseMap) {
TEST(JsonUtilTest, ParseMap) {
TestMap message;
(*message.mutable_string_map())["hello"] = 1234;
JsonPrintOptions print_options;
JsonParseOptions parse_options;
EXPECT_EQ("{\"stringMap\":{\"hello\":1234}}", ToJson(message, print_options));
auto printed = ToJson(message);
ASSERT_THAT(printed, IsOkAndHolds("{\"stringMap\":{\"hello\":1234}}"));
TestMap other;
ASSERT_TRUE(FromJson(ToJson(message, print_options), &other, parse_options));
EXPECT_EQ(message.DebugString(), other.DebugString());
ASSERT_OK(FromJson(*printed, &other));
EXPECT_EQ(other.DebugString(), message.DebugString());
}
TEST_F(JsonUtilTest, ParsePrimitiveMapIn) {
TEST(JsonUtilTest, ParsePrimitiveMapIn) {
MapIn message;
JsonPrintOptions print_options;
print_options.always_print_primitive_fields = true;
JsonParseOptions parse_options;
EXPECT_EQ("{\"other\":\"\",\"things\":[],\"mapInput\":{},\"mapAny\":{}}",
ToJson(message, print_options));
auto printed = ToJson(message, print_options);
ASSERT_THAT(
ToJson(message, print_options),
IsOkAndHolds(
"{\"other\":\"\",\"things\":[],\"mapInput\":{},\"mapAny\":{}}"));
MapIn other;
ASSERT_TRUE(FromJson(ToJson(message, print_options), &other, parse_options));
EXPECT_EQ(message.DebugString(), other.DebugString());
ASSERT_OK(FromJson(*printed, &other));
EXPECT_EQ(other.DebugString(), message.DebugString());
}
TEST_F(JsonUtilTest, PrintPrimitiveOneof) {
TEST(JsonUtilTest, PrintPrimitiveOneof) {
TestOneof message;
JsonPrintOptions options;
options.always_print_primitive_fields = true;
message.mutable_oneof_message_value();
EXPECT_EQ("{\"oneofMessageValue\":{\"value\":0}}", ToJson(message, options));
EXPECT_THAT(ToJson(message, options),
IsOkAndHolds("{\"oneofMessageValue\":{\"value\":0}}"));
message.set_oneof_int32_value(1);
EXPECT_EQ("{\"oneofInt32Value\":1}", ToJson(message, options));
EXPECT_THAT(ToJson(message, options),
IsOkAndHolds("{\"oneofInt32Value\":1}"));
}
TEST_F(JsonUtilTest, TestParseIgnoreUnknownFields) {
TEST(JsonUtilTest, TestParseIgnoreUnknownFields) {
TestMessage m;
JsonParseOptions options;
options.ignore_unknown_fields = true;
EXPECT_TRUE(FromJson("{\"unknownName\":0}", &m, options));
EXPECT_OK(FromJson("{\"unknownName\":0}", &m, options));
}
TEST_F(JsonUtilTest, TestParseErrors) {
TEST(JsonUtilTest, TestParseErrors) {
TestMessage m;
JsonParseOptions options;
// Parsing should fail if the field name can not be recognized.
EXPECT_FALSE(FromJson("{\"unknownName\":0}", &m, options));
EXPECT_THAT(FromJson(R"json({"unknownName": 0})json", &m),
StatusIs(util::StatusCode::kInvalidArgument));
// Parsing should fail if the value is invalid.
EXPECT_FALSE(FromJson("{\"int32Value\":2147483648}", &m, options));
EXPECT_THAT(FromJson(R"json("{"int32Value": 2147483648})json", &m),
StatusIs(util::StatusCode::kInvalidArgument));
}
TEST_F(JsonUtilTest, TestDynamicMessage) {
// Some random message but good enough to test the wrapper functions.
std::string input =
"{\n"
" \"int32Value\": 1024,\n"
" \"repeatedInt32Value\": [1, 2],\n"
" \"messageValue\": {\n"
" \"value\": 2048\n"
" },\n"
" \"repeatedMessageValue\": [\n"
" {\"value\": 40}, {\"value\": 96}\n"
" ]\n"
"}\n";
TEST(JsonUtilTest, TestDynamicMessage) {
// Create a new DescriptorPool with the same protos as the generated one.
DescriptorPoolDatabase database(*DescriptorPool::generated_pool());
DescriptorPool pool(&database);
@ -363,218 +378,223 @@ TEST_F(JsonUtilTest, TestDynamicMessage) {
std::unique_ptr<Message> message(
factory.GetPrototype(pool.FindMessageTypeByName("proto3.TestMessage"))
->New());
EXPECT_TRUE(FromJson(input, message.get()));
EXPECT_OK(FromJson(R"json(
{
"int32Value": 1024,
"repeatedInt32Value": [1, 2],
"messageValue": {
"value": 2048
},
"repeatedMessageValue": [
{"value": 40},
{"value": 96}
]
}
)json",
message.get()));
// Convert to generated message for easy inspection.
TestMessage generated;
EXPECT_TRUE(generated.ParseFromString(message->SerializeAsString()));
EXPECT_EQ(1024, generated.int32_value());
ASSERT_EQ(2, generated.repeated_int32_value_size());
EXPECT_EQ(1, generated.repeated_int32_value(0));
EXPECT_EQ(2, generated.repeated_int32_value(1));
EXPECT_EQ(2048, generated.message_value().value());
ASSERT_EQ(2, generated.repeated_message_value_size());
EXPECT_EQ(40, generated.repeated_message_value(0).value());
EXPECT_EQ(96, generated.repeated_message_value(1).value());
JsonOptions options;
EXPECT_EQ(ToJson(generated, options), ToJson(*message, options));
EXPECT_EQ(generated.int32_value(), 1024);
ASSERT_EQ(generated.repeated_int32_value_size(), 2);
EXPECT_EQ(generated.repeated_int32_value(0), 1);
EXPECT_EQ(generated.repeated_int32_value(1), 2);
EXPECT_EQ(generated.message_value().value(), 2048);
ASSERT_EQ(generated.repeated_message_value_size(), 2);
EXPECT_EQ(generated.repeated_message_value(0).value(), 40);
EXPECT_EQ(generated.repeated_message_value(1).value(), 96);
auto message_json = ToJson(*message);
ASSERT_OK(message_json);
auto generated_json = ToJson(generated);
ASSERT_OK(generated_json);
EXPECT_EQ(*message_json, *generated_json);
}
TEST_F(JsonUtilTest, TestParsingUnknownAnyFields) {
std::string input =
"{\n"
" \"value\": {\n"
" \"@type\": \"type.googleapis.com/proto3.TestMessage\",\n"
" \"unknown_field\": \"UNKNOWN_VALUE\",\n"
" \"string_value\": \"expected_value\"\n"
" }\n"
"}";
TEST(JsonUtilTest, TestParsingUnknownAnyFields) {
StringPiece input = R"json(
{
"value": {
"@type": "type.googleapis.com/proto3.TestMessage",
"unknown_field": "UNKNOWN_VALUE",
"string_value": "expected_value"
}
}
)json";
TestAny m;
JsonParseOptions options;
EXPECT_FALSE(FromJson(input, &m, options));
EXPECT_THAT(FromJson(input, &m),
StatusIs(util::StatusCode::kInvalidArgument));
JsonParseOptions options;
options.ignore_unknown_fields = true;
EXPECT_TRUE(FromJson(input, &m, options));
EXPECT_OK(FromJson(input, &m, options));
TestMessage t;
EXPECT_TRUE(m.value().UnpackTo(&t));
EXPECT_EQ("expected_value", t.string_value());
EXPECT_EQ(t.string_value(), "expected_value");
}
TEST_F(JsonUtilTest, TestParsingUnknownEnumsProto2) {
std::string input =
"{\n"
" \"a\": \"UNKNOWN_VALUE\"\n"
"}";
TEST(JsonUtilTest, TestParsingUnknownEnumsProto2) {
StringPiece input = R"json({"a": "UNKNOWN_VALUE"})json";
protobuf_unittest::TestNumbers m;
JsonParseOptions options;
EXPECT_FALSE(FromJson(input, &m, options));
EXPECT_THAT(FromJson(input, &m, options),
StatusIs(util::StatusCode::kInvalidArgument));
options.ignore_unknown_fields = true;
EXPECT_TRUE(FromJson(input, &m, options));
EXPECT_OK(FromJson(input, &m, options));
EXPECT_FALSE(m.has_a());
}
TEST_F(JsonUtilTest, TestParsingUnknownEnumsProto3) {
TEST(JsonUtilTest, TestParsingUnknownEnumsProto3) {
TestMessage m;
{
JsonParseOptions options;
ASSERT_FALSE(options.ignore_unknown_fields);
std::string input =
"{\n"
" \"enum_value\":\"UNKNOWN_VALUE\"\n"
"}";
m.set_enum_value(proto3::BAR);
EXPECT_FALSE(FromJson(input, &m, options));
ASSERT_EQ(proto3::BAR, m.enum_value()); // Keep previous value
options.ignore_unknown_fields = true;
EXPECT_TRUE(FromJson(input, &m, options));
EXPECT_EQ(0, m.enum_value()); // Unknown enum value must be decoded as 0
}
// Integer values are read as usual
{
JsonParseOptions options;
std::string input =
"{\n"
" \"enum_value\":12345\n"
"}";
m.set_enum_value(proto3::BAR);
EXPECT_TRUE(FromJson(input, &m, options));
ASSERT_EQ(12345, m.enum_value());
options.ignore_unknown_fields = true;
EXPECT_TRUE(FromJson(input, &m, options));
EXPECT_EQ(12345, m.enum_value());
}
StringPiece input = R"json({"enum_value":"UNKNOWN_VALUE"})json";
// Trying to pass an object as an enum field value is always treated as an
// error
{
JsonParseOptions options;
std::string input =
"{\n"
" \"enum_value\":{}\n"
"}";
options.ignore_unknown_fields = true;
EXPECT_FALSE(FromJson(input, &m, options));
options.ignore_unknown_fields = false;
EXPECT_FALSE(FromJson(input, &m, options));
}
// Trying to pass an array as an enum field value is always treated as an
// error
{
JsonParseOptions options;
std::string input =
"{\n"
" \"enum_value\":[]\n"
"}";
EXPECT_FALSE(FromJson(input, &m, options));
options.ignore_unknown_fields = true;
EXPECT_FALSE(FromJson(input, &m, options));
}
m.set_enum_value(proto3::BAR);
EXPECT_THAT(FromJson(input, &m),
StatusIs(util::StatusCode::kInvalidArgument));
ASSERT_EQ(m.enum_value(), proto3::BAR); // Keep previous value
JsonParseOptions options;
options.ignore_unknown_fields = true;
EXPECT_OK(FromJson(input, &m, options));
EXPECT_EQ(m.enum_value(), 0); // Unknown enum value must be decoded as 0
}
TEST_F(JsonUtilTest, TestParsingEnumIgnoreCase) {
TEST(JsonUtilTest, TestParsingUnknownEnumsProto3FromInt) {
TestMessage m;
{
JsonParseOptions options;
std::string input =
"{\n"
" \"enum_value\":\"bar\"\n"
"}";
m.set_enum_value(proto3::FOO);
EXPECT_FALSE(FromJson(input, &m, options));
// Default behavior is case-sensitive, so keep previous value.
ASSERT_EQ(proto3::FOO, m.enum_value());
}
{
JsonParseOptions options;
options.case_insensitive_enum_parsing = false;
std::string input =
"{\n"
" \"enum_value\":\"bar\"\n"
"}";
m.set_enum_value(proto3::FOO);
EXPECT_FALSE(FromJson(input, &m, options));
ASSERT_EQ(proto3::FOO, m.enum_value()); // Keep previous value
}
{
JsonParseOptions options;
options.case_insensitive_enum_parsing = true;
std::string input =
"{\n"
" \"enum_value\":\"bar\"\n"
"}";
m.set_enum_value(proto3::FOO);
EXPECT_TRUE(FromJson(input, &m, options));
ASSERT_EQ(proto3::BAR, m.enum_value());
}
StringPiece input = R"json({"enum_value":12345})json";
m.set_enum_value(proto3::BAR);
EXPECT_OK(FromJson(input, &m));
ASSERT_EQ(m.enum_value(), 12345);
JsonParseOptions options;
options.ignore_unknown_fields = true;
EXPECT_OK(FromJson(input, &m, options));
EXPECT_EQ(m.enum_value(), 12345);
}
// Trying to pass an object as an enum field value is always treated as an
// error
TEST(JsonUtilTest, TestParsingUnknownEnumsProto3FromObject) {
TestMessage m;
StringPiece input = R"json({"enum_value": {}})json";
JsonParseOptions options;
options.ignore_unknown_fields = true;
EXPECT_THAT(FromJson(input, &m, options),
StatusIs(util::StatusCode::kInvalidArgument));
EXPECT_THAT(FromJson(input, &m),
StatusIs(util::StatusCode::kInvalidArgument));
}
TEST(JsonUtilTest, TestParsingUnknownEnumsProto3FromArray) {
TestMessage m;
StringPiece input = R"json({"enum_value": []})json";
EXPECT_THAT(FromJson(input, &m),
StatusIs(util::StatusCode::kInvalidArgument));
JsonParseOptions options;
options.ignore_unknown_fields = true;
EXPECT_THAT(FromJson(input, &m, options),
StatusIs(util::StatusCode::kInvalidArgument));
}
TEST(JsonUtilTest, TestParsingEnumCaseSensitive) {
TestMessage m;
StringPiece input = R"json({"enum_value": "bar"})json";
m.set_enum_value(proto3::FOO);
EXPECT_THAT(FromJson(input, &m),
StatusIs(util::StatusCode::kInvalidArgument));
// Default behavior is case-sensitive, so keep previous value.
ASSERT_EQ(m.enum_value(), proto3::FOO);
}
TEST(JsonUtilTest, TestParsingEnumIgnoreCase) {
TestMessage m;
StringPiece input = R"json({"enum_value":"bar"})json";
m.set_enum_value(proto3::FOO);
JsonParseOptions options;
options.case_insensitive_enum_parsing = true;
EXPECT_OK(FromJson(input, &m, options));
ASSERT_EQ(m.enum_value(), proto3::BAR);
}
typedef std::pair<char*, int> Segment;
// A ZeroCopyOutputStream that writes to multiple buffers.
class SegmentedZeroCopyOutputStream : public io::ZeroCopyOutputStream {
public:
explicit SegmentedZeroCopyOutputStream(std::list<Segment> segments)
: segments_(segments),
last_segment_(static_cast<char*>(NULL), 0),
byte_count_(0) {}
explicit SegmentedZeroCopyOutputStream(
std::vector<StringPiece> segments)
: segments_(segments) {
// absl::c_* functions are not cloned in OSS.
std::reverse(segments_.begin(), segments_.end());
}
bool Next(void** buffer, int* length) override {
if (segments_.empty()) {
return false;
}
last_segment_ = segments_.front();
segments_.pop_front();
*buffer = last_segment_.first;
*length = last_segment_.second;
byte_count_ += *length;
last_segment_ = segments_.back();
segments_.pop_back();
// TODO(b/234159981): This is only ever constructed in test code, and only
// from non-const bytes, so this is a valid cast. We need to do this since
// OSS proto does not yet have absl::Span; once we take a full Abseil
// dependency we should use that here instead.
*buffer = const_cast<char*>(last_segment_.data());
*length = static_cast<int>(last_segment_.size());
byte_count_ += static_cast<int64_t>(last_segment_.size());
return true;
}
void BackUp(int length) override {
GOOGLE_CHECK(length <= last_segment_.second);
segments_.push_front(
Segment(last_segment_.first + last_segment_.second - length, length));
last_segment_ = Segment(last_segment_.first, last_segment_.second - length);
byte_count_ -= length;
GOOGLE_CHECK(length <= static_cast<int>(last_segment_.size()));
size_t backup = last_segment_.size() - static_cast<size_t>(length);
segments_.push_back(last_segment_.substr(backup));
last_segment_ = last_segment_.substr(0, backup);
byte_count_ -= static_cast<int64_t>(length);
}
int64_t ByteCount() const override { return byte_count_; }
private:
std::list<Segment> segments_;
Segment last_segment_;
int64_t byte_count_;
std::vector<StringPiece> segments_;
StringPiece last_segment_;
int64_t byte_count_ = 0;
};
// This test splits the output buffer and also the input data into multiple
// segments and checks that the implementation of ZeroCopyStreamByteSink
// handles all possible cases correctly.
TEST(ZeroCopyStreamByteSinkTest, TestAllInputOutputPatterns) {
static const int kOutputBufferLength = 10;
static constexpr int kOutputBufferLength = 10;
// An exhaustive test takes too long, skip some combinations to make the test
// run faster.
static const int kSkippedPatternCount = 7;
static constexpr int kSkippedPatternCount = 7;
char buffer[kOutputBufferLength];
for (int split_pattern = 0; split_pattern < (1 << (kOutputBufferLength - 1));
split_pattern += kSkippedPatternCount) {
// Split the buffer into small segments according to the split_pattern.
std::list<Segment> segments;
std::vector<StringPiece> segments;
int segment_start = 0;
for (int i = 0; i < kOutputBufferLength - 1; ++i) {
if (split_pattern & (1 << i)) {
segments.push_back(
Segment(buffer + segment_start, i - segment_start + 1));
StringPiece(buffer + segment_start, i - segment_start + 1));
segment_start = i + 1;
}
}
segments.push_back(
Segment(buffer + segment_start, kOutputBufferLength - segment_start));
segments.push_back(StringPiece(buffer + segment_start,
kOutputBufferLength - segment_start));
// Write exactly 10 bytes through the ByteSink.
std::string input_data = "0123456789";
@ -593,7 +613,7 @@ TEST(ZeroCopyStreamByteSinkTest, TestAllInputOutputPatterns) {
}
byte_sink.Append(&input_data[start], input_data.length() - start);
}
EXPECT_EQ(input_data, std::string(buffer, input_data.length()));
EXPECT_EQ(std::string(buffer, input_data.length()), input_data);
}
// Write only 9 bytes through the ByteSink.
@ -613,8 +633,8 @@ TEST(ZeroCopyStreamByteSinkTest, TestAllInputOutputPatterns) {
}
byte_sink.Append(&input_data[start], input_data.length() - start);
}
EXPECT_EQ(input_data, std::string(buffer, input_data.length()));
EXPECT_EQ(0, buffer[input_data.length()]);
EXPECT_EQ(std::string(buffer, input_data.length()), input_data);
EXPECT_EQ(buffer[input_data.length()], 0);
}
// Write 11 bytes through the ByteSink. The extra byte will just
@ -641,29 +661,29 @@ TEST(ZeroCopyStreamByteSinkTest, TestAllInputOutputPatterns) {
}
}
TEST_F(JsonUtilTest, TestWrongJsonInput) {
const char json[] = "{\"unknown_field\":\"some_value\"}";
io::ArrayInputStream input_stream(json, strlen(json));
TEST(JsonUtilTest, TestWrongJsonInput) {
StringPiece json = "{\"unknown_field\":\"some_value\"}";
io::ArrayInputStream input_stream(json.data(), json.size());
char proto_buffer[10000];
io::ArrayOutputStream output_stream(proto_buffer, sizeof(proto_buffer));
std::string message_type = "type.googleapis.com/proto3.TestMessage";
TypeResolver* resolver = NewTypeResolverForDescriptorPool(
"type.googleapis.com", DescriptorPool::generated_pool());
auto result_status = util::JsonToBinaryStream(resolver, message_type,
&input_stream, &output_stream);
auto* resolver = NewTypeResolverForDescriptorPool(
"type.googleapis.com", DescriptorPool::generated_pool());
EXPECT_THAT(JsonToBinaryStream(resolver, message_type, &input_stream,
&output_stream),
StatusIs(util::StatusCode::kInvalidArgument));
delete resolver;
EXPECT_FALSE(result_status.ok());
EXPECT_TRUE(util::IsInvalidArgument(result_status));
}
TEST_F(JsonUtilTest, HtmlEscape) {
TEST(JsonUtilTest, HtmlEscape) {
TestMessage m;
m.set_string_value("</script>");
JsonPrintOptions options;
EXPECT_EQ("{\"stringValue\":\"\\u003c/script\\u003e\"}", ToJson(m, options));
EXPECT_THAT(ToJson(m, options),
IsOkAndHolds("{\"stringValue\":\"\\u003c/script\\u003e\"}"));
}
} // namespace

@ -1 +1 @@
Subproject commit 5b7683f49e1e9223cf9927b24f6fd3d6bd82e3f8
Subproject commit 0baacde3618ca617da95375e0af13ce1baadea47
Loading…
Cancel
Save