Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 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> |
Feng Xiao | 818c5ee | 2015-06-15 21:42:57 -0700 | [diff] [blame] | 34 | #include <google/protobuf/util/internal/utility.h> |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 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: |
| 47 | JsonObjectWriterTest() |
| 48 | : str_stream_(new StringOutputStream(&output_)), |
| 49 | out_stream_(new CodedOutputStream(str_stream_)), |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 50 | ow_(NULL) {} |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 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 | ObjectWriter* ow_; |
| 62 | }; |
| 63 | |
| 64 | TEST_F(JsonObjectWriterTest, EmptyRootObject) { |
| 65 | ow_ = new JsonObjectWriter("", out_stream_); |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 66 | ow_->StartObject("")->EndObject(); |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 67 | EXPECT_EQ("{}", output_.substr(0, out_stream_->ByteCount())); |
| 68 | } |
| 69 | |
| 70 | TEST_F(JsonObjectWriterTest, EmptyObject) { |
| 71 | ow_ = new JsonObjectWriter("", out_stream_); |
| 72 | ow_->StartObject("") |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 73 | ->RenderString("test", "value") |
| 74 | ->StartObject("empty") |
| 75 | ->EndObject() |
| 76 | ->EndObject(); |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 77 | EXPECT_EQ("{\"test\":\"value\",\"empty\":{}}", |
| 78 | output_.substr(0, out_stream_->ByteCount())); |
| 79 | } |
| 80 | |
| 81 | TEST_F(JsonObjectWriterTest, EmptyRootList) { |
| 82 | ow_ = new JsonObjectWriter("", out_stream_); |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 83 | ow_->StartList("")->EndList(); |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 84 | EXPECT_EQ("[]", output_.substr(0, out_stream_->ByteCount())); |
| 85 | } |
| 86 | |
| 87 | TEST_F(JsonObjectWriterTest, EmptyList) { |
| 88 | ow_ = new JsonObjectWriter("", out_stream_); |
| 89 | ow_->StartObject("") |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 90 | ->RenderString("test", "value") |
| 91 | ->StartList("empty") |
| 92 | ->EndList() |
| 93 | ->EndObject(); |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 94 | EXPECT_EQ("{\"test\":\"value\",\"empty\":[]}", |
| 95 | output_.substr(0, out_stream_->ByteCount())); |
| 96 | } |
| 97 | |
| 98 | TEST_F(JsonObjectWriterTest, ObjectInObject) { |
| 99 | ow_ = new JsonObjectWriter("", out_stream_); |
| 100 | ow_->StartObject("") |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 101 | ->StartObject("nested") |
| 102 | ->RenderString("field", "value") |
| 103 | ->EndObject() |
| 104 | ->EndObject(); |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 105 | EXPECT_EQ("{\"nested\":{\"field\":\"value\"}}", |
| 106 | output_.substr(0, out_stream_->ByteCount())); |
| 107 | } |
| 108 | |
| 109 | TEST_F(JsonObjectWriterTest, ListInObject) { |
| 110 | ow_ = new JsonObjectWriter("", out_stream_); |
| 111 | ow_->StartObject("") |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 112 | ->StartList("nested") |
| 113 | ->RenderString("", "value") |
| 114 | ->EndList() |
| 115 | ->EndObject(); |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 116 | EXPECT_EQ("{\"nested\":[\"value\"]}", |
| 117 | output_.substr(0, out_stream_->ByteCount())); |
| 118 | } |
| 119 | |
| 120 | TEST_F(JsonObjectWriterTest, ObjectInList) { |
| 121 | ow_ = new JsonObjectWriter("", out_stream_); |
| 122 | ow_->StartList("") |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 123 | ->StartObject("") |
| 124 | ->RenderString("field", "value") |
| 125 | ->EndObject() |
| 126 | ->EndList(); |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 127 | EXPECT_EQ("[{\"field\":\"value\"}]", |
| 128 | output_.substr(0, out_stream_->ByteCount())); |
| 129 | } |
| 130 | |
| 131 | TEST_F(JsonObjectWriterTest, ListInList) { |
| 132 | ow_ = new JsonObjectWriter("", out_stream_); |
| 133 | ow_->StartList("") |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 134 | ->StartList("") |
| 135 | ->RenderString("", "value") |
| 136 | ->EndList() |
| 137 | ->EndList(); |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 138 | EXPECT_EQ("[[\"value\"]]", output_.substr(0, out_stream_->ByteCount())); |
| 139 | } |
| 140 | |
| 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," |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 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\":\"\"}", |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 168 | output_.substr(0, out_stream_->ByteCount())); |
| 169 | } |
| 170 | |
Feng Xiao | eee38b0 | 2015-08-22 18:25:48 -0700 | [diff] [blame] | 171 | TEST_F(JsonObjectWriterTest, BytesEncodesAsNonWebSafeBase64) { |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 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=" |
Feng Xiao | eee38b0 | 2015-08-22 18:25:48 -0700 | [diff] [blame] | 178 | EXPECT_EQ("{\"bytes\":\"/+8=\"}", |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 179 | output_.substr(0, out_stream_->ByteCount())); |
| 180 | } |
| 181 | |
| 182 | TEST_F(JsonObjectWriterTest, PrettyPrintList) { |
| 183 | ow_ = new JsonObjectWriter(" ", out_stream_); |
| 184 | ow_->StartObject("") |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 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())); |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 203 | } |
| 204 | |
| 205 | TEST_F(JsonObjectWriterTest, PrettyPrintObject) { |
| 206 | ow_ = new JsonObjectWriter(" ", out_stream_); |
| 207 | ow_->StartObject("") |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 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())); |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 226 | } |
| 227 | |
| 228 | TEST_F(JsonObjectWriterTest, PrettyPrintEmptyObjectInEmptyList) { |
| 229 | ow_ = new JsonObjectWriter(" ", out_stream_); |
| 230 | ow_->StartObject("") |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 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())); |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 243 | } |
| 244 | |
| 245 | TEST_F(JsonObjectWriterTest, PrettyPrintDoubleIndent) { |
| 246 | ow_ = new JsonObjectWriter(" ", out_stream_); |
| 247 | ow_->StartObject("") |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 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())); |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 257 | } |
| 258 | |
| 259 | TEST_F(JsonObjectWriterTest, StringsEscapedAndEnclosedInDoubleQuotes) { |
| 260 | ow_ = new JsonObjectWriter("", out_stream_); |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 261 | ow_->StartObject("")->RenderString("string", "'<>&\\\"\r\n")->EndObject(); |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 262 | EXPECT_EQ("{\"string\":\"'\\u003c\\u003e&\\\\\\\"\\r\\n\"}", |
| 263 | output_.substr(0, out_stream_->ByteCount())); |
| 264 | } |
| 265 | |
| 266 | TEST_F(JsonObjectWriterTest, Stringification) { |
| 267 | ow_ = new JsonObjectWriter("", out_stream_); |
| 268 | ow_->StartObject("") |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 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(); |
Feng Xiao | e96ff30 | 2015-06-15 18:21:48 -0700 | [diff] [blame] | 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 | |
| 286 | } // namespace converter |
| 287 | } // namespace util |
| 288 | } // namespace protobuf |
| 289 | } // namespace google |