This is an automated email from the ASF dual-hosted git repository.
jensg pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/thrift.git
The following commit(s) were added to refs/heads/master by this push:
new ec57271 THRIFT-5251 StringUtils<T>.ToString() raises an exception for
enum values outside range Client: Delphi Patch: Jens Geyer
ec57271 is described below
commit ec57271d5b90ba06eaad99dda26dc0af9bd2af71
Author: Jens Geyer <[email protected]>
AuthorDate: Mon Jul 13 21:15:31 2020 +0200
THRIFT-5251 StringUtils<T>.ToString() raises an exception for enum values
outside range
Client: Delphi
Patch: Jens Geyer
---
lib/delphi/src/Thrift.Utils.pas | 12 +++
lib/delphi/test/typeregistry/Test.EnumToString.pas | 93 ++++++++++++++++++++++
...{TestTypeRegistry.dpr => Test.TypeRegistry.pas} | 40 +++++-----
lib/delphi/test/typeregistry/TestTypeRegistry.dpr | 57 +++----------
4 files changed, 136 insertions(+), 66 deletions(-)
diff --git a/lib/delphi/src/Thrift.Utils.pas b/lib/delphi/src/Thrift.Utils.pas
index bc9b460..bfd020e 100644
--- a/lib/delphi/src/Thrift.Utils.pas
+++ b/lib/delphi/src/Thrift.Utils.pas
@@ -313,6 +313,7 @@ begin
pType := PTypeInfo(TypeInfo(T));
if Assigned(pType) then begin
case pType^.Kind of
+
tkInterface : begin
pIntf := PInterface(@value);
if Supports( pIntf^, ISupportsToString, stos) then begin
@@ -320,6 +321,17 @@ begin
Exit;
end;
end;
+
+ tkEnumeration : begin
+ case SizeOf(value) of
+ 1 : begin result := EnumUtils<T>.ToString( PShortInt(@value)^);
Exit; end;
+ 2 : begin result := EnumUtils<T>.ToString( PSmallInt(@value)^);
Exit; end;
+ 4 : begin result := EnumUtils<T>.ToString( PLongInt(@value)^);
Exit; end;
+ else
+ ASSERT(FALSE); // in theory, this should not happen
+ end;
+ end;
+
end;
end;
diff --git a/lib/delphi/test/typeregistry/Test.EnumToString.pas
b/lib/delphi/test/typeregistry/Test.EnumToString.pas
new file mode 100644
index 0000000..a3d095d
--- /dev/null
+++ b/lib/delphi/test/typeregistry/Test.EnumToString.pas
@@ -0,0 +1,93 @@
+(*
+ * 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 Test.EnumToString;
+
+interface
+
+uses
+ Classes, SysUtils,
+ Thrift.Utils,
+ DebugProtoTest;
+
+
+procedure RunTest;
+
+
+implementation
+
+{$SCOPEDENUMS ON}
+
+type
+ TIrregularEnum = ( // has gaps and/or does not start at zero
+ FiveHundretOne = 501,
+ FiveHundretTwo = 502,
+ FiveHundretFive = 505
+ );
+
+ TRegularEnum = ( // starts at zero, no gaps, no duplicates
+ One,
+ Two,
+ Three
+ );
+
+
+procedure IrregularEnumToString;
+// TIrregularEnum does not run from 0 to N, so we don't have RTTI for it
+// Search for "E2134: Type has no typeinfo" message to get the details
+// Unfortunately, this also means that StringUtils<T>.ToString() does not work
for enums w/o RTTI
+var value : Integer;
+ sA,sB : string;
+begin
+ for value := Pred(Ord(Low(TIrregularEnum))) to
Succ(Ord(High(TIrregularEnum))) do begin
+ sA := EnumUtils<TIrregularEnum>.ToString(Ord(value)); //
much more reliable
+ sB := StringUtils<TIrregularEnum>.ToString(TIrregularEnum(value)); //
does not really work
+ WriteLn( '- TIrregularEnum('+IntToStr(value)+'): EnumUtils => ',sA,',
StringUtils => ', sB);
+ end;
+end;
+
+
+procedure RegularEnumToString;
+// Regular enums have RTTI and work like a charm
+var value : Integer;
+ sA,sB : string;
+begin
+ for value := Pred(Ord(Low(TRegularEnum))) to Succ(Ord(High(TRegularEnum)))
do begin
+ sA := EnumUtils<TRegularEnum>.ToString(Ord(value));
+ sB := StringUtils<TRegularEnum>.ToString(TRegularEnum(value));
+ if sA = sB // both are expected to work with regular enums
+ then WriteLn( '- TRegularEnum('+IntToStr(value)+'): ',sA,' = ', sB)
+ else raise Exception.Create( 'Test failed: '+sA+' <> '+sB);
+ end;
+end;
+
+
+procedure RunTest;
+begin
+ Writeln('Testing enum utils ...');
+
+ RegularEnumToString;
+ IrregularEnumToString;
+
+ Writeln;
+end;
+
+
+end.
+
diff --git a/lib/delphi/test/typeregistry/TestTypeRegistry.dpr
b/lib/delphi/test/typeregistry/Test.TypeRegistry.pas
similarity index 68%
copy from lib/delphi/test/typeregistry/TestTypeRegistry.dpr
copy to lib/delphi/test/typeregistry/Test.TypeRegistry.pas
index 31c0fb2..96e30d8 100644
--- a/lib/delphi/test/typeregistry/TestTypeRegistry.dpr
+++ b/lib/delphi/test/typeregistry/Test.TypeRegistry.pas
@@ -17,34 +17,31 @@
* under the License.
*)
-program TestTypeRegistry;
+unit Test.TypeRegistry;
-{$APPTYPE CONSOLE}
+interface
uses
- Classes, Windows, SysUtils, Generics.Collections, TypInfo,
- Thrift in '..\..\src\Thrift.pas',
- Thrift.Transport in '..\..\src\Thrift.Transport.pas',
- Thrift.Exception in '..\..\src\Thrift.Exception.pas',
- Thrift.Socket in '..\..\src\Thrift.Socket.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.Configuration in '..\..\src\Thrift.Configuration.pas',
- Thrift.Server in '..\..\src\Thrift.Server.pas',
- Thrift.Utils in '..\..\src\Thrift.Utils.pas',
- Thrift.Serializer in '..\..\src\Thrift.Serializer.pas',
- Thrift.Stream in '..\..\src\Thrift.Stream.pas',
- Thrift.WinHTTP in '..\..\src\Thrift.WinHTTP.pas',
- Thrift.TypeRegistry in '..\..\src\Thrift.TypeRegistry.pas',
+ Classes, SysUtils, TypInfo,
+ Thrift,
+ Thrift.TypeRegistry,
DebugProtoTest;
+
+procedure RunTest;
+
+
+implementation
+
+
type
Tester<T : IInterface> = class
public
class procedure Test;
end;
+
+
class procedure Tester<T>.Test;
var instance : T;
name : string;
@@ -59,8 +56,11 @@ begin
end;
end;
+
+procedure RunTest;
begin
- Writeln('Testing ...');
+ Writeln('Testing type registry ...');
+
Tester<IDoubles>.Test;
Tester<IOneOfEach>.Test;
Tester<IBonk>.Test;
@@ -85,7 +85,9 @@ begin
Tester<IBigFieldIdStruct>.Test;
Tester<IBreaksRubyCompactProtocol>.Test;
Tester<ITupleProtocolTestStruct>.Test;
- Writeln('Completed.');
+
+ Writeln;
+end;
end.
diff --git a/lib/delphi/test/typeregistry/TestTypeRegistry.dpr
b/lib/delphi/test/typeregistry/TestTypeRegistry.dpr
index 31c0fb2..2896bbf 100644
--- a/lib/delphi/test/typeregistry/TestTypeRegistry.dpr
+++ b/lib/delphi/test/typeregistry/TestTypeRegistry.dpr
@@ -37,56 +37,19 @@ uses
Thrift.Stream in '..\..\src\Thrift.Stream.pas',
Thrift.WinHTTP in '..\..\src\Thrift.WinHTTP.pas',
Thrift.TypeRegistry in '..\..\src\Thrift.TypeRegistry.pas',
- DebugProtoTest;
+ Thrift.Test, // in 'gen-delphi\Thrift.Test.pas',
+ Test.TypeRegistry,
+ Test.EnumToString;
-type
- Tester<T : IInterface> = class
- public
- class procedure Test;
- end;
-
-class procedure Tester<T>.Test;
-var instance : T;
- name : string;
-begin
- instance := TypeRegistry.Construct<T>;
- name := GetTypeName(TypeInfo(T));
- if instance <> nil
- then Writeln( name, ' = ok')
- else begin
- Writeln( name, ' = failed');
- raise Exception.Create( 'Test with '+name+' failed!');
- end;
-end;
begin
- Writeln('Testing ...');
- Tester<IDoubles>.Test;
- Tester<IOneOfEach>.Test;
- Tester<IBonk>.Test;
- Tester<INesting>.Test;
- Tester<IHolyMoley>.Test;
- Tester<IBackwards>.Test;
- Tester<IEmpty>.Test;
- Tester<IWrapper>.Test;
- Tester<IRandomStuff>.Test;
- Tester<IBase64>.Test;
- Tester<ICompactProtoTestStruct>.Test;
- Tester<ISingleMapTestStruct>.Test;
- Tester<IBlowUp>.Test;
- Tester<IReverseOrderStruct>.Test;
- Tester<IStructWithSomeEnum>.Test;
- Tester<ITestUnion>.Test;
- Tester<ITestUnionMinusStringField>.Test;
- Tester<IComparableUnion>.Test;
- Tester<IStructWithAUnion>.Test;
- Tester<IPrimitiveThenStruct>.Test;
- Tester<IStructWithASomemap>.Test;
- Tester<IBigFieldIdStruct>.Test;
- Tester<IBreaksRubyCompactProtocol>.Test;
- Tester<ITupleProtocolTestStruct>.Test;
- Writeln('Completed.');
-
+ try
+ Test.TypeRegistry.RunTest;
+ Test.EnumToString.RunTest;
+ Writeln('Completed.');
+ except
+ on e:Exception do Writeln(e.ClassName,': ',e.Message);
+ end;
end.