tccollection.pp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. unit tccollection;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, fpcunit, testregistry;
  6. type
  7. { TMyItem }
  8. TMyItem = Class(TCollectionItem)
  9. private
  10. FNr: integer;
  11. protected
  12. // Expose
  13. function GetOwner: TPersistent; override;
  14. published
  15. Property Nr : integer Read FNr Write FNr;
  16. end;
  17. { TMyCollection }
  18. TMyCollection = Class(TCollection)
  19. Private
  20. FOwner : TPersistent;
  21. FUpdateCount : Integer;
  22. FLastNotifyItem,
  23. FLastUpdate : TCollectionItem;
  24. FNotifyCount : Integer;
  25. FLastNotify : TCollectionNotification;
  26. Function GetOwner : TPersistent; override;
  27. Public
  28. procedure Update(Item: TCollectionItem); override;
  29. procedure Notify(Item: TCollectionItem;Action: TCollectionNotification); override;
  30. Procedure ResetUpdate;
  31. Procedure ResetNotify;
  32. property PropName;
  33. end;
  34. { TTestTCollection }
  35. TTestTCollection= class(TTestCase)
  36. private
  37. procedure AccessNegativeIndex;
  38. procedure AccessTooBigIndex;
  39. procedure DeleteNegativeIndex;
  40. procedure DeleteTooBigIndex;
  41. procedure MoveNegativeIndex;
  42. procedure MoveTooBigIndex;
  43. protected
  44. FColl : TMyCollection;
  45. Function MyItem(I : integer) : TMyItem;
  46. procedure AddItems(ACount : Integer);
  47. procedure SetUp; override;
  48. procedure TearDown; override;
  49. published
  50. procedure TestCreate;
  51. procedure TestAdd;
  52. procedure TestItemCollection;
  53. procedure TestAddTwo;
  54. Procedure TestDelete;
  55. procedure TestClear;
  56. Procedure TestFreeItem;
  57. Procedure TestMoveForward;
  58. Procedure TestMoveBackward;
  59. Procedure TestID;
  60. Procedure TestItemOwner;
  61. Procedure TestDisplayName;
  62. procedure TestOwnerNamePath;
  63. Procedure TestItemNamePath;
  64. Procedure TestOwnerItemNamePath;
  65. Procedure TestChangeCollection;
  66. procedure TestAccesIndexOutOfBounds;
  67. procedure TestDeleteIndexOutOfBounds;
  68. procedure TestMoveIndexOutOfBounds;
  69. Procedure TestUpdateAdd;
  70. Procedure TestUpdateDelete;
  71. Procedure TestUpdateDisplayName;
  72. Procedure TestUpdateCount;
  73. Procedure TestUpdateCountNested;
  74. Procedure TestUpdateMove;
  75. Procedure TestNotifyAdd;
  76. Procedure TestNotifyDelete;
  77. end;
  78. implementation
  79. procedure TTestTCollection.TestCreate;
  80. begin
  81. AssertEquals('Item count 0 at create',0,FColl.Count);
  82. AssertEquals('ItemClass is TMyItem',TMyItem,FColl.ItemClass);
  83. end;
  84. procedure TTestTCollection.TestAdd;
  85. begin
  86. AddItems(1);
  87. AssertEquals('Item count is 1 after add',1,FColl.Count);
  88. AssertEquals('Item class is correct',FColl.ItemClass,FColl.Items[0].ClassType);
  89. AssertEquals('Item index is 0',0,FColl.Items[0].Index);
  90. AssertEquals('Item ID is 0',0,FColl.Items[0].Id);
  91. end;
  92. procedure TTestTCollection.TestItemCollection;
  93. begin
  94. AddItems(1);
  95. If MyItem(0).Collection<>FColl then
  96. Fail('Item''s Collection is not collection');
  97. end;
  98. procedure TTestTCollection.TestAddTwo;
  99. Var
  100. I: Integer;
  101. begin
  102. AddItems(3);
  103. AssertEquals('Item count is 3 after add',3,FColl.Count);
  104. For I:=0 to 2 do
  105. begin
  106. AssertEquals(Format('Item %d class is correct',[i]),FColl.ItemClass,FColl.Items[i].ClassType);
  107. AssertEquals(Format('Item %d index is 0',[i]),i,FColl.Items[i].Index);
  108. AssertEquals(Format('Item %d ID is 0',[i]),i,FColl.Items[i].Id);
  109. AssertEquals(Format('Item %d ID is %d',[i,i+1]),i+1,MyItem(i).Nr);
  110. end;
  111. end;
  112. procedure TTestTCollection.TestDelete;
  113. begin
  114. AddItems(3);
  115. FColl.Delete(1);
  116. AssertEquals('Item count after delete',2,FColl.Count);
  117. AssertEquals('Item 0 ok after delete',1,MyItem(0).Nr);
  118. AssertEquals('Item 1 ok after delete',3,MyItem(1).Nr);
  119. end;
  120. procedure TTestTCollection.TestClear;
  121. begin
  122. AddItems(3);
  123. FColl.Clear;
  124. AssertEquals('Item count after clear',0,FColl.Count);
  125. end;
  126. procedure TTestTCollection.TestFreeItem;
  127. begin
  128. AddItems(3);
  129. MyItem(1).Free;
  130. AssertEquals('Item count after free',2,FColl.Count);
  131. AssertEquals('Item 0 ok after free',1,MyItem(0).Nr);
  132. AssertEquals('Item 1 ok after free',3,MyItem(1).Nr);
  133. end;
  134. procedure TTestTCollection.TestMoveForward;
  135. begin
  136. AddItems(5);
  137. MyItem(4).Index:=1;
  138. AssertEquals('Item 0 ok after move',1,MyItem(0).Nr);
  139. AssertEquals('Item 1 ok after move',5,MyItem(1).Nr);
  140. AssertEquals('Item 2 ok after move',2,MyItem(2).Nr);
  141. AssertEquals('Item 3 ok after move',3,MyItem(3).Nr);
  142. AssertEquals('Item 4 ok after move',4,MyItem(4).Nr);
  143. end;
  144. procedure TTestTCollection.TestMoveBackward;
  145. begin
  146. AddItems(5);
  147. MyItem(1).Index:=3;
  148. AssertEquals('Item 0 ok after move',1,MyItem(0).Nr);
  149. AssertEquals('Item 1 ok after move',3,MyItem(1).Nr);
  150. AssertEquals('Item 2 ok after move',4,MyItem(2).Nr);
  151. AssertEquals('Item 3 ok after move',2,MyItem(3).Nr);
  152. AssertEquals('Item 4 ok after move',5,MyItem(4).Nr);
  153. end;
  154. procedure TTestTCollection.TestID;
  155. Var
  156. I : TMyItem;
  157. begin
  158. AddItems(5);
  159. FColl.Delete(2);
  160. FColl.Delete(2);
  161. I:=TMyItem(FColl.Add);
  162. AssertEquals('ID keeps counting up',5,I.Id)
  163. end;
  164. procedure TTestTCollection.TestItemOwner;
  165. begin
  166. AddItems(1);
  167. If (MyItem(0).GetOwner<>FColl) then
  168. Fail('Item owner is not collection');
  169. end;
  170. procedure TTestTCollection.TestDisplayName;
  171. begin
  172. AddItems(1);
  173. AssertEquals('Displayname is classname','TMyItem',MyItem(0).DisplayName);
  174. end;
  175. procedure TTestTCollection.TestItemNamePath;
  176. begin
  177. AddItems(2);
  178. AssertEquals('Item namepath is collection namepath+index',FColl.GetNamePath+'[0]',MyItem(0).GetNamePath);
  179. AssertEquals('Item namepath is collection namepath+index',FColl.GetNamePath+'[1]',MyItem(1).GetNamePath);
  180. end;
  181. procedure TTestTCollection.TestOwnerItemNamePath;
  182. Var
  183. P : TPersistent;
  184. begin
  185. P:=TPersistent.Create;
  186. try
  187. TMyCollection(FColl).FOwner:=P;
  188. AddItems(2);
  189. TMyCollection(FColl).PropName:='Something';
  190. AssertEquals('Item namepath is collection namepath+index','TPersistent.Something[0]',MyItem(0).GetNamePath);
  191. finally
  192. P.Free;
  193. end;
  194. end;
  195. procedure TTestTCollection.TestOwnerNamePath;
  196. Var
  197. P : TPersistent;
  198. begin
  199. P:=TPersistent.Create;
  200. try
  201. TMyCollection(FColl).FOwner:=P;
  202. AddItems(2);
  203. TMyCollection(FColl).PropName:='Something';
  204. AssertEquals('Namepath is collection namepath+index','TPersistent.Something',FColl.GetNamePath);
  205. finally
  206. P.Free;
  207. end;
  208. end;
  209. procedure TTestTCollection.TestChangeCollection;
  210. Var
  211. FCol2 : TCollection;
  212. I : TCollectionItem;
  213. begin
  214. AddItems(2);
  215. FCol2:=TCollection.Create(TMyItem);
  216. try
  217. I:=FCol2.Add;
  218. I.Collection:=FColl;
  219. AssertEquals('Moved item, count of source is zero',0,FCol2.Count);
  220. AssertEquals('Moved item, count of dest is 1',3,FColl.Count);
  221. AssertEquals('Moved item, index is 2',2,I.Index);
  222. If (FColl.Items[0].Collection<>FColl) then
  223. Fail('Collection owner is not set correctly after move');
  224. AssertEquals('Moved item, ID is 2',2,I.ID);
  225. finally
  226. FCol2.free;
  227. end;
  228. end;
  229. procedure TTestTCollection.AccessNegativeIndex;
  230. begin
  231. FColl.Items[-1];
  232. end;
  233. procedure TTestTCollection.AccessTooBigIndex;
  234. begin
  235. FColl.Items[3];
  236. end;
  237. procedure TTestTCollection.TestAccesIndexOutOfBounds;
  238. begin
  239. AddItems(3);
  240. AssertException('Access Negative Index',EListError,@AccessNegativeIndex);
  241. AssertException('Access Index too big',EListError,@AccessTooBigIndex);
  242. end;
  243. procedure TTestTCollection.DeleteNegativeIndex;
  244. begin
  245. FColl.Delete(-1);
  246. end;
  247. procedure TTestTCollection.DeleteTooBigIndex;
  248. begin
  249. FColl.Delete(3);
  250. end;
  251. procedure TTestTCollection.TestDeleteIndexOutOfBounds;
  252. begin
  253. AddItems(3);
  254. AssertException('Delete Negative Index',EListError,@DeleteNegativeIndex);
  255. AssertException('Delete Index too big',EListError,@DeleteTooBigIndex);
  256. end;
  257. procedure TTestTCollection.MoveNegativeIndex;
  258. begin
  259. FColl.Items[1].Index:=-1;
  260. end;
  261. procedure TTestTCollection.MoveTooBigIndex;
  262. begin
  263. FColl.Items[1].Index:=3;
  264. end;
  265. procedure TTestTCollection.TestMoveIndexOutOfBounds;
  266. begin
  267. AddItems(3);
  268. AssertException('Move Negative first index',EListError,@MoveNegativeIndex);
  269. AssertException('Exchange Negative second index',EListError,@MoveTooBigIndex);
  270. end;
  271. procedure TTestTCollection.TestUpdateAdd;
  272. begin
  273. AddItems(1);
  274. If (FColl.FLastUpdate<>Nil) then
  275. Fail('update item found !');
  276. AssertEquals('Update count is 1',1,FColl.FUpdateCount);
  277. end;
  278. procedure TTestTCollection.TestUpdateDelete;
  279. begin
  280. AddItems(1);
  281. FColl.ResetUpdate;
  282. FColl.Delete(0);
  283. If (FColl.FLastUpdate<>Nil) then
  284. Fail('update item found !');
  285. AssertEquals('Update count is 1',1,FColl.FUpdateCount);
  286. end;
  287. procedure TTestTCollection.TestUpdateDisplayName;
  288. begin
  289. AddItems(1);
  290. FColl.ResetUpdate;
  291. MyItem(0).DisplayName:='Something';
  292. AssertEquals('Display name notification. Update count is 1',1,FColl.FUpdateCount);
  293. If (FColl.FLastUpdate<>MyItem(0)) then
  294. Fail('No displayname update');
  295. end;
  296. procedure TTestTCollection.TestUpdateCount;
  297. begin
  298. FColl.BeginUpdate;
  299. Try
  300. AddItems(2);
  301. AssertEquals('Beginupdate; adds. Update count is 0',0,FColl.FUpdateCount);
  302. If (FColl.FLastUpdate<>Nil) then
  303. Fail('Beginupdate; FlastUpdate not nil');
  304. finally
  305. FColl.EndUpdate;
  306. end;
  307. AssertEquals('Endupdate; adds. Update count is 1',1,FColl.FUpdateCount);
  308. If (FColl.FLastUpdate<>Nil) then
  309. Fail('Endupdate; FlastUpdate not nil');
  310. end;
  311. procedure TTestTCollection.TestUpdateCountNested;
  312. begin
  313. FColl.BeginUpdate;
  314. Try
  315. AddItems(2);
  316. FColl.BeginUpdate;
  317. Try
  318. AddItems(2);
  319. AssertEquals('Beginupdate 2; adds. Update count is 0',0,FColl.FUpdateCount);
  320. If (FColl.FLastUpdate<>Nil) then
  321. Fail('Beginupdate 2; FlastUpdate not nil');
  322. finally
  323. FColl.EndUpdate;
  324. end;
  325. AssertEquals('Endupdate 1; Update count is 0',0,FColl.FUpdateCount);
  326. If (FColl.FLastUpdate<>Nil) then
  327. Fail('EndUpdate 1; FlastUpdate not nil');
  328. finally
  329. FColl.EndUpdate;
  330. end;
  331. AssertEquals('Endupdate 2; adds. Update count is 1',1,FColl.FUpdateCount);
  332. If (FColl.FLastUpdate<>Nil) then
  333. Fail('Endupdate 2; FlastUpdate not nil');
  334. end;
  335. procedure TTestTCollection.TestUpdateMove;
  336. begin
  337. AddItems(5);
  338. FColl.ResetUpdate;
  339. MyItem(4).Index:=2;
  340. AssertEquals('Moved item. Update count is 1',1,FColl.FUpdateCount);
  341. If (FColl.FLastUpdate<>Nil) then
  342. Fail('Moved item notification - not all items updated');
  343. end;
  344. procedure TTestTCollection.TestNotifyAdd;
  345. begin
  346. AddItems(1);
  347. If (FColl.FLastNotifyItem<>MyItem(0)) then
  348. Fail('No notify item found !');
  349. AssertEquals('Notify count is 1',1,FColl.FNotifyCount);
  350. AssertEquals('Notify action is cnAdded',Ord(cnAdded),Ord(FColl.FLastNotify));
  351. end;
  352. procedure TTestTCollection.TestNotifyDelete;
  353. begin
  354. AddItems(3);
  355. FColl.ResetNotify;
  356. FColl.Delete(1);
  357. // cnDeleting/cnExtracing. Can't currently test for 2 events...
  358. AssertEquals('Notify count is 2',2,FColl.FNotifyCount);
  359. AssertEquals('Notify action is cnExtracted',Ord(cnExtracting),Ord(FColl.FLastNotify));
  360. end;
  361. function TTestTCollection.MyItem(I: integer): TMyItem;
  362. begin
  363. Result:=TMyItem(FColl.Items[i]);
  364. end;
  365. procedure TTestTCollection.AddItems(ACount: Integer);
  366. Var
  367. I : integer;
  368. begin
  369. For I:=1 to ACount do
  370. TMyItem(FColl.Add).Nr:=I;
  371. end;
  372. procedure TTestTCollection.SetUp;
  373. begin
  374. FColl:=TMyCollection.Create(TMyItem);
  375. end;
  376. procedure TTestTCollection.TearDown;
  377. begin
  378. FreeAndNil(FColl);
  379. end;
  380. { TMyItem }
  381. function TMyItem.GetOwner: TPersistent;
  382. begin
  383. Result:=inherited GetOwner;
  384. end;
  385. { TMyCollection }
  386. function TMyCollection.GetOwner: TPersistent;
  387. begin
  388. Result:=FOwner;
  389. If (Result=Nil) then
  390. Result:=Inherited GetOwner;
  391. end;
  392. procedure TMyCollection.Update(Item: TCollectionItem);
  393. begin
  394. Inc(FUpdateCount);
  395. FLastUpdate:=Item;
  396. end;
  397. procedure TMyCollection.Notify(Item: TCollectionItem;
  398. Action: TCollectionNotification);
  399. begin
  400. Inc(FNotifyCount);
  401. FLastNotify:=Action;
  402. FLastNotifyItem:=Item;
  403. end;
  404. procedure TMyCollection.ResetUpdate;
  405. begin
  406. FUpdateCount:=0;
  407. FLastUpdate:=Nil;
  408. end;
  409. procedure TMyCollection.ResetNotify;
  410. begin
  411. FNotifyCount:=0;
  412. FLastNotifyItem:=Nil;
  413. end;
  414. initialization
  415. RegisterTest(TTestTCollection);
  416. end.