Added: unit tests for hashes
Added: Clear method Fixed: bug in key storage and comparison
This commit is contained in:
parent
6628708958
commit
6429b349c3
@ -1,4 +1,4 @@
|
|||||||
unit UBits;
|
unit BitsTest;
|
||||||
|
|
||||||
interface
|
interface
|
||||||
uses
|
uses
|
||||||
@ -20,7 +20,7 @@ uses
|
|||||||
X2UtBits;
|
X2UtBits;
|
||||||
|
|
||||||
const
|
const
|
||||||
BitsTest = [bit1, bit2, bit4, bit7];
|
Bits = [bit1, bit2, bit4, bit7];
|
||||||
BitsValue = 150;
|
BitsValue = 150;
|
||||||
BitsString = '10010110';
|
BitsString = '10010110';
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ var
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
bValue := BitsValue;
|
bValue := BitsValue;
|
||||||
Check(eBits = BitsTest, 'Bits do not match the value!');
|
Check(eBits = Bits, 'Bits do not match the value!');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TBitsTest.testSet;
|
procedure TBitsTest.testSet;
|
||||||
@ -42,7 +42,7 @@ var
|
|||||||
eBits: T8Bits absolute bValue;
|
eBits: T8Bits absolute bValue;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
eBits := BitsTest;
|
eBits := Bits;
|
||||||
Check(bValue = BitsValue, 'Value does not match the bits!');
|
Check(bValue = BitsValue, 'Value does not match the bits!');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ var
|
|||||||
sValue: String;
|
sValue: String;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
eBits := BitsTest;
|
eBits := Bits;
|
||||||
sValue := BitsToString(eBits, bs8);
|
sValue := BitsToString(eBits, bs8);
|
||||||
|
|
||||||
Check(sValue = BitsString, 'Bits do not match the string!');
|
Check(sValue = BitsString, 'Bits do not match the string!');
|
||||||
@ -82,7 +82,7 @@ begin
|
|||||||
sValue := BitsString;
|
sValue := BitsString;
|
||||||
eBits := StringToBits(sValue);
|
eBits := StringToBits(sValue);
|
||||||
|
|
||||||
Check(eBits = BitsTest, 'String does not match the bits!');
|
Check(eBits = Bits, 'String does not match the bits!');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
217
UnitTests/Units/HashesTest.pas
Normal file
217
UnitTests/Units/HashesTest.pas
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
unit HashesTest;
|
||||||
|
|
||||||
|
interface
|
||||||
|
uses
|
||||||
|
TestFramework,
|
||||||
|
X2UtHashes;
|
||||||
|
|
||||||
|
type
|
||||||
|
THashesTest = class(TTestCase)
|
||||||
|
private
|
||||||
|
FHash: TX2CustomHash;
|
||||||
|
protected
|
||||||
|
procedure TearDown(); override;
|
||||||
|
procedure FillTestItems(); virtual; abstract;
|
||||||
|
published
|
||||||
|
procedure testSet(); virtual; abstract;
|
||||||
|
procedure testGet(); virtual; abstract;
|
||||||
|
procedure testClear();
|
||||||
|
procedure testDelete(); virtual; abstract;
|
||||||
|
procedure testIterate(); virtual; abstract;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Two test cases involving all value managers.
|
||||||
|
// This should be sufficient for a realistic scenario.
|
||||||
|
THashesSITest = class(THashesTest)
|
||||||
|
private
|
||||||
|
function GetHash(): TX2SIHash;
|
||||||
|
|
||||||
|
property Hash: TX2SIHash read GetHash;
|
||||||
|
protected
|
||||||
|
procedure SetUp(); override;
|
||||||
|
procedure FillTestItems(); override;
|
||||||
|
published
|
||||||
|
procedure testSet(); override;
|
||||||
|
procedure testGet(); override;
|
||||||
|
procedure testDelete(); override;
|
||||||
|
procedure testIterate(); override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
THashesPOTest = class(THashesTest)
|
||||||
|
private
|
||||||
|
function GetHash(): TX2POHash;
|
||||||
|
|
||||||
|
property Hash: TX2POHash read GetHash;
|
||||||
|
protected
|
||||||
|
procedure SetUp(); override;
|
||||||
|
procedure FillTestItems(); override;
|
||||||
|
published
|
||||||
|
procedure testSet(); override;
|
||||||
|
procedure testGet(); override;
|
||||||
|
procedure testDelete(); override;
|
||||||
|
procedure testIterate(); override;
|
||||||
|
end;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
uses
|
||||||
|
SysUtils;
|
||||||
|
|
||||||
|
type
|
||||||
|
TObject0 = class(TObject);
|
||||||
|
TObject1 = class(TObject);
|
||||||
|
TObject2 = class(TObject);
|
||||||
|
|
||||||
|
|
||||||
|
{ THashesTest }
|
||||||
|
procedure THashesTest.TearDown;
|
||||||
|
begin
|
||||||
|
FreeAndNil(FHash);
|
||||||
|
|
||||||
|
inherited;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure THashesTest.testClear;
|
||||||
|
begin
|
||||||
|
FillTestItems();
|
||||||
|
FHash.Clear();
|
||||||
|
CheckEquals(0, FHash.Count);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ THashesSITest }
|
||||||
|
procedure THashesSITest.SetUp;
|
||||||
|
begin
|
||||||
|
inherited;
|
||||||
|
|
||||||
|
FHash := TX2SIHash.Create();
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure THashesSITest.FillTestItems;
|
||||||
|
begin
|
||||||
|
Hash['Key1'] := 1;
|
||||||
|
Hash['Key2'] := 2;
|
||||||
|
Hash['Key3'] := 3;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure THashesSITest.testSet;
|
||||||
|
begin
|
||||||
|
FillTestItems();
|
||||||
|
CheckEquals(3, Hash.Count);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure THashesSITest.testGet;
|
||||||
|
begin
|
||||||
|
FillTestItems();
|
||||||
|
CheckEquals(1, Hash['Key1']);
|
||||||
|
CheckEquals(2, Hash['Key2']);
|
||||||
|
CheckEquals(3, Hash['Key3']);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure THashesSITest.testDelete;
|
||||||
|
begin
|
||||||
|
FillTestItems();
|
||||||
|
Hash.Delete('Key2');
|
||||||
|
|
||||||
|
CheckEquals(2, Hash.Count);
|
||||||
|
CheckTrue(Hash.Exists('Key1'), 'Key1 does not exist!');
|
||||||
|
CheckFalse(Hash.Exists('Key2'), 'Key2 still exists!');
|
||||||
|
CheckTrue(Hash.Exists('Key3'), 'Key3 does not exist!');
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure THashesSITest.testIterate;
|
||||||
|
var
|
||||||
|
aPresent: array[1..3] of Boolean;
|
||||||
|
|
||||||
|
begin
|
||||||
|
FillTestItems();
|
||||||
|
FillChar(aPresent, SizeOf(aPresent), #0);
|
||||||
|
Hash.First();
|
||||||
|
while Hash.Next() do
|
||||||
|
if ((Hash.CurrentKey = 'Key1') and (Hash.CurrentValue = 1)) or
|
||||||
|
((Hash.CurrentKey = 'Key2') and (Hash.CurrentValue = 2)) or
|
||||||
|
((Hash.CurrentKey = 'Key3') and (Hash.CurrentValue = 3)) then
|
||||||
|
aPresent[Hash.CurrentValue] := True;
|
||||||
|
|
||||||
|
CheckTrue(aPresent[1], 'Key1 was not in the iteration!');
|
||||||
|
CheckTrue(aPresent[2], 'Key2 was not in the iteration!');
|
||||||
|
CheckTrue(aPresent[3], 'Key3 was not in the iteration!');
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function THashesSITest.GetHash(): TX2SIHash;
|
||||||
|
begin
|
||||||
|
Result := TX2SIHash(FHash);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ THashesPOTest }
|
||||||
|
procedure THashesPOTest.SetUp;
|
||||||
|
begin
|
||||||
|
inherited;
|
||||||
|
|
||||||
|
FHash := TX2POHash.Create(True);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure THashesPOTest.FillTestItems;
|
||||||
|
begin
|
||||||
|
Hash[Pointer(0)] := TObject0.Create();
|
||||||
|
Hash[Pointer(1)] := TObject1.Create();
|
||||||
|
Hash[Pointer(2)] := TObject2.Create();
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure THashesPOTest.testSet;
|
||||||
|
begin
|
||||||
|
FillTestItems();
|
||||||
|
CheckEquals(3, Hash.Count);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure THashesPOTest.testGet;
|
||||||
|
begin
|
||||||
|
FillTestItems();
|
||||||
|
CheckTrue(Hash[Pointer(0)] is TObject0);
|
||||||
|
CheckTrue(Hash[Pointer(1)] is TObject1);
|
||||||
|
CheckTrue(Hash[Pointer(2)] is TObject2);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure THashesPOTest.testDelete;
|
||||||
|
begin
|
||||||
|
FillTestItems();
|
||||||
|
Hash.Delete(Pointer(1));
|
||||||
|
|
||||||
|
CheckEquals(2, Hash.Count);
|
||||||
|
CheckTrue(Hash.Exists(Pointer(0)), 'Key1 does not exist!');
|
||||||
|
CheckFalse(Hash.Exists(Pointer(1)), 'Key2 still exists!');
|
||||||
|
CheckTrue(Hash.Exists(Pointer(2)), 'Key3 does not exist!');
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure THashesPOTest.testIterate;
|
||||||
|
var
|
||||||
|
aPresent: array[0..2] of Boolean;
|
||||||
|
|
||||||
|
begin
|
||||||
|
FillTestItems();
|
||||||
|
FillChar(aPresent, SizeOf(aPresent), #0);
|
||||||
|
Hash.First();
|
||||||
|
while Hash.Next() do
|
||||||
|
if ((Hash.CurrentKey = Pointer(0)) and (Hash.CurrentValue is TObject0)) or
|
||||||
|
((Hash.CurrentKey = Pointer(1)) and (Hash.CurrentValue is TObject1)) or
|
||||||
|
((Hash.CurrentKey = Pointer(2)) and (Hash.CurrentValue is TObject2)) then
|
||||||
|
aPresent[Integer(Hash.CurrentKey)] := True;
|
||||||
|
|
||||||
|
CheckTrue(aPresent[0], 'Key1 was not in the iteration!');
|
||||||
|
CheckTrue(aPresent[1], 'Key2 was not in the iteration!');
|
||||||
|
CheckTrue(aPresent[2], 'Key3 was not in the iteration!');
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function THashesPOTest.GetHash(): TX2POHash;
|
||||||
|
begin
|
||||||
|
Result := TX2POHash(FHash);
|
||||||
|
end;
|
||||||
|
|
||||||
|
initialization
|
||||||
|
RegisterTest('Hashes', THashesSITest.Suite);
|
||||||
|
RegisterTest('Hashes', THashesPOTest.Suite);
|
||||||
|
|
||||||
|
end.
|
@ -105,10 +105,6 @@ HostApplication=
|
|||||||
Launcher=
|
Launcher=
|
||||||
UseLauncher=0
|
UseLauncher=0
|
||||||
DebugCWD=
|
DebugCWD=
|
||||||
[Language]
|
|
||||||
ActiveLang=
|
|
||||||
ProjectLang=
|
|
||||||
RootDir=
|
|
||||||
[Version Info]
|
[Version Info]
|
||||||
IncludeVerInfo=0
|
IncludeVerInfo=0
|
||||||
AutoIncBuild=0
|
AutoIncBuild=0
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
program X2UtUnitTests;
|
program X2UtUnitTests;
|
||||||
|
|
||||||
uses
|
uses
|
||||||
|
MemCheck,
|
||||||
TestFramework,
|
TestFramework,
|
||||||
GUITestRunner,
|
GUITestRunner,
|
||||||
UBits in 'Units\UBits.pas',
|
BitsTest in 'Units\BitsTest.pas',
|
||||||
UTrees in 'Units\UTrees.pas';
|
HashesTest in 'Units\HashesTest.pas';
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
MemChk();
|
||||||
RunRegisteredTests();
|
RunRegisteredTests();
|
||||||
end.
|
end.
|
||||||
|
|
@ -194,6 +194,8 @@ type
|
|||||||
constructor Create(); virtual;
|
constructor Create(); virtual;
|
||||||
destructor Destroy(); override;
|
destructor Destroy(); override;
|
||||||
|
|
||||||
|
procedure Clear();
|
||||||
|
|
||||||
procedure First();
|
procedure First();
|
||||||
function Next(): Boolean;
|
function Next(): Boolean;
|
||||||
|
|
||||||
@ -713,7 +715,7 @@ end;
|
|||||||
function TX2CustomHashManager.ToPointer(const AValue: Pointer;
|
function TX2CustomHashManager.ToPointer(const AValue: Pointer;
|
||||||
const ASize: Cardinal): Pointer;
|
const ASize: Cardinal): Pointer;
|
||||||
begin
|
begin
|
||||||
Result := Pointer(AValue);
|
Result := Pointer(AValue^);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TX2CustomHashManager.ToValue(const AData: Pointer;
|
function TX2CustomHashManager.ToValue(const AData: Pointer;
|
||||||
@ -726,7 +728,7 @@ end;
|
|||||||
function TX2CustomHashManager.Compare(const AData: Pointer; const AValue: Pointer;
|
function TX2CustomHashManager.Compare(const AData: Pointer; const AValue: Pointer;
|
||||||
const ASize: Cardinal): Boolean;
|
const ASize: Cardinal): Boolean;
|
||||||
begin
|
begin
|
||||||
Result := (Pointer(AValue) = AData);
|
Result := (Pointer(AValue^) = AData);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -735,7 +737,7 @@ end;
|
|||||||
========================================}
|
========================================}
|
||||||
function TX2HashPointerManager.ToPointer(const AValue: Pointer): Pointer;
|
function TX2HashPointerManager.ToPointer(const AValue: Pointer): Pointer;
|
||||||
begin
|
begin
|
||||||
Result := ToPointer(AValue, SizeOf(Pointer));
|
Result := ToPointer(@AValue, SizeOf(Pointer));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TX2HashPointerManager.ToValue(const AData: Pointer): Pointer;
|
function TX2HashPointerManager.ToValue(const AData: Pointer): Pointer;
|
||||||
@ -749,7 +751,7 @@ end;
|
|||||||
========================================}
|
========================================}
|
||||||
function TX2HashIntegerManager.ToPointer(const AValue: Integer): Pointer;
|
function TX2HashIntegerManager.ToPointer(const AValue: Integer): Pointer;
|
||||||
begin
|
begin
|
||||||
Result := ToPointer(Pointer(AValue), SizeOf(Integer));
|
Result := ToPointer(@AValue, SizeOf(Integer));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TX2HashIntegerManager.ToValue(const AData: Pointer): Integer;
|
function TX2HashIntegerManager.ToValue(const AData: Pointer): Integer;
|
||||||
@ -771,7 +773,7 @@ end;
|
|||||||
|
|
||||||
function TX2HashObjectManager.ToPointer(const AValue: TObject): Pointer;
|
function TX2HashObjectManager.ToPointer(const AValue: TObject): Pointer;
|
||||||
begin
|
begin
|
||||||
Result := ToPointer(Pointer(AValue), SizeOf(Integer));
|
Result := ToPointer(@AValue, SizeOf(Integer));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TX2HashObjectManager.ToValue(const AData: Pointer): TObject;
|
function TX2HashObjectManager.ToValue(const AData: Pointer): TObject;
|
||||||
@ -871,42 +873,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TX2CustomHash.Destroy();
|
destructor TX2CustomHash.Destroy();
|
||||||
procedure DestroyBucket(const ABucket: PX2HashBucket);
|
|
||||||
var
|
|
||||||
iItem: Integer;
|
|
||||||
pNext: PX2HashValue;
|
|
||||||
pValue: PX2HashValue;
|
|
||||||
|
|
||||||
begin
|
|
||||||
for iItem := Pred(LeafSize) downto 0 do
|
|
||||||
if ABucket^.Items[iItem] <> nil then
|
|
||||||
case ABucket^.Items[iItem].ID of
|
|
||||||
HIDBucket:
|
|
||||||
DestroyBucket(PX2HashBucket(ABucket^.Items[iItem]));
|
|
||||||
HIDValue:
|
|
||||||
begin
|
|
||||||
pValue := PX2HashValue(ABucket^.Items[iItem]);
|
|
||||||
repeat
|
|
||||||
FKeyManager.Finalize(pValue^.Key);
|
|
||||||
FValueManager.Finalize(pValue^.Value);
|
|
||||||
|
|
||||||
pNext := pValue^.Next;
|
|
||||||
FreeMem(pValue, SizeOf(TX2HashValue));
|
|
||||||
pValue := pNext;
|
|
||||||
until pValue = nil;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
FreeMem(ABucket, SizeOf(TX2HashBucket));
|
|
||||||
end;
|
|
||||||
|
|
||||||
begin
|
begin
|
||||||
if Assigned(FRoot) then
|
Clear();
|
||||||
begin
|
|
||||||
DestroyBucket(FRoot);
|
|
||||||
FRoot := nil;
|
|
||||||
end;
|
|
||||||
|
|
||||||
FreeAndNil(FValueManager);
|
FreeAndNil(FValueManager);
|
||||||
FreeAndNil(FKeyManager);
|
FreeAndNil(FKeyManager);
|
||||||
FreeAndNil(FCursor);
|
FreeAndNil(FCursor);
|
||||||
@ -1134,6 +1102,47 @@ begin
|
|||||||
AAllowCreate);
|
AAllowCreate);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TX2CustomHash.Clear();
|
||||||
|
procedure DestroyBucket(const ABucket: PX2HashBucket);
|
||||||
|
var
|
||||||
|
iItem: Integer;
|
||||||
|
pNext: PX2HashValue;
|
||||||
|
pValue: PX2HashValue;
|
||||||
|
|
||||||
|
begin
|
||||||
|
for iItem := Pred(LeafSize) downto 0 do
|
||||||
|
if ABucket^.Items[iItem] <> nil then
|
||||||
|
case ABucket^.Items[iItem].ID of
|
||||||
|
HIDBucket:
|
||||||
|
DestroyBucket(PX2HashBucket(ABucket^.Items[iItem]));
|
||||||
|
HIDValue:
|
||||||
|
begin
|
||||||
|
pValue := PX2HashValue(ABucket^.Items[iItem]);
|
||||||
|
repeat
|
||||||
|
FKeyManager.Finalize(pValue^.Key);
|
||||||
|
FValueManager.Finalize(pValue^.Value);
|
||||||
|
|
||||||
|
pNext := pValue^.Next;
|
||||||
|
FreeMem(pValue, SizeOf(TX2HashValue));
|
||||||
|
pValue := pNext;
|
||||||
|
until pValue = nil;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
FreeMem(ABucket, SizeOf(TX2HashBucket));
|
||||||
|
end;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if FRoot <> nil then
|
||||||
|
begin
|
||||||
|
DestroyBucket(FRoot);
|
||||||
|
FCount := 0;
|
||||||
|
FRoot := nil;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
function TX2CustomHash.Exists(const AKey: Pointer;
|
function TX2CustomHash.Exists(const AKey: Pointer;
|
||||||
const ASize: Cardinal): Boolean;
|
const ASize: Cardinal): Boolean;
|
||||||
begin
|
begin
|
||||||
|
Loading…
Reference in New Issue
Block a user