tests.generics.dictionary.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. unit tests.generics.dictionary;
  2. {$mode objfpc}
  3. interface
  4. uses
  5. fpcunit, testregistry, Classes, SysUtils, Generics.Defaults, Generics.Collections;
  6. Type
  7. TMySimpleDict = Class(Specialize TDictionary<Integer,String>);
  8. {$IFDEF FPC}
  9. EDictionary = EListError;
  10. TMyPair = specialize TPair<Integer,String>;
  11. {$ENDIF}
  12. { TTestSimpleDictionary }
  13. TTestSimpleDictionary = Class(TTestCase)
  14. Private
  15. FDict : TMySimpleDict;
  16. FnotifyMessage : String;
  17. FCurrentKeyNotify : Integer;
  18. FCurrentValueNotify : Integer;
  19. FExpectKeys : Array of Integer;
  20. FExpectValues : Array of String;
  21. FExpectValueAction,
  22. FExpectKeyAction: Array of TCollectionNotification;
  23. procedure DoAdd(aCount: Integer; aOffset: Integer=0);
  24. procedure DoAdd2;
  25. Procedure DoneExpectKeys;
  26. Procedure DoneExpectValues;
  27. procedure DoGetValue(aKey: Integer; Match: String; ExceptionClass: TClass=nil);
  28. procedure DoKeyNotify(ASender: TObject; {$ifdef fpc}constref{$else}const{$endif} AItem: Integer; AAction: TCollectionNotification);
  29. procedure DoValueNotify(ASender: TObject; {$ifdef fpc}constref{$else}const{$endif} AItem: String; AAction: TCollectionNotification);
  30. Public
  31. Procedure SetExpectKeys(aMessage : string; AKeys : Array of Integer; AActions : Array of TCollectionNotification; DoReverse : Boolean = False);
  32. Procedure SetExpectValues(aMessage : string; AKeys : Array of String; AActions : Array of TCollectionNotification; DoReverse : Boolean = False);
  33. Procedure SetUp; override;
  34. Procedure TearDown; override;
  35. Property Dict : TMySimpleDict Read FDict;
  36. Published
  37. Procedure TestEmpty;
  38. Procedure TestAdd;
  39. Procedure TestClear;
  40. Procedure TestTryGetValue;
  41. Procedure TestGetValue;
  42. Procedure TestSetValue;
  43. Procedure TestAddDuplicate;
  44. Procedure TestAddOrSet;
  45. Procedure TestContainsKey;
  46. Procedure TestContainsValue;
  47. Procedure TestDelete;
  48. Procedure TestToArray;
  49. procedure TestKeys;
  50. Procedure TestValues;
  51. Procedure TestEnumerator;
  52. Procedure TestNotification;
  53. procedure TestNotificationDelete;
  54. procedure TestValueNotification;
  55. procedure TestValueNotificationDelete;
  56. procedure TestKeyValueNotificationSet;
  57. end;
  58. implementation
  59. { TTestSimpleDictionary }
  60. procedure TTestSimpleDictionary.SetUp;
  61. begin
  62. inherited SetUp;
  63. FDict:=TMySimpleDict.Create;
  64. FCurrentKeyNotify:=0;
  65. FCurrentValueNotify:=0;
  66. FExpectKeys:=[];
  67. FExpectKeyAction:=[];
  68. FExpectValues:=[];
  69. FExpectValueAction:=[];
  70. end;
  71. procedure TTestSimpleDictionary.TearDown;
  72. begin
  73. // So we don't get clear messages
  74. FDict.OnKeyNotify:=Nil;
  75. FDict.OnValueNotify:=Nil;
  76. FreeAndNil(FDict);
  77. inherited TearDown;
  78. end;
  79. procedure TTestSimpleDictionary.TestEmpty;
  80. begin
  81. AssertNotNull('Have dictionary',Dict);
  82. AssertEquals('empty dictionary',0,Dict.Count);
  83. end;
  84. procedure TTestSimpleDictionary.DoAdd(aCount : Integer; aOffset : Integer=0);
  85. Var
  86. I : Integer;
  87. begin
  88. if aOffset=-1 then
  89. aOffset:=Dict.Count;
  90. For I:=aOffset+1 to aOffset+aCount do
  91. Dict.Add(I,IntToStr(i));
  92. end;
  93. procedure TTestSimpleDictionary.TestAdd;
  94. begin
  95. DoAdd(1);
  96. AssertEquals('Count OK',1,Dict.Count);
  97. AssertTrue('Has added value',Dict.ContainsKey(1));
  98. DoAdd(1,1);
  99. AssertEquals('Count OK',2,Dict.Count);
  100. AssertTrue('Has added value',Dict.ContainsKey(2));
  101. end;
  102. procedure TTestSimpleDictionary.TestClear;
  103. begin
  104. DoAdd(3);
  105. AssertEquals('Count OK',3,Dict.Count);
  106. Dict.Clear;
  107. AssertEquals('Count after clear OK',0,Dict.Count);
  108. end;
  109. procedure TTestSimpleDictionary.TestTryGetValue;
  110. Var
  111. I : integer;
  112. SI,A : string;
  113. begin
  114. DoAdd(3);
  115. For I:=1 to 3 do
  116. begin
  117. SI:=IntToStr(I);
  118. AssertTrue('Have value '+SI,Dict.TryGetValue(I,A));
  119. AssertEquals('Value is correct '+SI,SI,A);
  120. end;
  121. AssertFalse('Have no value 4',Dict.TryGetValue(4,A));
  122. end;
  123. procedure TTestSimpleDictionary.DoGetValue(aKey: Integer; Match: String; ExceptionClass: TClass);
  124. Var
  125. EC : TClass;
  126. A,EM : String;
  127. begin
  128. EC:=Nil;
  129. try
  130. A:=Dict.Items[aKey];
  131. except
  132. On E : Exception do
  133. begin
  134. EC:=E.ClassType;
  135. EM:=E.Message;
  136. end
  137. end;
  138. if ExceptionClass=Nil then
  139. begin
  140. if EC<>Nil then
  141. Fail('Got exception '+EC.ClassName+' with message: '+EM);
  142. AssertEquals('Value is correct for '+IntToStr(aKey),Match,A)
  143. end
  144. else
  145. begin
  146. if EC=Nil then
  147. Fail('Expected exception '+ExceptionClass.ClassName+' but got none');
  148. if EC<>ExceptionClass then
  149. Fail('Expected exception class '+ExceptionClass.ClassName+' but got '+EC.ClassName+' with message '+EM);
  150. end;
  151. end;
  152. procedure TTestSimpleDictionary.DoKeyNotify(ASender: TObject; {$ifdef fpc}constref{$else}const{$endif} AItem: Integer; AAction: TCollectionNotification);
  153. begin
  154. Writeln(FnotifyMessage+' Notification',FCurrentKeyNotify);
  155. AssertSame(FnotifyMessage+' Correct sender', FDict,aSender);
  156. if (FCurrentKeyNotify>=Length(FExpectKeys)) then
  157. Fail(FnotifyMessage+' Too many notificiations');
  158. AssertEquals(FnotifyMessage+' Notification Key no '+IntToStr(FCurrentKeyNotify),FExpectKeys[FCurrentKeyNotify],aItem);
  159. Inc(FCurrentKeyNotify);
  160. end;
  161. procedure TTestSimpleDictionary.DoValueNotify(ASender: TObject; {$ifdef fpc}constref{$else}const{$endif} AItem: String; AAction: TCollectionNotification);
  162. begin
  163. Writeln(FnotifyMessage+' value Notification',FCurrentValueNotify);
  164. AssertSame(FnotifyMessage+' value Correct sender', FDict,aSender);
  165. if (FCurrentValueNotify>=Length(FExpectValues)) then
  166. Fail(FnotifyMessage+' Too many value notificiations');
  167. AssertEquals(FnotifyMessage+' Notification value no '+IntToStr(FCurrentValueNotify),FExpectValues[FCurrentValueNotify],aItem);
  168. Inc(FCurrentValueNotify);
  169. end;
  170. procedure TTestSimpleDictionary.SetExpectKeys(aMessage: string; AKeys: array of Integer;
  171. AActions: array of TCollectionNotification; DoReverse: Boolean = False);
  172. Var
  173. I,L : integer;
  174. begin
  175. FnotifyMessage:=aMessage;
  176. FCurrentKeyNotify:=0;
  177. L:=Length(aKeys);
  178. AssertEquals('SetExpectkeys: Lengths arrays equal',l,Length(aActions));
  179. SetLength(FExpectKeys,L);
  180. SetLength(FExpectKeyAction,L);
  181. Dec(L);
  182. if DoReverse then
  183. For I:=0 to L do
  184. begin
  185. FExpectKeys[L-i]:=AKeys[i];
  186. FExpectKeyAction[L-i]:=AActions[I];
  187. end
  188. else
  189. For I:=0 to L do
  190. begin
  191. FExpectKeys[i]:=AKeys[i];
  192. FExpectKeyAction[i]:=AActions[I];
  193. end;
  194. end;
  195. procedure TTestSimpleDictionary.SetExpectValues(aMessage: string; AKeys: array of String;
  196. AActions: array of TCollectionNotification; DoReverse: Boolean);
  197. Var
  198. I,L : integer;
  199. begin
  200. FnotifyMessage:=aMessage;
  201. FCurrentValueNotify:=0;
  202. L:=Length(aKeys);
  203. AssertEquals('SetExpectValues: Lengths arrays equal',l,Length(aActions));
  204. SetLength(FExpectValues,L);
  205. SetLength(FExpectValueAction,L);
  206. Dec(L);
  207. if DoReverse then
  208. For I:=0 to L do
  209. begin
  210. FExpectValues[L-i]:=AKeys[i];
  211. FExpectValueAction[L-i]:=AActions[I];
  212. end
  213. else
  214. For I:=0 to L do
  215. begin
  216. FExpectValues[i]:=AKeys[i];
  217. FExpectValueAction[i]:=AActions[I];
  218. end;
  219. end;
  220. procedure TTestSimpleDictionary.TestGetValue;
  221. Var
  222. I : integer;
  223. begin
  224. DoAdd(3);
  225. For I:=1 to 3 do
  226. DoGetValue(I,IntToStr(I));
  227. DoGetValue(4,'4',EDictionary);
  228. end;
  229. procedure TTestSimpleDictionary.TestSetValue;
  230. begin
  231. TestGetValue;
  232. Dict.Items[3]:='Six';
  233. DoGetValue(3,'Six');
  234. end;
  235. procedure TTestSimpleDictionary.DoAdd2;
  236. begin
  237. Dict.Add(2,'A new 2');
  238. end;
  239. procedure TTestSimpleDictionary.DoneExpectKeys;
  240. begin
  241. AssertEquals(FnotifyMessage+' Expected number of keys seen',Length(FExpectKeys),FCurrentKeyNotify);
  242. end;
  243. procedure TTestSimpleDictionary.DoneExpectValues;
  244. begin
  245. AssertEquals(FnotifyMessage+' Expected number of values seen',Length(FExpectValues),FCurrentValueNotify);
  246. end;
  247. procedure TTestSimpleDictionary.TestAddDuplicate;
  248. begin
  249. DoAdd(3);
  250. AssertException('Cannot add duplicate',EDictionary,@DoAdd2);
  251. end;
  252. procedure TTestSimpleDictionary.TestAddOrSet;
  253. begin
  254. DoAdd(3);
  255. Dict.AddOrSetValue(2,'a new 2');
  256. DoGetValue(2,'a new 2');
  257. end;
  258. procedure TTestSimpleDictionary.TestContainsKey;
  259. Var
  260. I : Integer;
  261. begin
  262. DoAdd(3);
  263. For I:=1 to 3 do
  264. AssertTrue('Has '+IntToStr(i),Dict.ContainsKey(I));
  265. AssertFalse('Has not 4',Dict.ContainsKey(4));
  266. end;
  267. procedure TTestSimpleDictionary.TestContainsValue;
  268. Var
  269. I : Integer;
  270. begin
  271. DoAdd(3);
  272. For I:=1 to 3 do
  273. AssertTrue('Has '+IntToStr(i),Dict.ContainsValue(IntToStr(i)));
  274. AssertFalse('Has not 4',Dict.ContainsValue('4'));
  275. end;
  276. procedure TTestSimpleDictionary.TestDelete;
  277. begin
  278. DoAdd(3);
  279. Dict.Remove(2);
  280. AssertEquals('Count',2,Dict.Count);
  281. AssertFalse('Has not 2',Dict.ContainsKey(2));
  282. end;
  283. procedure TTestSimpleDictionary.TestToArray;
  284. Var
  285. {$ifdef fpc}
  286. A : specialize TArray<TMyPair>;
  287. {$else}
  288. A : specialize TArray<TMySimpleDict.TMyPair>;
  289. {$endif}
  290. I : Integer;
  291. SI : String;
  292. begin
  293. DoAdd(3);
  294. A:=Dict.ToArray;
  295. AssertEquals('Length Ok',3,Length(A));
  296. For I:=1 to 3 do
  297. begin
  298. SI:=IntToStr(I);
  299. AssertEquals('key '+SI,I,A[i-1].Key);
  300. AssertEquals('Value '+SI,SI,A[i-1].Value);
  301. end;
  302. end;
  303. procedure TTestSimpleDictionary.TestKeys;
  304. Var
  305. A : Array of Integer;
  306. I : Integer;
  307. SI : String;
  308. begin
  309. DoAdd(3);
  310. A:=Dict.Keys.ToArray;
  311. AssertEquals('Length Ok',3,Length(A));
  312. For I:=1 to 3 do
  313. begin
  314. SI:=IntToStr(I);
  315. AssertEquals('key '+SI,I,A[i-1]);
  316. end;
  317. end;
  318. procedure TTestSimpleDictionary.TestValues;
  319. Var
  320. A : Array of String;
  321. I : Integer;
  322. SI : String;
  323. begin
  324. DoAdd(3);
  325. A:=Dict.Values.ToArray;
  326. AssertEquals('Length Ok',3,Length(A));
  327. For I:=1 to 3 do
  328. begin
  329. SI:=IntToStr(I);
  330. AssertEquals('Value '+SI,SI,A[i-1]);
  331. end;
  332. end;
  333. procedure TTestSimpleDictionary.TestEnumerator;
  334. Var
  335. {$ifdef fpc}
  336. A : TMyPair;
  337. {$else}
  338. A : TMySimpleDict.TMyPair;
  339. {$endif}
  340. I : Integer;
  341. SI : String;
  342. begin
  343. DoAdd(3);
  344. I:=1;
  345. For A in Dict do
  346. begin
  347. SI:=IntToStr(I);
  348. AssertEquals('key '+SI,I,A.Key);
  349. AssertEquals('Value '+SI,SI,A.Value);
  350. Inc(I);
  351. end;
  352. end;
  353. procedure TTestSimpleDictionary.TestNotification;
  354. begin
  355. Dict.OnKeyNotify:=@DoKeyNotify;
  356. SetExpectKeys('Add',[1,2,3],[cnAdded,cnAdded,cnAdded]);
  357. DoAdd(3);
  358. DoneExpectKeys;
  359. end;
  360. procedure TTestSimpleDictionary.TestNotificationDelete;
  361. begin
  362. DoAdd(3);
  363. Dict.OnKeyNotify:=@DoKeyNotify;
  364. SetExpectKeys('Clear',[1,2,3],[cnRemoved,cnRemoved,cnRemoved],{$IFDEF FPC}true{$ELSE}False{$endif});
  365. Dict.Clear;
  366. DoneExpectKeys;
  367. end;
  368. procedure TTestSimpleDictionary.TestValueNotification;
  369. begin
  370. Dict.OnValueNotify:=@DoValueNotify;
  371. SetExpectValues('Add',['1','2','3'],[cnAdded,cnAdded,cnAdded]);
  372. DoAdd(3);
  373. DoneExpectValues;
  374. end;
  375. procedure TTestSimpleDictionary.TestValueNotificationDelete;
  376. begin
  377. DoAdd(3);
  378. Dict.OnValueNotify:=@DoValueNotify;
  379. SetExpectValues('Clear',['1','2','3'],[cnRemoved,cnRemoved,cnRemoved],{$IFDEF FPC}true{$ELSE}False{$endif});
  380. Dict.Clear;
  381. DoneExpectValues;
  382. end;
  383. procedure TTestSimpleDictionary.TestKeyValueNotificationSet;
  384. begin
  385. DoAdd(3);
  386. Dict.OnValueNotify:=@DoValueNotify;
  387. Dict.OnKeyNotify:=@DoKeyNotify;
  388. SetExpectValues('Set',['2','Six'],[cnRemoved,cnAdded]);
  389. SetExpectKeys('Set',[],[]);
  390. Dict[2]:='Six';
  391. DoneExpectKeys;
  392. DoneExpectValues;
  393. end;
  394. begin
  395. RegisterTest(TTestSimpleDictionary);
  396. end.