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 37namespace google { 38namespace protobuf { 39namespace util { 40namespace converter { 41 42using google::protobuf::io::CodedOutputStream; 43using google::protobuf::io::StringOutputStream; 44 45class JsonObjectWriterTest : public ::testing::Test { 46 protected: 47 JsonObjectWriterTest() 48 : str_stream_(new StringOutputStream(&output_)), 49 out_stream_(new CodedOutputStream(str_stream_)), 50 ow_(NULL) {} 51 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 64TEST_F(JsonObjectWriterTest, EmptyRootObject) { 65 ow_ = new JsonObjectWriter("", out_stream_); 66 ow_->StartObject("")->EndObject(); 67 EXPECT_EQ("{}", output_.substr(0, out_stream_->ByteCount())); 68} 69 70TEST_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 81TEST_F(JsonObjectWriterTest, EmptyRootList) { 82 ow_ = new JsonObjectWriter("", out_stream_); 83 ow_->StartList("")->EndList(); 84 EXPECT_EQ("[]", output_.substr(0, out_stream_->ByteCount())); 85} 86 87TEST_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 98TEST_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 109TEST_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 120TEST_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 131TEST_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 141TEST_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 171TEST_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 182TEST_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 205TEST_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 228TEST_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 245TEST_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 259TEST_F(JsonObjectWriterTest, StringsEscapedAndEnclosedInDoubleQuotes) { 260 ow_ = new JsonObjectWriter("", out_stream_); 261 ow_->StartObject("")->RenderString("string", "'<>&\\\"\r\n")->EndObject(); 262 EXPECT_EQ("{\"string\":\"'\\u003c\\u003e&\\\\\\\"\\r\\n\"}", 263 output_.substr(0, out_stream_->ByteCount())); 264} 265 266TEST_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 286TEST_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 298TEST_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