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/json_util.h> 32 33#include <list> 34#include <string> 35 36#include <google/protobuf/io/zero_copy_stream.h> 37#include <google/protobuf/util/json_format_proto3.pb.h> 38#include <google/protobuf/util/type_resolver.h> 39#include <google/protobuf/util/type_resolver_util.h> 40#include <gtest/gtest.h> 41 42namespace google { 43namespace protobuf { 44namespace util { 45namespace { 46 47using proto3::FOO; 48using proto3::BAR; 49using proto3::TestMessage; 50using proto3::TestMap; 51 52static const char kTypeUrlPrefix[] = "type.googleapis.com"; 53 54static string GetTypeUrl(const Descriptor* message) { 55 return string(kTypeUrlPrefix) + "/" + message->full_name(); 56} 57 58// As functions defined in json_util.h are just thin wrappers around the 59// JSON conversion code in //net/proto2/util/converter, in this test we 60// only cover some very basic cases to make sure the wrappers have forwarded 61// parameters to the underlying implementation correctly. More detailed 62// tests are contained in the //net/proto2/util/converter directory. 63class JsonUtilTest : public testing::Test { 64 protected: 65 JsonUtilTest() { 66 resolver_.reset(NewTypeResolverForDescriptorPool( 67 kTypeUrlPrefix, DescriptorPool::generated_pool())); 68 } 69 70 string ToJson(const Message& message, const JsonOptions& options) { 71 string result; 72 GOOGLE_CHECK_OK(BinaryToJsonString(resolver_.get(), 73 GetTypeUrl(message.GetDescriptor()), 74 message.SerializeAsString(), &result, options)); 75 return result; 76 } 77 78 bool FromJson(const string& json, Message* message) { 79 string binary; 80 if (!JsonToBinaryString(resolver_.get(), 81 GetTypeUrl(message->GetDescriptor()), json, &binary) 82 .ok()) { 83 return false; 84 } 85 return message->ParseFromString(binary); 86 } 87 88 google::protobuf::scoped_ptr<TypeResolver> resolver_; 89}; 90 91TEST_F(JsonUtilTest, TestWhitespaces) { 92 TestMessage m; 93 m.mutable_message_value(); 94 95 JsonOptions options; 96 EXPECT_EQ("{\"messageValue\":{}}", ToJson(m, options)); 97 options.add_whitespace = true; 98 EXPECT_EQ( 99 "{\n" 100 " \"messageValue\": {}\n" 101 "}\n", 102 ToJson(m, options)); 103} 104 105TEST_F(JsonUtilTest, TestDefaultValues) { 106 TestMessage m; 107 JsonOptions options; 108 EXPECT_EQ("{}", ToJson(m, options)); 109 options.always_print_primitive_fields = true; 110 EXPECT_EQ( 111 "{\"boolValue\":false," 112 "\"int32Value\":0," 113 "\"int64Value\":\"0\"," 114 "\"uint32Value\":0," 115 "\"uint64Value\":\"0\"," 116 "\"floatValue\":0," 117 "\"doubleValue\":0," 118 "\"stringValue\":\"\"," 119 "\"bytesValue\":\"\"," 120 "\"enumValue\":\"FOO\"," 121 "\"repeatedBoolValue\":[]," 122 "\"repeatedInt32Value\":[]," 123 "\"repeatedInt64Value\":[]," 124 "\"repeatedUint32Value\":[]," 125 "\"repeatedUint64Value\":[]," 126 "\"repeatedFloatValue\":[]," 127 "\"repeatedDoubleValue\":[]," 128 "\"repeatedStringValue\":[]," 129 "\"repeatedBytesValue\":[]," 130 "\"repeatedEnumValue\":[]," 131 "\"repeatedMessageValue\":[]" 132 "}", 133 ToJson(m, options)); 134} 135 136TEST_F(JsonUtilTest, ParseMessage) { 137 // Some random message but good enough to verify that the parsing warpper 138 // functions are working properly. 139 string input = 140 "{\n" 141 " \"int32Value\": 1024,\n" 142 " \"repeatedInt32Value\": [1, 2],\n" 143 " \"messageValue\": {\n" 144 " \"value\": 2048\n" 145 " },\n" 146 " \"repeatedMessageValue\": [\n" 147 " {\"value\": 40}, {\"value\": 96}\n" 148 " ]\n" 149 "}\n"; 150 TestMessage m; 151 ASSERT_TRUE(FromJson(input, &m)); 152 EXPECT_EQ(1024, m.int32_value()); 153 ASSERT_EQ(2, m.repeated_int32_value_size()); 154 EXPECT_EQ(1, m.repeated_int32_value(0)); 155 EXPECT_EQ(2, m.repeated_int32_value(1)); 156 EXPECT_EQ(2048, m.message_value().value()); 157 ASSERT_EQ(2, m.repeated_message_value_size()); 158 EXPECT_EQ(40, m.repeated_message_value(0).value()); 159 EXPECT_EQ(96, m.repeated_message_value(1).value()); 160} 161 162TEST_F(JsonUtilTest, ParseMap) { 163 TestMap message; 164 (*message.mutable_string_map())["hello"] = 1234; 165 JsonOptions options; 166 EXPECT_EQ("{\"stringMap\":{\"hello\":1234}}", ToJson(message, options)); 167 TestMap other; 168 ASSERT_TRUE(FromJson(ToJson(message, options), &other)); 169 EXPECT_EQ(message.DebugString(), other.DebugString()); 170} 171 172TEST_F(JsonUtilTest, TestParseErrors) { 173 TestMessage m; 174 JsonOptions options; 175 // Parsing should fail if the field name can not be recognized. 176 EXPECT_FALSE(FromJson("{\"unknownName\":0}", &m)); 177 // Parsing should fail if the value is invalid. 178 EXPECT_FALSE(FromJson("{\"int32Value\":2147483648}", &m)); 179} 180 181typedef pair<char*, int> Segment; 182// A ZeroCopyOutputStream that writes to multiple buffers. 183class SegmentedZeroCopyOutputStream : public io::ZeroCopyOutputStream { 184 public: 185 explicit SegmentedZeroCopyOutputStream(list<Segment> segments) 186 : segments_(segments), last_segment_(static_cast<char*>(NULL), 0), byte_count_(0) {} 187 188 virtual bool Next(void** buffer, int* length) { 189 if (segments_.empty()) { 190 return false; 191 } 192 last_segment_ = segments_.front(); 193 segments_.pop_front(); 194 *buffer = last_segment_.first; 195 *length = last_segment_.second; 196 byte_count_ += *length; 197 return true; 198 } 199 200 virtual void BackUp(int length) { 201 GOOGLE_CHECK(length <= last_segment_.second); 202 segments_.push_front( 203 Segment(last_segment_.first + last_segment_.second - length, length)); 204 last_segment_ = Segment(last_segment_.first, last_segment_.second - length); 205 byte_count_ -= length; 206 } 207 208 virtual int64 ByteCount() const { return byte_count_; } 209 210 private: 211 list<Segment> segments_; 212 Segment last_segment_; 213 int64 byte_count_; 214}; 215 216// This test splits the output buffer and also the input data into multiple 217// segments and checks that the implementation of ZeroCopyStreamByteSink 218// handles all possible cases correctly. 219TEST(ZeroCopyStreamByteSinkTest, TestAllInputOutputPatterns) { 220 static const int kOutputBufferLength = 10; 221 // An exhaustive test takes too long, skip some combinations to make the test 222 // run faster. 223 static const int kSkippedPatternCount = 7; 224 225 char buffer[kOutputBufferLength]; 226 for (int split_pattern = 0; split_pattern < (1 << (kOutputBufferLength - 1)); 227 split_pattern += kSkippedPatternCount) { 228 // Split the buffer into small segments according to the split_pattern. 229 list<Segment> segments; 230 int segment_start = 0; 231 for (int i = 0; i < kOutputBufferLength - 1; ++i) { 232 if (split_pattern & (1 << i)) { 233 segments.push_back( 234 Segment(buffer + segment_start, i - segment_start + 1)); 235 segment_start = i + 1; 236 } 237 } 238 segments.push_back( 239 Segment(buffer + segment_start, kOutputBufferLength - segment_start)); 240 241 // Write exactly 10 bytes through the ByteSink. 242 string input_data = "0123456789"; 243 for (int input_pattern = 0; input_pattern < (1 << (input_data.size() - 1)); 244 input_pattern += kSkippedPatternCount) { 245 memset(buffer, 0, sizeof(buffer)); 246 { 247 SegmentedZeroCopyOutputStream output_stream(segments); 248 internal::ZeroCopyStreamByteSink byte_sink(&output_stream); 249 int start = 0; 250 for (int j = 0; j < input_data.length() - 1; ++j) { 251 if (input_pattern & (1 << j)) { 252 byte_sink.Append(&input_data[start], j - start + 1); 253 start = j + 1; 254 } 255 } 256 byte_sink.Append(&input_data[start], input_data.length() - start); 257 } 258 EXPECT_EQ(input_data, string(buffer, input_data.length())); 259 } 260 261 // Write only 9 bytes through the ByteSink. 262 input_data = "012345678"; 263 for (int input_pattern = 0; input_pattern < (1 << (input_data.size() - 1)); 264 input_pattern += kSkippedPatternCount) { 265 memset(buffer, 0, sizeof(buffer)); 266 { 267 SegmentedZeroCopyOutputStream output_stream(segments); 268 internal::ZeroCopyStreamByteSink byte_sink(&output_stream); 269 int start = 0; 270 for (int j = 0; j < input_data.length() - 1; ++j) { 271 if (input_pattern & (1 << j)) { 272 byte_sink.Append(&input_data[start], j - start + 1); 273 start = j + 1; 274 } 275 } 276 byte_sink.Append(&input_data[start], input_data.length() - start); 277 } 278 EXPECT_EQ(input_data, string(buffer, input_data.length())); 279 EXPECT_EQ(0, buffer[input_data.length()]); 280 } 281 282 // Write 11 bytes through the ByteSink. The extra byte will just 283 // be ignored. 284 input_data = "0123456789A"; 285 for (int input_pattern = 0; input_pattern < (1 << (input_data.size() - 1)); 286 input_pattern += kSkippedPatternCount) { 287 memset(buffer, 0, sizeof(buffer)); 288 { 289 SegmentedZeroCopyOutputStream output_stream(segments); 290 internal::ZeroCopyStreamByteSink byte_sink(&output_stream); 291 int start = 0; 292 for (int j = 0; j < input_data.length() - 1; ++j) { 293 if (input_pattern & (1 << j)) { 294 byte_sink.Append(&input_data[start], j - start + 1); 295 start = j + 1; 296 } 297 } 298 byte_sink.Append(&input_data[start], input_data.length() - start); 299 } 300 EXPECT_EQ(input_data.substr(0, kOutputBufferLength), 301 string(buffer, kOutputBufferLength)); 302 } 303 } 304} 305 306} // namespace 307} // namespace util 308} // namespace protobuf 309} // namespace google 310