blob: 83d67b1dc665b7eea3808b7fdd82e069af0f2d6a [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_,
44 DebugProtoTest,
45 TestSerializer.Data;
46
47
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
61 private
62 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 Geyered994552019-11-09 23:24:52 +010076 procedure Test_Serializer_Deserializer;
77 procedure Test_OneOfEach( const method : TMethod; const factory : TFactoryPair; const stream : TFileStream);
78 procedure Test_CompactStruct( const method : TMethod; const factory : TFactoryPair; const stream : TFileStream);
79
80 public
81 constructor Create;
82 destructor Destroy; override;
83
84 procedure RunTests;
85 end;
86
87
88implementation
89
90
91{ TTestSerializer }
92
93constructor TTestSerializer.Create;
94begin
95 inherited Create;
96 FProtocols := TList< TFactoryPair>.Create;
97
98 AddFactoryCombination( TBinaryProtocolImpl.TFactory.Create, nil);
99 AddFactoryCombination( TCompactProtocolImpl.TFactory.Create, nil);
100 AddFactoryCombination( TJSONProtocolImpl.TFactory.Create, nil);
101
102 AddFactoryCombination( TBinaryProtocolImpl.TFactory.Create, TFramedTransportImpl.TFactory.Create);
103 AddFactoryCombination( TCompactProtocolImpl.TFactory.Create, TFramedTransportImpl.TFactory.Create);
104 AddFactoryCombination( TJSONProtocolImpl.TFactory.Create, TFramedTransportImpl.TFactory.Create);
105
106 AddFactoryCombination( TBinaryProtocolImpl.TFactory.Create, TBufferedTransportImpl.TFactory.Create);
107 AddFactoryCombination( TCompactProtocolImpl.TFactory.Create, TBufferedTransportImpl.TFactory.Create);
108 AddFactoryCombination( TJSONProtocolImpl.TFactory.Create, TBufferedTransportImpl.TFactory.Create);
109end;
110
111
112destructor TTestSerializer.Destroy;
113begin
114 try
115 FreeAndNil( FProtocols);
116 finally
117 inherited Destroy;
118 end;
119end;
120
121
122procedure TTestSerializer.AddFactoryCombination( const aProto : IProtocolFactory; const aTrans : ITransportFactory);
123var rec : TFactoryPair;
124begin
125 rec.prot := aProto;
126 rec.trans := aTrans;
127 FProtocols.Add( rec);
128end;
129
130
131procedure TTestSerializer.Test_OneOfEach( const method : TMethod; const factory : TFactoryPair; const stream : TFileStream);
132var tested, correct : IOneOfEach;
133 bytes : TBytes;
134 i : Integer;
135begin
136 // write
137 tested := Fixtures.CreateOneOfEach;
138 case method of
139 mt_Bytes: bytes := Serialize( tested, factory);
140 mt_Stream: begin
141 stream.Size := 0;
142 Serialize( tested, factory, stream);
143 end
144 else
145 ASSERT( FALSE);
146 end;
147
148 // init + read
149 tested := TOneOfEachImpl.Create;
150 case method of
151 mt_Bytes: Deserialize( bytes, tested, factory);
152 mt_Stream: begin
153 stream.Position := 0;
154 Deserialize( stream, tested, factory);
155 end
156 else
157 ASSERT( FALSE);
158 end;
159
160 // check
161 correct := Fixtures.CreateOneOfEach;
162 ASSERT( tested.Im_true = correct.Im_true);
163 ASSERT( tested.Im_false = correct.Im_false);
164 ASSERT( tested.A_bite = correct.A_bite);
165 ASSERT( tested.Integer16 = correct.Integer16);
166 ASSERT( tested.Integer32 = correct.Integer32);
167 ASSERT( tested.Integer64 = correct.Integer64);
168 ASSERT( Abs( tested.Double_precision - correct.Double_precision) < 1E-12);
169 ASSERT( tested.Some_characters = correct.Some_characters);
170 ASSERT( tested.Zomg_unicode = correct.Zomg_unicode);
171 ASSERT( tested.What_who = correct.What_who);
172
173 ASSERT( Length(tested.Base64) = Length(correct.Base64));
174 ASSERT( CompareMem( @tested.Base64[0], @correct.Base64[0], Length(correct.Base64)));
175
176 ASSERT( tested.Byte_list.Count = correct.Byte_list.Count);
177 for i := 0 to tested.Byte_list.Count-1
178 do ASSERT( tested.Byte_list[i] = correct.Byte_list[i]);
179
180 ASSERT( tested.I16_list.Count = correct.I16_list.Count);
181 for i := 0 to tested.I16_list.Count-1
182 do ASSERT( tested.I16_list[i] = correct.I16_list[i]);
183
184 ASSERT( tested.I64_list.Count = correct.I64_list.Count);
185 for i := 0 to tested.I64_list.Count-1
186 do ASSERT( tested.I64_list[i] = correct.I64_list[i]);
187end;
188
189
190procedure TTestSerializer.Test_CompactStruct( const method : TMethod; const factory : TFactoryPair; const stream : TFileStream);
191var tested, correct : ICompactProtoTestStruct;
192 bytes : TBytes;
193begin
194 // write
195 tested := Fixtures.CreateCompactProtoTestStruct;
196 case method of
197 mt_Bytes: bytes := Serialize( tested, factory);
198 mt_Stream: begin
199 stream.Size := 0;
200 Serialize( tested, factory, stream);
201 end
202 else
203 ASSERT( FALSE);
204 end;
205
206 // init + read
207 correct := TCompactProtoTestStructImpl.Create;
208 case method of
209 mt_Bytes: Deserialize( bytes, tested, factory);
210 mt_Stream: begin
211 stream.Position := 0;
212 Deserialize( stream, tested, factory);
213 end
214 else
215 ASSERT( FALSE);
216 end;
217
218 // check
219 correct := Fixtures.CreateCompactProtoTestStruct;
220 ASSERT( correct.Field500 = tested.Field500);
221 ASSERT( correct.Field5000 = tested.Field5000);
222 ASSERT( correct.Field20000 = tested.Field20000);
223end;
224
225
226procedure TTestSerializer.Test_Serializer_Deserializer;
227var factory : TFactoryPair;
228 stream : TFileStream;
229 method : TMethod;
230begin
231 stream := TFileStream.Create( 'TestSerializer.dat', fmCreate);
232 try
233 for method in [Low(TMethod)..High(TMethod)] do begin
234 Writeln( UserFriendlyName(method));
235
236 for factory in FProtocols do begin
237 Writeln('- '+UserFriendlyName(factory));
238
239 Test_OneOfEach( method, factory, stream);
240 Test_CompactStruct( method, factory, stream);
241 end;
242
243 Writeln;
244 end;
245
246 finally
247 stream.Free;
248 end;
249end;
250
251
252class function TTestSerializer.UserFriendlyName( const factory : TFactoryPair) : string;
253begin
254 result := Copy( (factory.prot as TObject).ClassName, 2, MAXINT);
255
256 if factory.trans <> nil
257 then result := Copy( (factory.trans as TObject).ClassName, 2, MAXINT) +' '+ result;
258
259 result := StringReplace( result, 'Impl', '', [rfReplaceAll]);
260 result := StringReplace( result, 'Transport.TFactory', '', [rfReplaceAll]);
261 result := StringReplace( result, 'Protocol.TFactory', '', [rfReplaceAll]);
262end;
263
264
265class function TTestSerializer.UserFriendlyName( const method : TMethod) : string;
266begin
267 result := EnumUtils<TMethod>.ToString(Ord(method));
268 result := StringReplace( result, 'mt_', '', [rfReplaceAll]);
269end;
270
271
272procedure TTestSerializer.RunTests;
273begin
274 try
275 Test_Serializer_Deserializer;
276 except
277 on e:Exception do begin
278 Writeln( e.ClassName+': '+ e.Message);
279 Write('Hit ENTER to close ... '); Readln;
280 end;
281 end;
282end;
283
284
285class function TTestSerializer.Serialize(const input : IBase; const factory : TFactoryPair) : TBytes;
286var serial : TSerializer;
Jens Geyera019cda2019-11-09 23:24:52 +0100287 config : IThriftConfiguration;
Jens Geyered994552019-11-09 23:24:52 +0100288begin
Jens Geyera019cda2019-11-09 23:24:52 +0100289 config := TThriftConfigurationImpl.Create;
290 config.MaxMessageSize := 0; // we don't read anything here
291
292 serial := TSerializer.Create( factory.prot, factory.trans, config);
Jens Geyered994552019-11-09 23:24:52 +0100293 try
294 result := serial.Serialize( input);
295 finally
296 serial.Free;
297 end;
298end;
299
300
301class procedure TTestSerializer.Serialize(const input : IBase; const factory : TFactoryPair; const aStream : TStream);
302var serial : TSerializer;
Jens Geyera019cda2019-11-09 23:24:52 +0100303 config : IThriftConfiguration;
Jens Geyered994552019-11-09 23:24:52 +0100304begin
Jens Geyera019cda2019-11-09 23:24:52 +0100305 config := TThriftConfigurationImpl.Create;
306 config.MaxMessageSize := 0; // we don't read anything here
307
308 serial := TSerializer.Create( factory.prot, factory.trans, config);
Jens Geyered994552019-11-09 23:24:52 +0100309 try
310 serial.Serialize( input, aStream);
311 finally
312 serial.Free;
313 end;
314end;
315
316
317class procedure TTestSerializer.Deserialize( const input : TBytes; const target : IBase; const factory : TFactoryPair);
318var serial : TDeserializer;
Jens Geyera019cda2019-11-09 23:24:52 +0100319 config : IThriftConfiguration;
Jens Geyered994552019-11-09 23:24:52 +0100320begin
Jens Geyera019cda2019-11-09 23:24:52 +0100321 config := TThriftConfigurationImpl.Create;
322 config.MaxMessageSize := Length(input);
323
324 serial := TDeserializer.Create( factory.prot, factory.trans, config);
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
334class procedure TTestSerializer.Deserialize( const input : TStream; const target : IBase; const factory : TFactoryPair);
335var serial : TDeserializer;
Jens Geyera019cda2019-11-09 23:24:52 +0100336 config : IThriftConfiguration;
Jens Geyered994552019-11-09 23:24:52 +0100337begin
Jens Geyera019cda2019-11-09 23:24:52 +0100338 config := TThriftConfigurationImpl.Create;
339 config.MaxMessageSize := input.Size;
340
341 serial := TDeserializer.Create( factory.prot, factory.trans, config);
Jens Geyered994552019-11-09 23:24:52 +0100342 try
343 serial.Deserialize( input, target);
Jens Geyer41f47af2019-11-09 23:24:52 +0100344 ValidateReadToEnd( input, serial);
Jens Geyered994552019-11-09 23:24:52 +0100345 finally
346 serial.Free;
347 end;
348end;
349
350
Jens Geyer41f47af2019-11-09 23:24:52 +0100351class procedure TTestSerializer.ValidateReadToEnd( const input : TBytes; const serial : TDeserializer);
352// we should not have any more byte to read
353var dummy : IBase;
354begin
355 try
356 dummy := TOneOfEachImpl.Create;
357 serial.Deserialize( input, dummy);
358 raise EInOutError.Create('Expected exception not thrown?');
359 except
360 on e:TTransportExceptionEndOfFile do {expected};
361 on e:Exception do raise; // unexpected
362 end;
363end;
364
365
366class procedure TTestSerializer.ValidateReadToEnd( const input : TStream; const serial : TDeserializer);
367// we should not have any more byte to read
368var dummy : IBase;
369begin
370 try
371 input.Position := 0;
372 dummy := TOneOfEachImpl.Create;
373 serial.Deserialize( input, dummy);
374 raise EInOutError.Create('Expected exception not thrown?');
375 except
376 on e:TTransportExceptionEndOfFile do {expected};
377 on e:Exception do raise; // unexpected
378 end;
379end;
380
Jens Geyered994552019-11-09 23:24:52 +0100381end.