Thrift-1670: Incompatibilities between different versions of a Thrift interface
Client: delphi
Patch: Jens Geyer
The method TProtocolUtil.Skip() lacks implementation, which leads to exceptions after unknown message members are found by the generated deserialisation code.
git-svn-id: https://svn.apache.org/repos/asf/thrift/trunk@1378429 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/delphi/src/Thrift.Protocol.pas b/lib/delphi/src/Thrift.Protocol.pas
index a54008f..33e17d7 100644
--- a/lib/delphi/src/Thrift.Protocol.pas
+++ b/lib/delphi/src/Thrift.Protocol.pas
@@ -556,8 +556,60 @@
{ TProtocolUtil }
class procedure TProtocolUtil.Skip( prot: IProtocol; type_: TType);
+var field : IField;
+ map : IMap;
+ set_ : ISet;
+ list : IList;
+ i : Integer;
begin
+ case type_ of
+ // simple types
+ TType.Bool_ : prot.ReadBool();
+ TType.Byte_ : prot.ReadByte();
+ TType.I16 : prot.ReadI16();
+ TType.I32 : prot.ReadI32();
+ TType.I64 : prot.ReadI64();
+ TType.Double_ : prot.ReadDouble();
+ TType.String_ : prot.ReadBinary();// Don't try to decode the string, just skip it.
+ // structured types
+ TType.Struct : begin
+ prot.ReadStructBegin();
+ while TRUE do begin
+ field := prot.ReadFieldBegin();
+ if (field.Type_ = TType.Stop) then Break;
+ Skip(prot, field.Type_);
+ prot.ReadFieldEnd();
+ end;
+ prot.ReadStructEnd();
+ end;
+
+ TType.Map : begin
+ map := prot.ReadMapBegin();
+ for i := 0 to map.Count-1 do begin
+ Skip(prot, map.KeyType);
+ Skip(prot, map.ValueType);
+ end;
+ prot.ReadMapEnd();
+ end;
+
+ TType.Set_ : begin
+ set_ := prot.ReadSetBegin();
+ for i := 0 to set_.Count-1
+ do Skip( prot, set_.ElementType);
+ prot.ReadSetEnd();
+ end;
+
+ TType.List : begin
+ list := prot.ReadListBegin();
+ for i := 0 to list.Count-1
+ do Skip( prot, list.ElementType);
+ prot.ReadListEnd();
+ end;
+
+ else
+ ASSERT( FALSE); // any new types?
+ end;
end;
{ TStructImpl }
@@ -1090,7 +1142,7 @@
version := VERSION_1 or Cardinal( msg.Type_);
WriteI32( Integer( version) );
WriteString( msg.Name);
- WriteI32( msg.SeqID);
+ WriteI32( msg.SeqID);
end else
begin
WriteString( msg.Name);
diff --git a/lib/delphi/test/skip/README.txt b/lib/delphi/test/skip/README.txt
new file mode 100644
index 0000000..90d5ff5
--- /dev/null
+++ b/lib/delphi/test/skip/README.txt
@@ -0,0 +1,11 @@
+These two projects belong together. Both programs
+simulate server and client for different versions
+of the same protocol.
+
+The intention of this test is to ensure fully
+working compatibilty features of the Delphi Thrift
+implementation.
+
+The expected test result is, that no errors occur
+with both programs, regardless in which order they
+might be started.
diff --git a/lib/delphi/test/skip/idl/skiptest_version_1.thrift b/lib/delphi/test/skip/idl/skiptest_version_1.thrift
new file mode 100644
index 0000000..20b91b8
--- /dev/null
+++ b/lib/delphi/test/skip/idl/skiptest_version_1.thrift
@@ -0,0 +1,45 @@
+(*
+ * 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.
+ *)
+
+
+ // version 1 of the interface
+
+namespace * Skiptest.One
+
+const i32 SKIPTESTSERVICE_VERSION = 1
+
+struct Pong {
+ 1 : optional i32 version1
+}
+
+struct Ping {
+ 1 : optional i32 version1
+}
+
+exception PongFailed {
+ 222 : optional i32 pongErrorCode
+}
+
+
+service SkipTestService {
+ void PingPong( 1: Ping pong) throws (444: PongFailed pof);
+}
+
+
+// EOF
\ No newline at end of file
diff --git a/lib/delphi/test/skip/idl/skiptest_version_2.thrift b/lib/delphi/test/skip/idl/skiptest_version_2.thrift
new file mode 100644
index 0000000..df55aff
--- /dev/null
+++ b/lib/delphi/test/skip/idl/skiptest_version_2.thrift
@@ -0,0 +1,69 @@
+(*
+ * 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.
+ *)
+
+
+ // version 2 of the interface
+
+namespace * Skiptest.Two
+
+const i32 SKIPTESTSERVICE_VERSION = 2
+
+struct Pong {
+ 1 : optional i32 version1
+ 2 : optional i16 version2
+}
+
+struct Ping {
+ 1 : optional i32 version1
+ 10 : optional bool boolVal
+ 11 : optional byte byteVal
+ 12 : optional double dbVal
+ 13 : optional i16 i16Val
+ 14 : optional i32 i32Val
+ 15 : optional i64 i64Val
+ 16 : optional string strVal
+ 17 : optional Pong structVal
+ 18 : optional map< list< Pong>, set< string>> mapVal
+}
+
+exception PingFailed {
+ 1 : optional i32 pingErrorCode
+}
+
+exception PongFailed {
+ 222 : optional i32 pongErrorCode
+ 10 : optional bool boolVal
+ 11 : optional byte byteVal
+ 12 : optional double dbVal
+ 13 : optional i16 i16Val
+ 14 : optional i32 i32Val
+ 15 : optional i64 i64Val
+ 16 : optional string strVal
+ 17 : optional Pong structVal
+ 18 : optional map< list< Pong>, set< string>> mapVal
+}
+
+
+service SkipTestService {
+ Ping PingPong( 1: Ping ping, 3: Pong pong) throws (1: PingFailed pif, 444: PongFailed pof);
+}
+
+
+// EOF
+
diff --git a/lib/delphi/test/skip/skiptest_version1.dpr b/lib/delphi/test/skip/skiptest_version1.dpr
new file mode 100644
index 0000000..367b5e7
--- /dev/null
+++ b/lib/delphi/test/skip/skiptest_version1.dpr
@@ -0,0 +1,200 @@
+(*
+ * 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,
+ Skiptest.One,
+ Thrift in '..\..\..\lib\delphi\src\Thrift.pas',
+ Thrift.Transport in '..\..\..\lib\delphi\src\Thrift.Transport.pas',
+ Thrift.Protocol in '..\..\..\lib\delphi\src\Thrift.Protocol.pas',
+ Thrift.Protocol.JSON in '..\..\..\lib\delphi\src\Thrift.Protocol.JSON.pas',
+ Thrift.Collections in '..\..\..\lib\delphi\src\Thrift.Collections.pas',
+ Thrift.Server in '..\..\..\lib\delphi\src\Thrift.Server.pas',
+ Thrift.Console in '..\..\..\lib\delphi\src\Thrift.Console.pas',
+ Thrift.Utils in '..\..\..\lib\delphi\src\Thrift.Utils.pas',
+ Thrift.Stream in '..\..\..\lib\delphi\src\Thrift.Stream.pas';
+
+const
+ REQUEST_EXT = '.request';
+ RESPONSE_EXT = '.response';
+
+
+function CreatePing : IPing;
+begin
+ result := TPingImpl.Create;
+ result.Version1 := Skiptest.One.TConstants.SKIPTESTSERVICE_VERSION;
+end;
+
+
+type
+ TDummyServer = class( TInterfacedObject, TSkipTestService.Iface)
+ protected
+ // TSkipTestService.Iface
+ procedure PingPong(const ping: IPing);
+ end;
+
+
+procedure TDummyServer.PingPong(const ping: IPing);
+// TSkipTestService.Iface
+begin
+ Writeln('- performing request from version '+IntToStr(ping.Version1)+' client');
+end;
+
+
+function CreateProtocol( protfact : IProtocolFactory; stm : TStream; aForInput : Boolean) : IProtocol;
+var adapt : IThriftStream;
+ trans : ITransport;
+begin
+ adapt := TThriftStreamAdapterDelphi.Create( stm, FALSE);
+ if aForInput
+ then trans := TStreamTransportImpl.Create( adapt, nil)
+ else trans := TStreamTransportImpl.Create( nil, adapt);
+ result := protfact.GetProtocol( trans);
+end;
+
+
+procedure CreateRequest( protfact : IProtocolFactory; fname : string);
+var stm : TFileStream;
+ ping : IPing;
+ proto : IProtocol;
+ client : TSkipTestService.TClient; // we need access to send/recv_pingpong()
+ cliRef : IUnknown; // holds the refcount
+begin
+ Writeln('- creating new request');
+ stm := TFileStream.Create( fname+REQUEST_EXT+'.tmp', fmCreate);
+ try
+ ping := CreatePing;
+
+ // save request data
+ proto := CreateProtocol( protfact, stm, FALSE);
+ client := TSkipTestService.TClient.Create( nil, proto);
+ cliRef := client as IUnknown;
+ client.send_PingPong( ping);
+
+ finally
+ client := nil; // not Free!
+ cliRef := nil;
+ stm.Free;
+ if client = nil then {warning supressed};
+ end;
+
+ DeleteFile( fname+REQUEST_EXT);
+ RenameFile( fname+REQUEST_EXT+'.tmp', fname+REQUEST_EXT);
+end;
+
+
+procedure ReadResponse( protfact : IProtocolFactory; fname : string);
+var stm : TFileStream;
+ ping : IPing;
+ proto : IProtocol;
+ client : TSkipTestService.TClient; // we need access to send/recv_pingpong()
+ cliRef : IUnknown; // holds the refcount
+begin
+ Writeln('- reading response');
+ stm := TFileStream.Create( fname+RESPONSE_EXT, fmOpenRead);
+ try
+ // save request data
+ proto := CreateProtocol( protfact, stm, TRUE);
+ client := TSkipTestService.TClient.Create( proto, nil);
+ cliRef := client as IUnknown;
+ client.recv_PingPong;
+
+ finally
+ client := nil; // not Free!
+ cliRef := nil;
+ stm.Free;
+ if client = nil then {warning supressed};
+ end;
+end;
+
+
+procedure ProcessFile( protfact : IProtocolFactory; fname : string);
+var stmIn, stmOut : TFileStream;
+ protIn, protOut : IProtocol;
+ server : IProcessor;
+begin
+ Writeln('- processing request');
+ stmOut := nil;
+ stmIn := TFileStream.Create( fname+REQUEST_EXT, fmOpenRead);
+ try
+ stmOut := TFileStream.Create( fname+RESPONSE_EXT+'.tmp', fmCreate);
+
+ // process request and write response data
+ protIn := CreateProtocol( protfact, stmIn, TRUE);
+ protOut := CreateProtocol( protfact, stmOut, FALSE);
+
+ server := TSkipTestService.TProcessorImpl.Create( TDummyServer.Create);
+ server.Process( protIn, protOut);
+
+ finally
+ server := nil; // not Free!
+ stmIn.Free;
+ stmOut.Free;
+ if server = nil then {warning supressed};
+ end;
+
+ DeleteFile( fname+RESPONSE_EXT);
+ RenameFile( fname+RESPONSE_EXT+'.tmp', fname+RESPONSE_EXT);
+end;
+
+
+procedure Test( protfact : IProtocolFactory; fname : string);
+begin
+ // try to read an existing request
+ if FileExists( fname + REQUEST_EXT) then begin
+ ProcessFile( protfact, fname);
+ ReadResponse( protfact, fname);
+ end;
+
+ // create a new request and try to process
+ CreateRequest( protfact, fname);
+ ProcessFile( protfact, fname);
+ ReadResponse( protfact, fname);
+end;
+
+
+const
+ FILE_BINARY = 'pingpong.bin';
+ FILE_JSON = 'pingpong.json';
+begin
+ try
+ Writeln( 'Delphi SkipTest '+IntToStr(TConstants.SKIPTESTSERVICE_VERSION)+' using '+Thrift.Version);
+
+ Writeln;
+ Writeln('Binary protocol');
+ Test( TBinaryProtocolImpl.TFactory.Create, FILE_BINARY);
+
+ Writeln;
+ Writeln('JSON protocol');
+ Test( TJSONProtocolImpl.TFactory.Create, FILE_JSON);
+
+ Writeln;
+ Writeln('Test completed without errors.');
+ Writeln;
+ Write('Press ENTER to close ...'); Readln;
+ except
+ on E: Exception do
+ Writeln(E.ClassName, ': ', E.Message);
+ end;
+end.
+
diff --git a/lib/delphi/test/skip/skiptest_version1.dproj b/lib/delphi/test/skip/skiptest_version1.dproj
new file mode 100644
index 0000000..1c55463
--- /dev/null
+++ b/lib/delphi/test/skip/skiptest_version1.dproj
@@ -0,0 +1,116 @@
+ <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <ProjectGuid>{EEF476C6-43AE-4CC3-AE51-10C5B35071F1}</ProjectGuid>
+ <MainSource>skiptest_version1.dpr</MainSource>
+ <Basis>True</Basis>
+ <Config Condition="'$(Config)'==''">Debug</Config>
+ <Platform>Win32</Platform>
+ <AppType>Console</AppType>
+ <FrameworkType>None</FrameworkType>
+ <DCC_DCCCompiler>DCC32</DCC_DCCCompiler>
+ <ProjectVersion>12.3</ProjectVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Config)'=='Basis' or '$(Base)'!=''">
+ <Base>true</Base>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''">
+ <Cfg_1>true</Cfg_1>
+ <CfgParent>Base</CfgParent>
+ <Base>true</Base>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''">
+ <Cfg_2>true</Cfg_2>
+ <CfgParent>Base</CfgParent>
+ <Base>true</Base>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Base)'!=''">
+ <DCC_UnitSearchPath>C:\D\TPCPP\X_ThirdParty\Thrift\wc-XE-all\thrift-testing\gen-delphi;C:\D\TPCPP\X_ThirdParty\Thrift\wc-XE-all\trunk\lib\delphi\src;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+ <DCC_E>false</DCC_E>
+ <DCC_ImageBase>00400000</DCC_ImageBase>
+ <DCC_UnitAlias>WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;WinTypes=Windows;WinProcs=Windows;$(DCC_UnitAlias)</DCC_UnitAlias>
+ <DCC_F>false</DCC_F>
+ <DCC_S>false</DCC_S>
+ <DCC_N>false</DCC_N>
+ <DCC_K>false</DCC_K>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Cfg_1)'!=''">
+ <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+ <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+ <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+ <DCC_DebugInformation>false</DCC_DebugInformation>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Cfg_2)'!=''">
+ <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+ <DCC_Optimize>false</DCC_Optimize>
+ <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+ </PropertyGroup>
+ <ItemGroup>
+ <DelphiCompile Include="skiptest_version1.dpr">
+ <MainSource>MainSource</MainSource>
+ </DelphiCompile>
+ <DCCReference Include="..\..\..\lib\delphi\src\Thrift.pas"/>
+ <DCCReference Include="..\..\..\lib\delphi\src\Thrift.Transport.pas"/>
+ <DCCReference Include="..\..\..\lib\delphi\src\Thrift.Protocol.pas"/>
+ <DCCReference Include="..\..\..\lib\delphi\src\Thrift.Protocol.JSON.pas"/>
+ <DCCReference Include="..\..\..\lib\delphi\src\Thrift.Collections.pas"/>
+ <DCCReference Include="..\..\..\lib\delphi\src\Thrift.Server.pas"/>
+ <DCCReference Include="..\..\..\lib\delphi\src\Thrift.Console.pas"/>
+ <DCCReference Include="..\..\..\lib\delphi\src\Thrift.Utils.pas"/>
+ <DCCReference Include="..\..\..\lib\delphi\src\Thrift.Stream.pas"/>
+ <BuildConfiguration Include="Debug">
+ <Key>Cfg_2</Key>
+ <CfgParent>Base</CfgParent>
+ </BuildConfiguration>
+ <BuildConfiguration Include="Basis">
+ <Key>Base</Key>
+ </BuildConfiguration>
+ <BuildConfiguration Include="Release">
+ <Key>Cfg_1</Key>
+ <CfgParent>Base</CfgParent>
+ </BuildConfiguration>
+ </ItemGroup>
+ <Import Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')" Project="$(BDS)\Bin\CodeGear.Delphi.Targets"/>
+ <Import Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')" Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj"/>
+ <ProjectExtensions>
+ <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+ <Borland.ProjectType>VCLApplication</Borland.ProjectType>
+ <BorlandProject>
+ <Delphi.Personality>
+ <Source>
+ <Source Name="MainSource">skiptest_version1.dpr</Source>
+ </Source>
+ <VersionInfo>
+ <VersionInfo Name="IncludeVerInfo">False</VersionInfo>
+ <VersionInfo Name="AutoIncBuild">False</VersionInfo>
+ <VersionInfo Name="MajorVer">1</VersionInfo>
+ <VersionInfo Name="MinorVer">0</VersionInfo>
+ <VersionInfo Name="Release">0</VersionInfo>
+ <VersionInfo Name="Build">0</VersionInfo>
+ <VersionInfo Name="Debug">False</VersionInfo>
+ <VersionInfo Name="PreRelease">False</VersionInfo>
+ <VersionInfo Name="Special">False</VersionInfo>
+ <VersionInfo Name="Private">False</VersionInfo>
+ <VersionInfo Name="DLL">False</VersionInfo>
+ <VersionInfo Name="Locale">1031</VersionInfo>
+ <VersionInfo Name="CodePage">1252</VersionInfo>
+ </VersionInfo>
+ <VersionInfoKeys>
+ <VersionInfoKeys Name="CompanyName"/>
+ <VersionInfoKeys Name="FileDescription"/>
+ <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
+ <VersionInfoKeys Name="InternalName"/>
+ <VersionInfoKeys Name="LegalCopyright"/>
+ <VersionInfoKeys Name="LegalTrademarks"/>
+ <VersionInfoKeys Name="OriginalFilename"/>
+ <VersionInfoKeys Name="ProductName"/>
+ <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
+ <VersionInfoKeys Name="Comments"/>
+ </VersionInfoKeys>
+ </Delphi.Personality>
+ <Platforms>
+ <Platform value="Win32">True</Platform>
+ </Platforms>
+ </BorlandProject>
+ <ProjectFileVersion>12</ProjectFileVersion>
+ </ProjectExtensions>
+ </Project>
diff --git a/lib/delphi/test/skip/skiptest_version2.dpr b/lib/delphi/test/skip/skiptest_version2.dpr
new file mode 100644
index 0000000..797b35a
--- /dev/null
+++ b/lib/delphi/test/skip/skiptest_version2.dpr
@@ -0,0 +1,226 @@
+(*
+ * 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_version2;
+
+{$APPTYPE CONSOLE}
+
+uses
+ Classes, Windows, SysUtils,
+ Skiptest.Two,
+ Thrift in '..\..\..\lib\delphi\src\Thrift.pas',
+ Thrift.Transport in '..\..\..\lib\delphi\src\Thrift.Transport.pas',
+ Thrift.Protocol in '..\..\..\lib\delphi\src\Thrift.Protocol.pas',
+ Thrift.Protocol.JSON in '..\..\..\lib\delphi\src\Thrift.Protocol.JSON.pas',
+ Thrift.Collections in '..\..\..\lib\delphi\src\Thrift.Collections.pas',
+ Thrift.Server in '..\..\..\lib\delphi\src\Thrift.Server.pas',
+ Thrift.Console in '..\..\..\lib\delphi\src\Thrift.Console.pas',
+ Thrift.Utils in '..\..\..\lib\delphi\src\Thrift.Utils.pas',
+ Thrift.Stream in '..\..\..\lib\delphi\src\Thrift.Stream.pas';
+
+const
+ REQUEST_EXT = '.request';
+ RESPONSE_EXT = '.response';
+
+function CreatePing : IPing;
+var list : IThriftList<IPong>;
+ set_ : IHashSet<string>;
+begin
+ result := TPingImpl.Create;
+ result.Version1 := Skiptest.Two.TConstants.SKIPTESTSERVICE_VERSION;
+ result.BoolVal := TRUE;
+ result.ByteVal := 2;
+ result.DbVal := 3;
+ result.I16Val := 4;
+ result.I32Val := 5;
+ result.I64Val := 6;
+ result.StrVal := 'seven';
+
+ result.StructVal := TPongImpl.Create;
+ result.StructVal.Version1 := -1;
+ result.StructVal.Version2 := -2;
+
+ list := TThriftListImpl<IPong>.Create;
+ list.Add( result.StructVal);
+ list.Add( result.StructVal);
+
+ set_ := THashSetImpl<string>.Create;
+ set_.Add( 'one');
+ set_.Add( 'uno');
+ set_.Add( 'eins');
+ set_.Add( 'een');
+
+ result.MapVal := TThriftDictionaryImpl< IThriftList<IPong>, IHashSet<string>>.Create;
+ result.MapVal.Add( list, set_);
+end;
+
+
+type
+ TDummyServer = class( TInterfacedObject, TSkipTestService.Iface)
+ protected
+ // TSkipTestService.Iface
+ function PingPong(const ping: IPing; const pong: IPong): IPing;
+ end;
+
+
+function TDummyServer.PingPong(const ping: IPing; const pong: IPong): IPing;
+// TSkipTestService.Iface
+begin
+ Writeln('- performing request from version '+IntToStr(ping.Version1)+' client');
+ result := CreatePing;
+end;
+
+
+function CreateProtocol( protfact : IProtocolFactory; stm : TStream; aForInput : Boolean) : IProtocol;
+var adapt : IThriftStream;
+ trans : ITransport;
+begin
+ adapt := TThriftStreamAdapterDelphi.Create( stm, FALSE);
+ if aForInput
+ then trans := TStreamTransportImpl.Create( adapt, nil)
+ else trans := TStreamTransportImpl.Create( nil, adapt);
+ result := protfact.GetProtocol( trans);
+end;
+
+
+procedure CreateRequest( protfact : IProtocolFactory; fname : string);
+var stm : TFileStream;
+ ping : IPing;
+ proto : IProtocol;
+ client : TSkipTestService.TClient; // we need access to send/recv_pingpong()
+ cliRef : IUnknown; // holds the refcount
+begin
+ Writeln('- creating new request');
+ stm := TFileStream.Create( fname+REQUEST_EXT+'.tmp', fmCreate);
+ try
+ ping := CreatePing;
+
+ // save request data
+ proto := CreateProtocol( protfact, stm, FALSE);
+ client := TSkipTestService.TClient.Create( nil, proto);
+ cliRef := client as IUnknown;
+ client.send_PingPong( ping, ping.StructVal);
+
+ finally
+ client := nil; // not Free!
+ cliRef := nil;
+ stm.Free;
+ if client = nil then {warning supressed};
+ end;
+
+ DeleteFile( fname+REQUEST_EXT);
+ RenameFile( fname+REQUEST_EXT+'.tmp', fname+REQUEST_EXT);
+end;
+
+
+procedure ReadResponse( protfact : IProtocolFactory; fname : string);
+var stm : TFileStream;
+ ping : IPing;
+ proto : IProtocol;
+ client : TSkipTestService.TClient; // we need access to send/recv_pingpong()
+ cliRef : IUnknown; // holds the refcount
+begin
+ Writeln('- reading response');
+ stm := TFileStream.Create( fname+RESPONSE_EXT, fmOpenRead);
+ try
+ // save request data
+ proto := CreateProtocol( protfact, stm, TRUE);
+ client := TSkipTestService.TClient.Create( proto, nil);
+ cliRef := client as IUnknown;
+ ping := client.recv_PingPong;
+
+ finally
+ client := nil; // not Free!
+ cliRef := nil;
+ stm.Free;
+ if client = nil then {warning supressed};
+ end;
+end;
+
+
+procedure ProcessFile( protfact : IProtocolFactory; fname : string);
+var stmIn, stmOut : TFileStream;
+ protIn, protOut : IProtocol;
+ server : IProcessor;
+begin
+ Writeln('- processing request');
+ stmOut := nil;
+ stmIn := TFileStream.Create( fname+REQUEST_EXT, fmOpenRead);
+ try
+ stmOut := TFileStream.Create( fname+RESPONSE_EXT+'.tmp', fmCreate);
+
+ // process request and write response data
+ protIn := CreateProtocol( protfact, stmIn, TRUE);
+ protOut := CreateProtocol( protfact, stmOut, FALSE);
+
+ server := TSkipTestService.TProcessorImpl.Create( TDummyServer.Create);
+ server.Process( protIn, protOut);
+
+ finally
+ server := nil; // not Free!
+ stmIn.Free;
+ stmOut.Free;
+ if server = nil then {warning supressed};
+ end;
+
+ DeleteFile( fname+RESPONSE_EXT);
+ RenameFile( fname+RESPONSE_EXT+'.tmp', fname+RESPONSE_EXT);
+end;
+
+
+procedure Test( protfact : IProtocolFactory; fname : string);
+begin
+ // try to read an existing request
+ if FileExists( fname + REQUEST_EXT) then begin
+ ProcessFile( protfact, fname);
+ ReadResponse( protfact, fname);
+ end;
+
+ // create a new request and try to process
+ CreateRequest( protfact, fname);
+ ProcessFile( protfact, fname);
+ ReadResponse( protfact, fname);
+end;
+
+
+const
+ FILE_BINARY = 'pingpong.bin';
+ FILE_JSON = 'pingpong.json';
+begin
+ try
+ Writeln( 'Delphi SkipTest '+IntToStr(TConstants.SKIPTESTSERVICE_VERSION)+' using '+Thrift.Version);
+
+ Writeln;
+ Writeln('Binary protocol');
+ Test( TBinaryProtocolImpl.TFactory.Create, FILE_BINARY);
+
+ Writeln;
+ Writeln('JSON protocol');
+ Test( TJSONProtocolImpl.TFactory.Create, FILE_JSON);
+
+ Writeln;
+ Writeln('Test completed without errors.');
+ Writeln;
+ Write('Press ENTER to close ...'); Readln;
+ except
+ on E: Exception do
+ Writeln(E.ClassName, ': ', E.Message);
+ end;
+end.
+
diff --git a/lib/delphi/test/skip/skiptest_version2.dproj b/lib/delphi/test/skip/skiptest_version2.dproj
new file mode 100644
index 0000000..faee7f4
--- /dev/null
+++ b/lib/delphi/test/skip/skiptest_version2.dproj
@@ -0,0 +1,116 @@
+ <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <ProjectGuid>{EEF476C6-43AE-4CC3-AE51-10C5B35071F1}</ProjectGuid>
+ <MainSource>skiptest_version2.dpr</MainSource>
+ <Basis>True</Basis>
+ <Config Condition="'$(Config)'==''">Debug</Config>
+ <Platform>Win32</Platform>
+ <AppType>Console</AppType>
+ <FrameworkType>None</FrameworkType>
+ <DCC_DCCCompiler>DCC32</DCC_DCCCompiler>
+ <ProjectVersion>12.3</ProjectVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Config)'=='Basis' or '$(Base)'!=''">
+ <Base>true</Base>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''">
+ <Cfg_1>true</Cfg_1>
+ <CfgParent>Base</CfgParent>
+ <Base>true</Base>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''">
+ <Cfg_2>true</Cfg_2>
+ <CfgParent>Base</CfgParent>
+ <Base>true</Base>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Base)'!=''">
+ <DCC_UnitSearchPath>C:\D\TPCPP\X_ThirdParty\Thrift\wc-XE-all\thrift-testing\gen-delphi;C:\D\TPCPP\X_ThirdParty\Thrift\wc-XE-all\trunk\lib\delphi\src;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
+ <DCC_E>false</DCC_E>
+ <DCC_ImageBase>00400000</DCC_ImageBase>
+ <DCC_UnitAlias>WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;WinTypes=Windows;WinProcs=Windows;$(DCC_UnitAlias)</DCC_UnitAlias>
+ <DCC_F>false</DCC_F>
+ <DCC_S>false</DCC_S>
+ <DCC_N>false</DCC_N>
+ <DCC_K>false</DCC_K>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Cfg_1)'!=''">
+ <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+ <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+ <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+ <DCC_DebugInformation>false</DCC_DebugInformation>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Cfg_2)'!=''">
+ <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+ <DCC_Optimize>false</DCC_Optimize>
+ <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+ </PropertyGroup>
+ <ItemGroup>
+ <DelphiCompile Include="skiptest_version2.dpr">
+ <MainSource>MainSource</MainSource>
+ </DelphiCompile>
+ <DCCReference Include="..\..\..\lib\delphi\src\Thrift.pas"/>
+ <DCCReference Include="..\..\..\lib\delphi\src\Thrift.Transport.pas"/>
+ <DCCReference Include="..\..\..\lib\delphi\src\Thrift.Protocol.pas"/>
+ <DCCReference Include="..\..\..\lib\delphi\src\Thrift.Protocol.JSON.pas"/>
+ <DCCReference Include="..\..\..\lib\delphi\src\Thrift.Collections.pas"/>
+ <DCCReference Include="..\..\..\lib\delphi\src\Thrift.Server.pas"/>
+ <DCCReference Include="..\..\..\lib\delphi\src\Thrift.Console.pas"/>
+ <DCCReference Include="..\..\..\lib\delphi\src\Thrift.Utils.pas"/>
+ <DCCReference Include="..\..\..\lib\delphi\src\Thrift.Stream.pas"/>
+ <BuildConfiguration Include="Debug">
+ <Key>Cfg_2</Key>
+ <CfgParent>Base</CfgParent>
+ </BuildConfiguration>
+ <BuildConfiguration Include="Basis">
+ <Key>Base</Key>
+ </BuildConfiguration>
+ <BuildConfiguration Include="Release">
+ <Key>Cfg_1</Key>
+ <CfgParent>Base</CfgParent>
+ </BuildConfiguration>
+ </ItemGroup>
+ <Import Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')" Project="$(BDS)\Bin\CodeGear.Delphi.Targets"/>
+ <Import Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')" Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj"/>
+ <ProjectExtensions>
+ <Borland.Personality>Delphi.Personality.12</Borland.Personality>
+ <Borland.ProjectType>VCLApplication</Borland.ProjectType>
+ <BorlandProject>
+ <Delphi.Personality>
+ <Source>
+ <Source Name="MainSource">skiptest_version2.dpr</Source>
+ </Source>
+ <VersionInfo>
+ <VersionInfo Name="IncludeVerInfo">False</VersionInfo>
+ <VersionInfo Name="AutoIncBuild">False</VersionInfo>
+ <VersionInfo Name="MajorVer">1</VersionInfo>
+ <VersionInfo Name="MinorVer">0</VersionInfo>
+ <VersionInfo Name="Release">0</VersionInfo>
+ <VersionInfo Name="Build">0</VersionInfo>
+ <VersionInfo Name="Debug">False</VersionInfo>
+ <VersionInfo Name="PreRelease">False</VersionInfo>
+ <VersionInfo Name="Special">False</VersionInfo>
+ <VersionInfo Name="Private">False</VersionInfo>
+ <VersionInfo Name="DLL">False</VersionInfo>
+ <VersionInfo Name="Locale">1031</VersionInfo>
+ <VersionInfo Name="CodePage">1252</VersionInfo>
+ </VersionInfo>
+ <VersionInfoKeys>
+ <VersionInfoKeys Name="CompanyName"/>
+ <VersionInfoKeys Name="FileDescription"/>
+ <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
+ <VersionInfoKeys Name="InternalName"/>
+ <VersionInfoKeys Name="LegalCopyright"/>
+ <VersionInfoKeys Name="LegalTrademarks"/>
+ <VersionInfoKeys Name="OriginalFilename"/>
+ <VersionInfoKeys Name="ProductName"/>
+ <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
+ <VersionInfoKeys Name="Comments"/>
+ </VersionInfoKeys>
+ </Delphi.Personality>
+ <Platforms>
+ <Platform value="Win32">True</Platform>
+ </Platforms>
+ </BorlandProject>
+ <ProjectFileVersion>12</ProjectFileVersion>
+ </ProjectExtensions>
+ </Project>