1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18library thrift.test.transport.t_json_protocol_test;
19
20import 'dart:async';
21import 'dart:typed_data' show Uint8List;
22
23import 'package:dart2_constant/convert.dart' show utf8;
24import 'package:test/test.dart';
25import 'package:thrift/thrift.dart';
26
27void main() {
28  final message = new TMessage('my message', TMessageType.ONEWAY, 123);
29
30  TProtocol protocol;
31
32  Primitive getPrimitive(int tType) {
33    switch (tType) {
34      case TType.BOOL:
35        return new Primitive(protocol.readBool, protocol.writeBool, false);
36
37      case TType.BYTE:
38        return new Primitive(protocol.readByte, protocol.writeByte, 0);
39
40      case TType.I16:
41        return new Primitive(protocol.readI16, protocol.writeI16, 0);
42
43      case TType.I32:
44        return new Primitive(protocol.readI32, protocol.writeI32, 0);
45
46      case TType.I64:
47        return new Primitive(protocol.readI64, protocol.writeI64, 0);
48
49      case TType.DOUBLE:
50        return new Primitive(protocol.readDouble, protocol.writeDouble, 0);
51
52      case TType.STRING:
53        return new Primitive(protocol.readString, protocol.writeString, '');
54
55      default:
56        throw new UnsupportedError("Unsupported TType $tType");
57    }
58  }
59
60  Future primitiveTest(Primitive primitive, input) async {
61    primitive.write(input);
62    protocol.writeMessageEnd();
63
64    await protocol.transport.flush();
65
66    protocol.readMessageBegin();
67    var output = primitive.read();
68
69    expect(output, input);
70  }
71
72  Future primitiveNullTest(Primitive primitive) async {
73    primitive.write(null);
74    protocol.writeMessageEnd();
75
76    await protocol.transport.flush();
77
78    protocol.readMessageBegin();
79    var output = primitive.read();
80
81    expect(output, primitive.defaultValue);
82  }
83
84  var sharedTests = () {
85    test('Test message', () async {
86      protocol.writeMessageEnd();
87
88      await protocol.transport.flush();
89
90      var subject = protocol.readMessageBegin();
91
92      expect(subject.name, message.name);
93      expect(subject.type, message.type);
94      expect(subject.seqid, message.seqid);
95    });
96
97    test('Test struct', () async {
98      var input = new TStruct();
99
100      protocol.writeStructBegin(input);
101      protocol.writeStructEnd();
102      protocol.writeMessageEnd();
103
104      await protocol.transport.flush();
105
106      protocol.readMessageBegin();
107      var output = protocol.readStructBegin();
108
109      // name is not serialized, see C# version for reference
110      expect(output, isNotNull);
111    });
112
113    test('Test field', () async {
114      var input = new TField('my field', TType.MAP, 123);
115
116      protocol.writeFieldBegin(input);
117      protocol.writeFieldEnd();
118      protocol.writeMessageEnd();
119
120      await protocol.transport.flush();
121
122      protocol.readMessageBegin();
123      var output = protocol.readFieldBegin();
124
125      // name is not serialized, see C# version for reference
126      expect(output.type, input.type);
127      expect(output.id, input.id);
128    });
129
130    test('Test map', () async {
131      var input = new TMap(TType.STRING, TType.STRUCT, 123);
132
133      protocol.writeMapBegin(input);
134      protocol.writeMapEnd();
135      protocol.writeMessageEnd();
136
137      await protocol.transport.flush();
138
139      protocol.readMessageBegin();
140      var output = protocol.readMapBegin();
141
142      expect(output.keyType, input.keyType);
143      expect(output.valueType, input.valueType);
144      expect(output.length, input.length);
145    });
146
147    test('Test list', () async {
148      var input = new TList(TType.STRING, 123);
149
150      protocol.writeListBegin(input);
151      protocol.writeListEnd();
152      protocol.writeMessageEnd();
153
154      await protocol.transport.flush();
155
156      protocol.readMessageBegin();
157      var output = protocol.readListBegin();
158
159      expect(output.elementType, input.elementType);
160      expect(output.length, input.length);
161    });
162
163    test('Test set', () async {
164      var input = new TSet(TType.STRING, 123);
165
166      protocol.writeSetBegin(input);
167      protocol.writeSetEnd();
168      protocol.writeMessageEnd();
169
170      await protocol.transport.flush();
171
172      protocol.readMessageBegin();
173      var output = protocol.readListBegin();
174
175      expect(output.elementType, input.elementType);
176      expect(output.length, input.length);
177    });
178
179    test('Test bool', () async {
180      await primitiveTest(getPrimitive(TType.BOOL), true);
181    });
182
183    test('Test bool null', () async {
184      await primitiveNullTest(getPrimitive(TType.BOOL));
185    });
186
187    test('Test byte', () async {
188      await primitiveTest(getPrimitive(TType.BYTE), 64);
189    });
190
191    test('Test byte null', () async {
192      await primitiveNullTest(getPrimitive(TType.BYTE));
193    });
194
195    test('Test I16', () async {
196      await primitiveTest(getPrimitive(TType.I16), 32767);
197    });
198
199    test('Test I16 null', () async {
200      await primitiveNullTest(getPrimitive(TType.I16));
201    });
202
203    test('Test I32', () async {
204      await primitiveTest(getPrimitive(TType.I32), 2147483647);
205    });
206
207    test('Test I32 null', () async {
208      await primitiveNullTest(getPrimitive(TType.I32));
209    });
210
211    test('Test I64', () async {
212      await primitiveTest(getPrimitive(TType.I64), 9223372036854775807);
213    });
214
215    test('Test I64 null', () async {
216      await primitiveNullTest(getPrimitive(TType.I64));
217    });
218
219    test('Test double', () async {
220      await primitiveTest(getPrimitive(TType.DOUBLE), 3.1415926);
221    });
222
223    test('Test double null', () async {
224      await primitiveNullTest(getPrimitive(TType.DOUBLE));
225    });
226
227    test('Test string', () async {
228      var input = 'There are only two hard things in computer science: '
229          'cache invalidation, naming things, and off-by-one errors.';
230      await primitiveTest(getPrimitive(TType.STRING), input);
231    });
232
233    test('Test string null', () async {
234      await primitiveNullTest(getPrimitive(TType.STRING));
235    });
236
237    test('Test binary', () async {
238      var input = new Uint8List.fromList(new List.filled(100, 123));
239
240      protocol.writeBinary(input);
241      protocol.writeMessageEnd();
242
243      await protocol.transport.flush();
244
245      protocol.readMessageBegin();
246      var output = protocol.readBinary();
247
248      expect(output.length, input.length);
249      expect(output.every((i) => i == 123), isTrue);
250    });
251
252    test('Test complex struct', () async {
253      // {1: {10: 20}, 2: {30: 40}}
254      protocol.writeStructBegin(new TStruct());
255      protocol.writeFieldBegin(new TField('success', TType.MAP, 0));
256      protocol.writeMapBegin(new TMap(TType.I32, TType.MAP, 2));
257
258      protocol.writeI32(1); // key
259      protocol.writeMapBegin(new TMap(TType.I32, TType.I32, 1));
260      protocol.writeI32(10); // key
261      protocol.writeI32(20); // value
262      protocol.writeMapEnd();
263
264      protocol.writeI32(2); // key
265      protocol.writeMapBegin(new TMap(TType.I32, TType.I32, 1));
266      protocol.writeI32(30); // key
267      protocol.writeI32(40); // value
268      protocol.writeMapEnd();
269
270      protocol.writeMapEnd();
271      protocol.writeFieldEnd();
272      protocol.writeFieldStop();
273      protocol.writeStructEnd();
274      protocol.writeMessageEnd();
275
276      await protocol.transport.flush();
277
278      protocol.readMessageBegin();
279      protocol.readStructBegin();
280      expect(protocol.readFieldBegin().type, TType.MAP);
281      expect(protocol.readMapBegin().length, 2);
282
283      expect(protocol.readI32(), 1); // key
284      expect(protocol.readMapBegin().length, 1);
285      expect(protocol.readI32(), 10); // key
286      expect(protocol.readI32(), 20); // value
287      protocol.readMapEnd();
288
289      expect(protocol.readI32(), 2); // key
290      expect(protocol.readMapBegin().length, 1);
291      expect(protocol.readI32(), 30); // key
292      expect(protocol.readI32(), 40); // value
293      protocol.readMapEnd();
294
295      protocol.readMapEnd();
296      protocol.readFieldEnd();
297      protocol.readStructEnd();
298      protocol.readMessageEnd();
299    });
300
301    test('Test nested maps and lists', () async {
302      // {1: [{10: 20}], 2: [{30: 40}]}
303      protocol.writeMapBegin(new TMap(TType.I32, TType.LIST, 2));
304
305      protocol.writeI32(1); // key
306      protocol.writeListBegin(new TList(TType.MAP, 1));
307      protocol.writeMapBegin(new TMap(TType.I32, TType.I32, 1));
308      protocol.writeI32(10); // key
309      protocol.writeI32(20); // value
310      protocol.writeMapEnd();
311      protocol.writeListEnd();
312
313      protocol.writeI32(2); // key
314      protocol.writeListBegin(new TList(TType.MAP, 1));
315      protocol.writeMapBegin(new TMap(TType.I32, TType.I32, 1));
316      protocol.writeI32(30); // key
317      protocol.writeI32(40); // value
318      protocol.writeMapEnd();
319      protocol.writeListEnd();
320
321      protocol.writeMapEnd();
322      protocol.writeMessageEnd();
323
324      await protocol.transport.flush();
325
326      protocol.readMessageBegin();
327      expect(protocol.readMapBegin().length, 2);
328
329      expect(protocol.readI32(), 1); // key
330      expect(protocol.readListBegin().length, 1);
331      expect(protocol.readMapBegin().length, 1);
332      expect(protocol.readI32(), 10); // key
333      expect(protocol.readI32(), 20); // value
334      protocol.readMapEnd();
335      protocol.readListEnd();
336
337      expect(protocol.readI32(), 2); // key
338      expect(protocol.readListBegin().length, 1);
339      expect(protocol.readMapBegin().length, 1);
340      expect(protocol.readI32(), 30); // key
341      expect(protocol.readI32(), 40); // value
342      protocol.readMapEnd();
343      protocol.readListEnd();
344
345      protocol.readMapEnd();
346      protocol.readMessageEnd();
347    });
348  };
349
350  group('JSON', () {
351    setUp(() {
352      protocol = new TJsonProtocol(new TBufferedTransport());
353      protocol.writeMessageBegin(message);
354    });
355
356    test('Test escaped unicode', () async {
357      /*
358         KOR_KAI
359           UTF-8:  0xE0 0xB8 0x81
360           UTF-16: 0x0E01
361         G clef:
362           UTF-8:  0xF0 0x9D 0x84 0x9E
363           UTF-16: 0xD834 0xDD1E
364       */
365      var buffer = utf8.encode(r'"\u0001\u0e01 \ud834\udd1e"');
366      var transport = new TBufferedTransport();
367      transport.writeAll(buffer);
368
369      var protocol = new TJsonProtocol(transport);
370
371      await protocol.transport.flush();
372
373      var subject = protocol.readString();
374      expect(subject,
375          utf8.decode([0x01, 0xE0, 0xB8, 0x81, 0x20, 0xF0, 0x9D, 0x84, 0x9E]));
376    });
377
378    group('shared tests', sharedTests);
379  });
380
381  group('binary', () {
382    setUp(() {
383      protocol = new TBinaryProtocol(new TBufferedTransport());
384      protocol.writeMessageBegin(message);
385    });
386
387    group('shared tests', sharedTests);
388  });
389
390  group('compact', () {
391    setUp(() {
392      protocol = new TCompactProtocol(new TBufferedTransport());
393      protocol.writeMessageBegin(message);
394    });
395
396    group('shared tests', sharedTests);
397  });
398}
399
400class Primitive {
401  final Function read;
402  final Function write;
403  final defaultValue;
404
405  Primitive(this.read, this.write, this.defaultValue);
406}
407