THRIFT-5048 EnumUtils<T>.ToString() throws for elements not known to the receiving end [ci skip]
Client: Delphi
Patch: Jens Geyer
diff --git a/lib/delphi/src/Thrift.Utils.pas b/lib/delphi/src/Thrift.Utils.pas
index ede2656..bc9b460 100644
--- a/lib/delphi/src/Thrift.Utils.pas
+++ b/lib/delphi/src/Thrift.Utils.pas
@@ -97,7 +97,7 @@
   THRIFT_MIMETYPE = 'application/x-thrift';
 
 {$IFDEF Win64}
-function InterlockedExchangeAdd64( var Addend : Int64; Value : Int64) : Int64;  
+function InterlockedExchangeAdd64( var Addend : Int64; Value : Int64) : Int64;
 {$ENDIF}
 
 
@@ -289,8 +289,15 @@
 var pType : PTypeInfo;
 begin
   pType := PTypeInfo(TypeInfo(T));
-  if Assigned(pType) and (pType^.Kind = tkEnumeration)
-  then result := GetEnumName(pType,value)
+  if Assigned(pType)
+  and (pType^.Kind = tkEnumeration)
+  {$IF CompilerVersion >= 23.0}   // TODO: Range correct? What we know is that XE does not offer it, but Rio has it
+  and (pType^.TypeData^.MaxValue >= value)
+  and (pType^.TypeData^.MinValue <= value)
+  {$ELSE}
+  and FALSE  // THRIFT-5048: pType^.TypeData^ member not supported -> prevent GetEnumName() from reading outside the legal range
+  {$IFEND}
+  then result := GetEnumName( PTypeInfo(pType), value)
   else result := IntToStr(Ord(value));
 end;
 
diff --git a/lib/delphi/test/skip/idl/skiptest_version_1.thrift b/lib/delphi/test/skip/idl/skiptest_version_1.thrift
index 8353c5e..4221177 100644
--- a/lib/delphi/test/skip/idl/skiptest_version_1.thrift
+++ b/lib/delphi/test/skip/idl/skiptest_version_1.thrift
@@ -24,12 +24,14 @@
 
 const i32 SKIPTESTSERVICE_VERSION = 1
 
-struct Pong {
-  1 : optional i32 version1
+enum PingPongEnum {
+	PingOne = 0,
+	PongOne = 1,
 }
 
 struct Ping {
   1 : optional i32 version1
+  100 : PingPongEnum EnumTest
 }
 
 exception PongFailed {
@@ -38,7 +40,7 @@
 
 
 service SkipTestService {
-  void PingPong( 1: Ping pong) throws (444: PongFailed pof);
+  Ping PingPong( 1: Ping ping) throws (444: PongFailed pof);
 }
 
 
diff --git a/lib/delphi/test/skip/idl/skiptest_version_2.thrift b/lib/delphi/test/skip/idl/skiptest_version_2.thrift
index f3352d3..3ea69f7 100644
--- a/lib/delphi/test/skip/idl/skiptest_version_2.thrift
+++ b/lib/delphi/test/skip/idl/skiptest_version_2.thrift
@@ -24,9 +24,17 @@
 
 const i32 SKIPTESTSERVICE_VERSION = 2
 
+enum PingPongEnum {
+	PingOne = 0,
+	PongOne = 1,
+	PingTwo = 2,
+	PongTwo = 3,
+}
+
 struct Pong {
   1 : optional i32 version1
   2 : optional i16 version2
+  100 : PingPongEnum EnumTest
 }
 
 struct Ping {
@@ -40,6 +48,7 @@
   16 : optional string strVal
   17 : optional Pong structVal
   18 : optional map< list< Pong>, set< string>> mapVal
+  100 : PingPongEnum EnumTest
 }
 
 exception PingFailed {
diff --git a/lib/delphi/test/skip/skiptest_version1.dpr b/lib/delphi/test/skip/skiptest_version1.dpr
index c97e50b..f7cde2f 100644
--- a/lib/delphi/test/skip/skiptest_version1.dpr
+++ b/lib/delphi/test/skip/skiptest_version1.dpr
@@ -30,6 +30,7 @@
   Thrift.Transport in '..\..\src\Thrift.Transport.pas',
   Thrift.Protocol in '..\..\src\Thrift.Protocol.pas',
   Thrift.Protocol.JSON in '..\..\src\Thrift.Protocol.JSON.pas',
+  Thrift.Protocol.Compact in '..\..\src\Thrift.Protocol.Compact.pas',
   Thrift.Collections in '..\..\src\Thrift.Collections.pas',
   Thrift.Configuration in '..\..\src\Thrift.Configuration.pas',
   Thrift.Server in '..\..\src\Thrift.Server.pas',
@@ -47,6 +48,7 @@
 begin
   result := TPingImpl.Create;
   result.Version1  := Tskiptest_version_1Constants.SKIPTESTSERVICE_VERSION;
+  result.EnumTest  := TPingPongEnum.PingOne;
 end;
 
 
@@ -54,14 +56,16 @@
   TDummyServer = class( TInterfacedObject, TSkipTestService.Iface)
   protected
     // TSkipTestService.Iface
-    procedure PingPong(const ping: IPing);
+    function PingPong(const ping: IPing): IPing;
   end;
 
 
-procedure TDummyServer.PingPong(const ping: IPing);
+function TDummyServer.PingPong(const ping: IPing): IPing;
 // TSkipTestService.Iface
 begin
   Writeln('- performing request from version '+IntToStr(ping.Version1)+' client');
+  Writeln( ping.ToString);
+  result := CreatePing;
 end;
 
 
@@ -109,6 +113,7 @@
 
 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
@@ -116,11 +121,11 @@
   Writeln('- reading response');
   stm := TFileStream.Create( fname+RESPONSE_EXT, fmOpenRead);
   try
-    // save request data
+    // load request data
     proto  := CreateProtocol( protfact, stm, TRUE);
     client := TSkipTestService.TClient.Create( proto, nil);
     cliRef := client as IUnknown;
-    client.recv_PingPong;
+    ping   := client.recv_PingPong;
 
   finally
     client := nil;  // not Free!
@@ -164,12 +169,14 @@
 procedure Test( protfact : IProtocolFactory; fname : string);
 begin
   // try to read an existing request
+  Writeln('Reading data file '+fname);
   if FileExists( fname + REQUEST_EXT) then begin
     ProcessFile( protfact, fname);
     ReadResponse( protfact, fname);
   end;
 
   // create a new request and try to process
+  Writeln('Writing data file '+fname);
   CreateRequest( protfact, fname);
   ProcessFile( protfact, fname);
   ReadResponse( protfact, fname);
@@ -177,8 +184,9 @@
 
 
 const
-  FILE_BINARY = 'pingpong.bin';
-  FILE_JSON   = 'pingpong.json';
+  FILE_BINARY  = 'pingpong.bin';
+  FILE_JSON    = 'pingpong.json';
+  FILE_COMPACT = 'pingpong.compact';
 begin
   try
     Writeln( 'Delphi SkipTest '+IntToStr(Tskiptest_version_1Constants.SKIPTESTSERVICE_VERSION)+' using '+Thrift.Version);
@@ -192,6 +200,10 @@
     Test( TJSONProtocolImpl.TFactory.Create,   FILE_JSON);
 
     Writeln;
+    Writeln('Compact protocol');
+    Test( TCompactProtocolImpl.TFactory.Create, FILE_COMPACT);
+
+    Writeln;
     Writeln('Test completed without errors.');
     Writeln;
     Write('Press ENTER to close ...');  Readln;
diff --git a/lib/delphi/test/skip/skiptest_version2.dpr b/lib/delphi/test/skip/skiptest_version2.dpr
index 07c2c9a..478ea7c 100644
--- a/lib/delphi/test/skip/skiptest_version2.dpr
+++ b/lib/delphi/test/skip/skiptest_version2.dpr
@@ -30,6 +30,7 @@
   Thrift.Transport in '..\..\src\Thrift.Transport.pas',
   Thrift.Protocol in '..\..\src\Thrift.Protocol.pas',
   Thrift.Protocol.JSON in '..\..\src\Thrift.Protocol.JSON.pas',
+  Thrift.Protocol.Compact in '..\..\src\Thrift.Protocol.Compact.pas',
   Thrift.Collections in '..\..\src\Thrift.Collections.pas',
   Thrift.Configuration in '..\..\src\Thrift.Configuration.pas',
   Thrift.Server in '..\..\src\Thrift.Server.pas',
@@ -42,12 +43,15 @@
   REQUEST_EXT  = '.request';
   RESPONSE_EXT = '.response';
 
+
 function CreatePing : IPing;
 var list : IThriftList<IPong>;
     set_ : IHashSet<string>;
 begin
   result := TPingImpl.Create;
   result.Version1  := Tskiptest_version_2Constants.SKIPTESTSERVICE_VERSION;
+  result.EnumTest  := TPingPongEnum.PingTwo;
+
   result.BoolVal   := TRUE;
   result.ByteVal   := 2;
   result.DbVal     := 3;
@@ -59,6 +63,7 @@
   result.StructVal := TPongImpl.Create;
   result.StructVal.Version1 := -1;
   result.StructVal.Version2 := -2;
+  result.StructVal.EnumTest := TPingPongEnum.PongTwo;
 
   list := TThriftListImpl<IPong>.Create;
   list.Add( result.StructVal);
@@ -87,6 +92,7 @@
 // TSkipTestService.Iface
 begin
   Writeln('- performing request from version '+IntToStr(ping.Version1)+' client');
+  Writeln( ping.ToString);
   result := CreatePing;
 end;
 
@@ -143,7 +149,7 @@
   Writeln('- reading response');
   stm := TFileStream.Create( fname+RESPONSE_EXT, fmOpenRead);
   try
-    // save request data
+    // load request data
     proto  := CreateProtocol( protfact, stm, TRUE);
     client := TSkipTestService.TClient.Create( proto, nil);
     cliRef := client as IUnknown;
@@ -191,12 +197,16 @@
 procedure Test( protfact : IProtocolFactory; fname : string);
 begin
   // try to read an existing request
+  Writeln;
+  Writeln('Reading data file '+fname);
   if FileExists( fname + REQUEST_EXT) then begin
     ProcessFile( protfact, fname);
     ReadResponse( protfact, fname);
   end;
 
   // create a new request and try to process
+  Writeln;
+  Writeln('Writing data file '+fname);
   CreateRequest( protfact, fname);
   ProcessFile( protfact, fname);
   ReadResponse( protfact, fname);
@@ -204,8 +214,9 @@
 
 
 const
-  FILE_BINARY = 'pingpong.bin';
-  FILE_JSON   = 'pingpong.json';
+  FILE_BINARY  = 'pingpong.bin';
+  FILE_JSON    = 'pingpong.json';
+  FILE_COMPACT = 'pingpong.compact';
 begin
   try
     Writeln( 'Delphi SkipTest '+IntToStr(Tskiptest_version_2Constants.SKIPTESTSERVICE_VERSION)+' using '+Thrift.Version);
@@ -219,6 +230,10 @@
     Test( TJSONProtocolImpl.TFactory.Create,   FILE_JSON);
 
     Writeln;
+    Writeln('Compact protocol');
+    Test( TCompactProtocolImpl.TFactory.Create, FILE_COMPACT);
+
+    Writeln;
     Writeln('Test completed without errors.');
     Writeln;
     Write('Press ENTER to close ...');  Readln;