tclist.pp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  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. List2 : TList;
  23. List3 : TList;
  24. Pointers : Packed Array[0..20] of Byte;
  25. procedure SetUp; override;
  26. procedure TearDown; override;
  27. Procedure FillList(ACount : Integer); overload;
  28. Procedure FillList(AList : TList; AOffSet, ACount : Integer); overload;
  29. procedure HavePointer(I: Integer);
  30. published
  31. procedure TestCreate;
  32. procedure TestAdd;
  33. procedure TestAddIndex;
  34. procedure TestAdd2;
  35. procedure TestInsertFirst;
  36. Procedure TestInsertMiddle;
  37. procedure TestDelete;
  38. Procedure TestClear;
  39. Procedure TestIndexOf;
  40. procedure TestExchange;
  41. procedure TestAccesIndexOutOfBounds;
  42. procedure TestDeleteIndexOutOfBounds;
  43. procedure TestExchangeIndexOutOfBounds;
  44. Procedure TestSort;
  45. procedure TestExtractCount;
  46. procedure TestExtractResult;
  47. procedure TestExtractNonExisting;
  48. procedure TestExtractNonExistingResult;
  49. procedure TestExtractOnlyFirst;
  50. Procedure TestNotifyAdd;
  51. Procedure TestNotifyDelete;
  52. Procedure TestNotifyExtract;
  53. Procedure TestPack;
  54. Procedure TestAssignCopy;
  55. Procedure TestAssignCopy2;
  56. Procedure TestAssignAnd;
  57. procedure TestAssignAnd2;
  58. Procedure TestAssignOr;
  59. procedure TestAssignOr2;
  60. procedure TestAssignXOr;
  61. procedure TestAssignXOr2;
  62. procedure TestAssignSrcUnique;
  63. procedure TestAssignSrcUnique2;
  64. procedure TestAssignDestUnique;
  65. procedure TestAssignDestUnique2;
  66. end;
  67. { TMyList }
  68. TMyList = Class(TList)
  69. procedure Notify(Ptr: Pointer; Action: TListNotification); override;
  70. FLastPointer : Pointer;
  71. FLastAction : TListNotification;
  72. end;
  73. implementation
  74. procedure TTestTList.SetUp;
  75. Var
  76. I : Integer;
  77. begin
  78. List:=TMyList.Create;
  79. List2:=TMyList.Create;
  80. List3:=TMyList.Create;
  81. For I:=0 to 20 do
  82. Pointers[i]:=I; // Zero serves as sentinel.
  83. end;
  84. procedure TTestTList.TearDown;
  85. begin
  86. FreeAndNil(List);
  87. FreeAndNil(List2);
  88. FreeAndNil(List3);
  89. end;
  90. procedure TTestTList.FillList(ACount: Integer);
  91. begin
  92. FillList(List,0,ACount);
  93. end;
  94. procedure TTestTList.FillList(AList: TList; AOffSet, ACount: Integer);
  95. Var
  96. I : integer;
  97. begin
  98. If ACount+AOffSet>20 then
  99. Fail('Too many elements added to list. Max is 20');
  100. For I:=1+AOffSet to AOffSet+ACount do
  101. AList.Add(@Pointers[i]);
  102. end;
  103. procedure TTestTList.TestCreate;
  104. begin
  105. AssertEquals('Empty list has count 0',0,List.Count);
  106. end;
  107. procedure TTestTList.AssertEquals(Msg : String; P1,P2 : Pointer);
  108. begin
  109. If (P1<>P2) then
  110. Fail(Format('%s: Pointers differ. Expected <%x>, got: <%x>',[Msg,PtrInt(P1),PtrInt(P2)]));
  111. end;
  112. procedure TTestTList.TestAdd;
  113. begin
  114. FillList(1);
  115. AssertEquals('Add 1 element, count is 1',1,List.Count);
  116. AssertEquals('Add 1 element, last element is Ptrint(1)',@Pointers[1],List[0]);
  117. end;
  118. procedure TTestTList.TestAddIndex;
  119. begin
  120. AssertEquals('Add first element at index 0',0,List.Add(Nil));
  121. AssertEquals('Add second element, at index 1',1,List.Add(Nil));
  122. end;
  123. procedure TTestTList.TestAdd2;
  124. begin
  125. FillList(2);
  126. AssertEquals('Add 2 elements, count is 2',2,List.Count);
  127. AssertEquals('Add 2 elements, first element is Pointers[1]',@Pointers[1],List[0]);
  128. AssertEquals('Add 2 elements, second element is Pointers[2]',@Pointers[2],List[1]);
  129. end;
  130. procedure TTestTList.TestInsertFirst;
  131. begin
  132. FillList(3);
  133. List.Insert(0,@Pointers[0]);
  134. AssertEquals('Insert 1 in 3, count is 4',4,List.Count);
  135. AssertEquals('Insert 1 in 3, first is inserted',@Pointers[0],List[0]);
  136. AssertEquals('Insert 1 in 3, second is old first',@Pointers[1],List[1]);
  137. end;
  138. procedure TTestTList.TestInsertMiddle;
  139. begin
  140. FillList(3);
  141. List.Insert(1,@Pointers[0]);
  142. AssertEquals('Insert 1 in 3, count is 4',4,List.Count);
  143. AssertEquals('Insert 1 in 3, 1 is inserted',@Pointers[0],List[1]);
  144. AssertEquals('Insert 1 in 3, 2 is old 2',@Pointers[2],List[2]);
  145. AssertEquals('Insert 1 in 3, 0 is untouched',@Pointers[1],List[0]);
  146. end;
  147. procedure TTestTList.TestClear;
  148. begin
  149. FillList(3);
  150. List.Clear;
  151. AssertEquals('Clear: count is 0',0,List.Count);
  152. end;
  153. procedure TTestTList.TestIndexOf;
  154. begin
  155. FillList(11);
  156. AssertEquals('Find third element',2,List.IndexOf(@Pointers[3]));
  157. end;
  158. procedure TTestTList.TestDelete;
  159. begin
  160. FillList(3);
  161. List.Delete(1);
  162. AssertEquals('Delete 1 from 3, count is 2',2,List.Count);
  163. AssertEquals('Delete 1 from 3, first is pointers[1]',@Pointers[1],List[0]);
  164. AssertEquals('Delete 1 from 3, second is "pointers[3]',@Pointers[3],List[1]);
  165. end;
  166. procedure TTestTList.TestExchange;
  167. begin
  168. FillList(3);
  169. List.Exchange(0,2);
  170. AssertEquals('Exchange 0 and 2, count is 3',3,List.Count);
  171. AssertEquals('Exchange 0 and 2, first is Pointers[3]',@Pointers[3],List[0]);
  172. AssertEquals('Exchange 0 and 2, second is Pointers[2]',@Pointers[2],List[1]);
  173. AssertEquals('Exchange 0 and 2, third is Pointers[1]',@Pointers[1],List[2]);
  174. end;
  175. procedure TTestTList.DeleteNegativeIndex;
  176. begin
  177. List.Delete(-1);
  178. end;
  179. procedure TTestTList.DeleteTooBigIndex;
  180. begin
  181. List.Delete(3);
  182. end;
  183. procedure TTestTList.ExchangeNegativeIndex1;
  184. begin
  185. List.Exchange(-1,2);
  186. end;
  187. procedure TTestTList.ExchangeTooBigIndex1;
  188. begin
  189. List.Exchange(3,2);
  190. end;
  191. procedure TTestTList.ExchangeNegativeIndex2;
  192. begin
  193. List.Exchange(2,-1);
  194. end;
  195. procedure TTestTList.ExchangeTooBigIndex2;
  196. begin
  197. List.Exchange(2,3);
  198. end;
  199. procedure TTestTList.AccessNegativeIndex;
  200. begin
  201. List[-1];
  202. end;
  203. procedure TTestTList.AccessTooBigIndex;
  204. begin
  205. List[3];
  206. end;
  207. procedure TTestTList.Shuffle;
  208. Var
  209. I,I1,I2 : Integer;
  210. begin
  211. For I:=1 to List.Count* 2 do
  212. begin
  213. I1:=Random(List.Count);
  214. I2:=Random(List.Count);
  215. if I1<>I2 then
  216. List.Exchange(I1,I2);
  217. end;
  218. end;
  219. procedure TTestTList.TestAccesIndexOutOfBounds;
  220. begin
  221. FillList(3);
  222. AssertException('Access Negative Index',EListError,@AccessNegativeIndex);
  223. AssertException('Access Index too big',EListError,@AccessTooBigIndex);
  224. end;
  225. procedure TTestTList.TestDeleteIndexOutOfBounds;
  226. begin
  227. FillList(3);
  228. AssertException('Delete Negative Index',EListError,@DeleteNegativeIndex);
  229. AssertException('Delete Index too big',EListError,@DeleteTooBigIndex);
  230. end;
  231. procedure TTestTList.TestExchangeIndexOutOfBounds;
  232. begin
  233. FillList(3);
  234. AssertException('Exchange Negative first index',EListError,@ExchangeNegativeIndex1);
  235. AssertException('Exchange Negative second index',EListError,@ExchangeNegativeIndex2);
  236. AssertException('Exchange first Index too big',EListError,@ExchangeTooBigIndex1);
  237. AssertException('Exchange second Index too big',EListError,@ExchangeTooBigIndex2);
  238. end;
  239. Function CompareBytePointers(P1,P2 : Pointer) : Integer;
  240. begin
  241. Result:=PByte(P1)^-PByte(P2)^;
  242. end;
  243. procedure TTestTList.TestSort;
  244. Var
  245. I : Integer;
  246. begin
  247. FillList(9);
  248. Shuffle;
  249. List.Sort(@CompareBytePointers);
  250. For I:=0 to List.Count-1 do
  251. If (List[i]<>@Pointers[i+1]) then
  252. Fail(Format('Item at position %d is out of place (%d)',[I,PByte(List[i])^]));
  253. end;
  254. procedure TTestTList.TestExtractResult;
  255. begin
  256. FillList(9);
  257. AssertEquals('Extracting pointers[4]',@Pointers[4],List.Extract(@Pointers[4]));
  258. end;
  259. procedure TTestTList.TestExtractCount;
  260. begin
  261. FillList(9);
  262. List.Extract(@Pointers[4]);
  263. AssertEquals('Extracting pointers[4], count is 8',8,List.Count);
  264. end;
  265. procedure TTestTList.TestExtractNonExisting;
  266. begin
  267. FillList(9);
  268. List.Extract(@List);
  269. AssertEquals('Extracting unexisting, count remains 9',9,List.Count);
  270. end;
  271. procedure TTestTList.TestExtractNonExistingResult;
  272. begin
  273. FillList(9);
  274. AssertEquals('Extracting unexisting, result is nil',Nil,List.Extract(@List));
  275. end;
  276. procedure TTestTList.TestExtractOnlyFirst;
  277. begin
  278. FillList(9);
  279. List.Insert(0,@Pointers[4]);
  280. List.Extract(@Pointers[4]);
  281. AssertEquals('Extracting pointers[4], result is nil',3,List.IndexOf(@Pointers[4]));
  282. end;
  283. procedure TTestTList.TestNotifyAdd;
  284. begin
  285. List.Add(@Pointers[1]);
  286. AssertEquals('Add notification, pointer is pointer[1]',@Pointers[1],TMyList(List).FLastPointer);
  287. AssertEquals('Add notification, action is lnAdded',ord(lnAdded),Ord(TMyList(List).FLastAction));
  288. end;
  289. procedure TTestTList.TestNotifyDelete;
  290. begin
  291. FillList(9);
  292. List.Delete(3);
  293. AssertEquals('Delete notification, pointer is pointer[4]',@Pointers[4],TMyList(List).FLastPointer);
  294. AssertEquals('Delete notification, action is lnDeleted',ord(lnDeleted),Ord(TMyList(List).FLastAction));
  295. end;
  296. procedure TTestTList.TestNotifyExtract;
  297. begin
  298. FillList(9);
  299. List.Extract(@Pointers[4]);
  300. AssertEquals('Extract notification, pointer is pointer[4]',@Pointers[4],TMyList(List).FLastPointer);
  301. AssertEquals('Extract notification, action is lnExtracted',ord(lnExtracted),Ord(TMyList(List).FLastAction));
  302. end;
  303. procedure TTestTList.TestPack;
  304. Var
  305. I : integer;
  306. begin
  307. FillList(9);
  308. List[3]:=Nil;
  309. List[6]:=Nil;
  310. List.Pack;
  311. AssertEquals('Pack, count is 7',7,List.Count);
  312. For I:=0 to List.Count-1 do
  313. If (List[i]=Nil) then
  314. Fail(Format('Packed list contains nil pointer at position %d',[i]));
  315. AssertEquals('Packed list[3] is @pointer[5]',@Pointers[5],List[3]);
  316. AssertEquals('Packed list[6] is @pointer[9]',@pointers[9],List[6]);
  317. end;
  318. procedure TTestTList.TestAssignCopy;
  319. Var
  320. I : Integer;
  321. begin
  322. FillList(20);
  323. List2.Assign(List,laCopy);
  324. AssertEquals('20 elements copied',20,List2.Count);
  325. For I:=0 to 19 do
  326. AssertSame(Format('Element %d copied correctly',[i]),@Pointers[I+1],List2[i]);
  327. end;
  328. procedure TTestTList.TestAssignAnd;
  329. Var
  330. I : Integer;
  331. begin
  332. FillList(10); // 1--10
  333. FillList(List2,5,10); // 6--15
  334. List.Assign(List2,laAnd); // Should have 6-10
  335. AssertEquals('5 elements copied',5,List.Count);
  336. For I:=0 to 4 do
  337. HavePointer(6+i);
  338. end;
  339. procedure TTestTList.TestAssignAnd2;
  340. Var
  341. I : Integer;
  342. begin
  343. FillList(10); // 1--10
  344. FillList(List2,5,10); // 6--15
  345. FillList(List3,10,9); // 11--19
  346. List.Assign(List2,laAnd,List3); // Should have 11-15
  347. AssertEquals('5 elements copied',5,List.Count);
  348. For I:=0 to 4 do
  349. HavePointer(11+i);
  350. end;
  351. procedure TTestTList.TestAssignOr;
  352. Var
  353. I : Integer;
  354. begin
  355. FillList(10); // 1--10
  356. FillList(List2,5,10); // 6--15
  357. List.Assign(List2,laOr); // Should have 6-10
  358. AssertEquals('15 elements copied',15,List.Count);
  359. For I:=0 to 14 do
  360. HavePointer(1+i);
  361. end;
  362. procedure TTestTList.TestAssignOr2;
  363. Var
  364. I : Integer;
  365. begin
  366. FillList(10); // 1--10
  367. FillList(List2,5,10); // 6--15
  368. FillList(List3,10,9); // 11--19
  369. List.Assign(List2,laOr,List3); // Should have 6-19
  370. AssertEquals('14 elements copied',14,List.Count);
  371. For I:=0 to 13 do
  372. HavePointer(6+i);
  373. end;
  374. procedure TTestTList.TestAssignXOr;
  375. Var
  376. I : Integer;
  377. begin
  378. FillList(10); // 1--10
  379. FillList(List2,5,10); // 6--15
  380. List.Assign(List2,laxOr); // Should have 1-5 and 11-15
  381. AssertEquals('10 elements copied',10,List.Count);
  382. For I:=0 to 4 do
  383. HavePointer(1+i);
  384. For I:=5 to 9 do
  385. HavePointer(6+i);
  386. end;
  387. procedure TTestTList.TestAssignXOr2;
  388. Var
  389. I : Integer;
  390. begin
  391. FillList(10); // 1--10
  392. FillList(List2,5,10); // 6--15
  393. FillList(List3,10,9); // 11--19
  394. List.Assign(List2,laXor,List3); // Should have 6-10 and 16-19
  395. AssertEquals('14 elements copied',9,List.Count);
  396. For I:=0 to 4 do
  397. HavePointer(6+i);
  398. For I:=5 to 8 do
  399. HavePointer(11+i);
  400. end;
  401. procedure TTestTList.TestAssignSrcUnique;
  402. Var
  403. I : Integer;
  404. begin
  405. FillList(10); // 1--10
  406. FillList(List2,5,10); // 6--15
  407. List.Assign(List2,laSrcUnique); // Should have 1-5
  408. AssertEquals('5 elements copied',5,List.Count);
  409. For I:=0 to 4 do
  410. HavePointer(1+i);
  411. end;
  412. procedure TTestTList.TestAssignSrcUnique2;
  413. Var
  414. I : Integer;
  415. begin
  416. FillList(10); // 1--10
  417. FillList(List2,5,10); // 6--15
  418. FillList(List3,10,9); // 11--19
  419. List.Assign(List2,laSrcUnique,List3); // Should have 6-10
  420. AssertEquals('5 elements copied',5,List.Count);
  421. For I:=0 to 4 do
  422. HavePointer(6+i);
  423. end;
  424. procedure TTestTList.HavePointer(I : Integer);
  425. begin
  426. If List.IndexOf(@Pointers[i])=-1 then
  427. Fail(Format('Pointer to %d not in list',[i]));
  428. end;
  429. procedure TTestTList.TestAssignDestUnique;
  430. Var
  431. I : Integer;
  432. begin
  433. FillList(10); // 1--10
  434. FillList(List2,5,10); // 6--15
  435. List.Assign(List2,laDestUnique); // Should have 11-15
  436. AssertEquals('5 elements copied',5,List.Count);
  437. For I:=0 to 4 do
  438. HavePointer(11+I);
  439. end;
  440. procedure TTestTList.TestAssignDestUnique2;
  441. Var
  442. I : Integer;
  443. begin
  444. FillList(10); // 1--10
  445. FillList(List2,5,10); // 6--15
  446. FillList(List3,10,9); // 11--19
  447. List.Assign(List2,laDestUnique,List3); // Should have 16-19
  448. AssertEquals('4 elements copied',4,List.Count);
  449. For I:=0 to 3 do
  450. HavePointer(16+i);
  451. end;
  452. procedure TTestTList.TestAssignCopy2;
  453. Var
  454. I : Integer;
  455. begin
  456. FillList(6); // 1--6
  457. FillList(List2,6,6); // 7--12
  458. FillList(List3,12,6); // 13--18
  459. List.Assign(List2,laCopy,List3); // Should have 13-18
  460. AssertEquals('6 elements copied',6,List.Count);
  461. For I:=1 to 6 do
  462. HavePointer(12+i);
  463. end;
  464. { TMyList }
  465. procedure TMyList.Notify(Ptr: Pointer; Action: TListNotification);
  466. begin
  467. inherited Notify(Ptr, Action);
  468. FLastAction:=Action;
  469. FLastPointer:=Ptr;
  470. end;
  471. initialization
  472. RegisterTest(TTestTList);
  473. end.