1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.  All rights reserved.
3// https://developers.google.com/protocol-buffers/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9//     * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11//     * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15//     * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31#include <google/protobuf/util/json_util.h>
32
33#include <list>
34#include <string>
35
36#include <google/protobuf/io/zero_copy_stream.h>
37#include <google/protobuf/util/json_format_proto3.pb.h>
38#include <google/protobuf/util/type_resolver.h>
39#include <google/protobuf/util/type_resolver_util.h>
40#include <gtest/gtest.h>
41
42namespace google {
43namespace protobuf {
44namespace util {
45namespace {
46
47using proto3::FOO;
48using proto3::BAR;
49using proto3::TestMessage;
50using proto3::TestMap;
51
52static const char kTypeUrlPrefix[] = "type.googleapis.com";
53
54static string GetTypeUrl(const Descriptor* message) {
55  return string(kTypeUrlPrefix) + "/" + message->full_name();
56}
57
58// As functions defined in json_util.h are just thin wrappers around the
59// JSON conversion code in //net/proto2/util/converter, in this test we
60// only cover some very basic cases to make sure the wrappers have forwarded
61// parameters to the underlying implementation correctly. More detailed
62// tests are contained in the //net/proto2/util/converter directory.
63class JsonUtilTest : public testing::Test {
64 protected:
65  JsonUtilTest() {
66    resolver_.reset(NewTypeResolverForDescriptorPool(
67        kTypeUrlPrefix, DescriptorPool::generated_pool()));
68  }
69
70  string ToJson(const Message& message, const JsonOptions& options) {
71    string result;
72    GOOGLE_CHECK_OK(BinaryToJsonString(resolver_.get(),
73                                GetTypeUrl(message.GetDescriptor()),
74                                message.SerializeAsString(), &result, options));
75    return result;
76  }
77
78  bool FromJson(const string& json, Message* message) {
79    string binary;
80    if (!JsonToBinaryString(resolver_.get(),
81                            GetTypeUrl(message->GetDescriptor()), json, &binary)
82             .ok()) {
83      return false;
84    }
85    return message->ParseFromString(binary);
86  }
87
88  google::protobuf::scoped_ptr<TypeResolver> resolver_;
89};
90
91TEST_F(JsonUtilTest, TestWhitespaces) {
92  TestMessage m;
93  m.mutable_message_value();
94
95  JsonOptions options;
96  EXPECT_EQ("{\"messageValue\":{}}", ToJson(m, options));
97  options.add_whitespace = true;
98  EXPECT_EQ(
99      "{\n"
100      " \"messageValue\": {}\n"
101      "}\n",
102      ToJson(m, options));
103}
104
105TEST_F(JsonUtilTest, TestDefaultValues) {
106  TestMessage m;
107  JsonOptions options;
108  EXPECT_EQ("{}", ToJson(m, options));
109  options.always_print_primitive_fields = true;
110  EXPECT_EQ(
111      "{\"boolValue\":false,"
112      "\"int32Value\":0,"
113      "\"int64Value\":\"0\","
114      "\"uint32Value\":0,"
115      "\"uint64Value\":\"0\","
116      "\"floatValue\":0,"
117      "\"doubleValue\":0,"
118      "\"stringValue\":\"\","
119      "\"bytesValue\":\"\","
120      "\"enumValue\":\"FOO\","
121      "\"repeatedBoolValue\":[],"
122      "\"repeatedInt32Value\":[],"
123      "\"repeatedInt64Value\":[],"
124      "\"repeatedUint32Value\":[],"
125      "\"repeatedUint64Value\":[],"
126      "\"repeatedFloatValue\":[],"
127      "\"repeatedDoubleValue\":[],"
128      "\"repeatedStringValue\":[],"
129      "\"repeatedBytesValue\":[],"
130      "\"repeatedEnumValue\":[],"
131      "\"repeatedMessageValue\":[]"
132      "}",
133      ToJson(m, options));
134}
135
136TEST_F(JsonUtilTest, ParseMessage) {
137  // Some random message but good enough to verify that the parsing warpper
138  // functions are working properly.
139  string input =
140      "{\n"
141      "  \"int32Value\": 1024,\n"
142      "  \"repeatedInt32Value\": [1, 2],\n"
143      "  \"messageValue\": {\n"
144      "    \"value\": 2048\n"
145      "  },\n"
146      "  \"repeatedMessageValue\": [\n"
147      "    {\"value\": 40}, {\"value\": 96}\n"
148      "  ]\n"
149      "}\n";
150  TestMessage m;
151  ASSERT_TRUE(FromJson(input, &m));
152  EXPECT_EQ(1024, m.int32_value());
153  ASSERT_EQ(2, m.repeated_int32_value_size());
154  EXPECT_EQ(1, m.repeated_int32_value(0));
155  EXPECT_EQ(2, m.repeated_int32_value(1));
156  EXPECT_EQ(2048, m.message_value().value());
157  ASSERT_EQ(2, m.repeated_message_value_size());
158  EXPECT_EQ(40, m.repeated_message_value(0).value());
159  EXPECT_EQ(96, m.repeated_message_value(1).value());
160}
161
162TEST_F(JsonUtilTest, ParseMap) {
163  TestMap message;
164  (*message.mutable_string_map())["hello"] = 1234;
165  JsonOptions options;
166  EXPECT_EQ("{\"stringMap\":{\"hello\":1234}}", ToJson(message, options));
167  TestMap other;
168  ASSERT_TRUE(FromJson(ToJson(message, options), &other));
169  EXPECT_EQ(message.DebugString(), other.DebugString());
170}
171
172TEST_F(JsonUtilTest, TestParseErrors) {
173  TestMessage m;
174  JsonOptions options;
175  // Parsing should fail if the field name can not be recognized.
176  EXPECT_FALSE(FromJson("{\"unknownName\":0}", &m));
177  // Parsing should fail if the value is invalid.
178  EXPECT_FALSE(FromJson("{\"int32Value\":2147483648}", &m));
179}
180
181typedef pair<char*, int> Segment;
182// A ZeroCopyOutputStream that writes to multiple buffers.
183class SegmentedZeroCopyOutputStream : public io::ZeroCopyOutputStream {
184 public:
185  explicit SegmentedZeroCopyOutputStream(list<Segment> segments)
186      : segments_(segments), last_segment_(static_cast<char*>(NULL), 0), byte_count_(0) {}
187
188  virtual bool Next(void** buffer, int* length) {
189    if (segments_.empty()) {
190      return false;
191    }
192    last_segment_ = segments_.front();
193    segments_.pop_front();
194    *buffer = last_segment_.first;
195    *length = last_segment_.second;
196    byte_count_ += *length;
197    return true;
198  }
199
200  virtual void BackUp(int length) {
201    GOOGLE_CHECK(length <= last_segment_.second);
202    segments_.push_front(
203        Segment(last_segment_.first + last_segment_.second - length, length));
204    last_segment_ = Segment(last_segment_.first, last_segment_.second - length);
205    byte_count_ -= length;
206  }
207
208  virtual int64 ByteCount() const { return byte_count_; }
209
210 private:
211  list<Segment> segments_;
212  Segment last_segment_;
213  int64 byte_count_;
214};
215
216// This test splits the output buffer and also the input data into multiple
217// segments and checks that the implementation of ZeroCopyStreamByteSink
218// handles all possible cases correctly.
219TEST(ZeroCopyStreamByteSinkTest, TestAllInputOutputPatterns) {
220  static const int kOutputBufferLength = 10;
221  // An exhaustive test takes too long, skip some combinations to make the test
222  // run faster.
223  static const int kSkippedPatternCount = 7;
224
225  char buffer[kOutputBufferLength];
226  for (int split_pattern = 0; split_pattern < (1 << (kOutputBufferLength - 1));
227       split_pattern += kSkippedPatternCount) {
228    // Split the buffer into small segments according to the split_pattern.
229    list<Segment> segments;
230    int segment_start = 0;
231    for (int i = 0; i < kOutputBufferLength - 1; ++i) {
232      if (split_pattern & (1 << i)) {
233        segments.push_back(
234            Segment(buffer + segment_start, i - segment_start + 1));
235        segment_start = i + 1;
236      }
237    }
238    segments.push_back(
239        Segment(buffer + segment_start, kOutputBufferLength - segment_start));
240
241    // Write exactly 10 bytes through the ByteSink.
242    string input_data = "0123456789";
243    for (int input_pattern = 0; input_pattern < (1 << (input_data.size() - 1));
244         input_pattern += kSkippedPatternCount) {
245      memset(buffer, 0, sizeof(buffer));
246      {
247        SegmentedZeroCopyOutputStream output_stream(segments);
248        internal::ZeroCopyStreamByteSink byte_sink(&output_stream);
249        int start = 0;
250        for (int j = 0; j < input_data.length() - 1; ++j) {
251          if (input_pattern & (1 << j)) {
252            byte_sink.Append(&input_data[start], j - start + 1);
253            start = j + 1;
254          }
255        }
256        byte_sink.Append(&input_data[start], input_data.length() - start);
257      }
258      EXPECT_EQ(input_data, string(buffer, input_data.length()));
259    }
260
261    // Write only 9 bytes through the ByteSink.
262    input_data = "012345678";
263    for (int input_pattern = 0; input_pattern < (1 << (input_data.size() - 1));
264         input_pattern += kSkippedPatternCount) {
265      memset(buffer, 0, sizeof(buffer));
266      {
267        SegmentedZeroCopyOutputStream output_stream(segments);
268        internal::ZeroCopyStreamByteSink byte_sink(&output_stream);
269        int start = 0;
270        for (int j = 0; j < input_data.length() - 1; ++j) {
271          if (input_pattern & (1 << j)) {
272            byte_sink.Append(&input_data[start], j - start + 1);
273            start = j + 1;
274          }
275        }
276        byte_sink.Append(&input_data[start], input_data.length() - start);
277      }
278      EXPECT_EQ(input_data, string(buffer, input_data.length()));
279      EXPECT_EQ(0, buffer[input_data.length()]);
280    }
281
282    // Write 11 bytes through the ByteSink. The extra byte will just
283    // be ignored.
284    input_data = "0123456789A";
285    for (int input_pattern = 0; input_pattern < (1 << (input_data.size() - 1));
286         input_pattern += kSkippedPatternCount) {
287      memset(buffer, 0, sizeof(buffer));
288      {
289        SegmentedZeroCopyOutputStream output_stream(segments);
290        internal::ZeroCopyStreamByteSink byte_sink(&output_stream);
291        int start = 0;
292        for (int j = 0; j < input_data.length() - 1; ++j) {
293          if (input_pattern & (1 << j)) {
294            byte_sink.Append(&input_data[start], j - start + 1);
295            start = j + 1;
296          }
297        }
298        byte_sink.Append(&input_data[start], input_data.length() - start);
299      }
300      EXPECT_EQ(input_data.substr(0, kOutputBufferLength),
301                string(buffer, kOutputBufferLength));
302    }
303  }
304}
305
306}  // namespace
307}  // namespace util
308}  // namespace protobuf
309}  // namespace google
310