Home | History | Annotate | Download | only in internal
      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:
     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 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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