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", "'<>&\\\"\r\n")->EndObject();
264 EXPECT_EQ("{\"string\":\"'\\u003c\\u003e&\\\\\\\"\\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