• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/internal/json_objectwriter.h>
32 
33 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
34 #include <google/protobuf/util/internal/utility.h>
35 #include <gtest/gtest.h>
36 
37 namespace google {
38 namespace protobuf {
39 namespace util {
40 namespace converter {
41 
42 using io::CodedOutputStream;
43 using io::StringOutputStream;
44 
45 class JsonObjectWriterTest : public ::testing::Test {
46  protected:
JsonObjectWriterTest()47   JsonObjectWriterTest()
48       : str_stream_(new StringOutputStream(&output_)),
49         out_stream_(new CodedOutputStream(str_stream_)),
50         ow_(nullptr) {}
51 
~JsonObjectWriterTest()52   ~JsonObjectWriterTest() override { delete ow_; }
53 
CloseStreamAndGetString()54   std::string CloseStreamAndGetString() {
55     delete out_stream_;
56     delete str_stream_;
57     return output_;
58   }
59 
60   std::string output_;
61   StringOutputStream* const str_stream_;
62   CodedOutputStream* const out_stream_;
63   JsonObjectWriter* ow_;
64 };
65 
TEST_F(JsonObjectWriterTest,EmptyRootObject)66 TEST_F(JsonObjectWriterTest, EmptyRootObject) {
67   ow_ = new JsonObjectWriter("", out_stream_);
68   ow_->StartObject("")->EndObject();
69   EXPECT_EQ("{}", CloseStreamAndGetString());
70 }
71 
TEST_F(JsonObjectWriterTest,EmptyObject)72 TEST_F(JsonObjectWriterTest, EmptyObject) {
73   ow_ = new JsonObjectWriter("", out_stream_);
74   ow_->StartObject("")
75       ->RenderString("test", "value")
76       ->StartObject("empty")
77       ->EndObject()
78       ->EndObject();
79   EXPECT_EQ("{\"test\":\"value\",\"empty\":{}}", CloseStreamAndGetString());
80 }
81 
TEST_F(JsonObjectWriterTest,EmptyRootList)82 TEST_F(JsonObjectWriterTest, EmptyRootList) {
83   ow_ = new JsonObjectWriter("", out_stream_);
84   ow_->StartList("")->EndList();
85   EXPECT_EQ("[]", CloseStreamAndGetString());
86 }
87 
TEST_F(JsonObjectWriterTest,EmptyList)88 TEST_F(JsonObjectWriterTest, EmptyList) {
89   ow_ = new JsonObjectWriter("", out_stream_);
90   ow_->StartObject("")
91       ->RenderString("test", "value")
92       ->StartList("empty")
93       ->EndList()
94       ->EndObject();
95   EXPECT_EQ("{\"test\":\"value\",\"empty\":[]}", CloseStreamAndGetString());
96 }
97 
TEST_F(JsonObjectWriterTest,EmptyObjectKey)98 TEST_F(JsonObjectWriterTest, EmptyObjectKey) {
99   ow_ = new JsonObjectWriter("", out_stream_);
100   ow_->StartObject("")->RenderString("", "value")->EndObject();
101   EXPECT_EQ("{\"\":\"value\"}", CloseStreamAndGetString());
102 }
103 
TEST_F(JsonObjectWriterTest,ObjectInObject)104 TEST_F(JsonObjectWriterTest, ObjectInObject) {
105   ow_ = new JsonObjectWriter("", out_stream_);
106   ow_->StartObject("")
107       ->StartObject("nested")
108       ->RenderString("field", "value")
109       ->EndObject()
110       ->EndObject();
111   EXPECT_EQ("{\"nested\":{\"field\":\"value\"}}", CloseStreamAndGetString());
112 }
113 
TEST_F(JsonObjectWriterTest,ListInObject)114 TEST_F(JsonObjectWriterTest, ListInObject) {
115   ow_ = new JsonObjectWriter("", out_stream_);
116   ow_->StartObject("")
117       ->StartList("nested")
118       ->RenderString("", "value")
119       ->EndList()
120       ->EndObject();
121   EXPECT_EQ("{\"nested\":[\"value\"]}", CloseStreamAndGetString());
122 }
123 
TEST_F(JsonObjectWriterTest,ObjectInList)124 TEST_F(JsonObjectWriterTest, ObjectInList) {
125   ow_ = new JsonObjectWriter("", out_stream_);
126   ow_->StartList("")
127       ->StartObject("")
128       ->RenderString("field", "value")
129       ->EndObject()
130       ->EndList();
131   EXPECT_EQ("[{\"field\":\"value\"}]", CloseStreamAndGetString());
132 }
133 
TEST_F(JsonObjectWriterTest,ListInList)134 TEST_F(JsonObjectWriterTest, ListInList) {
135   ow_ = new JsonObjectWriter("", out_stream_);
136   ow_->StartList("")
137       ->StartList("")
138       ->RenderString("", "value")
139       ->EndList()
140       ->EndList();
141   EXPECT_EQ("[[\"value\"]]", CloseStreamAndGetString());
142 }
143 
TEST_F(JsonObjectWriterTest,RenderPrimitives)144 TEST_F(JsonObjectWriterTest, RenderPrimitives) {
145   ow_ = new JsonObjectWriter("", out_stream_);
146   ow_->StartObject("")
147       ->RenderBool("bool", true)
148       ->RenderDouble("double", std::numeric_limits<double>::max())
149       ->RenderFloat("float", std::numeric_limits<float>::max())
150       ->RenderInt32("int", std::numeric_limits<int32>::min())
151       ->RenderInt64("long", std::numeric_limits<int64>::min())
152       ->RenderBytes("bytes", "abracadabra")
153       ->RenderString("string", "string")
154       ->RenderBytes("emptybytes", "")
155       ->RenderString("emptystring", string())
156       ->EndObject();
157   EXPECT_EQ(
158       "{\"bool\":true,"
159       "\"double\":" +
160           ValueAsString<double>(std::numeric_limits<double>::max()) +
161           ","
162           "\"float\":" +
163           ValueAsString<float>(std::numeric_limits<float>::max()) +
164           ","
165           "\"int\":-2147483648,"
166           "\"long\":\"-9223372036854775808\","
167           "\"bytes\":\"YWJyYWNhZGFicmE=\","
168           "\"string\":\"string\","
169           "\"emptybytes\":\"\","
170           "\"emptystring\":\"\"}",
171       CloseStreamAndGetString());
172 }
173 
TEST_F(JsonObjectWriterTest,BytesEncodesAsNonWebSafeBase64)174 TEST_F(JsonObjectWriterTest, BytesEncodesAsNonWebSafeBase64) {
175   std::string s;
176   s.push_back('\377');
177   s.push_back('\357');
178   ow_ = new JsonObjectWriter("", out_stream_);
179   ow_->StartObject("")->RenderBytes("bytes", s)->EndObject();
180   // Non-web-safe would encode this as "/+8="
181   EXPECT_EQ("{\"bytes\":\"/+8=\"}", CloseStreamAndGetString());
182 }
183 
TEST_F(JsonObjectWriterTest,PrettyPrintList)184 TEST_F(JsonObjectWriterTest, PrettyPrintList) {
185   ow_ = new JsonObjectWriter(" ", out_stream_);
186   ow_->StartObject("")
187       ->StartList("items")
188       ->RenderString("", "item1")
189       ->RenderString("", "item2")
190       ->RenderString("", "item3")
191       ->EndList()
192       ->StartList("empty")
193       ->EndList()
194       ->EndObject();
195   EXPECT_EQ(
196       "{\n"
197       " \"items\": [\n"
198       "  \"item1\",\n"
199       "  \"item2\",\n"
200       "  \"item3\"\n"
201       " ],\n"
202       " \"empty\": []\n"
203       "}\n",
204       CloseStreamAndGetString());
205 }
206 
TEST_F(JsonObjectWriterTest,PrettyPrintObject)207 TEST_F(JsonObjectWriterTest, PrettyPrintObject) {
208   ow_ = new JsonObjectWriter(" ", out_stream_);
209   ow_->StartObject("")
210       ->StartObject("items")
211       ->RenderString("key1", "item1")
212       ->RenderString("key2", "item2")
213       ->RenderString("key3", "item3")
214       ->EndObject()
215       ->StartObject("empty")
216       ->EndObject()
217       ->EndObject();
218   EXPECT_EQ(
219       "{\n"
220       " \"items\": {\n"
221       "  \"key1\": \"item1\",\n"
222       "  \"key2\": \"item2\",\n"
223       "  \"key3\": \"item3\"\n"
224       " },\n"
225       " \"empty\": {}\n"
226       "}\n",
227       CloseStreamAndGetString());
228 }
229 
TEST_F(JsonObjectWriterTest,PrettyPrintEmptyObjectInEmptyList)230 TEST_F(JsonObjectWriterTest, PrettyPrintEmptyObjectInEmptyList) {
231   ow_ = new JsonObjectWriter(" ", out_stream_);
232   ow_->StartObject("")
233       ->StartList("list")
234       ->StartObject("")
235       ->EndObject()
236       ->EndList()
237       ->EndObject();
238   EXPECT_EQ(
239       "{\n"
240       " \"list\": [\n"
241       "  {}\n"
242       " ]\n"
243       "}\n",
244       CloseStreamAndGetString());
245 }
246 
TEST_F(JsonObjectWriterTest,PrettyPrintDoubleIndent)247 TEST_F(JsonObjectWriterTest, PrettyPrintDoubleIndent) {
248   ow_ = new JsonObjectWriter("  ", out_stream_);
249   ow_->StartObject("")
250       ->RenderBool("bool", true)
251       ->RenderInt32("int", 42)
252       ->EndObject();
253   EXPECT_EQ(
254       "{\n"
255       "  \"bool\": true,\n"
256       "  \"int\": 42\n"
257       "}\n",
258       CloseStreamAndGetString());
259 }
260 
TEST_F(JsonObjectWriterTest,StringsEscapedAndEnclosedInDoubleQuotes)261 TEST_F(JsonObjectWriterTest, StringsEscapedAndEnclosedInDoubleQuotes) {
262   ow_ = new JsonObjectWriter("", out_stream_);
263   ow_->StartObject("")->RenderString("string", "'<>&amp;\\\"\r\n")->EndObject();
264   EXPECT_EQ("{\"string\":\"'\\u003c\\u003e&amp;\\\\\\\"\\r\\n\"}",
265             CloseStreamAndGetString());
266 }
267 
TEST_F(JsonObjectWriterTest,Stringification)268 TEST_F(JsonObjectWriterTest, Stringification) {
269   ow_ = new JsonObjectWriter("", out_stream_);
270   ow_->StartObject("")
271       ->RenderDouble("double_nan", std::numeric_limits<double>::quiet_NaN())
272       ->RenderFloat("float_nan", std::numeric_limits<float>::quiet_NaN())
273       ->RenderDouble("double_pos", std::numeric_limits<double>::infinity())
274       ->RenderFloat("float_pos", std::numeric_limits<float>::infinity())
275       ->RenderDouble("double_neg", -std::numeric_limits<double>::infinity())
276       ->RenderFloat("float_neg", -std::numeric_limits<float>::infinity())
277       ->EndObject();
278   EXPECT_EQ(
279       "{\"double_nan\":\"NaN\","
280       "\"float_nan\":\"NaN\","
281       "\"double_pos\":\"Infinity\","
282       "\"float_pos\":\"Infinity\","
283       "\"double_neg\":\"-Infinity\","
284       "\"float_neg\":\"-Infinity\"}",
285       CloseStreamAndGetString());
286 }
287 
TEST_F(JsonObjectWriterTest,TestRegularByteEncoding)288 TEST_F(JsonObjectWriterTest, TestRegularByteEncoding) {
289   ow_ = new JsonObjectWriter("", out_stream_);
290   ow_->StartObject("")
291       ->RenderBytes("bytes", "\x03\xef\xc0")
292       ->EndObject();
293 
294   // Test that we get regular (non websafe) base64 encoding on byte fields by
295   // default.
296   EXPECT_EQ("{\"bytes\":\"A+/A\"}", CloseStreamAndGetString());
297 }
298 
TEST_F(JsonObjectWriterTest,TestWebsafeByteEncoding)299 TEST_F(JsonObjectWriterTest, TestWebsafeByteEncoding) {
300   ow_ = new JsonObjectWriter("", out_stream_);
301   ow_->set_use_websafe_base64_for_bytes(true);
302   ow_->StartObject("")
303       ->RenderBytes("bytes", "\x03\xef\xc0\x10")
304       ->EndObject();
305 
306   // Test that we get websafe base64 encoding when explicitly asked.
307   EXPECT_EQ("{\"bytes\":\"A-_AEA==\"}", CloseStreamAndGetString());
308 }
309 
310 }  // namespace converter
311 }  // namespace util
312 }  // namespace protobuf
313 }  // namespace google
314