OLD | NEW |
1 // Protocol Buffers - Google's data interchange format | 1 // Protocol Buffers - Google's data interchange format |
2 // Copyright 2008 Google Inc. All rights reserved. | 2 // Copyright 2008 Google Inc. All rights reserved. |
3 // https://developers.google.com/protocol-buffers/ | 3 // https://developers.google.com/protocol-buffers/ |
4 // | 4 // |
5 // Redistribution and use in source and binary forms, with or without | 5 // Redistribution and use in source and binary forms, with or without |
6 // modification, are permitted provided that the following conditions are | 6 // modification, are permitted provided that the following conditions are |
7 // met: | 7 // met: |
8 // | 8 // |
9 // * Redistributions of source code must retain the above copyright | 9 // * Redistributions of source code must retain the above copyright |
10 // notice, this list of conditions and the following disclaimer. | 10 // notice, this list of conditions and the following disclaimer. |
(...skipping 16 matching lines...) Expand all Loading... |
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | 30 |
31 #include <google/protobuf/util/json_util.h> | 31 #include <google/protobuf/util/json_util.h> |
32 | 32 |
33 #include <list> | 33 #include <list> |
34 #include <string> | 34 #include <string> |
35 | 35 |
36 #include <google/protobuf/io/zero_copy_stream.h> | 36 #include <google/protobuf/io/zero_copy_stream.h> |
| 37 #include <google/protobuf/descriptor_database.h> |
| 38 #include <google/protobuf/dynamic_message.h> |
37 #include <google/protobuf/util/json_format_proto3.pb.h> | 39 #include <google/protobuf/util/json_format_proto3.pb.h> |
38 #include <google/protobuf/util/type_resolver.h> | 40 #include <google/protobuf/util/type_resolver.h> |
39 #include <google/protobuf/util/type_resolver_util.h> | 41 #include <google/protobuf/util/type_resolver_util.h> |
40 #include <gtest/gtest.h> | 42 #include <gtest/gtest.h> |
41 | 43 |
42 namespace google { | 44 namespace google { |
43 namespace protobuf { | 45 namespace protobuf { |
44 namespace util { | 46 namespace util { |
45 namespace { | 47 namespace { |
46 | 48 |
47 using proto3::FOO; | 49 using proto3::FOO; |
48 using proto3::BAR; | 50 using proto3::BAR; |
49 using proto3::TestMessage; | 51 using proto3::TestMessage; |
50 using proto3::TestMap; | 52 using proto3::TestMap; |
51 | 53 |
52 static const char kTypeUrlPrefix[] = "type.googleapis.com"; | 54 static const char kTypeUrlPrefix[] = "type.googleapis.com"; |
53 | 55 |
54 static string GetTypeUrl(const Descriptor* message) { | 56 static string GetTypeUrl(const Descriptor* message) { |
55 return string(kTypeUrlPrefix) + "/" + message->full_name(); | 57 return string(kTypeUrlPrefix) + "/" + message->full_name(); |
56 } | 58 } |
57 | 59 |
58 // As functions defined in json_util.h are just thin wrappers around the | 60 // 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 | 61 // 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 | 62 // only cover some very basic cases to make sure the wrappers have forwarded |
61 // parameters to the underlying implementation correctly. More detailed | 63 // parameters to the underlying implementation correctly. More detailed |
62 // tests are contained in the //net/proto2/util/converter directory. | 64 // tests are contained in the //net/proto2/util/converter directory. |
63 class JsonUtilTest : public testing::Test { | 65 class JsonUtilTest : public testing::Test { |
64 protected: | 66 protected: |
65 JsonUtilTest() { | 67 JsonUtilTest() { |
66 resolver_.reset(NewTypeResolverForDescriptorPool( | |
67 kTypeUrlPrefix, DescriptorPool::generated_pool())); | |
68 } | 68 } |
69 | 69 |
70 string ToJson(const Message& message, const JsonOptions& options) { | 70 string ToJson(const Message& message, const JsonPrintOptions& options) { |
71 string result; | 71 string result; |
72 GOOGLE_CHECK_OK(BinaryToJsonString(resolver_.get(), | 72 GOOGLE_CHECK_OK(MessageToJsonString(message, &result, options)); |
73 GetTypeUrl(message.GetDescriptor()), | |
74 message.SerializeAsString(), &result, options)); | |
75 return result; | 73 return result; |
76 } | 74 } |
77 | 75 |
| 76 bool FromJson(const string& json, Message* message, |
| 77 const JsonParseOptions& options) { |
| 78 return JsonStringToMessage(json, message, options).ok(); |
| 79 } |
| 80 |
78 bool FromJson(const string& json, Message* message) { | 81 bool FromJson(const string& json, Message* message) { |
79 string binary; | 82 return FromJson(json, message, JsonParseOptions()); |
80 if (!JsonToBinaryString(resolver_.get(), | |
81 GetTypeUrl(message->GetDescriptor()), json, &binary) | |
82 .ok()) { | |
83 return false; | |
84 } | |
85 return message->ParseFromString(binary); | |
86 } | 83 } |
87 | 84 |
88 google::protobuf::scoped_ptr<TypeResolver> resolver_; | 85 google::protobuf::scoped_ptr<TypeResolver> resolver_; |
89 }; | 86 }; |
90 | 87 |
91 TEST_F(JsonUtilTest, TestWhitespaces) { | 88 TEST_F(JsonUtilTest, TestWhitespaces) { |
92 TestMessage m; | 89 TestMessage m; |
93 m.mutable_message_value(); | 90 m.mutable_message_value(); |
94 | 91 |
95 JsonOptions options; | 92 JsonPrintOptions options; |
96 EXPECT_EQ("{\"messageValue\":{}}", ToJson(m, options)); | 93 EXPECT_EQ("{\"messageValue\":{}}", ToJson(m, options)); |
97 options.add_whitespace = true; | 94 options.add_whitespace = true; |
98 EXPECT_EQ( | 95 EXPECT_EQ( |
99 "{\n" | 96 "{\n" |
100 " \"messageValue\": {}\n" | 97 " \"messageValue\": {}\n" |
101 "}\n", | 98 "}\n", |
102 ToJson(m, options)); | 99 ToJson(m, options)); |
103 } | 100 } |
104 | 101 |
105 TEST_F(JsonUtilTest, TestDefaultValues) { | 102 TEST_F(JsonUtilTest, TestDefaultValues) { |
106 TestMessage m; | 103 TestMessage m; |
107 JsonOptions options; | 104 JsonPrintOptions options; |
108 EXPECT_EQ("{}", ToJson(m, options)); | 105 EXPECT_EQ("{}", ToJson(m, options)); |
109 options.always_print_primitive_fields = true; | 106 options.always_print_primitive_fields = true; |
110 EXPECT_EQ( | 107 EXPECT_EQ( |
111 "{\"boolValue\":false," | 108 "{\"boolValue\":false," |
112 "\"int32Value\":0," | 109 "\"int32Value\":0," |
113 "\"int64Value\":\"0\"," | 110 "\"int64Value\":\"0\"," |
114 "\"uint32Value\":0," | 111 "\"uint32Value\":0," |
115 "\"uint64Value\":\"0\"," | 112 "\"uint64Value\":\"0\"," |
116 "\"floatValue\":0," | 113 "\"floatValue\":0," |
117 "\"doubleValue\":0," | 114 "\"doubleValue\":0," |
118 "\"stringValue\":\"\"," | 115 "\"stringValue\":\"\"," |
119 "\"bytesValue\":\"\"," | 116 "\"bytesValue\":\"\"," |
120 "\"enumValue\":\"FOO\"," | 117 "\"enumValue\":\"FOO\"," |
121 "\"repeatedBoolValue\":[]," | 118 "\"repeatedBoolValue\":[]," |
122 "\"repeatedInt32Value\":[]," | 119 "\"repeatedInt32Value\":[]," |
123 "\"repeatedInt64Value\":[]," | 120 "\"repeatedInt64Value\":[]," |
124 "\"repeatedUint32Value\":[]," | 121 "\"repeatedUint32Value\":[]," |
125 "\"repeatedUint64Value\":[]," | 122 "\"repeatedUint64Value\":[]," |
126 "\"repeatedFloatValue\":[]," | 123 "\"repeatedFloatValue\":[]," |
127 "\"repeatedDoubleValue\":[]," | 124 "\"repeatedDoubleValue\":[]," |
128 "\"repeatedStringValue\":[]," | 125 "\"repeatedStringValue\":[]," |
129 "\"repeatedBytesValue\":[]," | 126 "\"repeatedBytesValue\":[]," |
130 "\"repeatedEnumValue\":[]," | 127 "\"repeatedEnumValue\":[]," |
131 "\"repeatedMessageValue\":[]" | 128 "\"repeatedMessageValue\":[]" |
132 "}", | 129 "}", |
133 ToJson(m, options)); | 130 ToJson(m, options)); |
| 131 |
| 132 options.always_print_primitive_fields = true; |
| 133 m.set_string_value("i am a test string value"); |
| 134 m.set_bytes_value("i am a test bytes value"); |
| 135 EXPECT_EQ( |
| 136 "{\"boolValue\":false," |
| 137 "\"int32Value\":0," |
| 138 "\"int64Value\":\"0\"," |
| 139 "\"uint32Value\":0," |
| 140 "\"uint64Value\":\"0\"," |
| 141 "\"floatValue\":0," |
| 142 "\"doubleValue\":0," |
| 143 "\"stringValue\":\"i am a test string value\"," |
| 144 "\"bytesValue\":\"aSBhbSBhIHRlc3QgYnl0ZXMgdmFsdWU=\"," |
| 145 "\"enumValue\":\"FOO\"," |
| 146 "\"repeatedBoolValue\":[]," |
| 147 "\"repeatedInt32Value\":[]," |
| 148 "\"repeatedInt64Value\":[]," |
| 149 "\"repeatedUint32Value\":[]," |
| 150 "\"repeatedUint64Value\":[]," |
| 151 "\"repeatedFloatValue\":[]," |
| 152 "\"repeatedDoubleValue\":[]," |
| 153 "\"repeatedStringValue\":[]," |
| 154 "\"repeatedBytesValue\":[]," |
| 155 "\"repeatedEnumValue\":[]," |
| 156 "\"repeatedMessageValue\":[]" |
| 157 "}", |
| 158 ToJson(m, options)); |
134 } | 159 } |
135 | 160 |
136 TEST_F(JsonUtilTest, ParseMessage) { | 161 TEST_F(JsonUtilTest, ParseMessage) { |
137 // Some random message but good enough to verify that the parsing warpper | 162 // Some random message but good enough to verify that the parsing warpper |
138 // functions are working properly. | 163 // functions are working properly. |
139 string input = | 164 string input = |
140 "{\n" | 165 "{\n" |
141 " \"int32Value\": 1024,\n" | 166 " \"int32Value\": 1024,\n" |
142 " \"repeatedInt32Value\": [1, 2],\n" | 167 " \"repeatedInt32Value\": [1, 2],\n" |
143 " \"messageValue\": {\n" | 168 " \"messageValue\": {\n" |
144 " \"value\": 2048\n" | 169 " \"value\": 2048\n" |
145 " },\n" | 170 " },\n" |
146 " \"repeatedMessageValue\": [\n" | 171 " \"repeatedMessageValue\": [\n" |
147 " {\"value\": 40}, {\"value\": 96}\n" | 172 " {\"value\": 40}, {\"value\": 96}\n" |
148 " ]\n" | 173 " ]\n" |
149 "}\n"; | 174 "}\n"; |
| 175 JsonParseOptions options; |
150 TestMessage m; | 176 TestMessage m; |
151 ASSERT_TRUE(FromJson(input, &m)); | 177 ASSERT_TRUE(FromJson(input, &m, options)); |
152 EXPECT_EQ(1024, m.int32_value()); | 178 EXPECT_EQ(1024, m.int32_value()); |
153 ASSERT_EQ(2, m.repeated_int32_value_size()); | 179 ASSERT_EQ(2, m.repeated_int32_value_size()); |
154 EXPECT_EQ(1, m.repeated_int32_value(0)); | 180 EXPECT_EQ(1, m.repeated_int32_value(0)); |
155 EXPECT_EQ(2, m.repeated_int32_value(1)); | 181 EXPECT_EQ(2, m.repeated_int32_value(1)); |
156 EXPECT_EQ(2048, m.message_value().value()); | 182 EXPECT_EQ(2048, m.message_value().value()); |
157 ASSERT_EQ(2, m.repeated_message_value_size()); | 183 ASSERT_EQ(2, m.repeated_message_value_size()); |
158 EXPECT_EQ(40, m.repeated_message_value(0).value()); | 184 EXPECT_EQ(40, m.repeated_message_value(0).value()); |
159 EXPECT_EQ(96, m.repeated_message_value(1).value()); | 185 EXPECT_EQ(96, m.repeated_message_value(1).value()); |
160 } | 186 } |
161 | 187 |
162 TEST_F(JsonUtilTest, ParseMap) { | 188 TEST_F(JsonUtilTest, ParseMap) { |
163 TestMap message; | 189 TestMap message; |
164 (*message.mutable_string_map())["hello"] = 1234; | 190 (*message.mutable_string_map())["hello"] = 1234; |
165 JsonOptions options; | 191 JsonPrintOptions print_options; |
166 EXPECT_EQ("{\"stringMap\":{\"hello\":1234}}", ToJson(message, options)); | 192 JsonParseOptions parse_options; |
| 193 EXPECT_EQ("{\"stringMap\":{\"hello\":1234}}", ToJson(message, print_options)); |
167 TestMap other; | 194 TestMap other; |
168 ASSERT_TRUE(FromJson(ToJson(message, options), &other)); | 195 ASSERT_TRUE(FromJson(ToJson(message, print_options), &other, parse_options)); |
169 EXPECT_EQ(message.DebugString(), other.DebugString()); | 196 EXPECT_EQ(message.DebugString(), other.DebugString()); |
170 } | 197 } |
171 | 198 |
| 199 TEST_F(JsonUtilTest, TestParseIgnoreUnknownFields) { |
| 200 TestMessage m; |
| 201 JsonParseOptions options; |
| 202 options.ignore_unknown_fields = true; |
| 203 EXPECT_TRUE(FromJson("{\"unknownName\":0}", &m, options)); |
| 204 } |
| 205 |
172 TEST_F(JsonUtilTest, TestParseErrors) { | 206 TEST_F(JsonUtilTest, TestParseErrors) { |
173 TestMessage m; | 207 TestMessage m; |
174 JsonOptions options; | 208 JsonParseOptions options; |
175 // Parsing should fail if the field name can not be recognized. | 209 // Parsing should fail if the field name can not be recognized. |
176 EXPECT_FALSE(FromJson("{\"unknownName\":0}", &m)); | 210 EXPECT_FALSE(FromJson("{\"unknownName\":0}", &m, options)); |
177 // Parsing should fail if the value is invalid. | 211 // Parsing should fail if the value is invalid. |
178 EXPECT_FALSE(FromJson("{\"int32Value\":2147483648}", &m)); | 212 EXPECT_FALSE(FromJson("{\"int32Value\":2147483648}", &m, options)); |
179 } | 213 } |
180 | 214 |
181 typedef pair<char*, int> Segment; | 215 TEST_F(JsonUtilTest, TestDynamicMessage) { |
| 216 // Some random message but good enough to test the wrapper functions. |
| 217 string input = |
| 218 "{\n" |
| 219 " \"int32Value\": 1024,\n" |
| 220 " \"repeatedInt32Value\": [1, 2],\n" |
| 221 " \"messageValue\": {\n" |
| 222 " \"value\": 2048\n" |
| 223 " },\n" |
| 224 " \"repeatedMessageValue\": [\n" |
| 225 " {\"value\": 40}, {\"value\": 96}\n" |
| 226 " ]\n" |
| 227 "}\n"; |
| 228 |
| 229 // Create a new DescriptorPool with the same protos as the generated one. |
| 230 DescriptorPoolDatabase database(*DescriptorPool::generated_pool()); |
| 231 DescriptorPool pool(&database); |
| 232 // A dynamic version of the test proto. |
| 233 DynamicMessageFactory factory; |
| 234 google::protobuf::scoped_ptr<Message> message(factory.GetPrototype( |
| 235 pool.FindMessageTypeByName("proto3.TestMessage"))->New()); |
| 236 EXPECT_TRUE(FromJson(input, message.get())); |
| 237 |
| 238 // Convert to generated message for easy inspection. |
| 239 TestMessage generated; |
| 240 EXPECT_TRUE(generated.ParseFromString(message->SerializeAsString())); |
| 241 EXPECT_EQ(1024, generated.int32_value()); |
| 242 ASSERT_EQ(2, generated.repeated_int32_value_size()); |
| 243 EXPECT_EQ(1, generated.repeated_int32_value(0)); |
| 244 EXPECT_EQ(2, generated.repeated_int32_value(1)); |
| 245 EXPECT_EQ(2048, generated.message_value().value()); |
| 246 ASSERT_EQ(2, generated.repeated_message_value_size()); |
| 247 EXPECT_EQ(40, generated.repeated_message_value(0).value()); |
| 248 EXPECT_EQ(96, generated.repeated_message_value(1).value()); |
| 249 |
| 250 JsonOptions options; |
| 251 EXPECT_EQ(ToJson(generated, options), ToJson(*message, options)); |
| 252 } |
| 253 |
| 254 typedef std::pair<char*, int> Segment; |
182 // A ZeroCopyOutputStream that writes to multiple buffers. | 255 // A ZeroCopyOutputStream that writes to multiple buffers. |
183 class SegmentedZeroCopyOutputStream : public io::ZeroCopyOutputStream { | 256 class SegmentedZeroCopyOutputStream : public io::ZeroCopyOutputStream { |
184 public: | 257 public: |
185 explicit SegmentedZeroCopyOutputStream(list<Segment> segments) | 258 explicit SegmentedZeroCopyOutputStream(std::list<Segment> segments) |
186 : segments_(segments), last_segment_(static_cast<char*>(NULL), 0), byte_co
unt_(0) {} | 259 : segments_(segments), last_segment_(static_cast<char*>(NULL), 0), byte_co
unt_(0) {} |
187 | 260 |
188 virtual bool Next(void** buffer, int* length) { | 261 virtual bool Next(void** buffer, int* length) { |
189 if (segments_.empty()) { | 262 if (segments_.empty()) { |
190 return false; | 263 return false; |
191 } | 264 } |
192 last_segment_ = segments_.front(); | 265 last_segment_ = segments_.front(); |
193 segments_.pop_front(); | 266 segments_.pop_front(); |
194 *buffer = last_segment_.first; | 267 *buffer = last_segment_.first; |
195 *length = last_segment_.second; | 268 *length = last_segment_.second; |
196 byte_count_ += *length; | 269 byte_count_ += *length; |
197 return true; | 270 return true; |
198 } | 271 } |
199 | 272 |
200 virtual void BackUp(int length) { | 273 virtual void BackUp(int length) { |
201 GOOGLE_CHECK(length <= last_segment_.second); | 274 GOOGLE_CHECK(length <= last_segment_.second); |
202 segments_.push_front( | 275 segments_.push_front( |
203 Segment(last_segment_.first + last_segment_.second - length, length)); | 276 Segment(last_segment_.first + last_segment_.second - length, length)); |
204 last_segment_ = Segment(last_segment_.first, last_segment_.second - length); | 277 last_segment_ = Segment(last_segment_.first, last_segment_.second - length); |
205 byte_count_ -= length; | 278 byte_count_ -= length; |
206 } | 279 } |
207 | 280 |
208 virtual int64 ByteCount() const { return byte_count_; } | 281 virtual int64 ByteCount() const { return byte_count_; } |
209 | 282 |
210 private: | 283 private: |
211 list<Segment> segments_; | 284 std::list<Segment> segments_; |
212 Segment last_segment_; | 285 Segment last_segment_; |
213 int64 byte_count_; | 286 int64 byte_count_; |
214 }; | 287 }; |
215 | 288 |
216 // This test splits the output buffer and also the input data into multiple | 289 // This test splits the output buffer and also the input data into multiple |
217 // segments and checks that the implementation of ZeroCopyStreamByteSink | 290 // segments and checks that the implementation of ZeroCopyStreamByteSink |
218 // handles all possible cases correctly. | 291 // handles all possible cases correctly. |
219 TEST(ZeroCopyStreamByteSinkTest, TestAllInputOutputPatterns) { | 292 TEST(ZeroCopyStreamByteSinkTest, TestAllInputOutputPatterns) { |
220 static const int kOutputBufferLength = 10; | 293 static const int kOutputBufferLength = 10; |
221 // An exhaustive test takes too long, skip some combinations to make the test | 294 // An exhaustive test takes too long, skip some combinations to make the test |
222 // run faster. | 295 // run faster. |
223 static const int kSkippedPatternCount = 7; | 296 static const int kSkippedPatternCount = 7; |
224 | 297 |
225 char buffer[kOutputBufferLength]; | 298 char buffer[kOutputBufferLength]; |
226 for (int split_pattern = 0; split_pattern < (1 << (kOutputBufferLength - 1)); | 299 for (int split_pattern = 0; split_pattern < (1 << (kOutputBufferLength - 1)); |
227 split_pattern += kSkippedPatternCount) { | 300 split_pattern += kSkippedPatternCount) { |
228 // Split the buffer into small segments according to the split_pattern. | 301 // Split the buffer into small segments according to the split_pattern. |
229 list<Segment> segments; | 302 std::list<Segment> segments; |
230 int segment_start = 0; | 303 int segment_start = 0; |
231 for (int i = 0; i < kOutputBufferLength - 1; ++i) { | 304 for (int i = 0; i < kOutputBufferLength - 1; ++i) { |
232 if (split_pattern & (1 << i)) { | 305 if (split_pattern & (1 << i)) { |
233 segments.push_back( | 306 segments.push_back( |
234 Segment(buffer + segment_start, i - segment_start + 1)); | 307 Segment(buffer + segment_start, i - segment_start + 1)); |
235 segment_start = i + 1; | 308 segment_start = i + 1; |
236 } | 309 } |
237 } | 310 } |
238 segments.push_back( | 311 segments.push_back( |
239 Segment(buffer + segment_start, kOutputBufferLength - segment_start)); | 312 Segment(buffer + segment_start, kOutputBufferLength - segment_start)); |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 EXPECT_EQ(input_data.substr(0, kOutputBufferLength), | 373 EXPECT_EQ(input_data.substr(0, kOutputBufferLength), |
301 string(buffer, kOutputBufferLength)); | 374 string(buffer, kOutputBufferLength)); |
302 } | 375 } |
303 } | 376 } |
304 } | 377 } |
305 | 378 |
306 } // namespace | 379 } // namespace |
307 } // namespace util | 380 } // namespace util |
308 } // namespace protobuf | 381 } // namespace protobuf |
309 } // namespace google | 382 } // namespace google |
OLD | NEW |