|
@@ -0,0 +1,398 @@
|
|
|
+unit tclist;
|
|
|
+
|
|
|
+{$mode objfpc}{$H+}
|
|
|
+
|
|
|
+interface
|
|
|
+
|
|
|
+uses
|
|
|
+ Classes, SysUtils, fpcunit, testutils, testregistry;
|
|
|
+
|
|
|
+type
|
|
|
+
|
|
|
+ { TTestTList }
|
|
|
+
|
|
|
+
|
|
|
+ TTestTList= class(TTestCase)
|
|
|
+ private
|
|
|
+ procedure AssertEquals(Msg: String; P1, P2: Pointer); overload;
|
|
|
+ procedure DeleteNegativeIndex;
|
|
|
+ procedure DeleteTooBigIndex;
|
|
|
+ procedure ExchangeNegativeIndex1;
|
|
|
+ procedure ExchangeNegativeIndex2;
|
|
|
+ procedure ExchangeTooBigIndex1;
|
|
|
+ procedure ExchangeTooBigIndex2;
|
|
|
+ procedure AccessNegativeIndex;
|
|
|
+ procedure AccessTooBigIndex;
|
|
|
+ procedure Shuffle;
|
|
|
+ protected
|
|
|
+ List : TList;
|
|
|
+ Pointers : Packed Array[0..20] of Byte;
|
|
|
+ procedure SetUp; override;
|
|
|
+ procedure TearDown; override;
|
|
|
+ Procedure FillList(ACount : Integer);
|
|
|
+ published
|
|
|
+ procedure TestCreate;
|
|
|
+ procedure TestAdd;
|
|
|
+ procedure TestAddIndex;
|
|
|
+ procedure TestAdd2;
|
|
|
+ procedure TestInsertFirst;
|
|
|
+ Procedure TestInsertMiddle;
|
|
|
+ procedure TestDelete;
|
|
|
+ Procedure TestClear;
|
|
|
+ Procedure TestIndexOf;
|
|
|
+ procedure TestExchange;
|
|
|
+ procedure TestAccesIndexOutOfBounds;
|
|
|
+ procedure TestDeleteIndexOutOfBounds;
|
|
|
+ procedure TestExchangeIndexOutOfBounds;
|
|
|
+ Procedure TestSort;
|
|
|
+ procedure TestExtractCount;
|
|
|
+ procedure TestExtractResult;
|
|
|
+ procedure TestExtractNonExisting;
|
|
|
+ procedure TestExtractNonExistingResult;
|
|
|
+ procedure TestExtractOnlyFirst;
|
|
|
+ Procedure TestNotifyAdd;
|
|
|
+ Procedure TestNotifyDelete;
|
|
|
+ Procedure TestNotifyExtract;
|
|
|
+ Procedure TestPack;
|
|
|
+ end;
|
|
|
+
|
|
|
+ { TMyList }
|
|
|
+
|
|
|
+ TMyList = Class(TList)
|
|
|
+ procedure Notify(Ptr: Pointer; Action: TListNotification); override;
|
|
|
+ FLastPointer : Pointer;
|
|
|
+ FLastAction : TListNotification;
|
|
|
+ end;
|
|
|
+
|
|
|
+implementation
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+procedure TTestTList.SetUp;
|
|
|
+
|
|
|
+Var
|
|
|
+ I : Integer;
|
|
|
+
|
|
|
+begin
|
|
|
+ List:=TMyList.Create;
|
|
|
+ For I:=0 to 20 do
|
|
|
+ Pointers[i]:=I; // Zero serves as sentinel.
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.TearDown;
|
|
|
+begin
|
|
|
+ FreeAndNil(List);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.TestCreate;
|
|
|
+begin
|
|
|
+ AssertEquals('Empty list has count 0',0,List.Count);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.AssertEquals(Msg : String; P1,P2 : Pointer);
|
|
|
+
|
|
|
+begin
|
|
|
+ If (P1<>P2) then
|
|
|
+ Fail(Format('%s: Pointers differ. Expected <%x>, got: <%x>',[Msg,PtrInt(P1),PtrInt(P2)]));
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.TestAdd;
|
|
|
+
|
|
|
+begin
|
|
|
+ FillList(1);
|
|
|
+ AssertEquals('Add 1 element, count is 1',1,List.Count);
|
|
|
+ AssertEquals('Add 1 element, last element is Ptrint(1)',@Pointers[1],List[0]);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.TestAddIndex;
|
|
|
+
|
|
|
+begin
|
|
|
+ AssertEquals('Add first element at index 0',0,List.Add(Nil));
|
|
|
+ AssertEquals('Add second element, at index 1',1,List.Add(Nil));
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.TestAdd2;
|
|
|
+
|
|
|
+begin
|
|
|
+ FillList(2);
|
|
|
+ AssertEquals('Add 2 elements, count is 2',2,List.Count);
|
|
|
+ AssertEquals('Add 2 elements, first element is Pointers[1]',@Pointers[1],List[0]);
|
|
|
+ AssertEquals('Add 2 elements, second element is Pointers[2]',@Pointers[2],List[1]);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.TestInsertFirst;
|
|
|
+begin
|
|
|
+ FillList(3);
|
|
|
+ List.Insert(0,@Pointers[0]);
|
|
|
+ AssertEquals('Insert 1 in 3, count is 4',4,List.Count);
|
|
|
+ AssertEquals('Insert 1 in 3, first is inserted',@Pointers[0],List[0]);
|
|
|
+ AssertEquals('Insert 1 in 3, second is old first',@Pointers[1],List[1]);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.TestInsertMiddle;
|
|
|
+begin
|
|
|
+ FillList(3);
|
|
|
+ List.Insert(1,@Pointers[0]);
|
|
|
+ AssertEquals('Insert 1 in 3, count is 4',4,List.Count);
|
|
|
+ AssertEquals('Insert 1 in 3, 1 is inserted',@Pointers[0],List[1]);
|
|
|
+ AssertEquals('Insert 1 in 3, 2 is old 2',@Pointers[2],List[2]);
|
|
|
+ AssertEquals('Insert 1 in 3, 0 is untouched',@Pointers[1],List[0]);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.TestClear;
|
|
|
+begin
|
|
|
+ FillList(3);
|
|
|
+ List.Clear;
|
|
|
+ AssertEquals('Clear: count is 0',0,List.Count);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.TestIndexOf;
|
|
|
+begin
|
|
|
+ FillList(11);
|
|
|
+ AssertEquals('Find third element',2,List.IndexOf(@Pointers[3]));
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.TestDelete;
|
|
|
+
|
|
|
+begin
|
|
|
+ FillList(3);
|
|
|
+ List.Delete(1);
|
|
|
+ AssertEquals('Delete 1 from 3, count is 2',2,List.Count);
|
|
|
+ AssertEquals('Delete 1 from 3, first is pointers[1]',@Pointers[1],List[0]);
|
|
|
+ AssertEquals('Delete 1 from 3, second is "pointers[3]',@Pointers[3],List[1]);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.TestExchange;
|
|
|
+
|
|
|
+begin
|
|
|
+ FillList(3);
|
|
|
+ List.Exchange(0,2);
|
|
|
+ AssertEquals('Exchange 0 and 2, count is 3',3,List.Count);
|
|
|
+ AssertEquals('Exchange 0 and 2, first is Pointers[3]',@Pointers[3],List[0]);
|
|
|
+ AssertEquals('Exchange 0 and 2, second is Pointers[2]',@Pointers[2],List[1]);
|
|
|
+ AssertEquals('Exchange 0 and 2, third is Pointers[1]',@Pointers[1],List[2]);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.DeleteNegativeIndex;
|
|
|
+begin
|
|
|
+ List.Delete(-1);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.DeleteTooBigIndex;
|
|
|
+begin
|
|
|
+ List.Delete(3);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.ExchangeNegativeIndex1;
|
|
|
+begin
|
|
|
+ List.Exchange(-1,2);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.ExchangeTooBigIndex1;
|
|
|
+begin
|
|
|
+ List.Exchange(3,2);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.ExchangeNegativeIndex2;
|
|
|
+begin
|
|
|
+ List.Exchange(2,-1);
|
|
|
+
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.ExchangeTooBigIndex2;
|
|
|
+begin
|
|
|
+ List.Exchange(2,3);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.AccessNegativeIndex;
|
|
|
+
|
|
|
+begin
|
|
|
+ List[-1];
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.AccessTooBigIndex;
|
|
|
+
|
|
|
+begin
|
|
|
+ List[3];
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.Shuffle;
|
|
|
+
|
|
|
+Var
|
|
|
+ I,I1,I2 : Integer;
|
|
|
+
|
|
|
+begin
|
|
|
+ For I:=1 to List.Count* 2 do
|
|
|
+ begin
|
|
|
+ I1:=Random(List.Count);
|
|
|
+ I2:=Random(List.Count);
|
|
|
+ if I1<>I2 then
|
|
|
+ List.Exchange(I1,I2);
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.TestAccesIndexOutOfBounds;
|
|
|
+begin
|
|
|
+ FillList(3);
|
|
|
+ AssertException('Access Negative Index',EListError,@AccessNegativeIndex);
|
|
|
+ AssertException('Access Index too big',EListError,@AccessTooBigIndex);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.TestDeleteIndexOutOfBounds;
|
|
|
+begin
|
|
|
+ FillList(3);
|
|
|
+ AssertException('Delete Negative Index',EListError,@DeleteNegativeIndex);
|
|
|
+ AssertException('Delete Index too big',EListError,@DeleteTooBigIndex);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.TestExchangeIndexOutOfBounds;
|
|
|
+begin
|
|
|
+ FillList(3);
|
|
|
+ AssertException('Exchange Negative first index',EListError,@ExchangeNegativeIndex1);
|
|
|
+ AssertException('Exchange Negative second index',EListError,@ExchangeNegativeIndex2);
|
|
|
+ AssertException('Exchange first Index too big',EListError,@ExchangeTooBigIndex1);
|
|
|
+ AssertException('Exchange second Index too big',EListError,@ExchangeTooBigIndex2);
|
|
|
+end;
|
|
|
+
|
|
|
+Function CompareBytePointers(P1,P2 : Pointer) : Integer;
|
|
|
+
|
|
|
+begin
|
|
|
+ Result:=PByte(P1)^-PByte(P2)^;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.TestSort;
|
|
|
+
|
|
|
+Var
|
|
|
+ I : Integer;
|
|
|
+
|
|
|
+begin
|
|
|
+ FillList(9);
|
|
|
+ Shuffle;
|
|
|
+ List.Sort(@CompareBytePointers);
|
|
|
+ For I:=0 to List.Count-1 do
|
|
|
+ If (List[i]<>@Pointers[i+1]) then
|
|
|
+ Fail(Format('Item at position %d is out of place (%d)',[I,PByte(List[i])^]));
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.TestExtractResult;
|
|
|
+
|
|
|
+Var
|
|
|
+ I : Integer;
|
|
|
+
|
|
|
+begin
|
|
|
+ FillList(9);
|
|
|
+ AssertEquals('Extracting pointers[4]',@Pointers[4],List.Extract(@Pointers[4]));
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.TestExtractCount;
|
|
|
+
|
|
|
+Var
|
|
|
+ I : Integer;
|
|
|
+
|
|
|
+begin
|
|
|
+ FillList(9);
|
|
|
+ List.Extract(@Pointers[4]);
|
|
|
+ AssertEquals('Extracting pointers[4], count is 8',8,List.Count);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.TestExtractNonExisting;
|
|
|
+
|
|
|
+Var
|
|
|
+ I : Integer;
|
|
|
+
|
|
|
+begin
|
|
|
+ FillList(9);
|
|
|
+ List.Extract(@List);
|
|
|
+ AssertEquals('Extracting unexisting, count remains 9',9,List.Count);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.TestExtractNonExistingResult;
|
|
|
+
|
|
|
+Var
|
|
|
+ I : Integer;
|
|
|
+
|
|
|
+begin
|
|
|
+ FillList(9);
|
|
|
+ AssertEquals('Extracting unexisting, result is nil',Nil,List.Extract(@List));
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.TestExtractOnlyFirst;
|
|
|
+
|
|
|
+Var
|
|
|
+ I : Integer;
|
|
|
+
|
|
|
+begin
|
|
|
+ FillList(9);
|
|
|
+ List.Insert(0,@Pointers[4]);
|
|
|
+ List.Extract(@Pointers[4]);
|
|
|
+ AssertEquals('Extracting pointers[4], result is nil',3,List.IndexOf(@Pointers[4]));
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.TestNotifyAdd;
|
|
|
+begin
|
|
|
+ List.Add(@Pointers[1]);
|
|
|
+ AssertEquals('Add notification, pointer is pointer[1]',@Pointers[1],TMyList(List).FLastPointer);
|
|
|
+ AssertEquals('Add notification, action is lnAdded',ord(lnAdded),Ord(TMyList(List).FLastAction));
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.TestNotifyDelete;
|
|
|
+begin
|
|
|
+ FillList(9);
|
|
|
+ List.Delete(3);
|
|
|
+ AssertEquals('Delete notification, pointer is pointer[4]',@Pointers[4],TMyList(List).FLastPointer);
|
|
|
+ AssertEquals('Delete notification, action is lnDeleted',ord(lnDeleted),Ord(TMyList(List).FLastAction));
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.TestNotifyExtract;
|
|
|
+begin
|
|
|
+ FillList(9);
|
|
|
+ List.Extract(@Pointers[4]);
|
|
|
+ AssertEquals('Extract notification, pointer is pointer[4]',@Pointers[4],TMyList(List).FLastPointer);
|
|
|
+ AssertEquals('Extract notification, action is lnExtracted',ord(lnExtracted),Ord(TMyList(List).FLastAction));
|
|
|
+end;
|
|
|
+
|
|
|
+procedure TTestTList.TestPack;
|
|
|
+
|
|
|
+Var
|
|
|
+ I : integer;
|
|
|
+
|
|
|
+begin
|
|
|
+ FillList(9);
|
|
|
+ List[3]:=Nil;
|
|
|
+ List[6]:=Nil;
|
|
|
+ List.Pack;
|
|
|
+ AssertEquals('Pack, count is 7',7,List.Count);
|
|
|
+ For I:=0 to List.Count-1 do
|
|
|
+ If (List[i]=Nil) then
|
|
|
+ Fail(Format('Packed list contains nil pointer at position %d',[i]));
|
|
|
+ AssertEquals('Packed list[3] is @pointer[5]',@Pointers[5],List[3]);
|
|
|
+ AssertEquals('Packed list[6] is @pointer[9]',@pointers[9],List[6]);
|
|
|
+end;
|
|
|
+
|
|
|
+
|
|
|
+procedure TTestTList.FillList(ACount: Integer);
|
|
|
+
|
|
|
+Var
|
|
|
+ I : integer;
|
|
|
+
|
|
|
+begin
|
|
|
+ If ACount>20 then
|
|
|
+ Fail('Too many elements added to list. Max is 20');
|
|
|
+ For I:=1 to ACount do
|
|
|
+ List.Add(@Pointers[i]);
|
|
|
+end;
|
|
|
+
|
|
|
+{ TMyList }
|
|
|
+
|
|
|
+procedure TMyList.Notify(Ptr: Pointer; Action: TListNotification);
|
|
|
+begin
|
|
|
+ inherited Notify(Ptr, Action);
|
|
|
+ FLastAction:=Action;
|
|
|
+ FLastPointer:=Ptr;
|
|
|
+end;
|
|
|
+
|
|
|
+initialization
|
|
|
+
|
|
|
+ RegisterTest(TTestTList);
|
|
|
+end.
|
|
|
+
|