tclist.pp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. unit tclist;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, fpcunit, testutils, testregistry;
  6. type
  7. { TTestTList }
  8. TTestTList= class(TTestCase)
  9. private
  10. procedure AssertEquals(Msg: String; P1, P2: Pointer); overload;
  11. procedure DeleteNegativeIndex;
  12. procedure DeleteTooBigIndex;
  13. procedure ExchangeNegativeIndex1;
  14. procedure ExchangeNegativeIndex2;
  15. procedure ExchangeTooBigIndex1;
  16. procedure ExchangeTooBigIndex2;
  17. procedure AccessNegativeIndex;
  18. procedure AccessTooBigIndex;
  19. procedure Shuffle;
  20. protected
  21. List : TList;
  22. Pointers : Packed Array[0..20] of Byte;
  23. procedure SetUp; override;
  24. procedure TearDown; override;
  25. Procedure FillList(ACount : Integer);
  26. published
  27. procedure TestCreate;
  28. procedure TestAdd;
  29. procedure TestAddIndex;
  30. procedure TestAdd2;
  31. procedure TestInsertFirst;
  32. Procedure TestInsertMiddle;
  33. procedure TestDelete;
  34. Procedure TestClear;
  35. Procedure TestIndexOf;
  36. procedure TestExchange;
  37. procedure TestAccesIndexOutOfBounds;
  38. procedure TestDeleteIndexOutOfBounds;
  39. procedure TestExchangeIndexOutOfBounds;
  40. Procedure TestSort;
  41. procedure TestExtractCount;
  42. procedure TestExtractResult;
  43. procedure TestExtractNonExisting;
  44. procedure TestExtractNonExistingResult;
  45. procedure TestExtractOnlyFirst;
  46. Procedure TestNotifyAdd;
  47. Procedure TestNotifyDelete;
  48. Procedure TestNotifyExtract;
  49. Procedure TestPack;
  50. end;
  51. { TMyList }
  52. TMyList = Class(TList)
  53. procedure Notify(Ptr: Pointer; Action: TListNotification); override;
  54. FLastPointer : Pointer;
  55. FLastAction : TListNotification;
  56. end;
  57. implementation
  58. procedure TTestTList.SetUp;
  59. Var
  60. I : Integer;
  61. begin
  62. List:=TMyList.Create;
  63. For I:=0 to 20 do
  64. Pointers[i]:=I; // Zero serves as sentinel.
  65. end;
  66. procedure TTestTList.TearDown;
  67. begin
  68. FreeAndNil(List);
  69. end;
  70. procedure TTestTList.TestCreate;
  71. begin
  72. AssertEquals('Empty list has count 0',0,List.Count);
  73. end;
  74. procedure TTestTList.AssertEquals(Msg : String; P1,P2 : Pointer);
  75. begin
  76. If (P1<>P2) then
  77. Fail(Format('%s: Pointers differ. Expected <%x>, got: <%x>',[Msg,PtrInt(P1),PtrInt(P2)]));
  78. end;
  79. procedure TTestTList.TestAdd;
  80. begin
  81. FillList(1);
  82. AssertEquals('Add 1 element, count is 1',1,List.Count);
  83. AssertEquals('Add 1 element, last element is Ptrint(1)',@Pointers[1],List[0]);
  84. end;
  85. procedure TTestTList.TestAddIndex;
  86. begin
  87. AssertEquals('Add first element at index 0',0,List.Add(Nil));
  88. AssertEquals('Add second element, at index 1',1,List.Add(Nil));
  89. end;
  90. procedure TTestTList.TestAdd2;
  91. begin
  92. FillList(2);
  93. AssertEquals('Add 2 elements, count is 2',2,List.Count);
  94. AssertEquals('Add 2 elements, first element is Pointers[1]',@Pointers[1],List[0]);
  95. AssertEquals('Add 2 elements, second element is Pointers[2]',@Pointers[2],List[1]);
  96. end;
  97. procedure TTestTList.TestInsertFirst;
  98. begin
  99. FillList(3);
  100. List.Insert(0,@Pointers[0]);
  101. AssertEquals('Insert 1 in 3, count is 4',4,List.Count);
  102. AssertEquals('Insert 1 in 3, first is inserted',@Pointers[0],List[0]);
  103. AssertEquals('Insert 1 in 3, second is old first',@Pointers[1],List[1]);
  104. end;
  105. procedure TTestTList.TestInsertMiddle;
  106. begin
  107. FillList(3);
  108. List.Insert(1,@Pointers[0]);
  109. AssertEquals('Insert 1 in 3, count is 4',4,List.Count);
  110. AssertEquals('Insert 1 in 3, 1 is inserted',@Pointers[0],List[1]);
  111. AssertEquals('Insert 1 in 3, 2 is old 2',@Pointers[2],List[2]);
  112. AssertEquals('Insert 1 in 3, 0 is untouched',@Pointers[1],List[0]);
  113. end;
  114. procedure TTestTList.TestClear;
  115. begin
  116. FillList(3);
  117. List.Clear;
  118. AssertEquals('Clear: count is 0',0,List.Count);
  119. end;
  120. procedure TTestTList.TestIndexOf;
  121. begin
  122. FillList(11);
  123. AssertEquals('Find third element',2,List.IndexOf(@Pointers[3]));
  124. end;
  125. procedure TTestTList.TestDelete;
  126. begin
  127. FillList(3);
  128. List.Delete(1);
  129. AssertEquals('Delete 1 from 3, count is 2',2,List.Count);
  130. AssertEquals('Delete 1 from 3, first is pointers[1]',@Pointers[1],List[0]);
  131. AssertEquals('Delete 1 from 3, second is "pointers[3]',@Pointers[3],List[1]);
  132. end;
  133. procedure TTestTList.TestExchange;
  134. begin
  135. FillList(3);
  136. List.Exchange(0,2);
  137. AssertEquals('Exchange 0 and 2, count is 3',3,List.Count);
  138. AssertEquals('Exchange 0 and 2, first is Pointers[3]',@Pointers[3],List[0]);
  139. AssertEquals('Exchange 0 and 2, second is Pointers[2]',@Pointers[2],List[1]);
  140. AssertEquals('Exchange 0 and 2, third is Pointers[1]',@Pointers[1],List[2]);
  141. end;
  142. procedure TTestTList.DeleteNegativeIndex;
  143. begin
  144. List.Delete(-1);
  145. end;
  146. procedure TTestTList.DeleteTooBigIndex;
  147. begin
  148. List.Delete(3);
  149. end;
  150. procedure TTestTList.ExchangeNegativeIndex1;
  151. begin
  152. List.Exchange(-1,2);
  153. end;
  154. procedure TTestTList.ExchangeTooBigIndex1;
  155. begin
  156. List.Exchange(3,2);
  157. end;
  158. procedure TTestTList.ExchangeNegativeIndex2;
  159. begin
  160. List.Exchange(2,-1);
  161. end;
  162. procedure TTestTList.ExchangeTooBigIndex2;
  163. begin
  164. List.Exchange(2,3);
  165. end;
  166. procedure TTestTList.AccessNegativeIndex;
  167. begin
  168. List[-1];
  169. end;
  170. procedure TTestTList.AccessTooBigIndex;
  171. begin
  172. List[3];
  173. end;
  174. procedure TTestTList.Shuffle;
  175. Var
  176. I,I1,I2 : Integer;
  177. begin
  178. For I:=1 to List.Count* 2 do
  179. begin
  180. I1:=Random(List.Count);
  181. I2:=Random(List.Count);
  182. if I1<>I2 then
  183. List.Exchange(I1,I2);
  184. end;
  185. end;
  186. procedure TTestTList.TestAccesIndexOutOfBounds;
  187. begin
  188. FillList(3);
  189. AssertException('Access Negative Index',EListError,@AccessNegativeIndex);
  190. AssertException('Access Index too big',EListError,@AccessTooBigIndex);
  191. end;
  192. procedure TTestTList.TestDeleteIndexOutOfBounds;
  193. begin
  194. FillList(3);
  195. AssertException('Delete Negative Index',EListError,@DeleteNegativeIndex);
  196. AssertException('Delete Index too big',EListError,@DeleteTooBigIndex);
  197. end;
  198. procedure TTestTList.TestExchangeIndexOutOfBounds;
  199. begin
  200. FillList(3);
  201. AssertException('Exchange Negative first index',EListError,@ExchangeNegativeIndex1);
  202. AssertException('Exchange Negative second index',EListError,@ExchangeNegativeIndex2);
  203. AssertException('Exchange first Index too big',EListError,@ExchangeTooBigIndex1);
  204. AssertException('Exchange second Index too big',EListError,@ExchangeTooBigIndex2);
  205. end;
  206. Function CompareBytePointers(P1,P2 : Pointer) : Integer;
  207. begin
  208. Result:=PByte(P1)^-PByte(P2)^;
  209. end;
  210. procedure TTestTList.TestSort;
  211. Var
  212. I : Integer;
  213. begin
  214. FillList(9);
  215. Shuffle;
  216. List.Sort(@CompareBytePointers);
  217. For I:=0 to List.Count-1 do
  218. If (List[i]<>@Pointers[i+1]) then
  219. Fail(Format('Item at position %d is out of place (%d)',[I,PByte(List[i])^]));
  220. end;
  221. procedure TTestTList.TestExtractResult;
  222. Var
  223. I : Integer;
  224. begin
  225. FillList(9);
  226. AssertEquals('Extracting pointers[4]',@Pointers[4],List.Extract(@Pointers[4]));
  227. end;
  228. procedure TTestTList.TestExtractCount;
  229. Var
  230. I : Integer;
  231. begin
  232. FillList(9);
  233. List.Extract(@Pointers[4]);
  234. AssertEquals('Extracting pointers[4], count is 8',8,List.Count);
  235. end;
  236. procedure TTestTList.TestExtractNonExisting;
  237. Var
  238. I : Integer;
  239. begin
  240. FillList(9);
  241. List.Extract(@List);
  242. AssertEquals('Extracting unexisting, count remains 9',9,List.Count);
  243. end;
  244. procedure TTestTList.TestExtractNonExistingResult;
  245. Var
  246. I : Integer;
  247. begin
  248. FillList(9);
  249. AssertEquals('Extracting unexisting, result is nil',Nil,List.Extract(@List));
  250. end;
  251. procedure TTestTList.TestExtractOnlyFirst;
  252. Var
  253. I : Integer;
  254. begin
  255. FillList(9);
  256. List.Insert(0,@Pointers[4]);
  257. List.Extract(@Pointers[4]);
  258. AssertEquals('Extracting pointers[4], result is nil',3,List.IndexOf(@Pointers[4]));
  259. end;
  260. procedure TTestTList.TestNotifyAdd;
  261. begin
  262. List.Add(@Pointers[1]);
  263. AssertEquals('Add notification, pointer is pointer[1]',@Pointers[1],TMyList(List).FLastPointer);
  264. AssertEquals('Add notification, action is lnAdded',ord(lnAdded),Ord(TMyList(List).FLastAction));
  265. end;
  266. procedure TTestTList.TestNotifyDelete;
  267. begin
  268. FillList(9);
  269. List.Delete(3);
  270. AssertEquals('Delete notification, pointer is pointer[4]',@Pointers[4],TMyList(List).FLastPointer);
  271. AssertEquals('Delete notification, action is lnDeleted',ord(lnDeleted),Ord(TMyList(List).FLastAction));
  272. end;
  273. procedure TTestTList.TestNotifyExtract;
  274. begin
  275. FillList(9);
  276. List.Extract(@Pointers[4]);
  277. AssertEquals('Extract notification, pointer is pointer[4]',@Pointers[4],TMyList(List).FLastPointer);
  278. AssertEquals('Extract notification, action is lnExtracted',ord(lnExtracted),Ord(TMyList(List).FLastAction));
  279. end;
  280. procedure TTestTList.TestPack;
  281. Var
  282. I : integer;
  283. begin
  284. FillList(9);
  285. List[3]:=Nil;
  286. List[6]:=Nil;
  287. List.Pack;
  288. AssertEquals('Pack, count is 7',7,List.Count);
  289. For I:=0 to List.Count-1 do
  290. If (List[i]=Nil) then
  291. Fail(Format('Packed list contains nil pointer at position %d',[i]));
  292. AssertEquals('Packed list[3] is @pointer[5]',@Pointers[5],List[3]);
  293. AssertEquals('Packed list[6] is @pointer[9]',@pointers[9],List[6]);
  294. end;
  295. procedure TTestTList.FillList(ACount: Integer);
  296. Var
  297. I : integer;
  298. begin
  299. If ACount>20 then
  300. Fail('Too many elements added to list. Max is 20');
  301. For I:=1 to ACount do
  302. List.Add(@Pointers[i]);
  303. end;
  304. { TMyList }
  305. procedure TMyList.Notify(Ptr: Pointer; Action: TListNotification);
  306. begin
  307. inherited Notify(Ptr, Action);
  308. FLastAction:=Action;
  309. FLastPointer:=Ptr;
  310. end;
  311. initialization
  312. RegisterTest(TTestTList);
  313. end.