blob: 443a22d5f4f86fb6b2f5fce2b5af51e38fa9be62 [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,
Jens Geyera019cda2019-11-09 23:24:52 +010036 Thrift.Configuration,
Jens Geyered994552019-11-09 23:24:52 +010037 Thrift.Server,
38 Thrift.Utils,
39 Thrift.Serializer,
40 Thrift.Stream,
41 Thrift.WinHTTP,
42 Thrift.TypeRegistry,
43 System_,
Jens Geyer07f4bb52022-09-03 14:50:06 +020044 DebugProtoTest;
Jens Geyered994552019-11-09 23:24:52 +010045
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
Jens Geyer07f4bb52022-09-03 14:50:06 +020060 strict private
Jens Geyered994552019-11-09 23:24:52 +010061 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 Geyer07f4bb52022-09-03 14:50:06 +020075 class function LengthOf( const bytes : TBytes) : Integer; overload; inline;
76 class function LengthOf( const bytes : IThriftBytes) : Integer; overload; inline;
77
78 class function DataPtrOf( const bytes : TBytes) : Pointer; overload; inline;
79 class function DataPtrOf( const bytes : IThriftBytes) : Pointer; overload; inline;
80
Jens Geyered994552019-11-09 23:24:52 +010081 procedure Test_Serializer_Deserializer;
Jens Geyer07f4bb52022-09-03 14:50:06 +020082 procedure Test_COM_Types;
Jens Geyered994552019-11-09 23:24:52 +010083 procedure Test_OneOfEach( const method : TMethod; const factory : TFactoryPair; const stream : TFileStream);
84 procedure Test_CompactStruct( const method : TMethod; const factory : TFactoryPair; const stream : TFileStream);
85
86 public
87 constructor Create;
88 destructor Destroy; override;
89
90 procedure RunTests;
91 end;
92
93
94implementation
95
Jens Geyer07f4bb52022-09-03 14:50:06 +020096const SERIALIZERDATA_DLL = 'SerializerData.dll';
97function CreateOneOfEach : IOneOfEach; stdcall; external SERIALIZERDATA_DLL;
98function CreateNesting : INesting; stdcall; external SERIALIZERDATA_DLL;
99function CreateHolyMoley : IHolyMoley; stdcall; external SERIALIZERDATA_DLL;
100function CreateCompactProtoTestStruct : ICompactProtoTestStruct; stdcall; external SERIALIZERDATA_DLL;
101
Jens Geyered994552019-11-09 23:24:52 +0100102
103{ TTestSerializer }
104
105constructor TTestSerializer.Create;
106begin
107 inherited Create;
108 FProtocols := TList< TFactoryPair>.Create;
109
110 AddFactoryCombination( TBinaryProtocolImpl.TFactory.Create, nil);
111 AddFactoryCombination( TCompactProtocolImpl.TFactory.Create, nil);
112 AddFactoryCombination( TJSONProtocolImpl.TFactory.Create, nil);
113
114 AddFactoryCombination( TBinaryProtocolImpl.TFactory.Create, TFramedTransportImpl.TFactory.Create);
115 AddFactoryCombination( TCompactProtocolImpl.TFactory.Create, TFramedTransportImpl.TFactory.Create);
116 AddFactoryCombination( TJSONProtocolImpl.TFactory.Create, TFramedTransportImpl.TFactory.Create);
117
118 AddFactoryCombination( TBinaryProtocolImpl.TFactory.Create, TBufferedTransportImpl.TFactory.Create);
119 AddFactoryCombination( TCompactProtocolImpl.TFactory.Create, TBufferedTransportImpl.TFactory.Create);
120 AddFactoryCombination( TJSONProtocolImpl.TFactory.Create, TBufferedTransportImpl.TFactory.Create);
121end;
122
123
124destructor TTestSerializer.Destroy;
125begin
126 try
127 FreeAndNil( FProtocols);
128 finally
129 inherited Destroy;
130 end;
131end;
132
133
134procedure TTestSerializer.AddFactoryCombination( const aProto : IProtocolFactory; const aTrans : ITransportFactory);
135var rec : TFactoryPair;
136begin
137 rec.prot := aProto;
138 rec.trans := aTrans;
139 FProtocols.Add( rec);
140end;
141
142
Jens Geyer07f4bb52022-09-03 14:50:06 +0200143class function TTestSerializer.LengthOf( const bytes : TBytes) : Integer;
144begin
145 result := Length(bytes);
146end;
147
148
149class function TTestSerializer.LengthOf( const bytes : IThriftBytes) : Integer;
150begin
151 if bytes <> nil
152 then result := bytes.Count
153 else result := 0;
154end;
155
156
157class function TTestSerializer.DataPtrOf( const bytes : TBytes) : Pointer;
158begin
159 result := bytes;
160end;
161
162
163class function TTestSerializer.DataPtrOf( const bytes : IThriftBytes) : Pointer;
164begin
165 if bytes <> nil
166 then result := bytes.QueryRawDataPtr
167 else result := nil;
168end;
169
170
Jens Geyered994552019-11-09 23:24:52 +0100171procedure TTestSerializer.Test_OneOfEach( const method : TMethod; const factory : TFactoryPair; const stream : TFileStream);
172var tested, correct : IOneOfEach;
173 bytes : TBytes;
174 i : Integer;
175begin
176 // write
Jens Geyer07f4bb52022-09-03 14:50:06 +0200177 tested := CreateOneOfEach;
Jens Geyered994552019-11-09 23:24:52 +0100178 case method of
179 mt_Bytes: bytes := Serialize( tested, factory);
180 mt_Stream: begin
181 stream.Size := 0;
182 Serialize( tested, factory, stream);
183 end
184 else
185 ASSERT( FALSE);
186 end;
187
188 // init + read
189 tested := TOneOfEachImpl.Create;
190 case method of
191 mt_Bytes: Deserialize( bytes, tested, factory);
192 mt_Stream: begin
193 stream.Position := 0;
194 Deserialize( stream, tested, factory);
195 end
196 else
197 ASSERT( FALSE);
198 end;
199
200 // check
Jens Geyer07f4bb52022-09-03 14:50:06 +0200201 correct := CreateOneOfEach;
Jens Geyered994552019-11-09 23:24:52 +0100202 ASSERT( tested.Im_true = correct.Im_true);
203 ASSERT( tested.Im_false = correct.Im_false);
204 ASSERT( tested.A_bite = correct.A_bite);
205 ASSERT( tested.Integer16 = correct.Integer16);
206 ASSERT( tested.Integer32 = correct.Integer32);
207 ASSERT( tested.Integer64 = correct.Integer64);
208 ASSERT( Abs( tested.Double_precision - correct.Double_precision) < 1E-12);
209 ASSERT( tested.Some_characters = correct.Some_characters);
210 ASSERT( tested.Zomg_unicode = correct.Zomg_unicode);
211 ASSERT( tested.What_who = correct.What_who);
212
Jens Geyer07f4bb52022-09-03 14:50:06 +0200213 ASSERT( LengthOf(tested.Base64) = LengthOf(correct.Base64));
214 ASSERT( CompareMem( DataPtrOf(tested.Base64), DataPtrOf(correct.Base64), LengthOf(correct.Base64)));
Jens Geyered994552019-11-09 23:24:52 +0100215
216 ASSERT( tested.Byte_list.Count = correct.Byte_list.Count);
217 for i := 0 to tested.Byte_list.Count-1
218 do ASSERT( tested.Byte_list[i] = correct.Byte_list[i]);
219
220 ASSERT( tested.I16_list.Count = correct.I16_list.Count);
221 for i := 0 to tested.I16_list.Count-1
222 do ASSERT( tested.I16_list[i] = correct.I16_list[i]);
223
224 ASSERT( tested.I64_list.Count = correct.I64_list.Count);
225 for i := 0 to tested.I64_list.Count-1
226 do ASSERT( tested.I64_list[i] = correct.I64_list[i]);
227end;
228
229
230procedure TTestSerializer.Test_CompactStruct( const method : TMethod; const factory : TFactoryPair; const stream : TFileStream);
231var tested, correct : ICompactProtoTestStruct;
232 bytes : TBytes;
233begin
234 // write
Jens Geyer07f4bb52022-09-03 14:50:06 +0200235 tested := CreateCompactProtoTestStruct;
Jens Geyered994552019-11-09 23:24:52 +0100236 case method of
237 mt_Bytes: bytes := Serialize( tested, factory);
238 mt_Stream: begin
239 stream.Size := 0;
240 Serialize( tested, factory, stream);
241 end
242 else
243 ASSERT( FALSE);
244 end;
245
246 // init + read
247 correct := TCompactProtoTestStructImpl.Create;
248 case method of
249 mt_Bytes: Deserialize( bytes, tested, factory);
250 mt_Stream: begin
251 stream.Position := 0;
252 Deserialize( stream, tested, factory);
253 end
254 else
255 ASSERT( FALSE);
256 end;
257
258 // check
Jens Geyer07f4bb52022-09-03 14:50:06 +0200259 correct := CreateCompactProtoTestStruct;
Jens Geyered994552019-11-09 23:24:52 +0100260 ASSERT( correct.Field500 = tested.Field500);
261 ASSERT( correct.Field5000 = tested.Field5000);
262 ASSERT( correct.Field20000 = tested.Field20000);
263end;
264
265
266procedure TTestSerializer.Test_Serializer_Deserializer;
267var factory : TFactoryPair;
268 stream : TFileStream;
269 method : TMethod;
270begin
271 stream := TFileStream.Create( 'TestSerializer.dat', fmCreate);
272 try
273 for method in [Low(TMethod)..High(TMethod)] do begin
274 Writeln( UserFriendlyName(method));
275
276 for factory in FProtocols do begin
277 Writeln('- '+UserFriendlyName(factory));
278
279 Test_OneOfEach( method, factory, stream);
280 Test_CompactStruct( method, factory, stream);
281 end;
282
283 Writeln;
284 end;
285
286 finally
287 stream.Free;
288 end;
289end;
290
291
292class function TTestSerializer.UserFriendlyName( const factory : TFactoryPair) : string;
293begin
294 result := Copy( (factory.prot as TObject).ClassName, 2, MAXINT);
295
296 if factory.trans <> nil
297 then result := Copy( (factory.trans as TObject).ClassName, 2, MAXINT) +' '+ result;
298
299 result := StringReplace( result, 'Impl', '', [rfReplaceAll]);
300 result := StringReplace( result, 'Transport.TFactory', '', [rfReplaceAll]);
301 result := StringReplace( result, 'Protocol.TFactory', '', [rfReplaceAll]);
302end;
303
304
305class function TTestSerializer.UserFriendlyName( const method : TMethod) : string;
306begin
307 result := EnumUtils<TMethod>.ToString(Ord(method));
308 result := StringReplace( result, 'mt_', '', [rfReplaceAll]);
309end;
310
311
Jens Geyer07f4bb52022-09-03 14:50:06 +0200312procedure TTestSerializer.Test_COM_Types;
313var tested : IOneOfEach;
314begin
315 {$IF cDebugProtoTest_Option_COM_types}
316 ASSERT( SizeOf(TSomeEnum) = SizeOf(Int32)); // -> MINENUMSIZE 4
317
318 // try to set values that allocate memory
319 tested := CreateOneOfEach;
320 tested.Zomg_unicode := 'This is a test';
321 tested.Base64 := TThriftBytesImpl.Create( TEncoding.UTF8.GetBytes('abc'));
322 {$IFEND}
323end;
324
325
Jens Geyered994552019-11-09 23:24:52 +0100326procedure TTestSerializer.RunTests;
327begin
328 try
329 Test_Serializer_Deserializer;
Jens Geyer07f4bb52022-09-03 14:50:06 +0200330 Test_COM_Types;
Jens Geyered994552019-11-09 23:24:52 +0100331 except
332 on e:Exception do begin
333 Writeln( e.ClassName+': '+ e.Message);
334 Write('Hit ENTER to close ... '); Readln;
335 end;
336 end;
337end;
338
339
340class function TTestSerializer.Serialize(const input : IBase; const factory : TFactoryPair) : TBytes;
341var serial : TSerializer;
Jens Geyera019cda2019-11-09 23:24:52 +0100342 config : IThriftConfiguration;
Jens Geyered994552019-11-09 23:24:52 +0100343begin
Jens Geyera019cda2019-11-09 23:24:52 +0100344 config := TThriftConfigurationImpl.Create;
345 config.MaxMessageSize := 0; // we don't read anything here
346
347 serial := TSerializer.Create( factory.prot, factory.trans, config);
Jens Geyered994552019-11-09 23:24:52 +0100348 try
349 result := serial.Serialize( input);
350 finally
351 serial.Free;
352 end;
353end;
354
355
356class procedure TTestSerializer.Serialize(const input : IBase; const factory : TFactoryPair; const aStream : TStream);
357var serial : TSerializer;
Jens Geyera019cda2019-11-09 23:24:52 +0100358 config : IThriftConfiguration;
Jens Geyered994552019-11-09 23:24:52 +0100359begin
Jens Geyera019cda2019-11-09 23:24:52 +0100360 config := TThriftConfigurationImpl.Create;
361 config.MaxMessageSize := 0; // we don't read anything here
362
363 serial := TSerializer.Create( factory.prot, factory.trans, config);
Jens Geyered994552019-11-09 23:24:52 +0100364 try
365 serial.Serialize( input, aStream);
366 finally
367 serial.Free;
368 end;
369end;
370
371
372class procedure TTestSerializer.Deserialize( const input : TBytes; const target : IBase; const factory : TFactoryPair);
373var serial : TDeserializer;
Jens Geyera019cda2019-11-09 23:24:52 +0100374 config : IThriftConfiguration;
Jens Geyered994552019-11-09 23:24:52 +0100375begin
Jens Geyera019cda2019-11-09 23:24:52 +0100376 config := TThriftConfigurationImpl.Create;
377 config.MaxMessageSize := Length(input);
378
379 serial := TDeserializer.Create( factory.prot, factory.trans, config);
Jens Geyered994552019-11-09 23:24:52 +0100380 try
381 serial.Deserialize( input, target);
Jens Geyer41f47af2019-11-09 23:24:52 +0100382 ValidateReadToEnd( input, serial);
Jens Geyered994552019-11-09 23:24:52 +0100383 finally
384 serial.Free;
385 end;
386end;
387
388
389class procedure TTestSerializer.Deserialize( const input : TStream; const target : IBase; const factory : TFactoryPair);
390var serial : TDeserializer;
Jens Geyera019cda2019-11-09 23:24:52 +0100391 config : IThriftConfiguration;
Jens Geyered994552019-11-09 23:24:52 +0100392begin
Jens Geyera019cda2019-11-09 23:24:52 +0100393 config := TThriftConfigurationImpl.Create;
394 config.MaxMessageSize := input.Size;
395
396 serial := TDeserializer.Create( factory.prot, factory.trans, config);
Jens Geyered994552019-11-09 23:24:52 +0100397 try
398 serial.Deserialize( input, target);
Jens Geyer41f47af2019-11-09 23:24:52 +0100399 ValidateReadToEnd( input, serial);
Jens Geyered994552019-11-09 23:24:52 +0100400 finally
401 serial.Free;
402 end;
403end;
404
405
Jens Geyer41f47af2019-11-09 23:24:52 +0100406class procedure TTestSerializer.ValidateReadToEnd( const input : TBytes; const serial : TDeserializer);
407// we should not have any more byte to read
408var dummy : IBase;
409begin
410 try
411 dummy := TOneOfEachImpl.Create;
412 serial.Deserialize( input, dummy);
413 raise EInOutError.Create('Expected exception not thrown?');
414 except
415 on e:TTransportExceptionEndOfFile do {expected};
416 on e:Exception do raise; // unexpected
417 end;
418end;
419
420
421class procedure TTestSerializer.ValidateReadToEnd( const input : TStream; const serial : TDeserializer);
422// we should not have any more byte to read
423var dummy : IBase;
424begin
425 try
426 input.Position := 0;
427 dummy := TOneOfEachImpl.Create;
428 serial.Deserialize( input, dummy);
429 raise EInOutError.Create('Expected exception not thrown?');
430 except
431 on e:TTransportExceptionEndOfFile do {expected};
432 on e:Exception do raise; // unexpected
433 end;
434end;
435
Jens Geyered994552019-11-09 23:24:52 +0100436end.