From: Roger Meier Date: Wed, 12 Sep 2012 20:09:02 +0000 (+0000) Subject: THRIFT-1691 Serializer/deserializer support for Delphi X-Git-Tag: 0.9.1~311 X-Git-Url: https://source.supwisdom.com/gerrit/gitweb?a=commitdiff_plain;h=2b2c0b2eba61aa3ae0d7071e2002d13ad2f77d4f;p=common%2Fthrift.git THRIFT-1691 Serializer/deserializer support for Delphi Patch: Jens Geyer git-svn-id: https://svn.apache.org/repos/asf/thrift/trunk@1384105 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/lib/delphi/src/Thrift.Serializer.pas b/lib/delphi/src/Thrift.Serializer.pas new file mode 100644 index 00000000..a81cef08 --- /dev/null +++ b/lib/delphi/src/Thrift.Serializer.pas @@ -0,0 +1,223 @@ +(* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + *) +unit Thrift.Serializer; + +interface + +uses + Classes, Windows, SysUtils, + Thrift.Protocol, + Thrift.Transport, + Thrift.Stream; + + +type + // Generic utility for easily serializing objects into a byte array or Stream. + TSerializer = class + private + FStream : TMemoryStream; + FTransport : ITransport; + FProtocol : IProtocol; + + public + // Create a new TSerializer that uses the TBinaryProtocol by default. + constructor Create; overload; + + // Create a new TSerializer. + // It will use the TProtocol specified by the factory that is passed in. + constructor Create( const factory : IProtocolFactory); overload; + + // DTOR + destructor Destroy; override; + + // Serialize the Thrift object. + function Serialize( const input : IBase) : TBytes; overload; + procedure Serialize( const input : IBase; const aStm : TStream); overload; + end; + + + // Generic utility for easily deserializing objects from byte array or Stream. + TDeserializer = class + private + FStream : TMemoryStream; + FTransport : ITransport; + FProtocol : IProtocol; + + public + // Create a new TDeserializer that uses the TBinaryProtocol by default. + constructor Create; overload; + + // Create a new TDeserializer. + // It will use the TProtocol specified by the factory that is passed in. + constructor Create( const factory : IProtocolFactory); overload; + + // DTOR + destructor Destroy; override; + + // Deserialize the Thrift object data. + procedure Deserialize( const input : TBytes; const target : IBase); overload; + procedure Deserialize( const input : TStream; const target : IBase); overload; + end; + + + +implementation + + +{ TSerializer } + + +constructor TSerializer.Create(); +// Create a new TSerializer that uses the TBinaryProtocol by default. +begin + Create( TBinaryProtocolImpl.TFactory.Create); +end; + + +constructor TSerializer.Create( const factory : IProtocolFactory); +// Create a new TSerializer. +// It will use the TProtocol specified by the factory that is passed in. +var adapter : IThriftStream; +begin + inherited Create; + FStream := TMemoryStream.Create; + adapter := TThriftStreamAdapterDelphi.Create( FStream, FALSE); + FTransport := TStreamTransportImpl.Create( nil, adapter); + FProtocol := factory.GetProtocol( FTransport); +end; + + +destructor TSerializer.Destroy; +begin + try + FProtocol := nil; + FTransport := nil; + FreeAndNil( FStream); + finally + inherited Destroy; + end; +end; + + +function TSerializer.Serialize( const input : IBase) : TBytes; +// Serialize the Thrift object into a byte array. The process is simple, +// just clear the byte array output, write the object into it, and grab the +// raw bytes. +var iBytes : Int64; +begin + try + FStream.Size := 0; + input.Write( FProtocol); + SetLength( result, FStream.Size); + iBytes := Length(result); + if iBytes > 0 + then Move( FStream.Memory^, result[0], iBytes); + finally + FStream.Size := 0; // free any allocated memory + end; +end; + + +procedure TSerializer.Serialize( const input : IBase; const aStm : TStream); +// Serialize the Thrift object into a byte array. The process is simple, +// just clear the byte array output, write the object into it, and grab the +// raw bytes. +var iBytes : Int64; +const COPY_ENTIRE_STREAM = 0; +begin + try + FStream.Size := 0; + input.Write( FProtocol); + aStm.CopyFrom( FStream, COPY_ENTIRE_STREAM); + finally + FStream.Size := 0; // free any allocated memory + end; +end; + + +{ TDeserializer } + + +constructor TDeserializer.Create(); +// Create a new TDeserializer that uses the TBinaryProtocol by default. +begin + Create( TBinaryProtocolImpl.TFactory.Create); +end; + + +constructor TDeserializer.Create( const factory : IProtocolFactory); +// Create a new TDeserializer. +// It will use the TProtocol specified by the factory that is passed in. +var adapter : IThriftStream; +begin + inherited Create; + FStream := TMemoryStream.Create; + adapter := TThriftStreamAdapterDelphi.Create( FStream, FALSE); + FTransport := TStreamTransportImpl.Create( adapter, nil); + FProtocol := factory.GetProtocol( FTransport); +end; + + +destructor TDeserializer.Destroy; +begin + try + FProtocol := nil; + FTransport := nil; + FreeAndNil( FStream); + finally + inherited Destroy; + end; +end; + + +procedure TDeserializer.Deserialize( const input : TBytes; const target : IBase); +// Deserialize the Thrift object data from the byte array. +var iBytes : Int64; +begin + try + iBytes := Length(input); + FStream.Size := iBytes; + if iBytes > 0 + then Move( input[0], FStream.Memory^, iBytes); + + target.Read( FProtocol); + finally + FStream.Size := 0; // free any allocated memory + end; +end; + + +procedure TDeserializer.Deserialize( const input : TStream; const target : IBase); +// Deserialize the Thrift object data from the byte array. +const COPY_ENTIRE_STREAM = 0; +var before : Int64; +begin + try + before := FStream.Position; + FStream.CopyFrom( input, COPY_ENTIRE_STREAM); + FStream.Position := before; + target.Read( FProtocol); + finally + FStream.Size := 0; // free any allocated memory + end; +end; + + +end. + diff --git a/lib/delphi/test/serializer/TestSerializer.Data.pas b/lib/delphi/test/serializer/TestSerializer.Data.pas new file mode 100644 index 00000000..34ad4f61 --- /dev/null +++ b/lib/delphi/test/serializer/TestSerializer.Data.pas @@ -0,0 +1,347 @@ +(* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + *) + +unit TestSerializer.Data; + +interface + +uses + Thrift.Collections, + DebugProtoTest; + + +type + Fixtures = class + public + class function CreateOneOfEach : IOneOfEach; + class function CreateNesting : INesting; + class function CreateHolyMoley : IHolyMoley; + class function CreateCompactProtoTestStruct : ICompactProtoTestStruct; + + // These byte arrays are serialized versions of the above structs. + // They were serialized in binary protocol using thrift 0.6.x and are used to + // test backwards compatibility with respect to the standard scheme. + (* + all data copied from JAVA version, + to be used later + + public static final byte[] persistentBytesOneOfEach = new byte[] { + $02, $00, $01, $01, $02, $00, $02, $00, $03, $00, + $03, $D6, $06, $00, $04, $69, $78, $08, $00, $05, + $01, $00, $00, $00, $0A, $00, $06, $00, $00, $00, + $01, $65, $A0, $BC, $00, $04, $00, $07, $40, $09, + $21, $FB, $54, $44, $2D, $18, $0B, $00, $08, $00, + $00, $00, $0D, $4A, $53, $4F, $4E, $20, $54, $48, + $49, $53, $21, $20, $22, $01, $0B, $00, $09, $00, + $00, $00, $2E, $D3, $80, $E2, $85, $AE, $CE, $9D, + $20, $D0, $9D, $CE, $BF, $E2, $85, $BF, $D0, $BE, + $C9, $A1, $D0, $B3, $D0, $B0, $CF, $81, $E2, $84, + $8E, $20, $CE, $91, $74, $74, $CE, $B1, $E2, $85, + $BD, $CE, $BA, $EF, $BF, $BD, $E2, $80, $BC, $02, + $00, $0A, $00, $0B, $00, $0B, $00, $00, $00, $06, + $62, $61, $73, $65, $36, $34, $0F, $00, $0C, $03, + $00, $00, $00, $03, $01, $02, $03, $0F, $00, $0D, + $06, $00, $00, $00, $03, $00, $01, $00, $02, $00, + $03, $0F, $00, $0E, $0A, $00, $00, $00, $03, $00, + $00, $00, $00, $00, $00, $00, $01, $00, $00, $00, + $00, $00, $00, $00, $02, $00, $00, $00, $00, $00, + $00, $00, $03, $00 }; + + + public static final byte[] persistentBytesNesting = new byte[] { + $0C, $00, $01, $08, $00, $01, $00, $00, $7A, $69, + $0B, $00, $02, $00, $00, $00, $13, $49, $20, $61, + $6D, $20, $61, $20, $62, $6F, $6E, $6B, $2E, $2E, + $2E, $20, $78, $6F, $72, $21, $00, $0C, $00, $02, + $02, $00, $01, $01, $02, $00, $02, $00, $03, $00, + $03, $D6, $06, $00, $04, $69, $78, $08, $00, $05, + $01, $00, $00, $00, $0A, $00, $06, $00, $00, $00, + $01, $65, $A0, $BC, $00, $04, $00, $07, $40, $09, + $21, $FB, $54, $44, $2D, $18, $0B, $00, $08, $00, + $00, $00, $0D, $4A, $53, $4F, $4E, $20, $54, $48, + $49, $53, $21, $20, $22, $01, $0B, $00, $09, $00, + $00, $00, $2E, $D3, $80, $E2, $85, $AE, $CE, $9D, + $20, $D0, $9D, $CE, $BF, $E2, $85, $BF, $D0, $BE, + $C9, $A1, $D0, $B3, $D0, $B0, $CF, $81, $E2, $84, + $8E, $20, $CE, $91, $74, $74, $CE, $B1, $E2, $85, + $BD, $CE, $BA, $EF, $BF, $BD, $E2, $80, $BC, $02, + $00, $0A, $00, $0B, $00, $0B, $00, $00, $00, $06, + $62, $61, $73, $65, $36, $34, $0F, $00, $0C, $03, + $00, $00, $00, $03, $01, $02, $03, $0F, $00, $0D, + $06, $00, $00, $00, $03, $00, $01, $00, $02, $00, + $03, $0F, $00, $0E, $0A, $00, $00, $00, $03, $00, + $00, $00, $00, $00, $00, $00, $01, $00, $00, $00, + $00, $00, $00, $00, $02, $00, $00, $00, $00, $00, + $00, $00, $03, $00, $00 }; + + public static final byte[] persistentBytesHolyMoley = new byte[] { + $0F, $00, $01, $0C, $00, $00, $00, $02, $02, $00, + $01, $01, $02, $00, $02, $00, $03, $00, $03, $23, + $06, $00, $04, $69, $78, $08, $00, $05, $01, $00, + $00, $00, $0A, $00, $06, $00, $00, $00, $01, $65, + $A0, $BC, $00, $04, $00, $07, $40, $09, $21, $FB, + $54, $44, $2D, $18, $0B, $00, $08, $00, $00, $00, + $0D, $4A, $53, $4F, $4E, $20, $54, $48, $49, $53, + $21, $20, $22, $01, $0B, $00, $09, $00, $00, $00, + $2E, $D3, $80, $E2, $85, $AE, $CE, $9D, $20, $D0, + $9D, $CE, $BF, $E2, $85, $BF, $D0, $BE, $C9, $A1, + $D0, $B3, $D0, $B0, $CF, $81, $E2, $84, $8E, $20, + $CE, $91, $74, $74, $CE, $B1, $E2, $85, $BD, $CE, + $BA, $EF, $BF, $BD, $E2, $80, $BC, $02, $00, $0A, + $00, $0B, $00, $0B, $00, $00, $00, $06, $62, $61, + $73, $65, $36, $34, $0F, $00, $0C, $03, $00, $00, + $00, $03, $01, $02, $03, $0F, $00, $0D, $06, $00, + $00, $00, $03, $00, $01, $00, $02, $00, $03, $0F, + $00, $0E, $0A, $00, $00, $00, $03, $00, $00, $00, + $00, $00, $00, $00, $01, $00, $00, $00, $00, $00, + $00, $00, $02, $00, $00, $00, $00, $00, $00, $00, + $03, $00, $02, $00, $01, $01, $02, $00, $02, $00, + $03, $00, $03, $D6, $06, $00, $04, $69, $78, $08, + $00, $05, $01, $00, $00, $00, $0A, $00, $06, $00, + $00, $00, $01, $65, $A0, $BC, $00, $04, $00, $07, + $40, $09, $21, $FB, $54, $44, $2D, $18, $0B, $00, + $08, $00, $00, $00, $0D, $4A, $53, $4F, $4E, $20, + $54, $48, $49, $53, $21, $20, $22, $01, $0B, $00, + $09, $00, $00, $00, $2E, $D3, $80, $E2, $85, $AE, + $CE, $9D, $20, $D0, $9D, $CE, $BF, $E2, $85, $BF, + $D0, $BE, $C9, $A1, $D0, $B3, $D0, $B0, $CF, $81, + $E2, $84, $8E, $20, $CE, $91, $74, $74, $CE, $B1, + $E2, $85, $BD, $CE, $BA, $EF, $BF, $BD, $E2, $80, + $BC, $02, $00, $0A, $00, $0B, $00, $0B, $00, $00, + $00, $06, $62, $61, $73, $65, $36, $34, $0F, $00, + $0C, $03, $00, $00, $00, $03, $01, $02, $03, $0F, + $00, $0D, $06, $00, $00, $00, $03, $00, $01, $00, + $02, $00, $03, $0F, $00, $0E, $0A, $00, $00, $00, + $03, $00, $00, $00, $00, $00, $00, $00, $01, $00, + $00, $00, $00, $00, $00, $00, $02, $00, $00, $00, + $00, $00, $00, $00, $03, $00, $0E, $00, $02, $0F, + $00, $00, $00, $03, $0B, $00, $00, $00, $00, $0B, + $00, $00, $00, $03, $00, $00, $00, $0F, $74, $68, + $65, $6E, $20, $61, $20, $6F, $6E, $65, $2C, $20, + $74, $77, $6F, $00, $00, $00, $06, $74, $68, $72, + $65, $65, $21, $00, $00, $00, $06, $46, $4F, $55, + $52, $21, $21, $0B, $00, $00, $00, $02, $00, $00, + $00, $09, $61, $6E, $64, $20, $61, $20, $6F, $6E, + $65, $00, $00, $00, $09, $61, $6E, $64, $20, $61, + $20, $74, $77, $6F, $0D, $00, $03, $0B, $0F, $00, + $00, $00, $03, $00, $00, $00, $03, $74, $77, $6F, + $0C, $00, $00, $00, $02, $08, $00, $01, $00, $00, + $00, $01, $0B, $00, $02, $00, $00, $00, $05, $57, + $61, $69, $74, $2E, $00, $08, $00, $01, $00, $00, + $00, $02, $0B, $00, $02, $00, $00, $00, $05, $57, + $68, $61, $74, $3F, $00, $00, $00, $00, $05, $74, + $68, $72, $65, $65, $0C, $00, $00, $00, $00, $00, + $00, $00, $04, $7A, $65, $72, $6F, $0C, $00, $00, + $00, $00, $00 }; + + +*) + + private + const + kUnicodeBytes : packed array[0..43] of Byte + = ( $d3, $80, $e2, $85, $ae, $ce, $9d, $20, $d0, $9d, + $ce, $bf, $e2, $85, $bf, $d0, $be, $c9, $a1, $d0, + $b3, $d0, $b0, $cf, $81, $e2, $84, $8e, $20, $ce, + $91, $74, $74, $ce, $b1, $e2, $85, $bd, $ce, $ba, + $83, $e2, $80, $bc); + + end; + + +implementation + + +class function Fixtures.CreateOneOfEach : IOneOfEach; +var db : Double; + us : Utf8String; +begin + result := TOneOfEachImpl.Create; + result.setIm_true( TRUE); + result.setIm_false( FALSE); + result.setA_bite( ShortInt($D6)); + result.setInteger16( 27000); + result.setInteger32( 1 shl 24); + result.setInteger64( Int64(6000) * Int64(1000) * Int64(1000)); + db := Pi; + result.setDouble_precision( db); + result.setSome_characters( 'JSON THIS! \"\1'); + + // ?? + SetLength( us, Length(kUnicodeBytes)); + Move( kUnicodeBytes[0], us[1], Length(kUnicodeBytes)); + // ?? + SetString( us, PChar(@kUnicodeBytes[0]), Length(kUnicodeBytes)); + // !! + result.setZomg_unicode( UnicodeString( us)); + + {$IF cDebugProtoTest_Option_AnsiStr_Binary} + result.SetBase64('base64'); + {$ELSE} + not yet impl + {$IFEND} + + // byte, i16, and i64 lists are populated by default constructor +end; + + +class function Fixtures.CreateNesting : INesting; +var bonk : IBonk; +begin + bonk := TBonkImpl.Create; + bonk.Type_ := 31337; + bonk.Message := 'I am a bonk... xor!'; + + result := TNestingImpl.Create; + result.My_bonk := bonk; + result.My_ooe := CreateOneOfEach; +end; + + +class function Fixtures.CreateHolyMoley : IHolyMoley; +var big : IThriftList; + stage1 : IThriftList; + stage2 : IThriftList; + b : IBonk; +begin + result := THolyMoleyImpl.Create; + + big := TThriftListImpl.Create; + big.add( CreateOneOfEach); + big.add( CreateNesting.my_ooe); + result.Big := big; + result.Big[0].setA_bite( $22); + result.Big[0].setA_bite( $23); + + result.Contain := THashSetImpl< IThriftList>.Create; + stage1 := TThriftListImpl.Create; + stage1.add( 'and a one'); + stage1.add( 'and a two'); + result.Contain.add( stage1); + + stage1 := TThriftListImpl.Create; + stage1.add( 'then a one, two'); + stage1.add( 'three!'); + stage1.add( 'FOUR!!'); + result.Contain.add( stage1); + + stage1 := TThriftListImpl.Create; + result.Contain.add( stage1); + + stage2 := TThriftListImpl.Create; + result.Bonks := TThriftDictionaryImpl< String, IThriftList< IBonk>>.Create; + // one empty + result.Bonks.Add( 'zero', stage2); + + // one with two + stage2 := TThriftListImpl.Create; + b := TBonkImpl.Create; + b.type_ := 1; + b.message := 'Wait.'; + stage2.Add( b); + b := TBonkImpl.Create; + b.type_ := 2; + b.message := 'What?'; + stage2.Add( b); + result.Bonks.Add( 'two', stage2); + + // one with three + stage2 := TThriftListImpl.Create; + b := TBonkImpl.Create; + b.type_ := 3; + b.message := 'quoth'; + stage2.Add( b); + b := TBonkImpl.Create; + b.type_ := 4; + b.message := 'the raven'; + stage2.Add( b); + b := TBonkImpl.Create; + b.type_ := 5; + b.message := 'nevermore'; + stage2.Add( b); + result.bonks.Add( 'three', stage2); +end; + + +class function Fixtures.CreateCompactProtoTestStruct : ICompactProtoTestStruct; +// superhuge compact proto test struct +begin + result := TCompactProtoTestStructImpl.Create; + result.A_byte := TConstants.COMPACT_TEST.A_byte; + result.A_i16 := TConstants.COMPACT_TEST.A_i16; + result.A_i32 := TConstants.COMPACT_TEST.A_i32; + result.A_i64 := TConstants.COMPACT_TEST.A_i64; + result.A_double := TConstants.COMPACT_TEST.A_double; + result.A_string := TConstants.COMPACT_TEST.A_string; + result.A_binary := TConstants.COMPACT_TEST.A_binary; + result.True_field := TConstants.COMPACT_TEST.True_field; + result.False_field := TConstants.COMPACT_TEST.False_field; + result.Empty_struct_field := TConstants.COMPACT_TEST.Empty_struct_field; + result.Byte_list := TConstants.COMPACT_TEST.Byte_list; + result.I16_list := TConstants.COMPACT_TEST.I16_list; + result.I32_list := TConstants.COMPACT_TEST.I32_list; + result.I64_list := TConstants.COMPACT_TEST.I64_list; + result.Double_list := TConstants.COMPACT_TEST.Double_list; + result.String_list := TConstants.COMPACT_TEST.String_list; + result.Binary_list := TConstants.COMPACT_TEST.Binary_list; + result.Boolean_list := TConstants.COMPACT_TEST.Boolean_list; + result.Struct_list := TConstants.COMPACT_TEST.Struct_list; + result.Byte_set := TConstants.COMPACT_TEST.Byte_set; + result.I16_set := TConstants.COMPACT_TEST.I16_set; + result.I32_set := TConstants.COMPACT_TEST.I32_set; + result.I64_set := TConstants.COMPACT_TEST.I64_set; + result.Double_set := TConstants.COMPACT_TEST.Double_set; + result.String_set := TConstants.COMPACT_TEST.String_set; + result.String_set := TConstants.COMPACT_TEST.String_set; + result.String_set := TConstants.COMPACT_TEST.String_set; + result.Binary_set := TConstants.COMPACT_TEST.Binary_set; + result.Boolean_set := TConstants.COMPACT_TEST.Boolean_set; + result.Struct_set := TConstants.COMPACT_TEST.Struct_set; + result.Byte_byte_map := TConstants.COMPACT_TEST.Byte_byte_map; + result.I16_byte_map := TConstants.COMPACT_TEST.I16_byte_map; + result.I32_byte_map := TConstants.COMPACT_TEST.I32_byte_map; + result.I64_byte_map := TConstants.COMPACT_TEST.I64_byte_map; + result.Double_byte_map := TConstants.COMPACT_TEST.Double_byte_map; + result.String_byte_map := TConstants.COMPACT_TEST.String_byte_map; + result.Binary_byte_map := TConstants.COMPACT_TEST.Binary_byte_map; + result.Boolean_byte_map := TConstants.COMPACT_TEST.Boolean_byte_map; + result.Byte_i16_map := TConstants.COMPACT_TEST.Byte_i16_map; + result.Byte_i32_map := TConstants.COMPACT_TEST.Byte_i32_map; + result.Byte_i64_map := TConstants.COMPACT_TEST.Byte_i64_map; + result.Byte_double_map := TConstants.COMPACT_TEST.Byte_double_map; + result.Byte_string_map := TConstants.COMPACT_TEST.Byte_string_map; + result.Byte_binary_map := TConstants.COMPACT_TEST.Byte_binary_map; + result.Byte_boolean_map := TConstants.COMPACT_TEST.Byte_boolean_map; + result.List_byte_map := TConstants.COMPACT_TEST.List_byte_map; + result.Set_byte_map := TConstants.COMPACT_TEST.Set_byte_map; + result.Map_byte_map := TConstants.COMPACT_TEST.Map_byte_map; + result.Byte_map_map := TConstants.COMPACT_TEST.Byte_map_map; + result.Byte_set_map := TConstants.COMPACT_TEST.Byte_set_map; + result.Byte_list_map := TConstants.COMPACT_TEST.Byte_list_map; + + {$IF cDebugProtoTest_Option_AnsiStr_Binary} + result.A_binary := AnsiString( #0#1#2#3#4#5#6#7#8); + {$ELSE} + not yet impl + {$IFEND} +end; + + +end. + diff --git a/lib/delphi/test/serializer/TestSerializer.dpr b/lib/delphi/test/serializer/TestSerializer.dpr new file mode 100644 index 00000000..60e55c1c --- /dev/null +++ b/lib/delphi/test/serializer/TestSerializer.dpr @@ -0,0 +1,212 @@ +(* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + *) + +program skiptest_version1; + +{$APPTYPE CONSOLE} + +uses + Classes, Windows, SysUtils, Generics.Collections, + Thrift in '..\..\src\Thrift.pas', + Thrift.Transport in '..\..\src\Thrift.Transport.pas', + Thrift.Protocol in '..\..\src\Thrift.Protocol.pas', + Thrift.Protocol.JSON in '..\..\src\Thrift.Protocol.JSON.pas', + Thrift.Collections in '..\..\src\Thrift.Collections.pas', + Thrift.Server in '..\..\src\Thrift.Server.pas', + Thrift.Console in '..\..\src\Thrift.Console.pas', + Thrift.Utils in '..\..\src\Thrift.Utils.pas', + Thrift.Serializer in '..\..\src\Thrift.Serializer.pas', + Thrift.Stream in '..\..\src\Thrift.Stream.pas', + DebugProtoTest, + TestSerializer.Data; + + + +type + TTestSerializer = class //extends TestCase { + private + FProtocols : TList< IProtocolFactory>; + + class function Serialize(const input : IBase; const factory : IProtocolFactory) : TBytes; overload; + class procedure Serialize(const input : IBase; const factory : IProtocolFactory; const aStream : TStream); overload; + class procedure Deserialize( const input : TBytes; const target : IBase; const factory : IProtocolFactory); overload; + class procedure Deserialize( const input : TStream; const target : IBase; const factory : IProtocolFactory); overload; + + public + constructor Create; + destructor Destroy; override; + + procedure TestDeserialize; + end; + + + +{ TTestSerializer } + +constructor TTestSerializer.Create; +begin + inherited Create; + FProtocols := TList< IProtocolFactory>.Create; + FProtocols.Add( TBinaryProtocolImpl.TFactory.Create); + //FProtocols.Add( TCompactProtocolImpl.TFactory.Create); + FProtocols.Add( TJSONProtocolImpl.TFactory.Create); +end; + + +destructor TTestSerializer.Destroy; +begin + try + FreeAndNil( FProtocols); + finally + inherited Destroy; + end; +end; + + +procedure TTestSerializer.TestDeserialize; +type TMethod = (mt_Bytes, mt_Stream); +var level3ooe, correct : IOneOfEach; + factory : IProtocolFactory; + bytes : TBytes; + stream : TFileStream; + i : Integer; + method : TMethod; +begin + correct := Fixtures.CreateOneOfEach; + stream := TFileStream.Create( 'TestSerializer.dat', fmCreate); + try + + for method in [Low(TMethod)..High(TMethod)] do begin + for factory in FProtocols do begin + + // write + level3ooe := Fixtures.CreateOneOfEach; + case method of + mt_Bytes: bytes := Serialize( level3ooe, factory); + mt_Stream: begin + stream.Size := 0; + Serialize( level3ooe, factory, stream); + end + else + ASSERT( FALSE); + end; + + // init + read + level3ooe := TOneOfEachImpl.Create; + case method of + mt_Bytes: Deserialize( bytes, level3ooe, factory); + mt_Stream: begin + stream.Position := 0; + Deserialize( stream, level3ooe, factory); + end + else + ASSERT( FALSE); + end; + + + // check + ASSERT( level3ooe.Im_true = correct.Im_true); + ASSERT( level3ooe.Im_false = correct.Im_false); + ASSERT( level3ooe.A_bite = correct.A_bite); + ASSERT( level3ooe.Integer16 = correct.Integer16); + ASSERT( level3ooe.Integer32 = correct.Integer32); + ASSERT( level3ooe.Integer64 = correct.Integer64); + ASSERT( Abs( level3ooe.Double_precision - correct.Double_precision) < 1E-12); + ASSERT( level3ooe.Some_characters = correct.Some_characters); + ASSERT( level3ooe.Zomg_unicode = correct.Zomg_unicode); + ASSERT( level3ooe.What_who = correct.What_who); + ASSERT( level3ooe.Base64 = correct.Base64); + + ASSERT( level3ooe.Byte_list.Count = correct.Byte_list.Count); + for i := 0 to level3ooe.Byte_list.Count-1 + do ASSERT( level3ooe.Byte_list[i] = correct.Byte_list[i]); + + ASSERT( level3ooe.I16_list.Count = correct.I16_list.Count); + for i := 0 to level3ooe.I16_list.Count-1 + do ASSERT( level3ooe.I16_list[i] = correct.I16_list[i]); + + ASSERT( level3ooe.I64_list.Count = correct.I64_list.Count); + for i := 0 to level3ooe.I64_list.Count-1 + do ASSERT( level3ooe.I64_list[i] = correct.I64_list[i]); + end; + end; + + finally + stream.Free; + end; +end; + + +class function TTestSerializer.Serialize(const input : IBase; const factory : IProtocolFactory) : TBytes; +var serial : TSerializer; +begin + serial := TSerializer.Create( factory); + try + result := serial.Serialize( input); + finally + serial.Free; + end; +end; + + +class procedure TTestSerializer.Serialize(const input : IBase; const factory : IProtocolFactory; const aStream : TStream); +var serial : TSerializer; +begin + serial := TSerializer.Create( factory); + try + serial.Serialize( input, aStream); + finally + serial.Free; + end; +end; + + +class procedure TTestSerializer.Deserialize( const input : TBytes; const target : IBase; const factory : IProtocolFactory); +var serial : TDeserializer; +begin + serial := TDeserializer.Create( factory); + try + serial.Deserialize( input, target); + finally + serial.Free; + end; +end; + +class procedure TTestSerializer.Deserialize( const input : TStream; const target : IBase; const factory : IProtocolFactory); +var serial : TDeserializer; +begin + serial := TDeserializer.Create( factory); + try + serial.Deserialize( input, target); + finally + serial.Free; + end; +end; + + +var test : TTestSerializer; +begin + test := TTestSerializer.Create; + try + test.TestDeserialize; + finally + test.Free; + end; +end. +