// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include #include namespace google { namespace protobuf { namespace util { namespace converter { using google::protobuf::io::CodedOutputStream; using google::protobuf::io::StringOutputStream; class JsonObjectWriterTest : public ::testing::Test { protected: JsonObjectWriterTest() : str_stream_(new StringOutputStream(&output_)), out_stream_(new CodedOutputStream(str_stream_)), ow_(NULL) {} virtual ~JsonObjectWriterTest() { delete ow_; delete out_stream_; delete str_stream_; } string output_; StringOutputStream* const str_stream_; CodedOutputStream* const out_stream_; JsonObjectWriter* ow_; }; TEST_F(JsonObjectWriterTest, EmptyRootObject) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("")->EndObject(); EXPECT_EQ("{}", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, EmptyObject) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("") ->RenderString("test", "value") ->StartObject("empty") ->EndObject() ->EndObject(); EXPECT_EQ("{\"test\":\"value\",\"empty\":{}}", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, EmptyRootList) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartList("")->EndList(); EXPECT_EQ("[]", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, EmptyList) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("") ->RenderString("test", "value") ->StartList("empty") ->EndList() ->EndObject(); EXPECT_EQ("{\"test\":\"value\",\"empty\":[]}", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, ObjectInObject) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("") ->StartObject("nested") ->RenderString("field", "value") ->EndObject() ->EndObject(); EXPECT_EQ("{\"nested\":{\"field\":\"value\"}}", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, ListInObject) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("") ->StartList("nested") ->RenderString("", "value") ->EndList() ->EndObject(); EXPECT_EQ("{\"nested\":[\"value\"]}", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, ObjectInList) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartList("") ->StartObject("") ->RenderString("field", "value") ->EndObject() ->EndList(); EXPECT_EQ("[{\"field\":\"value\"}]", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, ListInList) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartList("") ->StartList("") ->RenderString("", "value") ->EndList() ->EndList(); EXPECT_EQ("[[\"value\"]]", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, RenderPrimitives) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("") ->RenderBool("bool", true) ->RenderDouble("double", std::numeric_limits::max()) ->RenderFloat("float", std::numeric_limits::max()) ->RenderInt32("int", std::numeric_limits::min()) ->RenderInt64("long", std::numeric_limits::min()) ->RenderBytes("bytes", "abracadabra") ->RenderString("string", "string") ->RenderBytes("emptybytes", "") ->RenderString("emptystring", string()) ->EndObject(); EXPECT_EQ( "{\"bool\":true," "\"double\":" + ValueAsString(std::numeric_limits::max()) + "," "\"float\":" + ValueAsString(std::numeric_limits::max()) + "," "\"int\":-2147483648," "\"long\":\"-9223372036854775808\"," "\"bytes\":\"YWJyYWNhZGFicmE=\"," "\"string\":\"string\"," "\"emptybytes\":\"\"," "\"emptystring\":\"\"}", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, BytesEncodesAsNonWebSafeBase64) { string s; s.push_back('\377'); s.push_back('\357'); ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("")->RenderBytes("bytes", s)->EndObject(); // Non-web-safe would encode this as "/+8=" EXPECT_EQ("{\"bytes\":\"/+8=\"}", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, PrettyPrintList) { ow_ = new JsonObjectWriter(" ", out_stream_); ow_->StartObject("") ->StartList("items") ->RenderString("", "item1") ->RenderString("", "item2") ->RenderString("", "item3") ->EndList() ->StartList("empty") ->EndList() ->EndObject(); EXPECT_EQ( "{\n" " \"items\": [\n" " \"item1\",\n" " \"item2\",\n" " \"item3\"\n" " ],\n" " \"empty\": []\n" "}\n", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, PrettyPrintObject) { ow_ = new JsonObjectWriter(" ", out_stream_); ow_->StartObject("") ->StartObject("items") ->RenderString("key1", "item1") ->RenderString("key2", "item2") ->RenderString("key3", "item3") ->EndObject() ->StartObject("empty") ->EndObject() ->EndObject(); EXPECT_EQ( "{\n" " \"items\": {\n" " \"key1\": \"item1\",\n" " \"key2\": \"item2\",\n" " \"key3\": \"item3\"\n" " },\n" " \"empty\": {}\n" "}\n", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, PrettyPrintEmptyObjectInEmptyList) { ow_ = new JsonObjectWriter(" ", out_stream_); ow_->StartObject("") ->StartList("list") ->StartObject("") ->EndObject() ->EndList() ->EndObject(); EXPECT_EQ( "{\n" " \"list\": [\n" " {}\n" " ]\n" "}\n", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, PrettyPrintDoubleIndent) { ow_ = new JsonObjectWriter(" ", out_stream_); ow_->StartObject("") ->RenderBool("bool", true) ->RenderInt32("int", 42) ->EndObject(); EXPECT_EQ( "{\n" " \"bool\": true,\n" " \"int\": 42\n" "}\n", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, StringsEscapedAndEnclosedInDoubleQuotes) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("")->RenderString("string", "'<>&\\\"\r\n")->EndObject(); EXPECT_EQ("{\"string\":\"'\\u003c\\u003e&\\\\\\\"\\r\\n\"}", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, Stringification) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("") ->RenderDouble("double_nan", std::numeric_limits::quiet_NaN()) ->RenderFloat("float_nan", std::numeric_limits::quiet_NaN()) ->RenderDouble("double_pos", std::numeric_limits::infinity()) ->RenderFloat("float_pos", std::numeric_limits::infinity()) ->RenderDouble("double_neg", -std::numeric_limits::infinity()) ->RenderFloat("float_neg", -std::numeric_limits::infinity()) ->EndObject(); EXPECT_EQ( "{\"double_nan\":\"NaN\"," "\"float_nan\":\"NaN\"," "\"double_pos\":\"Infinity\"," "\"float_pos\":\"Infinity\"," "\"double_neg\":\"-Infinity\"," "\"float_neg\":\"-Infinity\"}", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, TestRegularByteEncoding) { ow_ = new JsonObjectWriter("", out_stream_); ow_->StartObject("") ->RenderBytes("bytes", "\x03\xef\xc0") ->EndObject(); // Test that we get regular (non websafe) base64 encoding on byte fields by // default. EXPECT_EQ("{\"bytes\":\"A+/A\"}", output_.substr(0, out_stream_->ByteCount())); } TEST_F(JsonObjectWriterTest, TestWebsafeByteEncoding) { ow_ = new JsonObjectWriter("", out_stream_); ow_->set_use_websafe_base64_for_bytes(true); ow_->StartObject("") ->RenderBytes("bytes", "\x03\xef\xc0\x10") ->EndObject(); // Test that we get websafe base64 encoding when explicitly asked. EXPECT_EQ("{\"bytes\":\"A-_AEA==\"}", output_.substr(0, out_stream_->ByteCount())); } } // namespace converter } // namespace util } // namespace protobuf } // namespace google