blob: 6ed1a48a2c5a284645bb239e3689576b1391249b [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
Jens Geyer62445c12022-06-29 00:00:00 +020046{$TYPEINFO ON}
Jens Geyered994552019-11-09 23:24:52 +010047
48type
49 TFactoryPair = record
50 prot : IProtocolFactory;
51 trans : ITransportFactory;
52 end;
53
54 TTestSerializer = class //extends TestCase {
55 private type
56 TMethod = (
57 mt_Bytes,
58 mt_Stream
59 );
60
Jens Geyer07f4bb52022-09-03 14:50:06 +020061 strict private
Jens Geyered994552019-11-09 23:24:52 +010062 FProtocols : TList< TFactoryPair>;
63 procedure AddFactoryCombination( const aProto : IProtocolFactory; const aTrans : ITransportFactory);
64 class function UserFriendlyName( const factory : TFactoryPair) : string; overload;
65 class function UserFriendlyName( const method : TMethod) : string; overload;
66
67 class function Serialize(const input : IBase; const factory : TFactoryPair) : TBytes; overload;
68 class procedure Serialize(const input : IBase; const factory : TFactoryPair; const aStream : TStream); overload;
69
70 class procedure Deserialize( const input : TBytes; const target : IBase; const factory : TFactoryPair); overload;
71 class procedure Deserialize( const input : TStream; const target : IBase; const factory : TFactoryPair); overload;
72
Jens Geyer41f47af2019-11-09 23:24:52 +010073 class procedure ValidateReadToEnd( const input : TBytes; const serial : TDeserializer); overload;
74 class procedure ValidateReadToEnd( const input : TStream; const serial : TDeserializer); overload;
75
Jens Geyer07f4bb52022-09-03 14:50:06 +020076 class function LengthOf( const bytes : TBytes) : Integer; overload; inline;
77 class function LengthOf( const bytes : IThriftBytes) : Integer; overload; inline;
78
79 class function DataPtrOf( const bytes : TBytes) : Pointer; overload; inline;
80 class function DataPtrOf( const bytes : IThriftBytes) : Pointer; overload; inline;
81
Jens Geyered994552019-11-09 23:24:52 +010082 procedure Test_Serializer_Deserializer;
Jens Geyer07f4bb52022-09-03 14:50:06 +020083 procedure Test_COM_Types;
Jens Geyered994552019-11-09 23:24:52 +010084 procedure Test_OneOfEach( const method : TMethod; const factory : TFactoryPair; const stream : TFileStream);
85 procedure Test_CompactStruct( const method : TMethod; const factory : TFactoryPair; const stream : TFileStream);
86
87 public
88 constructor Create;
89 destructor Destroy; override;
90
91 procedure RunTests;
92 end;
93
94
95implementation
96
Jens Geyer07f4bb52022-09-03 14:50:06 +020097const SERIALIZERDATA_DLL = 'SerializerData.dll';
98function CreateOneOfEach : IOneOfEach; stdcall; external SERIALIZERDATA_DLL;
99function CreateNesting : INesting; stdcall; external SERIALIZERDATA_DLL;
100function CreateHolyMoley : IHolyMoley; stdcall; external SERIALIZERDATA_DLL;
101function CreateCompactProtoTestStruct : ICompactProtoTestStruct; stdcall; external SERIALIZERDATA_DLL;
102
Jens Geyered994552019-11-09 23:24:52 +0100103
104{ TTestSerializer }
105
106constructor TTestSerializer.Create;
107begin
108 inherited Create;
109 FProtocols := TList< TFactoryPair>.Create;
110
111 AddFactoryCombination( TBinaryProtocolImpl.TFactory.Create, nil);
112 AddFactoryCombination( TCompactProtocolImpl.TFactory.Create, nil);
113 AddFactoryCombination( TJSONProtocolImpl.TFactory.Create, nil);
114
115 AddFactoryCombination( TBinaryProtocolImpl.TFactory.Create, TFramedTransportImpl.TFactory.Create);
116 AddFactoryCombination( TCompactProtocolImpl.TFactory.Create, TFramedTransportImpl.TFactory.Create);
117 AddFactoryCombination( TJSONProtocolImpl.TFactory.Create, TFramedTransportImpl.TFactory.Create);
118
119 AddFactoryCombination( TBinaryProtocolImpl.TFactory.Create, TBufferedTransportImpl.TFactory.Create);
120 AddFactoryCombination( TCompactProtocolImpl.TFactory.Create, TBufferedTransportImpl.TFactory.Create);
121 AddFactoryCombination( TJSONProtocolImpl.TFactory.Create, TBufferedTransportImpl.TFactory.Create);
122end;
123
124
125destructor TTestSerializer.Destroy;
126begin
127 try
128 FreeAndNil( FProtocols);
129 finally
130 inherited Destroy;
131 end;
132end;
133
134
135procedure TTestSerializer.AddFactoryCombination( const aProto : IProtocolFactory; const aTrans : ITransportFactory);
136var rec : TFactoryPair;
137begin
138 rec.prot := aProto;
139 rec.trans := aTrans;
140 FProtocols.Add( rec);
141end;
142
143
Jens Geyer07f4bb52022-09-03 14:50:06 +0200144class function TTestSerializer.LengthOf( const bytes : TBytes) : Integer;
145begin
146 result := Length(bytes);
147end;
148
149
150class function TTestSerializer.LengthOf( const bytes : IThriftBytes) : Integer;
151begin
152 if bytes <> nil
153 then result := bytes.Count
154 else result := 0;
155end;
156
157
158class function TTestSerializer.DataPtrOf( const bytes : TBytes) : Pointer;
159begin
160 result := bytes;
161end;
162
163
164class function TTestSerializer.DataPtrOf( const bytes : IThriftBytes) : Pointer;
165begin
166 if bytes <> nil
167 then result := bytes.QueryRawDataPtr
168 else result := nil;
169end;
170
171
Jens Geyered994552019-11-09 23:24:52 +0100172procedure TTestSerializer.Test_OneOfEach( const method : TMethod; const factory : TFactoryPair; const stream : TFileStream);
173var tested, correct : IOneOfEach;
174 bytes : TBytes;
175 i : Integer;
176begin
177 // write
Jens Geyer07f4bb52022-09-03 14:50:06 +0200178 tested := CreateOneOfEach;
Jens Geyered994552019-11-09 23:24:52 +0100179 case method of
180 mt_Bytes: bytes := Serialize( tested, factory);
181 mt_Stream: begin
182 stream.Size := 0;
183 Serialize( tested, factory, stream);
184 end
185 else
186 ASSERT( FALSE);
187 end;
188
189 // init + read
190 tested := TOneOfEachImpl.Create;
191 case method of
192 mt_Bytes: Deserialize( bytes, tested, factory);
193 mt_Stream: begin
194 stream.Position := 0;
195 Deserialize( stream, tested, factory);
196 end
197 else
198 ASSERT( FALSE);
199 end;
200
201 // check
Jens Geyer07f4bb52022-09-03 14:50:06 +0200202 correct := CreateOneOfEach;
Jens Geyered994552019-11-09 23:24:52 +0100203 ASSERT( tested.Im_true = correct.Im_true);
204 ASSERT( tested.Im_false = correct.Im_false);
205 ASSERT( tested.A_bite = correct.A_bite);
206 ASSERT( tested.Integer16 = correct.Integer16);
207 ASSERT( tested.Integer32 = correct.Integer32);
208 ASSERT( tested.Integer64 = correct.Integer64);
209 ASSERT( Abs( tested.Double_precision - correct.Double_precision) < 1E-12);
210 ASSERT( tested.Some_characters = correct.Some_characters);
211 ASSERT( tested.Zomg_unicode = correct.Zomg_unicode);
Jens Geyer62445c12022-06-29 00:00:00 +0200212 ASSERT( tested.Rfc4122_uuid = correct.Rfc4122_uuid);
Jens Geyered994552019-11-09 23:24:52 +0100213 ASSERT( tested.What_who = correct.What_who);
214
Jens Geyer07f4bb52022-09-03 14:50:06 +0200215 ASSERT( LengthOf(tested.Base64) = LengthOf(correct.Base64));
216 ASSERT( CompareMem( DataPtrOf(tested.Base64), DataPtrOf(correct.Base64), LengthOf(correct.Base64)));
Jens Geyered994552019-11-09 23:24:52 +0100217
218 ASSERT( tested.Byte_list.Count = correct.Byte_list.Count);
219 for i := 0 to tested.Byte_list.Count-1
220 do ASSERT( tested.Byte_list[i] = correct.Byte_list[i]);
221
222 ASSERT( tested.I16_list.Count = correct.I16_list.Count);
223 for i := 0 to tested.I16_list.Count-1
224 do ASSERT( tested.I16_list[i] = correct.I16_list[i]);
225
226 ASSERT( tested.I64_list.Count = correct.I64_list.Count);
227 for i := 0 to tested.I64_list.Count-1
228 do ASSERT( tested.I64_list[i] = correct.I64_list[i]);
229end;
230
231
232procedure TTestSerializer.Test_CompactStruct( const method : TMethod; const factory : TFactoryPair; const stream : TFileStream);
233var tested, correct : ICompactProtoTestStruct;
234 bytes : TBytes;
235begin
236 // write
Jens Geyer07f4bb52022-09-03 14:50:06 +0200237 tested := CreateCompactProtoTestStruct;
Jens Geyered994552019-11-09 23:24:52 +0100238 case method of
239 mt_Bytes: bytes := Serialize( tested, factory);
240 mt_Stream: begin
241 stream.Size := 0;
242 Serialize( tested, factory, stream);
243 end
244 else
245 ASSERT( FALSE);
246 end;
247
248 // init + read
249 correct := TCompactProtoTestStructImpl.Create;
250 case method of
251 mt_Bytes: Deserialize( bytes, tested, factory);
252 mt_Stream: begin
253 stream.Position := 0;
254 Deserialize( stream, tested, factory);
255 end
256 else
257 ASSERT( FALSE);
258 end;
259
260 // check
Jens Geyer07f4bb52022-09-03 14:50:06 +0200261 correct := CreateCompactProtoTestStruct;
Jens Geyered994552019-11-09 23:24:52 +0100262 ASSERT( correct.Field500 = tested.Field500);
263 ASSERT( correct.Field5000 = tested.Field5000);
264 ASSERT( correct.Field20000 = tested.Field20000);
265end;
266
267
268procedure TTestSerializer.Test_Serializer_Deserializer;
269var factory : TFactoryPair;
270 stream : TFileStream;
271 method : TMethod;
272begin
273 stream := TFileStream.Create( 'TestSerializer.dat', fmCreate);
274 try
275 for method in [Low(TMethod)..High(TMethod)] do begin
276 Writeln( UserFriendlyName(method));
277
278 for factory in FProtocols do begin
279 Writeln('- '+UserFriendlyName(factory));
280
281 Test_OneOfEach( method, factory, stream);
282 Test_CompactStruct( method, factory, stream);
283 end;
284
285 Writeln;
286 end;
287
288 finally
289 stream.Free;
290 end;
291end;
292
293
294class function TTestSerializer.UserFriendlyName( const factory : TFactoryPair) : string;
295begin
296 result := Copy( (factory.prot as TObject).ClassName, 2, MAXINT);
297
298 if factory.trans <> nil
299 then result := Copy( (factory.trans as TObject).ClassName, 2, MAXINT) +' '+ result;
300
301 result := StringReplace( result, 'Impl', '', [rfReplaceAll]);
302 result := StringReplace( result, 'Transport.TFactory', '', [rfReplaceAll]);
303 result := StringReplace( result, 'Protocol.TFactory', '', [rfReplaceAll]);
304end;
305
306
307class function TTestSerializer.UserFriendlyName( const method : TMethod) : string;
Jens Geyer62445c12022-06-29 00:00:00 +0200308const NAMES : array[TMethod] of string = ('TBytes','Stream');
Jens Geyered994552019-11-09 23:24:52 +0100309begin
Jens Geyer62445c12022-06-29 00:00:00 +0200310 result := NAMES[method];
Jens Geyered994552019-11-09 23:24:52 +0100311end;
312
313
Jens Geyer07f4bb52022-09-03 14:50:06 +0200314procedure TTestSerializer.Test_COM_Types;
315var tested : IOneOfEach;
316begin
317 {$IF cDebugProtoTest_Option_COM_types}
318 ASSERT( SizeOf(TSomeEnum) = SizeOf(Int32)); // -> MINENUMSIZE 4
319
320 // try to set values that allocate memory
321 tested := CreateOneOfEach;
322 tested.Zomg_unicode := 'This is a test';
323 tested.Base64 := TThriftBytesImpl.Create( TEncoding.UTF8.GetBytes('abc'));
324 {$IFEND}
325end;
326
327
Jens Geyered994552019-11-09 23:24:52 +0100328procedure TTestSerializer.RunTests;
329begin
330 try
331 Test_Serializer_Deserializer;
Jens Geyer07f4bb52022-09-03 14:50:06 +0200332 Test_COM_Types;
Jens Geyered994552019-11-09 23:24:52 +0100333 except
334 on e:Exception do begin
335 Writeln( e.ClassName+': '+ e.Message);
336 Write('Hit ENTER to close ... '); Readln;
337 end;
338 end;
339end;
340
341
342class function TTestSerializer.Serialize(const input : IBase; const factory : TFactoryPair) : TBytes;
343var serial : TSerializer;
Jens Geyera019cda2019-11-09 23:24:52 +0100344 config : IThriftConfiguration;
Jens Geyered994552019-11-09 23:24:52 +0100345begin
Jens Geyera019cda2019-11-09 23:24:52 +0100346 config := TThriftConfigurationImpl.Create;
Jens Geyer62445c12022-06-29 00:00:00 +0200347 //config.MaxMessageSize := 0; // we don't read anything here
Jens Geyera019cda2019-11-09 23:24:52 +0100348
349 serial := TSerializer.Create( factory.prot, factory.trans, config);
Jens Geyered994552019-11-09 23:24:52 +0100350 try
351 result := serial.Serialize( input);
352 finally
353 serial.Free;
354 end;
355end;
356
357
358class procedure TTestSerializer.Serialize(const input : IBase; const factory : TFactoryPair; const aStream : TStream);
359var serial : TSerializer;
Jens Geyera019cda2019-11-09 23:24:52 +0100360 config : IThriftConfiguration;
Jens Geyered994552019-11-09 23:24:52 +0100361begin
Jens Geyera019cda2019-11-09 23:24:52 +0100362 config := TThriftConfigurationImpl.Create;
Jens Geyer62445c12022-06-29 00:00:00 +0200363 //config.MaxMessageSize := 0; // we don't read anything here
Jens Geyera019cda2019-11-09 23:24:52 +0100364
365 serial := TSerializer.Create( factory.prot, factory.trans, config);
Jens Geyered994552019-11-09 23:24:52 +0100366 try
367 serial.Serialize( input, aStream);
368 finally
369 serial.Free;
370 end;
371end;
372
373
374class procedure TTestSerializer.Deserialize( const input : TBytes; const target : IBase; const factory : TFactoryPair);
375var serial : TDeserializer;
Jens Geyera019cda2019-11-09 23:24:52 +0100376 config : IThriftConfiguration;
Jens Geyered994552019-11-09 23:24:52 +0100377begin
Jens Geyera019cda2019-11-09 23:24:52 +0100378 config := TThriftConfigurationImpl.Create;
379 config.MaxMessageSize := Length(input);
380
381 serial := TDeserializer.Create( factory.prot, factory.trans, config);
Jens Geyered994552019-11-09 23:24:52 +0100382 try
383 serial.Deserialize( input, target);
Jens Geyer41f47af2019-11-09 23:24:52 +0100384 ValidateReadToEnd( input, serial);
Jens Geyered994552019-11-09 23:24:52 +0100385 finally
386 serial.Free;
387 end;
388end;
389
390
391class procedure TTestSerializer.Deserialize( const input : TStream; const target : IBase; const factory : TFactoryPair);
392var serial : TDeserializer;
Jens Geyera019cda2019-11-09 23:24:52 +0100393 config : IThriftConfiguration;
Jens Geyered994552019-11-09 23:24:52 +0100394begin
Jens Geyera019cda2019-11-09 23:24:52 +0100395 config := TThriftConfigurationImpl.Create;
396 config.MaxMessageSize := input.Size;
397
398 serial := TDeserializer.Create( factory.prot, factory.trans, config);
Jens Geyered994552019-11-09 23:24:52 +0100399 try
400 serial.Deserialize( input, target);
Jens Geyer41f47af2019-11-09 23:24:52 +0100401 ValidateReadToEnd( input, serial);
Jens Geyered994552019-11-09 23:24:52 +0100402 finally
403 serial.Free;
404 end;
405end;
406
407
Jens Geyer41f47af2019-11-09 23:24:52 +0100408class procedure TTestSerializer.ValidateReadToEnd( const input : TBytes; const serial : TDeserializer);
409// we should not have any more byte to read
410var dummy : IBase;
411begin
412 try
413 dummy := TOneOfEachImpl.Create;
414 serial.Deserialize( input, dummy);
415 raise EInOutError.Create('Expected exception not thrown?');
416 except
417 on e:TTransportExceptionEndOfFile do {expected};
418 on e:Exception do raise; // unexpected
419 end;
420end;
421
422
423class procedure TTestSerializer.ValidateReadToEnd( const input : TStream; const serial : TDeserializer);
424// we should not have any more byte to read
425var dummy : IBase;
426begin
427 try
428 input.Position := 0;
429 dummy := TOneOfEachImpl.Create;
430 serial.Deserialize( input, dummy);
431 raise EInOutError.Create('Expected exception not thrown?');
432 except
433 on e:TTransportExceptionEndOfFile do {expected};
434 on e:Exception do raise; // unexpected
435 end;
436end;
437
Jens Geyered994552019-11-09 23:24:52 +0100438end.