unit uGenericsTests; {$mode objfpc}{$H+} interface uses Classes, SysUtils, fpcunit, testregistry, uutlGenerics; type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TTestObject = class private fData: Integer; fOnDestroy: TNotifyEvent; public property Data: Integer read fData; constructor Create(const aData: Integer; const aOnDestroy: TNotifyEvent); destructor Destroy; override; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TutlListTest = class(TTestCase) private type TTestList = specialize TutlList; private fList: TTestList; fTestObjs: array[0..9] of TTestObject; procedure TestObjectDestroy(aSender: TObject); protected procedure SetUp; override; procedure TearDown; override; published procedure GetItem; procedure SetItem; procedure Add; procedure Insert; procedure IndexOf; procedure Exchange; procedure Move; procedure Delete; procedure Extract; procedure Remove; procedure Clear; procedure First; procedure PushFirst; procedure PopFirst; procedure Last; procedure PushLast; procedure PopLast; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TutlHashSetTest = class(TTestCase) private type TTestObjComparer = specialize TutlEventComparer; TTestHashSet = specialize TutlCustomHashSet; private fHashSet: TTestHashSet; fTestObjs: array[0..9] of TTestObject; procedure TestObjectDestroy(aSender: TObject); protected procedure SetUp; override; procedure TearDown; override; public function CompareTestObjects(const i1, i2: TTestObject): Integer; published procedure Add; procedure Contains; procedure IndexOf; procedure Remove; procedure Delete; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TutlMapTest = class(TTestCase) private type TTestMap = specialize TutlMap; private fMap: TTestMap; fTestObjs: array[0..9] of TTestObject; fLastRemovedIndex: Integer; procedure TestObjectDestroy(aSender: TObject); function Key(const aIndex: Integer): Integer; function CreateObj: TTestObject; protected procedure SetUp; override; procedure TearDown; override; procedure AddExistingKey; published procedure GetValue; procedure SetValue; procedure GetValueAt; procedure SetValueAt; procedure GetKey; procedure Add; procedure IndexOf; procedure Delete; end; implementation //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TTestObject/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TTestObject.Create(const aData: Integer; const aOnDestroy: TNotifyEvent); begin inherited Create; fData := aData; fOnDestroy := aOnDestroy; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// destructor TTestObject.Destroy; begin if Assigned(fOnDestroy) then fOnDestroy(self); inherited Destroy; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TutlListTest////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListTest.TestObjectDestroy(aSender: TObject); var i: Integer; begin for i := Low(fTestObjs) to High(fTestObjs) do if (fTestObjs[i] = aSender) then fTestObjs[i] := nil; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListTest.SetUp; var i: Integer; begin inherited SetUp; fList := TTestList.Create(true); for i := Low(fTestObjs) to High(fTestObjs) do begin fTestObjs[i] := TTestObject.Create(i, @TestObjectDestroy); fList.Add(fTestObjs[i]); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListTest.TearDown; begin FreeAndNil(fList); inherited TearDown; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListTest.GetItem; var i: Integer; begin for i := Low(fTestObjs) to High(fTestObjs) do AssertTrue(fTestObjs[i] = fList[i - Low(fTestObjs)]); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListTest.SetItem; var o1, o2: TTestObject; begin o1 := fList[3]; o2 := fList[6]; fList[3] := o2; fList[6] := o1; AssertTrue(fList[6] = o1); AssertTrue(fList[3] = o2); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListTest.Add; var t: TTestObject; c: Integer; begin t := TTestObject.Create(123456, @TestObjectDestroy); c := fList.Count; fList.Add(t); AssertEquals(c+1, fList.Count); AssertTrue(fList[c] = t); AssertTrue(fList.Last = t); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListTest.Insert; var t: TTestObject; c: Integer; begin t := TTestObject.Create(123456, @TestObjectDestroy); c := fList.Count; fList.Insert(3, t); AssertEquals(c+1, fList.Count); AssertTrue(fList[3] = t); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListTest.IndexOf; var i: Integer; begin for i := Low(fTestObjs) to High(fTestObjs) do AssertEquals(i - Low(fTestObjs), fList.IndexOf(fTestObjs[i])); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListTest.Exchange; var o1, o2: TTestObject; begin o1 := fList[3]; o2 := fList[7]; fList.Exchange(3, 7); AssertTrue(fList[3] = o2); AssertTrue(fList[7] = o1); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListTest.Move; begin fList.Move(3, 6); AssertTrue(fList[3] = fTestObjs[4]); AssertTrue(fList[4] = fTestObjs[5]); AssertTrue(fList[5] = fTestObjs[6]); AssertTrue(fList[6] = fTestObjs[3]); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListTest.Delete; begin fList.Delete(3); AssertTrue(fTestObjs[3] = nil); AssertEquals(Length(fTestObjs)-1, fList.Count); fList.OwnsObjects := false; fList.Delete(4); AssertTrue(fTestObjs[5] <> nil); AssertEquals(Length(fTestObjs)-2, fList.Count); AssertTrue(fList[4] = fTestObjs[6]); FreeAndNil(fTestObjs[5]); fList.OwnsObjects := true; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListTest.Extract; var o1, o2, o3: TTestObject; begin o1 := fList[1]; o2 := TTestObject.Create(1234, @TestObjectDestroy); o3 := fList.Extract(o1, o2); try AssertTrue(o1 = o3); AssertEquals(Length(fTestObjs)-1, fList.Count); AssertTrue(fTestObjs[1] <> nil); finally FreeAndNil(o1); FreeAndNil(o2); end; o1 := fList[1]; o2 := TTestObject.Create(1234, @TestObjectDestroy); o3 := fList.Extract(o2, o1); try AssertTrue(o1 = o3); AssertEquals(Length(fTestObjs)-1, fList.Count); finally FreeAndNil(o2); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListTest.Remove; var o1: TTestObject; i: Integer; begin o1 := fList[3]; i := fList.Remove(o1); AssertEquals(3, i); AssertEquals(Length(fTestObjs)-1, fList.Count); AssertTrue(fTestObjs[3] = nil); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListTest.Clear; var o: TTestObject; begin fList.Clear; AssertEquals(0, fList.Count); for o in fTestObjs do AssertTrue(o = nil); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListTest.First; begin AssertTrue(fTestObjs[Low(fTestObjs)] = fList.First); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListTest.PushFirst; var o1: TTestObject; begin o1 := TTestObject.Create(1234, @TestObjectDestroy); fList.PushFirst(o1); AssertEquals(Length(fTestObjs)+1, fList.Count); AssertTrue(fList.First = o1); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListTest.PopFirst; var o1: TTestObject; begin o1 := fList.PopFirst; AssertEquals(Length(fTestObjs)-1, fList.Count); AssertTrue(o1 = fTestObjs[0]); FreeAndNil(o1); o1 := fList.PopFirst(true); AssertEquals(Length(fTestObjs)-2, fList.Count); AssertTrue(o1 = nil); AssertTrue(fTestObjs[1] = nil); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListTest.Last; begin AssertTrue(fTestObjs[High(fTestObjs)] = fList.Last); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListTest.PushLast; var o1: TTestObject; begin o1 := TTestObject.Create(1234, @TestObjectDestroy); fList.PushLast(o1); AssertEquals(Length(fTestObjs)+1, fList.Count); AssertTrue(fList.Last = o1); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlListTest.PopLast; var o1: TTestObject; begin o1 := fList.PopLast; AssertEquals(Length(fTestObjs)-1, fList.Count); AssertTrue(o1 = fTestObjs[High(fTestObjs)]); FreeAndNil(o1); o1 := fList.PopLast(true); AssertEquals(Length(fTestObjs)-2, fList.Count); AssertTrue(o1 = nil); AssertTrue(fTestObjs[High(fTestObjs)-1] = nil); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TutlHashSetTest/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlHashSetTest.TestObjectDestroy(aSender: TObject); var i: Integer; begin for i := Low(fTestObjs) to High(fTestObjs) do if (fTestObjs[i] = aSender) then fTestObjs[i] := nil; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlHashSetTest.SetUp; var i: Integer; begin inherited SetUp; fHashSet := TTestHashSet.Create(TTestObjComparer.Create(@CompareTestObjects), true); for i := Low(fTestObjs) to High(fTestObjs) do begin fTestObjs[i] := TTestObject.Create(i, @TestObjectDestroy); fHashSet.Add(fTestObjs[i]); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlHashSetTest.TearDown; begin FreeAndNil(fHashSet); inherited TearDown; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlHashSetTest.CompareTestObjects(const i1, i2: TTestObject): Integer; begin if (i1.Data < i2.Data) then result := -1 else if (i1.Data > i2.Data) then result := 1 else result := 0; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlHashSetTest.Add; var o1: TTestObject; b: Boolean; begin o1 := TTestObject.Create(1234, @TestObjectDestroy); b := fHashSet.Add(o1); AssertTrue(b); AssertEquals(Length(fTestObjs)+1, fHashSet.Count); b := fHashSet.Add(o1); AssertFalse(b); AssertEquals(Length(fTestObjs)+1, fHashSet.Count); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlHashSetTest.Contains; var o1: TTestObject; b: Boolean; begin o1 := TTestObject.Create(1234, @TestObjectDestroy); try b := fHashSet.Contains(fTestObjs[0]); AssertTrue(b); b := fHashSet.Contains(o1); AssertFalse(b); finally FreeAndNil(o1); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlHashSetTest.IndexOf; var o1: TTestObject; i: Integer; begin o1 := TTestObject.Create(1234, @TestObjectDestroy); try i := fHashSet.IndexOf(fTestObjs[4]); AssertEquals(4, i); i := fHashSet.IndexOf(o1); AssertEquals(-1, i); finally FreeAndNil(o1); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlHashSetTest.Remove; var b: Boolean; begin b := fHashSet.Remove(fTestObjs[5]); AssertTrue(fTestObjs[5] = nil); AssertTrue(b); AssertEquals(Length(fTestObjs)-1, fHashSet.Count); fHashSet.OwnsObjects := false; try b := fHashSet.Remove(fTestObjs[0]); AssertTrue(fTestObjs[0] <> nil); AssertEquals(Length(fTestObjs)-2, fHashSet.Count); AssertTrue(b); b := fHashSet.Remove(fTestObjs[0]); AssertFalse(b); AssertEquals(Length(fTestObjs)-2, fHashSet.Count); finally FreeAndNil(fTestObjs[0]); fHashSet.OwnsObjects := true; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlHashSetTest.Delete; begin fHashSet.Delete(0); AssertEquals(Length(fTestObjs)-1, fHashSet.Count); AssertTrue(fTestObjs[0] = nil); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TutlMapTest/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlMapTest.TestObjectDestroy(aSender: TObject); var i: Integer; begin for i := Low(fTestObjs) to High(fTestObjs) do if (fTestObjs[i] = aSender) then begin fLastRemovedIndex := i; fTestObjs[i] := nil; exit; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlMapTest.Key(const aIndex: Integer): Integer; begin result := fTestObjs[aIndex].Data; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TutlMapTest.CreateObj: TTestObject; var k: Integer; begin repeat k := random(10000); until not fMap.Contains(k); result := TTestObject.Create(k, @TestObjectDestroy); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlMapTest.SetUp; var i: Integer; o: TTestObject; begin inherited SetUp; fMap := TTestMap.Create(true); Randomize; for i := Low(fTestObjs) to High(fTestObjs) do begin o := CreateObj; fTestObjs[i] := o; fMap.Add(o.Data, o); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlMapTest.TearDown; begin FreeAndNil(fMap); inherited TearDown; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlMapTest.AddExistingKey; var o1: TTestObject; begin o1 := TTestObject.Create(fTestObjs[0].Data, @TestObjectDestroy); try fMap.Add(o1.Data, o1); finally FreeAndNil(o1); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlMapTest.GetValue; var i: Integer; begin for i := Low(fTestObjs) to High(fTestObjs) do AssertTrue(fMap[Key(i)] = fTestObjs[i]); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlMapTest.SetValue; var o1, o2: TTestObject; begin o1 := fMap[Key(2)]; o2 := CreateObj; fMap[Key(2)] := o2; try AssertTrue(fMap[Key(2)] = o2); finally FreeAndNil(o1); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlMapTest.GetValueAt; type TIntList = specialize TutlList; TIntComparer = specialize TutlComparer; var o: TTestObject; l: TIntList; i: Integer; begin l := TIntList.Create; try for o in fTestObjs do l.Add(o.Data); l.Sort(TIntComparer.Create); for i := 0 to l.Count-1 do AssertEquals(l[i], fMap.ValueAt[i].Data); finally FreeAndNil(l); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlMapTest.SetValueAt; var o1, o2: TTestObject; begin o1 := fMap.ValueAt[4]; o2 := TTestObject.Create(o1.Data, @TestObjectDestroy); fMap.ValueAt[4] := o2; try AssertTrue(fMap.ValueAt[4] = o2); finally FreeAndNil(o1); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlMapTest.GetKey; type TIntList = specialize TutlList; TIntComparer = specialize TutlComparer; var o: TTestObject; l: TIntList; i: Integer; begin l := TIntList.Create; try for o in fTestObjs do l.Add(o.Data); l.Sort(TIntComparer.Create); for i := 0 to l.Count-1 do AssertEquals(l[i], fMap.Keys[i]); finally FreeAndNil(l); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlMapTest.Add; var o1: TTestObject; begin o1 := CreateObj; fMap.Add(o1.Data, o1); AssertEquals(Length(fTestObjs)+1, fMap.Count); AssertException(EutlMap, @AddExistingKey); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlMapTest.IndexOf; type TIntList = specialize TutlList; TIntComparer = specialize TutlComparer; var o: TTestObject; l: TIntList; begin l := TIntList.Create; try for o in fTestObjs do l.Add(o.Data); l.Sort(TIntComparer.Create); for o in fTestObjs do AssertEquals(l.IndexOf(o.Data), fMap.IndexOf(o.Data)); finally FreeAndNil(l); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TutlMapTest.Delete; var i: Integer; begin for i := Low(fTestObjs) to High(fTestObjs) do begin fMap.Delete(Key(i)); AssertNull(fTestObjs[i]); AssertEquals('Count', Length(fTestObjs)-i-1, fMap.Count); AssertEquals('Index', fLastRemovedIndex, i); end; end; initialization RegisterTest(TutlListTest); RegisterTest(TutlHashSetTest); RegisterTest(TutlMapTest); end.