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