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