tests.generics.utils.pas 16 KB

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