Skip to content

Commit 73cabd2

Browse files
committed
Protocol conformity and serialization tests for UUIDs
1 parent 64e2aed commit 73cabd2

File tree

5 files changed

+292
-61
lines changed

5 files changed

+292
-61
lines changed

lib/delphi/src/Thrift.Serializer.pas

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,19 @@ TDeserializer = class
6666
public
6767
constructor Create( const aProtFact : IProtocolFactory = nil; // defaults to TBinaryProtocol
6868
const aTransFact : ITransportFactory = nil;
69-
const aConfig : IThriftConfiguration = nil);
69+
const aConfig : IThriftConfiguration = nil);
7070

7171
// DTOR
7272
destructor Destroy; override;
7373

7474
// Deserialize the Thrift object data.
7575
procedure Deserialize( const input : TBytes; const target : IBase); overload;
7676
procedure Deserialize( const input : TStream; const target : IBase); overload;
77+
78+
// helper
79+
property Protocol : IProtocol read FProtocol;
80+
property Transport : ITransport read FTransport;
81+
property Stream : TThriftMemoryStream read FStream;
7782
end;
7883

7984

@@ -164,14 +169,14 @@ procedure TSerializer.Serialize( const input : IBase; const aStm : TStream);
164169

165170
constructor TDeserializer.Create( const aProtFact : IProtocolFactory;
166171
const aTransFact : ITransportFactory;
167-
const aConfig : IThriftConfiguration);
172+
const aConfig : IThriftConfiguration);
168173
var adapter : IThriftStream;
169174
protfact : IProtocolFactory;
170175
begin
171176
inherited Create;
172177

173-
FStream := TThriftMemoryStream.Create;
174-
adapter := TThriftStreamAdapterDelphi.Create( FStream, FALSE);
178+
FStream := TThriftMemoryStream.Create;
179+
adapter := TThriftStreamAdapterDelphi.Create( FStream, FALSE);
175180

176181
FTransport := TStreamTransportImpl.Create( adapter, nil, aConfig);
177182
if aTransfact <> nil then FTransport := aTransfact.GetTransport( FTransport);
@@ -205,8 +210,11 @@ procedure TDeserializer.Deserialize( const input : TBytes; const target : IBase)
205210
try
206211
iBytes := Length(input);
207212
FStream.Size := iBytes;
208-
if iBytes > 0
209-
then Move( input[0], FStream.Memory^, iBytes);
213+
if iBytes > 0 then begin
214+
Move( input[0], FStream.Memory^, iBytes);
215+
Transport.ResetMessageSizeAndConsumedBytes(); // size has changed
216+
Transport.UpdateKnownMessageSize(iBytes);
217+
end;
210218

211219
target.Read( FProtocol);
212220
finally
@@ -221,9 +229,15 @@ procedure TDeserializer.Deserialize( const input : TStream; const target : IBase
221229
var before : Int64;
222230
begin
223231
try
224-
before := FStream.Position;
225-
FStream.CopyFrom( input, COPY_ENTIRE_STREAM);
226-
FStream.Position := before;
232+
if Assigned(input) then begin
233+
before := FStream.Position;
234+
ASSERT( before = 0);
235+
FStream.CopyFrom( input, COPY_ENTIRE_STREAM);
236+
FStream.Position := before;
237+
Transport.ResetMessageSizeAndConsumedBytes(); // size has changed
238+
Transport.UpdateKnownMessageSize(FStream.Size);
239+
end;
240+
227241
target.Read( FProtocol);
228242
finally
229243
FStream.Size := 0; // free any allocated memory

lib/delphi/test/serializer/TestSerializer.Tests.pas

Lines changed: 85 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ interface
4949

5050
type
5151
TFactoryPair = record
52-
prot : IProtocolFactory;
52+
proto : IProtocolFactory;
5353
trans : ITransportFactory;
5454
end;
5555

@@ -72,8 +72,9 @@ TTestSerializer = class //extends TestCase {
7272
class procedure Deserialize( const input : TBytes; const target : IBase; const factory : TFactoryPair); overload;
7373
class procedure Deserialize( const input : TStream; const target : IBase; const factory : TFactoryPair); overload;
7474

75-
class procedure ValidateReadToEnd( const input : TBytes; const serial : TDeserializer); overload;
76-
class procedure ValidateReadToEnd( const input : TStream; const serial : TDeserializer); overload;
75+
class procedure Deserialize( const input : TBytes; out target : TGuid; const factory : TFactoryPair); overload;
76+
77+
class procedure ValidateReadToEnd( const serial : TDeserializer); overload;
7778

7879
class function LengthOf( const bytes : TBytes) : Integer; overload; inline;
7980
class function LengthOf( const bytes : IThriftBytes) : Integer; overload; inline;
@@ -90,6 +91,9 @@ TTestSerializer = class //extends TestCase {
9091
procedure Test_ExceptionStruct( const method : TMethod; const factory : TFactoryPair; const stream : TFileStream);
9192
procedure Test_SimpleException( const method : TMethod; const factory : TFactoryPair; const stream : TFileStream);
9293

94+
procedure Test_ProtocolConformity( const factory : TFactoryPair; const stream : TFileStream);
95+
procedure Test_UuidDeserialization( const factory : TFactoryPair; const stream : TFileStream);
96+
9397
public
9498
constructor Create;
9599
destructor Destroy; override;
@@ -143,7 +147,7 @@ destructor TTestSerializer.Destroy;
143147
procedure TTestSerializer.AddFactoryCombination( const aProto : IProtocolFactory; const aTrans : ITransportFactory);
144148
var rec : TFactoryPair;
145149
begin
146-
rec.prot := aProto;
150+
rec.proto := aProto;
147151
rec.trans := aTrans;
148152
FProtocols.Add( rec);
149153
end;
@@ -177,6 +181,53 @@ class function TTestSerializer.DataPtrOf( const bytes : IThriftBytes) : Pointer;
177181
end;
178182

179183

184+
procedure TTestSerializer.Test_ProtocolConformity( const factory : TFactoryPair; const stream : TFileStream);
185+
begin
186+
Test_UuidDeserialization( factory, stream);
187+
// add more tests here
188+
end;
189+
190+
191+
procedure TTestSerializer.Test_UuidDeserialization( const factory : TFactoryPair; const stream : TFileStream);
192+
193+
function CreateGuidBytes : TBytes;
194+
var obj : TObject;
195+
i : Integer;
196+
begin
197+
obj := factory.proto as TObject;
198+
199+
if obj is TJSONProtocolImpl.TFactory then begin
200+
result := TEncoding.UTF8.GetBytes('"00112233-4455-6677-8899-aabbccddeeff"');
201+
Exit;
202+
end;
203+
204+
if (obj is TBinaryProtocolImpl.TFactory)
205+
or (obj is TCompactProtocolImpl.TFactory)
206+
then begin
207+
SetLength(result,16);
208+
for i := 0 to Length(result)-1 do result[i] := (i * $10) + i;
209+
Exit;
210+
end;
211+
212+
raise Exception.Create('Unhandled case');
213+
end;
214+
215+
216+
var tested, correct : TGuid;
217+
bytes : TBytes;
218+
begin
219+
// write
220+
bytes := CreateGuidBytes();
221+
222+
// init + read
223+
Deserialize( bytes, tested, factory);
224+
225+
// check
226+
correct := TGuid.Create('{00112233-4455-6677-8899-aabbccddeeff}');
227+
ASSERT( tested = correct);
228+
end;
229+
230+
180231
procedure TTestSerializer.Test_OneOfEach( const method : TMethod; const factory : TFactoryPair; const stream : TFileStream);
181232
var tested, correct : IOneOfEach;
182233
bytes : TBytes;
@@ -385,6 +436,11 @@ procedure TTestSerializer.Test_Serializer_Deserializer;
385436
for factory in FProtocols do begin
386437
Writeln('- '+UserFriendlyName(factory));
387438

439+
// protocol conformity tests
440+
if (method = TMethod.mt_Bytes) and (factory.trans = nil)
441+
then Test_ProtocolConformity( factory, stream);
442+
443+
// normal objects
388444
Test_OneOfEach( method, factory, stream);
389445
Test_CompactStruct( method, factory, stream);
390446
Test_ExceptionStruct( method, factory, stream);
@@ -402,7 +458,7 @@ procedure TTestSerializer.Test_Serializer_Deserializer;
402458

403459
class function TTestSerializer.UserFriendlyName( const factory : TFactoryPair) : string;
404460
begin
405-
result := Copy( (factory.prot as TObject).ClassName, 2, MAXINT);
461+
result := Copy( (factory.proto as TObject).ClassName, 2, MAXINT);
406462

407463
if factory.trans <> nil
408464
then result := Copy( (factory.trans as TObject).ClassName, 2, MAXINT) +' '+ result;
@@ -472,7 +528,7 @@ class function TTestSerializer.Serialize(const input : IBase; const factory : TF
472528
config := TThriftConfigurationImpl.Create;
473529
//config.MaxMessageSize := 0; // we don't read anything here
474530

475-
serial := TSerializer.Create( factory.prot, factory.trans, config);
531+
serial := TSerializer.Create( factory.proto, factory.trans, config);
476532
try
477533
result := serial.Serialize( input);
478534
finally
@@ -488,7 +544,7 @@ class procedure TTestSerializer.Serialize(const input : IBase; const factory : T
488544
config := TThriftConfigurationImpl.Create;
489545
//config.MaxMessageSize := 0; // we don't read anything here
490546

491-
serial := TSerializer.Create( factory.prot, factory.trans, config);
547+
serial := TSerializer.Create( factory.proto, factory.trans, config);
492548
try
493549
serial.Serialize( input, aStream);
494550
finally
@@ -504,10 +560,10 @@ class procedure TTestSerializer.Deserialize( const input : TBytes; const target
504560
config := TThriftConfigurationImpl.Create;
505561
config.MaxMessageSize := Length(input);
506562

507-
serial := TDeserializer.Create( factory.prot, factory.trans, config);
563+
serial := TDeserializer.Create( factory.proto, factory.trans, config);
508564
try
509565
serial.Deserialize( input, target);
510-
ValidateReadToEnd( input, serial);
566+
ValidateReadToEnd( serial);
511567
finally
512568
serial.Free;
513569
end;
@@ -521,44 +577,49 @@ class procedure TTestSerializer.Deserialize( const input : TStream; const target
521577
config := TThriftConfigurationImpl.Create;
522578
config.MaxMessageSize := input.Size;
523579

524-
serial := TDeserializer.Create( factory.prot, factory.trans, config);
580+
serial := TDeserializer.Create( factory.proto, factory.trans, config);
525581
try
526582
serial.Deserialize( input, target);
527-
ValidateReadToEnd( input, serial);
583+
ValidateReadToEnd( serial);
528584
finally
529585
serial.Free;
530586
end;
531587
end;
532588

533589

534-
class procedure TTestSerializer.ValidateReadToEnd( const input : TBytes; const serial : TDeserializer);
535-
// we should not have any more byte to read
536-
var dummy : IBase;
590+
class procedure TTestSerializer.Deserialize( const input : TBytes; out target : TGuid; const factory : TFactoryPair);
591+
var serial : TDeserializer;
592+
config : IThriftConfiguration;
537593
begin
594+
config := TThriftConfigurationImpl.Create;
595+
config.MaxMessageSize := Length(input);
596+
597+
serial := TDeserializer.Create( factory.proto, factory.trans, config);
538598
try
539-
dummy := TOneOfEachImpl.Create;
540-
serial.Deserialize( input, dummy);
541-
raise EInOutError.Create('Expected exception not thrown?');
542-
except
543-
on e:TTransportExceptionEndOfFile do {expected};
544-
on e:Exception do raise; // unexpected
599+
serial.Stream.Write(input[0], Length(input));
600+
serial.Stream.Position := 0;
601+
serial.Transport.ResetMessageSizeAndConsumedBytes(); // size has changed
602+
603+
target := serial.Protocol.ReadUuid;
604+
finally
605+
serial.Free;
545606
end;
546607
end;
547608

548609

549-
class procedure TTestSerializer.ValidateReadToEnd( const input : TStream; const serial : TDeserializer);
610+
class procedure TTestSerializer.ValidateReadToEnd( const serial : TDeserializer);
550611
// we should not have any more byte to read
551612
var dummy : IBase;
552613
begin
553614
try
554-
input.Position := 0;
555615
dummy := TOneOfEachImpl.Create;
556-
serial.Deserialize( input, dummy);
616+
serial.Deserialize( nil, dummy);
557617
raise EInOutError.Create('Expected exception not thrown?');
558618
except
559-
on e:TTransportExceptionEndOfFile do {expected};
619+
on e:TTransportException do {expected};
560620
on e:Exception do raise; // unexpected
561621
end;
562622
end;
563623

624+
564625
end.
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
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+
18+
using System;
19+
using System.IO;
20+
using System.Text;
21+
using System.Threading;
22+
using System.Threading.Tasks;
23+
using KellermanSoftware.CompareNetObjects;
24+
using Microsoft.VisualStudio.TestTools.UnitTesting;
25+
using Thrift.Protocol;
26+
using Thrift.Protocol.Entities;
27+
using Thrift.Transport;
28+
using Thrift.Transport.Client;
29+
30+
namespace Thrift.IntegrationTests.Protocols
31+
{
32+
[TestClass]
33+
public class ProtocolConformityTests : TestBase
34+
{
35+
[DataTestMethod]
36+
[DataRow(typeof(TBinaryProtocol))]
37+
[DataRow(typeof(TCompactProtocol))]
38+
[DataRow(typeof(TJsonProtocol))]
39+
public async Task ReadUuidFromStream(Type protocolType)
40+
{
41+
var expected = new Guid("{00112233-4455-6677-8899-aabbccddeeff}");
42+
43+
try
44+
{
45+
var tuple = GetProtocolInstance(protocolType);
46+
using var stream = tuple.Stream;
47+
48+
await GenerateGuidTestData(stream, protocolType, default);
49+
stream.Seek(0, SeekOrigin.Begin);
50+
tuple.Transport.ResetMessageSizeAndConsumedBytes(); // length has changed
51+
52+
var actual = await tuple.Protocol.ReadUuidAsync(default);
53+
54+
var result = _compareLogic.Compare(expected, actual);
55+
Assert.IsTrue(result.AreEqual, result.DifferencesString);
56+
}
57+
catch (Exception e)
58+
{
59+
throw new Exception($"Exception during testing of protocol: {protocolType.FullName}", e);
60+
}
61+
}
62+
63+
private static async Task GenerateGuidTestData(Stream stream, Type protocolType, CancellationToken cancel)
64+
{
65+
stream.Seek(0, SeekOrigin.Begin);
66+
67+
if(protocolType == typeof(TJsonProtocol))
68+
{
69+
await stream.WriteAsync(Encoding.UTF8.GetBytes("\"00112233-4455-6677-8899-aabbccddeeff\""), cancel);
70+
return;
71+
}
72+
73+
if (protocolType == typeof(TBinaryProtocol))
74+
{
75+
var data = new byte[16] { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
76+
await stream.WriteAsync(data, cancel);
77+
return;
78+
}
79+
80+
if (protocolType == typeof(TCompactProtocol))
81+
{
82+
var data = new byte[16] { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
83+
await stream.WriteAsync(data, cancel);
84+
return;
85+
}
86+
87+
throw new Exception($"Unhandled protocol: {protocolType.FullName}");
88+
}
89+
}
90+
}

0 commit comments

Comments
 (0)