blob: fe69f4efc60f17ec90bdc1c829416fb7ba403c14 [file] [log] [blame]
Jens Geyered994552019-11-09 23:24:52 +01001unit TestSerializer.Tests;
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
21interface
22
23uses
24 Classes,
25 Windows,
26 SysUtils,
27 Generics.Collections,
28 Thrift,
29 Thrift.Exception,
30 Thrift.Socket,
31 Thrift.Transport,
32 Thrift.Protocol,
33 Thrift.Protocol.JSON,
34 Thrift.Protocol.Compact,
35 Thrift.Collections,
36 Thrift.Server,
37 Thrift.Utils,
38 Thrift.Serializer,
39 Thrift.Stream,
40 Thrift.WinHTTP,
41 Thrift.TypeRegistry,
42 System_,
43 DebugProtoTest,
44 TestSerializer.Data;
45
46
47type
48 TFactoryPair = record
49 prot : IProtocolFactory;
50 trans : ITransportFactory;
51 end;
52
53 TTestSerializer = class //extends TestCase {
54 private type
55 TMethod = (
56 mt_Bytes,
57 mt_Stream
58 );
59
60 private
61 FProtocols : TList< TFactoryPair>;
62 procedure AddFactoryCombination( const aProto : IProtocolFactory; const aTrans : ITransportFactory);
63 class function UserFriendlyName( const factory : TFactoryPair) : string; overload;
64 class function UserFriendlyName( const method : TMethod) : string; overload;
65
66 class function Serialize(const input : IBase; const factory : TFactoryPair) : TBytes; overload;
67 class procedure Serialize(const input : IBase; const factory : TFactoryPair; const aStream : TStream); overload;
68
69 class procedure Deserialize( const input : TBytes; const target : IBase; const factory : TFactoryPair); overload;
70 class procedure Deserialize( const input : TStream; const target : IBase; const factory : TFactoryPair); overload;
71
Jens Geyer41f47af2019-11-09 23:24:52 +010072 class procedure ValidateReadToEnd( const input : TBytes; const serial : TDeserializer); overload;
73 class procedure ValidateReadToEnd( const input : TStream; const serial : TDeserializer); overload;
74
Jens Geyered994552019-11-09 23:24:52 +010075 procedure Test_Serializer_Deserializer;
76 procedure Test_OneOfEach( const method : TMethod; const factory : TFactoryPair; const stream : TFileStream);
77 procedure Test_CompactStruct( const method : TMethod; const factory : TFactoryPair; const stream : TFileStream);
78
79 public
80 constructor Create;
81 destructor Destroy; override;
82
83 procedure RunTests;
84 end;
85
86
87implementation
88
89
90{ TTestSerializer }
91
92constructor TTestSerializer.Create;
93begin
94 inherited Create;
95 FProtocols := TList< TFactoryPair>.Create;
96
97 AddFactoryCombination( TBinaryProtocolImpl.TFactory.Create, nil);
98 AddFactoryCombination( TCompactProtocolImpl.TFactory.Create, nil);
99 AddFactoryCombination( TJSONProtocolImpl.TFactory.Create, nil);
100
101 AddFactoryCombination( TBinaryProtocolImpl.TFactory.Create, TFramedTransportImpl.TFactory.Create);
102 AddFactoryCombination( TCompactProtocolImpl.TFactory.Create, TFramedTransportImpl.TFactory.Create);
103 AddFactoryCombination( TJSONProtocolImpl.TFactory.Create, TFramedTransportImpl.TFactory.Create);
104
105 AddFactoryCombination( TBinaryProtocolImpl.TFactory.Create, TBufferedTransportImpl.TFactory.Create);
106 AddFactoryCombination( TCompactProtocolImpl.TFactory.Create, TBufferedTransportImpl.TFactory.Create);
107 AddFactoryCombination( TJSONProtocolImpl.TFactory.Create, TBufferedTransportImpl.TFactory.Create);
108end;
109
110
111destructor TTestSerializer.Destroy;
112begin
113 try
114 FreeAndNil( FProtocols);
115 finally
116 inherited Destroy;
117 end;
118end;
119
120
121procedure TTestSerializer.AddFactoryCombination( const aProto : IProtocolFactory; const aTrans : ITransportFactory);
122var rec : TFactoryPair;
123begin
124 rec.prot := aProto;
125 rec.trans := aTrans;
126 FProtocols.Add( rec);
127end;
128
129
130procedure TTestSerializer.Test_OneOfEach( const method : TMethod; const factory : TFactoryPair; const stream : TFileStream);
131var tested, correct : IOneOfEach;
132 bytes : TBytes;
133 i : Integer;
134begin
135 // write
136 tested := Fixtures.CreateOneOfEach;
137 case method of
138 mt_Bytes: bytes := Serialize( tested, factory);
139 mt_Stream: begin
140 stream.Size := 0;
141 Serialize( tested, factory, stream);
142 end
143 else
144 ASSERT( FALSE);
145 end;
146
147 // init + read
148 tested := TOneOfEachImpl.Create;
149 case method of
150 mt_Bytes: Deserialize( bytes, tested, factory);
151 mt_Stream: begin
152 stream.Position := 0;
153 Deserialize( stream, tested, factory);
154 end
155 else
156 ASSERT( FALSE);
157 end;
158
159 // check
160 correct := Fixtures.CreateOneOfEach;
161 ASSERT( tested.Im_true = correct.Im_true);
162 ASSERT( tested.Im_false = correct.Im_false);
163 ASSERT( tested.A_bite = correct.A_bite);
164 ASSERT( tested.Integer16 = correct.Integer16);
165 ASSERT( tested.Integer32 = correct.Integer32);
166 ASSERT( tested.Integer64 = correct.Integer64);
167 ASSERT( Abs( tested.Double_precision - correct.Double_precision) < 1E-12);
168 ASSERT( tested.Some_characters = correct.Some_characters);
169 ASSERT( tested.Zomg_unicode = correct.Zomg_unicode);
170 ASSERT( tested.What_who = correct.What_who);
171
172 ASSERT( Length(tested.Base64) = Length(correct.Base64));
173 ASSERT( CompareMem( @tested.Base64[0], @correct.Base64[0], Length(correct.Base64)));
174
175 ASSERT( tested.Byte_list.Count = correct.Byte_list.Count);
176 for i := 0 to tested.Byte_list.Count-1
177 do ASSERT( tested.Byte_list[i] = correct.Byte_list[i]);
178
179 ASSERT( tested.I16_list.Count = correct.I16_list.Count);
180 for i := 0 to tested.I16_list.Count-1
181 do ASSERT( tested.I16_list[i] = correct.I16_list[i]);
182
183 ASSERT( tested.I64_list.Count = correct.I64_list.Count);
184 for i := 0 to tested.I64_list.Count-1
185 do ASSERT( tested.I64_list[i] = correct.I64_list[i]);
186end;
187
188
189procedure TTestSerializer.Test_CompactStruct( const method : TMethod; const factory : TFactoryPair; const stream : TFileStream);
190var tested, correct : ICompactProtoTestStruct;
191 bytes : TBytes;
192begin
193 // write
194 tested := Fixtures.CreateCompactProtoTestStruct;
195 case method of
196 mt_Bytes: bytes := Serialize( tested, factory);
197 mt_Stream: begin
198 stream.Size := 0;
199 Serialize( tested, factory, stream);
200 end
201 else
202 ASSERT( FALSE);
203 end;
204
205 // init + read
206 correct := TCompactProtoTestStructImpl.Create;
207 case method of
208 mt_Bytes: Deserialize( bytes, tested, factory);
209 mt_Stream: begin
210 stream.Position := 0;
211 Deserialize( stream, tested, factory);
212 end
213 else
214 ASSERT( FALSE);
215 end;
216
217 // check
218 correct := Fixtures.CreateCompactProtoTestStruct;
219 ASSERT( correct.Field500 = tested.Field500);
220 ASSERT( correct.Field5000 = tested.Field5000);
221 ASSERT( correct.Field20000 = tested.Field20000);
222end;
223
224
225procedure TTestSerializer.Test_Serializer_Deserializer;
226var factory : TFactoryPair;
227 stream : TFileStream;
228 method : TMethod;
229begin
230 stream := TFileStream.Create( 'TestSerializer.dat', fmCreate);
231 try
232 for method in [Low(TMethod)..High(TMethod)] do begin
233 Writeln( UserFriendlyName(method));
234
235 for factory in FProtocols do begin
236 Writeln('- '+UserFriendlyName(factory));
237
238 Test_OneOfEach( method, factory, stream);
239 Test_CompactStruct( method, factory, stream);
240 end;
241
242 Writeln;
243 end;
244
245 finally
246 stream.Free;
247 end;
248end;
249
250
251class function TTestSerializer.UserFriendlyName( const factory : TFactoryPair) : string;
252begin
253 result := Copy( (factory.prot as TObject).ClassName, 2, MAXINT);
254
255 if factory.trans <> nil
256 then result := Copy( (factory.trans as TObject).ClassName, 2, MAXINT) +' '+ result;
257
258 result := StringReplace( result, 'Impl', '', [rfReplaceAll]);
259 result := StringReplace( result, 'Transport.TFactory', '', [rfReplaceAll]);
260 result := StringReplace( result, 'Protocol.TFactory', '', [rfReplaceAll]);
261end;
262
263
264class function TTestSerializer.UserFriendlyName( const method : TMethod) : string;
265begin
266 result := EnumUtils<TMethod>.ToString(Ord(method));
267 result := StringReplace( result, 'mt_', '', [rfReplaceAll]);
268end;
269
270
271procedure TTestSerializer.RunTests;
272begin
273 try
274 Test_Serializer_Deserializer;
275 except
276 on e:Exception do begin
277 Writeln( e.ClassName+': '+ e.Message);
278 Write('Hit ENTER to close ... '); Readln;
279 end;
280 end;
281end;
282
283
284class function TTestSerializer.Serialize(const input : IBase; const factory : TFactoryPair) : TBytes;
285var serial : TSerializer;
286begin
287 serial := TSerializer.Create( factory.prot, factory.trans);
288 try
289 result := serial.Serialize( input);
290 finally
291 serial.Free;
292 end;
293end;
294
295
296class procedure TTestSerializer.Serialize(const input : IBase; const factory : TFactoryPair; const aStream : TStream);
297var serial : TSerializer;
298begin
299 serial := TSerializer.Create( factory.prot, factory.trans);
300 try
301 serial.Serialize( input, aStream);
302 finally
303 serial.Free;
304 end;
305end;
306
307
308class procedure TTestSerializer.Deserialize( const input : TBytes; const target : IBase; const factory : TFactoryPair);
309var serial : TDeserializer;
310begin
Jens Geyer41f47af2019-11-09 23:24:52 +0100311 serial := TDeserializer.Create( factory.prot, factory.trans, Length(input));
Jens Geyered994552019-11-09 23:24:52 +0100312 try
313 serial.Deserialize( input, target);
Jens Geyer41f47af2019-11-09 23:24:52 +0100314 ValidateReadToEnd( input, serial);
Jens Geyered994552019-11-09 23:24:52 +0100315 finally
316 serial.Free;
317 end;
318end;
319
320
321class procedure TTestSerializer.Deserialize( const input : TStream; const target : IBase; const factory : TFactoryPair);
322var serial : TDeserializer;
323begin
Jens Geyer41f47af2019-11-09 23:24:52 +0100324 serial := TDeserializer.Create( factory.prot, factory.trans, input.Size);
Jens Geyered994552019-11-09 23:24:52 +0100325 try
326 serial.Deserialize( input, target);
Jens Geyer41f47af2019-11-09 23:24:52 +0100327 ValidateReadToEnd( input, serial);
Jens Geyered994552019-11-09 23:24:52 +0100328 finally
329 serial.Free;
330 end;
331end;
332
333
Jens Geyer41f47af2019-11-09 23:24:52 +0100334class procedure TTestSerializer.ValidateReadToEnd( const input : TBytes; const serial : TDeserializer);
335// we should not have any more byte to read
336var dummy : IBase;
337begin
338 try
339 dummy := TOneOfEachImpl.Create;
340 serial.Deserialize( input, dummy);
341 raise EInOutError.Create('Expected exception not thrown?');
342 except
343 on e:TTransportExceptionEndOfFile do {expected};
344 on e:Exception do raise; // unexpected
345 end;
346end;
347
348
349class procedure TTestSerializer.ValidateReadToEnd( const input : TStream; const serial : TDeserializer);
350// we should not have any more byte to read
351var dummy : IBase;
352begin
353 try
354 input.Position := 0;
355 dummy := TOneOfEachImpl.Create;
356 serial.Deserialize( input, dummy);
357 raise EInOutError.Create('Expected exception not thrown?');
358 except
359 on e:TTransportExceptionEndOfFile do {expected};
360 on e:Exception do raise; // unexpected
361 end;
362end;
363
Jens Geyered994552019-11-09 23:24:52 +0100364end.