The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 1,860 other subscribers

In `System.SysUtils`, `class function TCardinalHelper.Parse` throws errors for valid Cardinal values

Posted by jpluimers on 2016/10/05

Oh nice System.SysUtils.TCardinalHelper.Parse:

class function TCardinalHelper.Parse(const S: string): Cardinal;
begin
  Result := StrToInt(S);
end;

Which means you get this nice EConvertError with message ''4294967295' is not a valid integer value'. with this simple test (which doesn’t even reach the Assert):

uses
  System.SysUtils;

procedure Cardinal_Parse_High_Cardinal_Succeeds();
var
  Expected: Cardinal;
  Value: string;
  Actual: Cardinal;
begin
  Expected := High(Cardinal);
  Value := Expected.ToString();
  Actual := Cardinal.Parse(Value);
  Assert(Expected = Actual);
end;

So I write some unit tests (see below) of which helpers for these types fail in one way or the other:

  • Cardinal
  • NativeUInt
  • Single
  • Double
  • Extended

These work for the boundary cases:

  • SmallInt
  • ShortInt
  • Integer
  • Int64
  • NativeInt
  • Byte
  • Word
  • UInt64
  • Boolean
  • ByteBool
  • WordBool
  • LongBool

 

–jeroen

via: Oh nice, in System.SysUtils: “` class function TCardinalHelper.Parse(const…


unit SysUtilsParseTests;
interface
uses
DUnitX.TestFramework;
type
[TestFixture]
TSmallIntParseTests = class(TObject)
strict private
type
TNumber = SmallInt;
public
[Test]
procedure ParseMaxValueSucceeds;
[Test]
procedure ParseMinValueSucceeds;
end;
type
[TestFixture]
TShortIntParseTests = class(TObject)
strict private
type
TNumber = ShortInt;
public
[Test]
procedure ParseMaxValueSucceeds;
[Test]
procedure ParseMinValueSucceeds;
end;
type
[TestFixture]
TIntegerParseTests = class(TObject)
strict private
type
TNumber = Integer;
public
[Test]
procedure ParseMaxValueSucceeds;
[Test]
procedure ParseMinValueSucceeds;
end;
type
[TestFixture]
TInt64ParseTests = class(TObject)
strict private
type
TNumber = Int64;
public
[Test]
procedure ParseMaxValueSucceeds;
[Test]
procedure ParseMinValueSucceeds;
end;
type
[TestFixture]
TNativeIntParseTests = class(TObject)
strict private
type
TNumber = NativeInt;
public
[Test]
procedure ParseMaxValueSucceeds;
[Test]
procedure ParseMinValueSucceeds;
end;
type
[TestFixture]
TByteParseTests = class(TObject)
strict private
type
TNumber = Byte;
public
[Test]
procedure ParseMaxValueSucceeds;
[Test]
procedure ParseMinValueSucceeds;
end;
type
[TestFixture]
TWordParseTests = class(TObject)
strict private
type
TNumber = Word;
public
[Test]
procedure ParseMaxValueSucceeds;
[Test]
procedure ParseMinValueSucceeds;
end;
type
[TestFixture]
TCardinalParseTests = class(TObject)
strict private
type
TNumber = Cardinal;
public
[Test]
procedure ParseMaxValueSucceeds;
[Test]
procedure ParseMinValueSucceeds;
end;
type
[TestFixture]
TUInt64ParseTests = class(TObject)
strict private
type
TNumber = UInt64;
public
[Test]
procedure ParseMaxValueSucceeds;
[Test]
procedure ParseMinValueSucceeds;
end;
type
[TestFixture]
TNativeUIntParseTests = class(TObject)
strict private
type
TNumber = NativeUInt;
public
[Test]
procedure ParseMaxValueSucceeds;
[Test]
procedure ParseMinValueSucceeds;
end;
type
[TestFixture]
TBooleanParseTests = class(TObject)
strict private
type
TNumber = Boolean;
public
[Test]
procedure ParseHighSucceeds;
[Test]
procedure ParseLowSucceeds;
end;
type
[TestFixture]
TByteBoolParseTests = class(TObject)
strict private
type
TNumber = ByteBool;
public
[Test]
procedure ParseHighSucceeds;
[Test]
procedure ParseLowSucceeds;
end;
type
[TestFixture]
TWordBoolParseTests = class(TObject)
strict private
type
TNumber = WordBool;
public
[Test]
procedure ParseHighSucceeds;
[Test]
procedure ParseLowSucceeds;
end;
type
[TestFixture]
TLongBoolParseTests = class(TObject)
strict private
type
TNumber = LongBool;
public
[Test]
procedure ParseHighSucceeds;
[Test]
procedure ParseLowSucceeds;
end;
type
[TestFixture]
TSingleParseTests = class(TObject)
strict private
type
TNumber = Single;
public
[Test]
procedure ParseMaxValueSucceeds;
[Test]
procedure ParseMinValueSucceeds;
end;
type
[TestFixture]
TDoubleParseTests = class(TObject)
strict private
type
TNumber = Double;
public
[Test]
procedure ParseMaxValueSucceeds;
[Test]
procedure ParseMinValueSucceeds;
end;
type
[TestFixture]
TExtendedParseTests = class(TObject)
strict private
type
TNumber = Extended;
public
[Test]
procedure ParseMaxValueSucceeds;
[Test]
procedure ParseMinValueSucceeds;
end;
implementation
uses
System.SysConst,
System.SysUtils;
procedure Cardinal_Parse_High_Cardinal_Succeeds();
var
Expected: Cardinal;
Value: string;
Actual: Cardinal;
begin
Expected := High(Cardinal);
Value := Expected.ToString();
Actual := Cardinal.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
{ TSmallIntParseTests }
procedure TSmallIntParseTests.ParseMaxValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MaxValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
procedure TSmallIntParseTests.ParseMinValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MinValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
{ TShortIntParseTests }
procedure TShortIntParseTests.ParseMaxValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MaxValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
procedure TShortIntParseTests.ParseMinValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MinValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
{ TIntegerParseTests }
procedure TIntegerParseTests.ParseMaxValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MaxValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
procedure TIntegerParseTests.ParseMinValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MinValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
{ TInt64ParseTests }
procedure TInt64ParseTests.ParseMaxValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MaxValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
procedure TInt64ParseTests.ParseMinValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MinValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
{ TNativeIntParseTests }
procedure TNativeIntParseTests.ParseMaxValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MaxValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
procedure TNativeIntParseTests.ParseMinValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MinValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
{ TByteParseTests }
procedure TByteParseTests.ParseMaxValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MaxValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
procedure TByteParseTests.ParseMinValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MinValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
{ TWordParseTests }
procedure TWordParseTests.ParseMaxValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MaxValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
procedure TWordParseTests.ParseMinValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MinValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
{ TCardinalParseTests }
procedure TCardinalParseTests.ParseMaxValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MaxValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
procedure TCardinalParseTests.ParseMinValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MinValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
{ TUInt64ParseTests }
procedure TUInt64ParseTests.ParseMaxValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MaxValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
procedure TUInt64ParseTests.ParseMinValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MinValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
{ TNativeUIntParseTests }
procedure TNativeUIntParseTests.ParseMaxValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MaxValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
procedure TNativeUIntParseTests.ParseMinValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MinValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
{ TBooleanParseTests }
procedure TBooleanParseTests.ParseHighSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := High(TNumber);
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
procedure TBooleanParseTests.ParseLowSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := Low(TNumber);
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
{ TByteBoolParseTests }
procedure TByteBoolParseTests.ParseHighSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := High(TNumber);
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
procedure TByteBoolParseTests.ParseLowSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := Low(TNumber);
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
{ TWordBoolParseTests }
procedure TWordBoolParseTests.ParseHighSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := High(TNumber);
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
procedure TWordBoolParseTests.ParseLowSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := Low(TNumber);
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
{ TLongBoolParseTests }
procedure TLongBoolParseTests.ParseHighSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := High(TNumber);
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
procedure TLongBoolParseTests.ParseLowSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := Low(TNumber);
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
{ TSingleParseTests }
procedure TSingleParseTests.ParseMaxValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MaxValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
procedure TSingleParseTests.ParseMinValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MinValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
{ TDoubleParseTests }
procedure TDoubleParseTests.ParseMaxValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MaxValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
procedure TDoubleParseTests.ParseMinValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MinValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
{ TExtendedParseTests }
procedure TExtendedParseTests.ParseMaxValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MaxValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
procedure TExtendedParseTests.ParseMinValueSucceeds;
var
Expected: TNumber;
Value: string;
Actual: TNumber;
begin
Expected := TNumber.MinValue;
Value := Expected.ToString();
Actual := TNumber.Parse(Value);
Assert.AreEqual(Expected, Actual);
end;
initialization
TDUnitX.RegisterTestFixture(TSmallIntParseTests);
TDUnitX.RegisterTestFixture(TShortIntParseTests);
TDUnitX.RegisterTestFixture(TIntegerParseTests);
TDUnitX.RegisterTestFixture(TInt64ParseTests);
TDUnitX.RegisterTestFixture(TNativeIntParseTests);
TDUnitX.RegisterTestFixture(TByteParseTests);
TDUnitX.RegisterTestFixture(TWordParseTests);
TDUnitX.RegisterTestFixture(TCardinalParseTests);
TDUnitX.RegisterTestFixture(TUInt64ParseTests);
TDUnitX.RegisterTestFixture(TNativeUIntParseTests);
TDUnitX.RegisterTestFixture(TBooleanParseTests);
TDUnitX.RegisterTestFixture(TByteBoolParseTests);
TDUnitX.RegisterTestFixture(TWordBoolParseTests);
TDUnitX.RegisterTestFixture(TLongBoolParseTests);
TDUnitX.RegisterTestFixture(TSingleParseTests);
TDUnitX.RegisterTestFixture(TDoubleParseTests);
TDUnitX.RegisterTestFixture(TExtendedParseTests);
end.


DUnitX – [SysUtilsParseMethodsFailWithBoundaryValuesProject.exe] – Starting Tests.
.E.E.E.E………………………..F.F………E………..E……
Tests Found : 34
Tests Ignored : 0
Tests Passed : 26
Tests Leaked : 0
Tests Failed : 2
Tests Errored : 6
Failing Tests
SysUtilsParseTests.TExtendedParseTests.ParseMaxValueSucceeds
Message: Expected 1,18973149535723E4932 but got 1,18973149535723E4932
SysUtilsParseTests.TExtendedParseTests.ParseMinValueSucceeds
Message: Expected -1,18973149535723E4932 but got -1,18973149535723E4932
Tests With Errors
SysUtilsParseTests.TSingleParseTests.ParseMaxValueSucceeds
Message: '3,40282346638529E38' is not a valid floating point value
SysUtilsParseTests.TSingleParseTests.ParseMinValueSucceeds
Message: '-3,40282346638529E38' is not a valid floating point value
SysUtilsParseTests.TDoubleParseTests.ParseMaxValueSucceeds
Message: '1,79769313486232E308' is not a valid floating point value
SysUtilsParseTests.TDoubleParseTests.ParseMinValueSucceeds
Message: '-1,79769313486232E308' is not a valid floating point value
SysUtilsParseTests.TCardinalParseTests.ParseMaxValueSucceeds
Message: '4294967295' is not a valid integer value
SysUtilsParseTests.TNativeUIntParseTests.ParseMaxValueSucceeds
Message: '4294967295' is not a valid integer value
Done.. press <Enter> key to quit.

5 Responses to “In `System.SysUtils`, `class function TCardinalHelper.Parse` throws errors for valid Cardinal values”

  1. If you look at the code for TCardinalHelper.Parse, it is not really surprise that anything above MaxInt gets rejected:

    class function TCardinalHelper.Parse(const S: string): Cardinal;
    begin
      Result := StrToInt(S);
    end;
    
  2. Wodzu's avatar

    Wodzu said

    Amazing, Embarcadero haven’t wrote tests for their own stuff… good job Jeroen!

  3. Reported to QualityPortal as RSP-16026 “Parse() methods of Integral helper classes raise errors for valid values”, https://quality.embarcadero.com/browse/RSP-16026

Leave a reply to Rudy Velthuis Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.