tests.generics.utils.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. {
  2. This file is part of the Free Pascal/NewPascal run time library.
  3. Copyright (c) 2014 by Maciej Izak (hnb)
  4. member of the NewPascal development team (http://newpascal.org)
  5. Copyright(c) 2004-2018 DaThoX
  6. It contains tests for the Free Pascal generics library
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. unit tests.generics.utils;
  14. {$mode delphi}
  15. interface
  16. uses
  17. fpcunit, testutils, testregistry,
  18. Classes, SysUtils, Generics.Collections;
  19. type
  20. TNotificationRec<T> = record
  21. Sender: TObject;
  22. Item: T;
  23. Action: TCollectionNotification;
  24. Executed: boolean;
  25. end;
  26. TNotificationNodeRec<TValue, TInfo> = record
  27. Sender: TObject;
  28. Key: string;
  29. Value: TValue;
  30. IgnoreNodePtr: boolean;
  31. Node: TCustomAVLTreeMap<string, TValue, TInfo>.PNode;
  32. Action: TCollectionNotification;
  33. Dispose: boolean;
  34. Executed: boolean;
  35. end;
  36. TTestCollections = class(TTestCase)
  37. private type
  38. TNotificationRec_String = TNotificationRec<string>;
  39. TNotificationRec_TObject = TNotificationRec<TObject>;
  40. TNotificationNodeRec_String = TNotificationNodeRec<string, TEmptyRecord>;
  41. TNotificationNodeRec_Empty = TNotificationNodeRec<TEmptyRecord, TEmptyRecord>;
  42. PNode_String = TCustomAVLTreeMap<string, string, TEmptyRecord>.PNode;
  43. PNode_Empty = TCustomAVLTreeMap<string, TEmptyRecord, TEmptyRecord>.PNode;
  44. private
  45. NotificationsListNode_String: TList<TNotificationNodeRec_String>;
  46. NotificationsListNode_Empty: TList<TNotificationNodeRec_Empty>;
  47. NotificationsListStr: TList<TNotificationRec_String>;
  48. NotificationsListObj: TList<TNotificationRec_TObject>;
  49. NotificationsIndex, NotificationsNodesIndex: Integer;
  50. protected
  51. procedure NotificationAdd(ASender: TObject; const AKey, AValue: string; ANode: PNode_String;
  52. AAction: TCollectionNotification; ADispose, AIgnoreNodePtr: boolean); overload;
  53. procedure NotificationAdd(ASender: TObject; const AKeys, AValues: array of string;
  54. const ANodes: array of PNode_String; AAction: TCollectionNotification; ADispose, AIgnoreNodePtr: boolean); overload;
  55. procedure NotificationAdd(ASender: TObject; const AKey: string; ANode: PNode_Empty;
  56. AAction: TCollectionNotification; ADispose, AIgnoreNodePtr: boolean); overload;
  57. procedure NotificationAdd(ASender: TObject; const AKeys: array of string;
  58. const ANodes: array of PNode_Empty; AAction: TCollectionNotification; ADispose, AIgnoreNodePtr: boolean); overload;
  59. procedure NotificationAdd(ASender: TObject; const AItem: string;
  60. AAction: TCollectionNotification); overload;
  61. procedure NotificationAdd(ASender: TObject; const AItems: array of string;
  62. AAction: TCollectionNotification); overload;
  63. procedure NotificationAdd(ASender: TObject; const AItem: TObject;
  64. AAction: TCollectionNotification); overload;
  65. procedure NotificationAdd(ASender: TObject; const AItems: array of TObject;
  66. AAction: TCollectionNotification); overload;
  67. procedure AssertNotificationsExecutedNodeStr;
  68. procedure ClearNotificationsNodeStr;
  69. procedure AssertNotificationsExecutedNodeEmpty;
  70. procedure ClearNotificationsNodeEmpty;
  71. procedure AssertNotificationsExecutedStr;
  72. procedure ClearNotificationsStr;
  73. procedure AssertNotificationsExecutedObj;
  74. procedure ClearNotificationsObj;
  75. procedure NotifyTestNodeStr(ASender: TObject; ANode: PNode_String; AAction: TCollectionNotification; ADispose: boolean);
  76. procedure NotifyTestNodeEmpty(ASender: TObject; ANode: PNode_Empty; AAction: TCollectionNotification; ADispose: boolean);
  77. procedure NotifyTestStr(ASender: TObject; const AItem: string; AAction: TCollectionNotification);
  78. procedure NotifyTestObj(ASender: TObject; const AItem: TObject; AAction: TCollectionNotification);
  79. procedure CreateObjects(var AArray: TArray<TObject>; ACount: Integer);
  80. procedure FreeObjects(AArray: TArray<TObject>);
  81. public
  82. constructor Create; override;
  83. destructor Destroy; override;
  84. end;
  85. TStringList = TList<string>;
  86. { TStringsEnumerator }
  87. TStringsEnumerator = class(TInterfacedObject, IEnumerator<string>)
  88. private
  89. FEnumerator: TStringList.TEnumerator;
  90. FCollection: TStringList;
  91. function GetCurrent: string;
  92. function MoveNext: Boolean;
  93. procedure Reset;
  94. property Current: string read GetCurrent;
  95. constructor Create(AEnumerator: TStringList.TEnumerator; ACollection: TStringList);
  96. destructor Destroy; override;
  97. end;
  98. { TStringsEnumerable }
  99. TStringsEnumerable = class(TInterfacedObject, IEnumerable<string>)
  100. private
  101. FEnumerable: TStringList;
  102. function GetEnumerator: IEnumerator<string>;
  103. constructor Create(const AItems: array of string);
  104. end;
  105. TObjectList = TList<TObject>;
  106. { TObjectEnumerator }
  107. TObjectEnumerator = class(TInterfacedObject, IEnumerator<TObject>)
  108. private
  109. FEnumerator: TObjectList.TEnumerator;
  110. FCollection: TObjectList;
  111. function GetCurrent: TObject;
  112. function MoveNext: Boolean;
  113. procedure Reset;
  114. property Current: TObject read GetCurrent;
  115. constructor Create(AEnumerator: TObjectList.TEnumerator; ACollection: TObjectList);
  116. destructor Destroy; override;
  117. end;
  118. { TObjectEnumerable }
  119. TObjectEnumerable = class(TInterfacedObject, IEnumerable<TObject>)
  120. private
  121. FEnumerable: TObjectList;
  122. function GetEnumerator: IEnumerator<TObject>;
  123. constructor Create(const AItems: array of TObject);
  124. end;
  125. function EnumerableStringsIntf(const AItems: array of string): IEnumerable<string>;
  126. function EnumerableStringsObj(const AItems: array of string): TEnumerable<string>;
  127. function EnumerableObjectsIntf(const AItems: array of TObject): IEnumerable<TObject>;
  128. function EnumerableObjectsObj(const AItems: array of TObject): TEnumerable<TObject>;
  129. implementation
  130. function EnumerableStringsIntf(const AItems: array of string): IEnumerable<string>;
  131. begin
  132. Result := TStringsEnumerable.Create(AItems);
  133. end;
  134. function EnumerableStringsObj(const AItems: array of string): TEnumerable<string>;
  135. begin
  136. Result := TStringList.Create;
  137. TStringList(Result).AddRange(AItems);
  138. end;
  139. function EnumerableObjectsIntf(const AItems: array of TObject): IEnumerable<TObject>;
  140. begin
  141. Result := TObjectEnumerable.Create(AItems);
  142. end;
  143. function EnumerableObjectsObj(const AItems: array of TObject): TEnumerable<TObject>;
  144. begin
  145. Result := TObjectList.Create;
  146. TObjectList(Result).AddRange(AItems);
  147. end;
  148. { TTestCollections }
  149. procedure TTestCollections.NotificationAdd(ASender: TObject;
  150. const AKey, AValue: string; ANode: PNode_String; AAction: TCollectionNotification; ADispose, AIgnoreNodePtr: boolean);
  151. var
  152. LNotification: TNotificationNodeRec_String;
  153. begin
  154. LNotification.Sender := ASender;
  155. LNotification.Key := AKey;
  156. LNotification.Value := AValue;
  157. LNotification.IgnoreNodePtr := AIgnoreNodePtr;
  158. LNotification.Node := ANode;
  159. LNotification.Action := AAction;
  160. LNotification.Dispose := ADispose;
  161. LNotification.Executed := False;
  162. NotificationsListNode_String.Add(LNotification);
  163. end;
  164. procedure TTestCollections.NotificationAdd(ASender: TObject;
  165. const AKeys, AValues: array of string; const ANodes: array of PNode_String; AAction: TCollectionNotification; ADispose, AIgnoreNodePtr: boolean);
  166. var
  167. i: Integer;
  168. begin
  169. Assert(Length(AKeys) = Length(ANodes));
  170. for i := 0 to High(AKeys) do
  171. NotificationAdd(ASender, AKeys[i], AValues[i], ANodes[i], AAction, ADispose, AIgnoreNodePtr);
  172. end;
  173. procedure TTestCollections.NotificationAdd(ASender: TObject;
  174. const AKey: string; ANode: PNode_Empty; AAction: TCollectionNotification; ADispose, AIgnoreNodePtr: boolean);
  175. var
  176. LNotification: TNotificationNodeRec_Empty;
  177. begin
  178. LNotification.Sender := ASender;
  179. LNotification.Key := AKey;
  180. LNotification.Value := EmptyRecord;
  181. LNotification.IgnoreNodePtr := AIgnoreNodePtr;
  182. LNotification.Node := ANode;
  183. LNotification.Action := AAction;
  184. LNotification.Dispose := ADispose;
  185. LNotification.Executed := False;
  186. NotificationsListNode_Empty.Add(LNotification);
  187. end;
  188. procedure TTestCollections.NotificationAdd(ASender: TObject;
  189. const AKeys: array of string; const ANodes: array of PNode_Empty; AAction: TCollectionNotification; ADispose, AIgnoreNodePtr: boolean);
  190. var
  191. i: Integer;
  192. begin
  193. Assert(Length(AKeys) = Length(ANodes));
  194. for i := 0 to High(AKeys) do
  195. NotificationAdd(ASender, AKeys[i], ANodes[i], AAction, ADispose, AIgnoreNodePtr);
  196. end;
  197. procedure TTestCollections.NotificationAdd(ASender: TObject;
  198. const AItem: string; AAction: TCollectionNotification);
  199. var
  200. LNotification: TNotificationRec_String;
  201. begin
  202. LNotification.Sender := ASender;
  203. LNotification.Item := AItem;
  204. LNotification.Action := AAction;
  205. LNotification.Executed := False;
  206. NotificationsListStr.Add(LNotification);
  207. end;
  208. procedure TTestCollections.NotificationAdd(ASender: TObject;
  209. const AItems: array of string; AAction: TCollectionNotification);
  210. var
  211. s: string;
  212. begin
  213. for s in AItems do
  214. NotificationAdd(ASender, s, AAction);
  215. end;
  216. procedure TTestCollections.NotificationAdd(ASender: TObject;
  217. const AItem: TObject; AAction: TCollectionNotification);
  218. var
  219. LNotification: TNotificationRec_TObject;
  220. begin
  221. LNotification.Sender := ASender;
  222. LNotification.Item := AItem;
  223. LNotification.Action := AAction;
  224. LNotification.Executed := False;
  225. NotificationsListObj.Add(LNotification);
  226. end;
  227. procedure TTestCollections.NotificationAdd(ASender: TObject;
  228. const AItems: array of TObject; AAction: TCollectionNotification);
  229. var
  230. o: TObject;
  231. begin
  232. for o in AItems do
  233. NotificationAdd(ASender, o, AAction);
  234. end;
  235. procedure TTestCollections.AssertNotificationsExecutedNodeStr;
  236. var
  237. p: ^TNotificationNodeRec_String;
  238. begin
  239. for p in NotificationsListNode_String.Ptr^ do
  240. AssertTrue(p^.Executed);
  241. AssertEquals(NotificationsNodesIndex, NotificationsListNode_String.Count);
  242. ClearNotificationsStr;
  243. end;
  244. procedure TTestCollections.ClearNotificationsNodeStr;
  245. begin
  246. NotificationsListNode_String.Clear;
  247. NotificationsNodesIndex := 0;
  248. end;
  249. procedure TTestCollections.AssertNotificationsExecutedNodeEmpty;
  250. var
  251. p: ^TNotificationNodeRec_Empty;
  252. begin
  253. for p in NotificationsListNode_Empty.Ptr^ do
  254. AssertTrue(p^.Executed);
  255. AssertEquals(NotificationsNodesIndex, NotificationsListNode_Empty.Count);
  256. ClearNotificationsStr;
  257. end;
  258. procedure TTestCollections.ClearNotificationsNodeEmpty;
  259. begin
  260. NotificationsListNode_Empty.Clear;
  261. NotificationsNodesIndex := 0;
  262. end;
  263. procedure TTestCollections.AssertNotificationsExecutedStr;
  264. var
  265. p: ^TNotificationRec_String;
  266. begin
  267. for p in NotificationsListStr.Ptr^ do
  268. AssertTrue(p^.Executed);
  269. AssertEquals(NotificationsIndex, NotificationsListStr.Count);
  270. ClearNotificationsStr;
  271. end;
  272. procedure TTestCollections.ClearNotificationsStr;
  273. begin
  274. NotificationsListStr.Clear;
  275. NotificationsIndex := 0;
  276. end;
  277. procedure TTestCollections.AssertNotificationsExecutedObj;
  278. var
  279. p: ^TNotificationRec_TObject;
  280. begin
  281. for p in NotificationsListObj.Ptr^ do
  282. AssertTrue(p^.Executed);
  283. AssertEquals(NotificationsIndex, NotificationsListObj.Count);
  284. ClearNotificationsObj;
  285. end;
  286. procedure TTestCollections.ClearNotificationsObj;
  287. begin
  288. NotificationsListObj.Clear;
  289. NotificationsIndex := 0;
  290. end;
  291. procedure TTestCollections.NotifyTestNodeStr(ASender: TObject; ANode: PNode_String; AAction: TCollectionNotification; ADispose: boolean);
  292. var
  293. LNotification: TNotificationNodeRec_String;
  294. begin
  295. AssertTrue(NotificationsNodesIndex < NotificationsListNode_String.Count);
  296. LNotification := NotificationsListNode_String[NotificationsNodesIndex];
  297. AssertTrue(ASender = LNotification.Sender);
  298. AssertEquals(ANode.Key, LNotification.Key);
  299. AssertEquals(ANode.Value, LNotification.Value);
  300. if not LNotification.IgnoreNodePtr then
  301. AssertSame(ANode, LNotification.Node);
  302. AssertTrue(AAction = LNotification.Action);
  303. AssertEquals(ADispose, LNotification.Dispose);
  304. AssertFalse(LNotification.Executed);
  305. LNotification.Executed := True;
  306. NotificationsListNode_String[NotificationsNodesIndex] := LNotification;
  307. Inc(NotificationsNodesIndex)
  308. end;
  309. procedure TTestCollections.NotifyTestNodeEmpty(ASender: TObject; ANode: PNode_Empty; AAction: TCollectionNotification; ADispose: boolean);
  310. var
  311. LNotification: TNotificationNodeRec_Empty;
  312. begin
  313. AssertTrue(NotificationsNodesIndex < NotificationsListNode_Empty.Count);
  314. LNotification := NotificationsListNode_Empty[NotificationsNodesIndex];
  315. AssertTrue(ASender = LNotification.Sender);
  316. AssertEquals(ANode.Key, LNotification.Key);
  317. if not LNotification.IgnoreNodePtr then
  318. AssertSame(ANode, LNotification.Node);
  319. AssertTrue(AAction = LNotification.Action);
  320. AssertEquals(ADispose, LNotification.Dispose);
  321. AssertFalse(LNotification.Executed);
  322. LNotification.Executed := True;
  323. NotificationsListNode_Empty[NotificationsNodesIndex] := LNotification;
  324. Inc(NotificationsNodesIndex)
  325. end;
  326. procedure TTestCollections.NotifyTestStr(ASender: TObject; const AItem: string; AAction: TCollectionNotification);
  327. var
  328. LNotification: TNotificationRec_String;
  329. begin
  330. AssertTrue(NotificationsIndex < NotificationsListStr.Count);
  331. LNotification := NotificationsListStr[NotificationsIndex];
  332. AssertTrue(ASender = LNotification.Sender);
  333. AssertEquals(AItem, LNotification.Item);
  334. AssertTrue(AAction = LNotification.Action);
  335. AssertFalse(LNotification.Executed);
  336. LNotification.Executed := True;
  337. NotificationsListStr[NotificationsIndex] := LNotification;
  338. Inc(NotificationsIndex)
  339. end;
  340. procedure TTestCollections.NotifyTestObj(ASender: TObject; const AItem: TObject; AAction: TCollectionNotification);
  341. var
  342. LNotification: TNotificationRec_TObject;
  343. begin
  344. AssertTrue(NotificationsIndex < NotificationsListObj.Count);
  345. LNotification := NotificationsListObj[NotificationsIndex];
  346. AssertTrue(ASender = LNotification.Sender);
  347. AssertTrue(AItem = LNotification.Item);
  348. AssertTrue(AAction = LNotification.Action);
  349. AssertFalse(LNotification.Executed);
  350. LNotification.Executed := True;
  351. NotificationsListObj[NotificationsIndex] := LNotification;
  352. Inc(NotificationsIndex)
  353. end;
  354. procedure TTestCollections.CreateObjects(var AArray: TArray<TObject>; ACount: Integer);
  355. var
  356. i: Integer;
  357. begin
  358. SetLength(AArray, ACount);
  359. for i := 0 to ACount - 1 do
  360. AArray[i] := TObject.Create;
  361. end;
  362. procedure TTestCollections.FreeObjects(AArray: TArray<TObject>);
  363. var
  364. o: TObject;
  365. begin
  366. for o in AArray do
  367. o.Free;
  368. end;
  369. constructor TTestCollections.Create;
  370. begin
  371. inherited;
  372. NotificationsListStr := TList<TNotificationRec_String>.Create;
  373. NotificationsListObj := TList<TNotificationRec_TObject>.Create;
  374. NotificationsListNode_String := TList<TNotificationNodeRec_String>.Create;
  375. NotificationsListNode_Empty := TList<TNotificationNodeRec_Empty>.Create;
  376. end;
  377. destructor TTestCollections.Destroy;
  378. begin
  379. NotificationsListNode_Empty.Free;
  380. NotificationsListNode_String.Free;
  381. NotificationsListObj.Free;
  382. NotificationsListStr.Free;
  383. inherited;
  384. end;
  385. { TStringsEnumerable }
  386. function TStringsEnumerable.GetEnumerator: IEnumerator<string>;
  387. begin
  388. Result := TStringsEnumerator.Create(FEnumerable.GetEnumerator, FEnumerable);
  389. end;
  390. constructor TStringsEnumerable.Create(const AItems: array of string);
  391. begin
  392. FEnumerable := TStringList.Create;
  393. FEnumerable.AddRange(AItems);
  394. end;
  395. { TStringsEnumerator }
  396. function TStringsEnumerator.GetCurrent: string;
  397. begin
  398. Result := FEnumerator.Current;
  399. end;
  400. function TStringsEnumerator.MoveNext: Boolean;
  401. begin
  402. Result := FEnumerator.MoveNext;
  403. end;
  404. procedure TStringsEnumerator.Reset;
  405. begin
  406. FEnumerator.Free;
  407. FEnumerator := FCollection.GetEnumerator;
  408. end;
  409. constructor TStringsEnumerator.Create(AEnumerator: TStringList.TEnumerator; ACollection: TStringList);
  410. begin
  411. FEnumerator := AEnumerator;
  412. FCollection := ACollection;
  413. end;
  414. destructor TStringsEnumerator.Destroy;
  415. begin
  416. FEnumerator.Free;
  417. inherited Destroy;
  418. end;
  419. { TObjectEnumerable }
  420. function TObjectEnumerable.GetEnumerator: IEnumerator<TObject>;
  421. begin
  422. Result := TObjectEnumerator.Create(FEnumerable.GetEnumerator, FEnumerable);
  423. end;
  424. constructor TObjectEnumerable.Create(const AItems: array of TObject);
  425. begin
  426. FEnumerable := TObjectList.Create;
  427. FEnumerable.AddRange(AItems);
  428. end;
  429. { TObjectEnumerator }
  430. function TObjectEnumerator.GetCurrent: TObject;
  431. begin
  432. Result := FEnumerator.Current;
  433. end;
  434. function TObjectEnumerator.MoveNext: Boolean;
  435. begin
  436. Result := FEnumerator.MoveNext;
  437. end;
  438. procedure TObjectEnumerator.Reset;
  439. begin
  440. FEnumerator.Free;
  441. FEnumerator := FCollection.GetEnumerator;
  442. end;
  443. constructor TObjectEnumerator.Create(AEnumerator: TObjectList.TEnumerator; ACollection: TObjectList);
  444. begin
  445. FEnumerator := AEnumerator;
  446. FCollection := ACollection;
  447. end;
  448. destructor TObjectEnumerator.Destroy;
  449. begin
  450. FEnumerator.Free;
  451. inherited Destroy;
  452. end;
  453. end.