tests.generics.hashmaps.pas 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2018 by Maciej Izak (hnb),
  4. member of the Free Pascal development team
  5. It contains tests for the Free Pascal generics library
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. Acknowledgment
  12. Thanks to Sphere 10 Software (http://sphere10.com) for sponsoring
  13. many new types, tests and major refactoring of entire library
  14. **********************************************************************}
  15. unit tests.generics.hashmaps;
  16. {$mode delphi}
  17. {$MACRO ON}
  18. interface
  19. uses
  20. fpcunit, testregistry, testutils, tests.generics.utils,
  21. typinfo, Classes, SysUtils, StrUtils, Generics.Collections, Generics.Defaults;
  22. type
  23. PCollectionNotification = ^TCollectionNotification;
  24. { TTestHashMaps }
  25. TTestHashMaps= class(TTestCollections)
  26. private
  27. procedure CountAsKey_Check(const AWhat: string; AValue, AExpectedValue: Integer;
  28. AAction: PCollectionNotification);
  29. procedure CountAsKey_Notify(const AKind: string; ASender: TObject; constref AItem: Integer; AAction: TCollectionNotification);
  30. procedure CountAsKey_NotifyValue(ASender: TObject; constref AItem: Integer; AAction: TCollectionNotification);
  31. procedure CountAsKey_NotifyKey(ASender: TObject; constref AItem: Integer; AAction: TCollectionNotification);
  32. published
  33. procedure Test_CountAsKey_OpenAddressingLP;
  34. procedure Test_CountAsKey_OpenAddressingLPT;
  35. procedure Test_CountAsKey_OpenAddressingQP;
  36. procedure Test_CountAsKey_OpenAddressingDH;
  37. procedure Test_CountAsKey_CuckooD2;
  38. procedure Test_CountAsKey_CuckooD4;
  39. procedure Test_CountAsKey_CuckooD6;
  40. procedure Test_OpenAddressingLP_Notification;
  41. procedure Test_OpenAddressingLPT_Notification;
  42. procedure Test_OpenAddressingQP_Notification;
  43. procedure Test_OpenAddressingDH_Notification;
  44. procedure Test_CuckooD2_Notification;
  45. procedure Test_CuckooD4_Notification;
  46. procedure Test_CuckooD6_Notification;
  47. procedure Test_OpenAddressingLP_TrimExcess;
  48. procedure Test_CuckooD2_TrimExcess;
  49. procedure Test_TryAddOrSetOrGetValue;
  50. end;
  51. implementation
  52. { TTestHashMaps }
  53. procedure TTestHashMaps.CountAsKey_Check(const AWhat: string; AValue, AExpectedValue: Integer;
  54. AAction: PCollectionNotification);
  55. var
  56. LCollectionNotificationStr: string;
  57. begin
  58. if Assigned(AAction) then
  59. LCollectionNotificationStr := GetEnumName(TypeInfo(TCollectionNotification), Ord(AAction^));
  60. AssertEquals(AWhat + LCollectionNotificationStr, AExpectedValue, AValue);
  61. end;
  62. procedure TTestHashMaps.CountAsKey_Notify(const AKind: string; ASender: TObject; constref
  63. AItem: Integer; AAction: TCollectionNotification);
  64. var
  65. LCount: Integer;
  66. begin
  67. CountAsKey_Check('Item ('+AKind+')', AItem, 0, @AAction);
  68. LCount := TCustomDictionary<Integer, Integer, TDefaultHashFactory>(ASender).Count;
  69. case AAction of
  70. cnAdded:
  71. CountAsKey_Check('Count', LCount, 1, @AAction);
  72. cnRemoved:
  73. CountAsKey_Check('Count', LCount, 0, @AAction);
  74. cnExtracted: Halt(4);
  75. end;
  76. end;
  77. procedure TTestHashMaps.CountAsKey_NotifyValue(ASender: TObject; constref AItem: Integer;
  78. AAction: TCollectionNotification);
  79. begin
  80. CountAsKey_Notify('Value', ASender, AItem, AAction);
  81. end;
  82. procedure TTestHashMaps.CountAsKey_NotifyKey(ASender: TObject; constref AItem: Integer;
  83. AAction: TCollectionNotification);
  84. begin
  85. CountAsKey_Notify('Key', ASender, AItem, AAction);
  86. end;
  87. {$DEFINE TEST_COUNT_AS_KEY :=
  88. LDictionary.OnKeyNotify := CountAsKey_NotifyKey;
  89. LDictionary.OnValueNotify := CountAsKey_NotifyValue;
  90. CountAsKey_Check('Count', LDictionary.Count, 0, nil);
  91. LDictionary.Add(LDictionary.Count,LDictionary.Count);
  92. CountAsKey_Check('Item', LDictionary[0], 0, nil);
  93. LDictionary.Free
  94. }
  95. procedure TTestHashMaps.Test_CountAsKey_OpenAddressingLP;
  96. var
  97. LDictionary: TOpenAddressingLP<Integer, Integer>;
  98. begin
  99. // TOpenAddressingLP
  100. LDictionary := TOpenAddressingLP<Integer, Integer>.Create;
  101. TEST_COUNT_AS_KEY;
  102. end;
  103. procedure TTestHashMaps.Test_CountAsKey_OpenAddressingLPT;
  104. var
  105. LDictionary: TOpenAddressingLPT<Integer, Integer>;
  106. begin
  107. // TOpenAddressingLPT
  108. LDictionary := TOpenAddressingLPT<Integer, Integer>.Create;
  109. TEST_COUNT_AS_KEY;
  110. end;
  111. procedure TTestHashMaps.Test_CountAsKey_OpenAddressingQP;
  112. var
  113. LDictionary: TOpenAddressingQP<Integer, Integer>;
  114. begin
  115. // TOpenAddressingQP
  116. LDictionary := TOpenAddressingQP<Integer, Integer>.Create;
  117. TEST_COUNT_AS_KEY;
  118. end;
  119. procedure TTestHashMaps.Test_CountAsKey_OpenAddressingDH;
  120. var
  121. LDictionary: TOpenAddressingDH<Integer, Integer>;
  122. begin
  123. // TOpenAddressingDH
  124. LDictionary := TOpenAddressingDH<Integer, Integer>.Create;
  125. TEST_COUNT_AS_KEY;
  126. end;
  127. procedure TTestHashMaps.Test_CountAsKey_CuckooD2;
  128. var
  129. LDictionary: TCuckooD2<Integer, Integer>;
  130. begin
  131. // TCuckooD2
  132. LDictionary := TCuckooD2<Integer, Integer>.Create;
  133. TEST_COUNT_AS_KEY;
  134. end;
  135. procedure TTestHashMaps.Test_CountAsKey_CuckooD4;
  136. var
  137. LDictionary: TCuckooD4<Integer, Integer>;
  138. begin
  139. // TCuckooD4
  140. LDictionary := TCuckooD4<Integer, Integer>.Create;
  141. TEST_COUNT_AS_KEY;
  142. end;
  143. procedure TTestHashMaps.Test_CountAsKey_CuckooD6;
  144. var
  145. LDictionary: TCuckooD6<Integer, Integer>;
  146. begin
  147. // TCuckooD6
  148. LDictionary := TCuckooD6<Integer, Integer>.Create;
  149. TEST_COUNT_AS_KEY;
  150. end;
  151. {$DEFINE TEST_NOTIFICATIONS :=
  152. try
  153. LDictionary.OnKeyNotify := NotifyTestStr;
  154. LDictionary.OnValueNotify := NotifyTestStr;
  155. // Add
  156. NotificationAdd(LDictionary, ['Aaa', 'Bbb', 'Ccc', 'Ddd', 'Eee', 'Fff'], cnAdded);
  157. LDictionary.Add('Aaa', 'Bbb');
  158. LDictionary.Add('Ccc', 'Ddd');
  159. LDictionary.Add('Eee', 'Fff');
  160. AssertNotificationsExecutedStr;
  161. // Remove and ExtractPair
  162. NotificationAdd(LDictionary, ['Ccc', 'Ddd'], cnRemoved);
  163. LDictionary.Remove('Ccc');
  164. AssertNotificationsExecutedStr;
  165. NotificationAdd(LDictionary, ['Aaa', 'Bbb'], cnExtracted);
  166. with LDictionary.ExtractPair('Aaa') do
  167. begin
  168. AssertEquals(Key, 'Aaa');
  169. AssertEquals(Value, 'Bbb');
  170. end;
  171. AssertNotificationsExecutedStr;
  172. // Clear
  173. NotificationAdd(LDictionary, ['Eee', 'Fff'], cnRemoved);
  174. LDictionary.Clear;
  175. AssertNotificationsExecutedStr;
  176. // SetItem
  177. NotificationAdd(LDictionary, ['FPC', 'Polandball'], cnAdded);
  178. LDictionary.AddOrSetValue('FPC', 'Polandball');
  179. AssertNotificationsExecutedStr;
  180. NotificationAdd(LDictionary, 'Polandball', cnRemoved);
  181. NotificationAdd(LDictionary, 'xD', cnAdded);
  182. NotificationAdd(LDictionary, 'xD', cnRemoved);
  183. NotificationAdd(LDictionary, 'Polandball', cnAdded);
  184. LDictionary['FPC'] := 'xD';
  185. LDictionary.AddOrSetValue('FPC', 'Polandball');
  186. AssertNotificationsExecutedStr;
  187. finally
  188. NotificationAdd(LDictionary, ['FPC', 'Polandball'], cnRemoved);
  189. LDictionary.Free;
  190. AssertNotificationsExecutedStr;
  191. end
  192. }
  193. procedure TTestHashMaps.Test_OpenAddressingLP_Notification;
  194. var
  195. LDictionary: TOpenAddressingLP<string, string>;
  196. begin
  197. LDictionary := TOpenAddressingLP<string, string>.Create;
  198. TEST_NOTIFICATIONS;
  199. end;
  200. procedure TTestHashMaps.Test_OpenAddressingLPT_Notification;
  201. var
  202. LDictionary: TOpenAddressingLPT<string, string>;
  203. begin
  204. LDictionary := TOpenAddressingLPT<string, string>.Create;
  205. TEST_NOTIFICATIONS;
  206. end;
  207. procedure TTestHashMaps.Test_OpenAddressingQP_Notification;
  208. var
  209. LDictionary: TOpenAddressingQP<string, string>;
  210. begin
  211. LDictionary := TOpenAddressingQP<string, string>.Create;
  212. TEST_NOTIFICATIONS;
  213. end;
  214. procedure TTestHashMaps.Test_OpenAddressingDH_Notification;
  215. var
  216. LDictionary: TOpenAddressingDH<string, string>;
  217. begin
  218. LDictionary := TOpenAddressingDH<string, string>.Create;
  219. TEST_NOTIFICATIONS;
  220. end;
  221. procedure TTestHashMaps.Test_CuckooD2_Notification;
  222. var
  223. LDictionary: TCuckooD2<string, string>;
  224. begin
  225. LDictionary := TCuckooD2<string, string>.Create;
  226. TEST_NOTIFICATIONS;
  227. end;
  228. procedure TTestHashMaps.Test_CuckooD4_Notification;
  229. var
  230. LDictionary: TCuckooD4<string, string>;
  231. begin
  232. LDictionary := TCuckooD4<string, string>.Create;
  233. TEST_NOTIFICATIONS;
  234. end;
  235. procedure TTestHashMaps.Test_CuckooD6_Notification;
  236. var
  237. LDictionary: TCuckooD6<string, string>;
  238. begin
  239. LDictionary := TCuckooD6<string, string>.Create;
  240. TEST_NOTIFICATIONS;
  241. end;
  242. {$DEFINE TEST_TRIMEXCESS :=
  243. try
  244. for i := 1 to 8 do
  245. LDictionary.Add(i, EmptyRecord);
  246. LDictionary.Remove(1);
  247. CheckNotEquals(LDictionary.Capacity, LDictionary.Count);
  248. LDictionary.TrimExcess;
  249. AssertEquals(LDictionary.Capacity, 8);
  250. finally
  251. LDictionary.Free;
  252. end;
  253. }
  254. procedure TTestHashMaps.Test_OpenAddressingLP_TrimExcess;
  255. var
  256. LDictionary: TOpenAddressingLP<Integer, TEmptyRecord>;
  257. i: Integer;
  258. begin
  259. LDictionary := TOpenAddressingLP<Integer, TEmptyRecord>.Create;
  260. TEST_TRIMEXCESS;
  261. end;
  262. procedure TTestHashMaps.Test_CuckooD2_TrimExcess;
  263. var
  264. LDictionary: TCuckooD2<Integer, TEmptyRecord>;
  265. i: Integer;
  266. begin
  267. LDictionary := TCuckooD2<Integer, TEmptyRecord>.Create;
  268. TEST_TRIMEXCESS;
  269. end;
  270. procedure TTestHashMaps.Test_TryAddOrSetOrGetValue;
  271. // modified test from Castle Game Engine (https://castle-engine.sourceforge.io)
  272. var
  273. LObjects: TDictionary<string, TObject>;
  274. LObject, LFoundObject: TObject;
  275. begin
  276. LObjects := TDictionary<string, TObject>.Create;
  277. try
  278. LObjects.TryGetValue('blah', LFoundObject);
  279. AssertTrue(nil = LFoundObject);
  280. LObject := TObject.Create;
  281. LObjects.AddOrSetValue('nope', LObject);
  282. LObjects.TryGetValue('blah', LFoundObject);
  283. AssertTrue(nil = LFoundObject);
  284. LObject := TObject.Create;
  285. LObjects.AddOrSetValue('blah', LObject);
  286. LObjects.TryGetValue('blah', LFoundObject);
  287. AssertTrue(LObject = LFoundObject);
  288. LObjects.Remove('blah');
  289. LObject.Free;
  290. LObjects.TryGetValue('blah', LFoundObject);
  291. AssertTrue(nil = LFoundObject);
  292. LObjects['nope'].Free;
  293. finally
  294. FreeAndNil(LObjects)
  295. end;
  296. end;
  297. begin
  298. RegisterTest(TTestHashMaps);
  299. end.