diff options
author | Feng Xiao <xfxyjwf@gmail.com> | 2015-06-17 13:12:11 -0700 |
---|---|---|
committer | Feng Xiao <xfxyjwf@gmail.com> | 2015-06-17 13:12:11 -0700 |
commit | e9a122eb19ec54dbca15da80355ed0c17cada9b1 (patch) | |
tree | fac37489873ccf47777b2e652db580f9315d7bc7 /src/google/protobuf/util/json_util_test.cc | |
parent | b36395b2bac88f70070544c325bc09234cb1f1a6 (diff) | |
parent | 818c5eee08840355d70d2f3bdf1a2f17986a5e70 (diff) | |
download | protobuf-e9a122eb19ec54dbca15da80355ed0c17cada9b1.tar.gz protobuf-e9a122eb19ec54dbca15da80355ed0c17cada9b1.tar.bz2 protobuf-e9a122eb19ec54dbca15da80355ed0c17cada9b1.zip |
Merge pull request #501 from xfxyjwf/down
Down-integrate from internal code base.
Diffstat (limited to 'src/google/protobuf/util/json_util_test.cc')
-rw-r--r-- | src/google/protobuf/util/json_util_test.cc | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/src/google/protobuf/util/json_util_test.cc b/src/google/protobuf/util/json_util_test.cc new file mode 100644 index 00000000..8399b408 --- /dev/null +++ b/src/google/protobuf/util/json_util_test.cc @@ -0,0 +1,277 @@ +// 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 <google/protobuf/util/json_util.h> + +#include <list> +#include <string> + +#include <google/protobuf/io/zero_copy_stream.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 <gtest/gtest.h> + +namespace google { +namespace protobuf { +namespace util { +namespace { + +using proto3::FOO; +using proto3::BAR; +using proto3::TestMessage; + +static const char kTypeUrlPrefix[] = "type.googleapis.com"; + +static string GetTypeUrl(const Descriptor* message) { + return string(kTypeUrlPrefix) + "/" + message->full_name(); +} + +// 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() { + resolver_.reset(NewTypeResolverForDescriptorPool( + kTypeUrlPrefix, DescriptorPool::generated_pool())); + } + + string ToJson(const Message& message, const JsonOptions& options) { + string result; + GOOGLE_CHECK_OK(BinaryToJsonString(resolver_.get(), + GetTypeUrl(message.GetDescriptor()), + message.SerializeAsString(), &result, options)); + return result; + } + + bool FromJson(const string& json, Message* message) { + string binary; + GOOGLE_CHECK_OK(JsonToBinaryString( + resolver_.get(), GetTypeUrl(message->GetDescriptor()), json, &binary)); + return message->ParseFromString(binary); + } + + google::protobuf::scoped_ptr<TypeResolver> resolver_; +}; + +TEST_F(JsonUtilTest, TestWhitespaces) { + TestMessage m; + m.mutable_message_value(); + + JsonOptions options; + EXPECT_EQ("{\"messageValue\":{}}", ToJson(m, options)); + options.add_whitespace = true; + EXPECT_EQ( + "{\n" + " \"messageValue\": {}\n" + "}\n", + ToJson(m, options)); +} + +TEST_F(JsonUtilTest, TestDefaultValues) { + TestMessage m; + JsonOptions 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\":\"\"," + // TODO(xiaofeng): The default enum value should be FOO. I believe + // this is a bug in DefaultValueObjectWriter. + "\"enumValue\":null" + "}", + ToJson(m, options)); +} + +TEST_F(JsonUtilTest, ParseMessage) { + // Some random message but good enough to verify that the parsing warpper + // functions are working properly. + 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"; + TestMessage m; + ASSERT_TRUE(FromJson(input, &m)); + EXPECT_EQ(1024, m.int32_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()); +} + +typedef pair<char*, int> Segment; +// A ZeroCopyOutputStream that writes to multiple buffers. +class SegmentedZeroCopyOutputStream : public io::ZeroCopyOutputStream { + public: + explicit SegmentedZeroCopyOutputStream(list<Segment> segments) + : segments_(segments), last_segment_(NULL, 0), byte_count_(0) {} + + virtual bool Next(void** buffer, int* length) { + if (segments_.empty()) { + return false; + } + last_segment_ = segments_.front(); + segments_.pop_front(); + *buffer = last_segment_.first; + *length = last_segment_.second; + byte_count_ += *length; + return true; + } + + virtual void BackUp(int length) { + 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; + } + + virtual int64 ByteCount() const { return byte_count_; } + + private: + list<Segment> segments_; + Segment last_segment_; + int64 byte_count_; +}; + +// 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; + // An exhaustive test takes too long, skip some combinations to make the test + // run faster. + static const 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. + list<Segment> 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)); + segment_start = i + 1; + } + } + segments.push_back( + Segment(buffer + segment_start, kOutputBufferLength - segment_start)); + + // Write exactly 10 bytes through the ByteSink. + string input_data = "0123456789"; + for (int input_pattern = 0; input_pattern < (1 << (input_data.size() - 1)); + input_pattern += kSkippedPatternCount) { + memset(buffer, 0, sizeof(buffer)); + { + SegmentedZeroCopyOutputStream output_stream(segments); + internal::ZeroCopyStreamByteSink byte_sink(&output_stream); + int start = 0; + for (int j = 0; j < input_data.length() - 1; ++j) { + if (input_pattern & (1 << j)) { + byte_sink.Append(&input_data[start], j - start + 1); + start = j + 1; + } + } + byte_sink.Append(&input_data[start], input_data.length() - start); + } + EXPECT_EQ(input_data, string(buffer, input_data.length())); + } + + // Write only 9 bytes through the ByteSink. + input_data = "012345678"; + for (int input_pattern = 0; input_pattern < (1 << (input_data.size() - 1)); + input_pattern += kSkippedPatternCount) { + memset(buffer, 0, sizeof(buffer)); + { + SegmentedZeroCopyOutputStream output_stream(segments); + internal::ZeroCopyStreamByteSink byte_sink(&output_stream); + int start = 0; + for (int j = 0; j < input_data.length() - 1; ++j) { + if (input_pattern & (1 << j)) { + byte_sink.Append(&input_data[start], j - start + 1); + start = j + 1; + } + } + byte_sink.Append(&input_data[start], input_data.length() - start); + } + EXPECT_EQ(input_data, string(buffer, input_data.length())); + EXPECT_EQ(0, buffer[input_data.length()]); + } + + // Write 11 bytes through the ByteSink. The extra byte will just + // be ignored. + input_data = "0123456789A"; + for (int input_pattern = 0; input_pattern < (1 << (input_data.size() - 1)); + input_pattern += kSkippedPatternCount) { + memset(buffer, 0, sizeof(buffer)); + { + SegmentedZeroCopyOutputStream output_stream(segments); + internal::ZeroCopyStreamByteSink byte_sink(&output_stream); + int start = 0; + for (int j = 0; j < input_data.length() - 1; ++j) { + if (input_pattern & (1 << j)) { + byte_sink.Append(&input_data[start], j - start + 1); + start = j + 1; + } + } + byte_sink.Append(&input_data[start], input_data.length() - start); + } + EXPECT_EQ(input_data.substr(0, kOutputBufferLength), + string(buffer, kOutputBufferLength)); + } + } +} + +} // namespace +} // namespace util +} // namespace protobuf +} // namespace google |