1# encoding: UTF-8
2#
3# Licensed to the Apache Software Foundation (ASF) under one
4# or more contributor license agreements. See the NOTICE file
5# distributed with this work for additional information
6# regarding copyright ownership. The ASF licenses this file
7# to you under the Apache License, Version 2.0 (the
8# "License"); you may not use this file except in compliance
9# with the License. You may obtain a copy of the License at
10#
11#   http://www.apache.org/licenses/LICENSE-2.0
12#
13# Unless required by applicable law or agreed to in writing,
14# software distributed under the License is distributed on an
15# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16# KIND, either express or implied. See the License for the
17# specific language governing permissions and limitations
18# under the License.
19#
20
21require 'spec_helper'
22
23describe 'JsonProtocol' do
24
25  describe Thrift::JsonProtocol do
26    before(:each) do
27      @trans = Thrift::MemoryBufferTransport.new
28      @prot = Thrift::JsonProtocol.new(@trans)
29    end
30
31    it "should write json escaped char" do
32      @prot.write_json_escape_char("\n")
33      expect(@trans.read(@trans.available)).to eq('\u000a')
34
35      @prot.write_json_escape_char(" ")
36      expect(@trans.read(@trans.available)).to eq('\u0020')
37    end
38
39    it "should write json char" do
40      @prot.write_json_char("\n")
41      expect(@trans.read(@trans.available)).to eq('\\n')
42
43      @prot.write_json_char(" ")
44      expect(@trans.read(@trans.available)).to eq(' ')
45
46      @prot.write_json_char("\\")
47      expect(@trans.read(@trans.available)).to eq("\\\\")
48
49      @prot.write_json_char("@")
50      expect(@trans.read(@trans.available)).to eq('@')
51    end
52
53    it "should write json string" do
54      @prot.write_json_string("this is a \\ json\nstring")
55      expect(@trans.read(@trans.available)).to eq("\"this is a \\\\ json\\nstring\"")
56    end
57
58    it "should write json base64" do
59      @prot.write_json_base64("this is a base64 string")
60      expect(@trans.read(@trans.available)).to eq("\"dGhpcyBpcyBhIGJhc2U2NCBzdHJpbmc=\"")
61    end
62
63    it "should write json integer" do
64      @prot.write_json_integer(45)
65      expect(@trans.read(@trans.available)).to eq("45")
66
67      @prot.write_json_integer(33000)
68      expect(@trans.read(@trans.available)).to eq("33000")
69
70      @prot.write_json_integer(3000000000)
71      expect(@trans.read(@trans.available)).to eq("3000000000")
72
73      @prot.write_json_integer(6000000000)
74      expect(@trans.read(@trans.available)).to eq("6000000000")
75    end
76
77    it "should write json double" do
78      @prot.write_json_double(12.3)
79      expect(@trans.read(@trans.available)).to eq("12.3")
80
81      @prot.write_json_double(-3.21)
82      expect(@trans.read(@trans.available)).to eq("-3.21")
83
84      @prot.write_json_double(((+1.0/0.0)/(+1.0/0.0)))
85      expect(@trans.read(@trans.available)).to eq("\"NaN\"")
86
87      @prot.write_json_double((+1.0/0.0))
88      expect(@trans.read(@trans.available)).to eq("\"Infinity\"")
89
90      @prot.write_json_double((-1.0/0.0))
91      expect(@trans.read(@trans.available)).to eq("\"-Infinity\"")
92    end
93
94    it "should write json object start" do
95      @prot.write_json_object_start
96      expect(@trans.read(@trans.available)).to eq("{")
97    end
98
99    it "should write json object end" do
100      @prot.write_json_object_end
101      expect(@trans.read(@trans.available)).to eq("}")
102    end
103
104    it "should write json array start" do
105      @prot.write_json_array_start
106      expect(@trans.read(@trans.available)).to eq("[")
107    end
108
109    it "should write json array end" do
110      @prot.write_json_array_end
111      expect(@trans.read(@trans.available)).to eq("]")
112    end
113
114    it "should write message begin" do
115      @prot.write_message_begin("name", 12, 32)
116      expect(@trans.read(@trans.available)).to eq("[1,\"name\",12,32")
117    end
118
119    it "should write message end" do
120      @prot.write_message_end
121      expect(@trans.read(@trans.available)).to eq("]")
122    end
123
124    it "should write struct begin" do
125      @prot.write_struct_begin("name")
126      expect(@trans.read(@trans.available)).to eq("{")
127    end
128
129    it "should write struct end" do
130      @prot.write_struct_end
131      expect(@trans.read(@trans.available)).to eq("}")
132    end
133
134    it "should write field begin" do
135      @prot.write_field_begin("name", Thrift::Types::STRUCT, 32)
136      expect(@trans.read(@trans.available)).to eq("32{\"rec\"")
137    end
138
139    it "should write field end" do
140      @prot.write_field_end
141      expect(@trans.read(@trans.available)).to eq("}")
142    end
143
144    it "should write field stop" do
145      @prot.write_field_stop
146      expect(@trans.read(@trans.available)).to eq("")
147    end
148
149    it "should write map begin" do
150      @prot.write_map_begin(Thrift::Types::STRUCT, Thrift::Types::LIST, 32)
151      expect(@trans.read(@trans.available)).to eq("[\"rec\",\"lst\",32,{")
152    end
153
154    it "should write map end" do
155      @prot.write_map_end
156      expect(@trans.read(@trans.available)).to eq("}]")
157    end
158
159    it "should write list begin" do
160      @prot.write_list_begin(Thrift::Types::STRUCT, 32)
161      expect(@trans.read(@trans.available)).to eq("[\"rec\",32")
162    end
163
164    it "should write list end" do
165      @prot.write_list_end
166      expect(@trans.read(@trans.available)).to eq("]")
167    end
168
169    it "should write set begin" do
170      @prot.write_set_begin(Thrift::Types::STRUCT, 32)
171      expect(@trans.read(@trans.available)).to eq("[\"rec\",32")
172    end
173
174    it "should write set end" do
175      @prot.write_set_end
176      expect(@trans.read(@trans.available)).to eq("]")
177    end
178
179    it "should write bool" do
180      @prot.write_bool(true)
181      expect(@trans.read(@trans.available)).to eq("1")
182
183      @prot.write_bool(false)
184      expect(@trans.read(@trans.available)).to eq("0")
185    end
186
187    it "should write byte" do
188      @prot.write_byte(100)
189      expect(@trans.read(@trans.available)).to eq("100")
190    end
191
192    it "should write i16" do
193      @prot.write_i16(1000)
194      expect(@trans.read(@trans.available)).to eq("1000")
195    end
196
197    it "should write i32" do
198      @prot.write_i32(3000000000)
199      expect(@trans.read(@trans.available)).to eq("3000000000")
200    end
201
202    it "should write i64" do
203      @prot.write_i64(6000000000)
204      expect(@trans.read(@trans.available)).to eq("6000000000")
205    end
206
207    it "should write double" do
208      @prot.write_double(1.23)
209      expect(@trans.read(@trans.available)).to eq("1.23")
210
211      @prot.write_double(-32.1)
212      expect(@trans.read(@trans.available)).to eq("-32.1")
213
214      @prot.write_double(((+1.0/0.0)/(+1.0/0.0)))
215      expect(@trans.read(@trans.available)).to eq("\"NaN\"")
216
217      @prot.write_double((+1.0/0.0))
218      expect(@trans.read(@trans.available)).to eq("\"Infinity\"")
219
220      @prot.write_double((-1.0/0.0))
221      expect(@trans.read(@trans.available)).to eq("\"-Infinity\"")
222    end
223
224    if RUBY_VERSION >= '1.9'
225      it 'should write string' do
226        @prot.write_string('this is a test string')
227        a = @trans.read(@trans.available)
228        expect(a).to eq('"this is a test string"'.force_encoding(Encoding::BINARY))
229        expect(a.encoding).to eq(Encoding::BINARY)
230      end
231
232      it 'should write string with unicode characters' do
233        @prot.write_string("this is a test string with unicode characters: \u20AC \u20AD")
234        a = @trans.read(@trans.available)
235        expect(a).to eq("\"this is a test string with unicode characters: \u20AC \u20AD\"".force_encoding(Encoding::BINARY))
236        expect(a.encoding).to eq(Encoding::BINARY)
237      end
238    else
239      it 'should write string' do
240        @prot.write_string('this is a test string')
241        expect(@trans.read(@trans.available)).to eq('"this is a test string"')
242      end
243    end
244
245    it "should write binary" do
246      @prot.write_binary("this is a base64 string")
247      expect(@trans.read(@trans.available)).to eq("\"dGhpcyBpcyBhIGJhc2U2NCBzdHJpbmc=\"")
248    end
249
250    it "should write long binary" do
251      @prot.write_binary((0...256).to_a.pack('C*'))
252      expect(@trans.read(@trans.available)).to eq("\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==\"")
253    end
254
255    it "should get type name for type id" do
256      expect {@prot.get_type_name_for_type_id(Thrift::Types::STOP)}.to raise_error(NotImplementedError)
257      expect {@prot.get_type_name_for_type_id(Thrift::Types::VOID)}.to raise_error(NotImplementedError)
258      expect(@prot.get_type_name_for_type_id(Thrift::Types::BOOL)).to eq("tf")
259      expect(@prot.get_type_name_for_type_id(Thrift::Types::BYTE)).to eq("i8")
260      expect(@prot.get_type_name_for_type_id(Thrift::Types::DOUBLE)).to eq("dbl")
261      expect(@prot.get_type_name_for_type_id(Thrift::Types::I16)).to eq("i16")
262      expect(@prot.get_type_name_for_type_id(Thrift::Types::I32)).to eq("i32")
263      expect(@prot.get_type_name_for_type_id(Thrift::Types::I64)).to eq("i64")
264      expect(@prot.get_type_name_for_type_id(Thrift::Types::STRING)).to eq("str")
265      expect(@prot.get_type_name_for_type_id(Thrift::Types::STRUCT)).to eq("rec")
266      expect(@prot.get_type_name_for_type_id(Thrift::Types::MAP)).to eq("map")
267      expect(@prot.get_type_name_for_type_id(Thrift::Types::SET)).to eq("set")
268      expect(@prot.get_type_name_for_type_id(Thrift::Types::LIST)).to eq("lst")
269    end
270
271    it "should get type id for type name" do
272      expect {@prot.get_type_id_for_type_name("pp")}.to raise_error(NotImplementedError)
273      expect(@prot.get_type_id_for_type_name("tf")).to eq(Thrift::Types::BOOL)
274      expect(@prot.get_type_id_for_type_name("i8")).to eq(Thrift::Types::BYTE)
275      expect(@prot.get_type_id_for_type_name("dbl")).to eq(Thrift::Types::DOUBLE)
276      expect(@prot.get_type_id_for_type_name("i16")).to eq(Thrift::Types::I16)
277      expect(@prot.get_type_id_for_type_name("i32")).to eq(Thrift::Types::I32)
278      expect(@prot.get_type_id_for_type_name("i64")).to eq(Thrift::Types::I64)
279      expect(@prot.get_type_id_for_type_name("str")).to eq(Thrift::Types::STRING)
280      expect(@prot.get_type_id_for_type_name("rec")).to eq(Thrift::Types::STRUCT)
281      expect(@prot.get_type_id_for_type_name("map")).to eq(Thrift::Types::MAP)
282      expect(@prot.get_type_id_for_type_name("set")).to eq(Thrift::Types::SET)
283      expect(@prot.get_type_id_for_type_name("lst")).to eq(Thrift::Types::LIST)
284    end
285
286    it "should read json syntax char" do
287      @trans.write('F')
288      expect {@prot.read_json_syntax_char('G')}.to raise_error(Thrift::ProtocolException)
289      @trans.write('H')
290      @prot.read_json_syntax_char('H')
291    end
292
293    it "should read json escape char" do
294      @trans.write('0054')
295      expect(@prot.read_json_escape_char).to eq('T')
296
297      @trans.write("\"\\\"\"")
298      expect(@prot.read_json_string(false)).to eq("\"")
299
300      @trans.write("\"\\\\\"")
301      expect(@prot.read_json_string(false)).to eq("\\")
302
303      @trans.write("\"\\/\"")
304      expect(@prot.read_json_string(false)).to eq("\/")
305
306      @trans.write("\"\\b\"")
307      expect(@prot.read_json_string(false)).to eq("\b")
308
309      @trans.write("\"\\f\"")
310      expect(@prot.read_json_string(false)).to eq("\f")
311
312      @trans.write("\"\\n\"")
313      expect(@prot.read_json_string(false)).to eq("\n")
314
315      @trans.write("\"\\r\"")
316      expect(@prot.read_json_string(false)).to eq("\r")
317
318      @trans.write("\"\\t\"")
319      expect(@prot.read_json_string(false)).to eq("\t")
320    end
321
322    it "should read json string" do
323      @trans.write("\"\\P")
324      expect {@prot.read_json_string(false)}.to raise_error(Thrift::ProtocolException)
325
326      @trans.write("\"this is a test string\"")
327      expect(@prot.read_json_string).to eq("this is a test string")
328    end
329
330    it "should read json base64" do
331      @trans.write("\"dGhpcyBpcyBhIHRlc3Qgc3RyaW5n\"")
332      expect(@prot.read_json_base64).to eq("this is a test string")
333    end
334
335    it "should is json numeric" do
336      expect(@prot.is_json_numeric("A")).to eq(false)
337      expect(@prot.is_json_numeric("+")).to eq(true)
338      expect(@prot.is_json_numeric("-")).to eq(true)
339      expect(@prot.is_json_numeric(".")).to eq(true)
340      expect(@prot.is_json_numeric("0")).to eq(true)
341      expect(@prot.is_json_numeric("1")).to eq(true)
342      expect(@prot.is_json_numeric("2")).to eq(true)
343      expect(@prot.is_json_numeric("3")).to eq(true)
344      expect(@prot.is_json_numeric("4")).to eq(true)
345      expect(@prot.is_json_numeric("5")).to eq(true)
346      expect(@prot.is_json_numeric("6")).to eq(true)
347      expect(@prot.is_json_numeric("7")).to eq(true)
348      expect(@prot.is_json_numeric("8")).to eq(true)
349      expect(@prot.is_json_numeric("9")).to eq(true)
350      expect(@prot.is_json_numeric("E")).to eq(true)
351      expect(@prot.is_json_numeric("e")).to eq(true)
352    end
353
354    it "should read json numeric chars" do
355      @trans.write("1.453E45T")
356      expect(@prot.read_json_numeric_chars).to eq("1.453E45")
357    end
358
359    it "should read json integer" do
360      @trans.write("1.45\"\"")
361      expect {@prot.read_json_integer}.to raise_error(Thrift::ProtocolException)
362      @prot.read_string
363
364      @trans.write("1453T")
365      expect(@prot.read_json_integer).to eq(1453)
366    end
367
368    it "should read json double" do
369      @trans.write("1.45e3e01\"\"")
370      expect {@prot.read_json_double}.to raise_error(Thrift::ProtocolException)
371      @prot.read_string
372
373      @trans.write("\"1.453e01\"")
374      expect {@prot.read_json_double}.to raise_error(Thrift::ProtocolException)
375
376      @trans.write("1.453e01\"\"")
377      expect(@prot.read_json_double).to eq(14.53)
378      @prot.read_string
379
380      @trans.write("\"NaN\"")
381      expect(@prot.read_json_double.nan?).to eq(true)
382
383      @trans.write("\"Infinity\"")
384      expect(@prot.read_json_double).to eq(+1.0/0.0)
385
386      @trans.write("\"-Infinity\"")
387      expect(@prot.read_json_double).to eq(-1.0/0.0)
388    end
389
390    it "should read json object start" do
391      @trans.write("{")
392      expect(@prot.read_json_object_start).to eq(nil)
393    end
394
395    it "should read json object end" do
396      @trans.write("}")
397      expect(@prot.read_json_object_end).to eq(nil)
398    end
399
400    it "should read json array start" do
401      @trans.write("[")
402      expect(@prot.read_json_array_start).to eq(nil)
403    end
404
405    it "should read json array end" do
406      @trans.write("]")
407      expect(@prot.read_json_array_end).to eq(nil)
408    end
409
410    it "should read_message_begin" do
411      @trans.write("[2,")
412      expect {@prot.read_message_begin}.to raise_error(Thrift::ProtocolException)
413
414      @trans.write("[1,\"name\",12,32\"\"")
415      expect(@prot.read_message_begin).to eq(["name", 12, 32])
416    end
417
418    it "should read message end" do
419      @trans.write("]")
420      expect(@prot.read_message_end).to eq(nil)
421    end
422
423    it "should read struct begin" do
424      @trans.write("{")
425      expect(@prot.read_struct_begin).to eq(nil)
426    end
427
428    it "should read struct end" do
429      @trans.write("}")
430      expect(@prot.read_struct_end).to eq(nil)
431    end
432
433    it "should read field begin" do
434      @trans.write("1{\"rec\"")
435      expect(@prot.read_field_begin).to eq([nil, 12, 1])
436    end
437
438    it "should read field end" do
439      @trans.write("}")
440      expect(@prot.read_field_end).to eq(nil)
441    end
442
443    it "should read map begin" do
444      @trans.write("[\"rec\",\"lst\",2,{")
445      expect(@prot.read_map_begin).to eq([12, 15, 2])
446    end
447
448    it "should read map end" do
449      @trans.write("}]")
450      expect(@prot.read_map_end).to eq(nil)
451    end
452
453    it "should read list begin" do
454      @trans.write("[\"rec\",2\"\"")
455      expect(@prot.read_list_begin).to eq([12, 2])
456    end
457
458    it "should read list end" do
459      @trans.write("]")
460      expect(@prot.read_list_end).to eq(nil)
461    end
462
463    it "should read set begin" do
464      @trans.write("[\"rec\",2\"\"")
465      expect(@prot.read_set_begin).to eq([12, 2])
466    end
467
468    it "should read set end" do
469      @trans.write("]")
470      expect(@prot.read_set_end).to eq(nil)
471    end
472
473    it "should read bool" do
474      @trans.write("0\"\"")
475      expect(@prot.read_bool).to eq(false)
476      @prot.read_string
477
478      @trans.write("1\"\"")
479      expect(@prot.read_bool).to eq(true)
480    end
481
482    it "should read byte" do
483      @trans.write("60\"\"")
484      expect(@prot.read_byte).to eq(60)
485    end
486
487    it "should read i16" do
488      @trans.write("1000\"\"")
489      expect(@prot.read_i16).to eq(1000)
490    end
491
492    it "should read i32" do
493      @trans.write("3000000000\"\"")
494      expect(@prot.read_i32).to eq(3000000000)
495    end
496
497    it "should read i64" do
498      @trans.write("6000000000\"\"")
499      expect(@prot.read_i64).to eq(6000000000)
500    end
501
502    it "should read double" do
503      @trans.write("12.23\"\"")
504      expect(@prot.read_double).to eq(12.23)
505    end
506
507    if RUBY_VERSION >= '1.9'
508      it 'should read string' do
509        @trans.write('"this is a test string"'.force_encoding(Encoding::BINARY))
510        a = @prot.read_string
511        expect(a).to eq('this is a test string')
512        expect(a.encoding).to eq(Encoding::UTF_8)
513      end
514
515      it 'should read string with unicode characters' do
516        @trans.write('"this is a test string with unicode characters: \u20AC \u20AD"'.force_encoding(Encoding::BINARY))
517        a = @prot.read_string
518        expect(a).to eq("this is a test string with unicode characters: \u20AC \u20AD")
519        expect(a.encoding).to eq(Encoding::UTF_8)
520      end
521    else
522      it 'should read string' do
523        @trans.write('"this is a test string"')
524        expect(@prot.read_string).to eq('this is a test string')
525      end
526    end
527
528    it "should read binary" do
529      @trans.write("\"dGhpcyBpcyBhIHRlc3Qgc3RyaW5n\"")
530      expect(@prot.read_binary).to eq("this is a test string")
531    end
532
533    it "should read long binary" do
534      @trans.write("\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==\"")
535      expect(@prot.read_binary.bytes.to_a).to eq((0...256).to_a)
536    end
537
538    it "should provide a reasonable to_s" do
539      expect(@prot.to_s).to eq("json(memory)")
540    end
541  end
542
543  describe Thrift::JsonProtocolFactory do
544    it "should create a JsonProtocol" do
545      expect(Thrift::JsonProtocolFactory.new.get_protocol(double("MockTransport"))).to be_instance_of(Thrift::JsonProtocol)
546    end
547
548    it "should provide a reasonable to_s" do
549      expect(Thrift::JsonProtocolFactory.new.to_s).to eq("json")
550    end
551  end
552end
553