tcgenericdictionary.pp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. unit tcgenericdictionary;
  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. { TMyObject }
  59. TMyObject = Class(TObject)
  60. Private
  61. fOnDestroy : TNotifyEvent;
  62. FID : Integer;
  63. public
  64. Constructor Create(aID : Integer; aOnDestroy : TNotifyEvent);
  65. destructor destroy; override;
  66. Property ID : Integer Read FID;
  67. end;
  68. TSingleObjectDict = Class(Specialize TObjectDictionary<Integer,TMyObject>);
  69. TDualObjectDict = Class(Specialize TObjectDictionary<TMyObject,TMyObject>);
  70. { TTestSingleObjectDict }
  71. TTestSingleObjectDict = Class(TTestCase)
  72. private
  73. FDict: TSingleObjectDict;
  74. FList : TFPList;
  75. procedure DoAdd(aID: Integer);
  76. procedure DoDestroy(Sender: TObject);
  77. Public
  78. Procedure SetUp; override;
  79. Procedure TearDown; override;
  80. Property Dict : TSingleObjectDict Read FDict;
  81. Published
  82. Procedure TestEmpty;
  83. Procedure TestFreeOnRemove;
  84. Procedure TestNoFreeOnRemove;
  85. end;
  86. TTestDualObjectDict = Class(TTestCase)
  87. private
  88. FDict: TDualObjectDict;
  89. FList : TFPList;
  90. procedure DoAdd(aID: Integer);
  91. procedure DoDestroy(Sender: TObject);
  92. Public
  93. Procedure SetUp; override;
  94. Procedure TearDown; override;
  95. Property Dict : TDualObjectDict Read FDict;
  96. Published
  97. Procedure TestEmpty;
  98. Procedure TestFreeOnRemove;
  99. Procedure TestNoFreeOnRemove;
  100. end;
  101. implementation
  102. { TTestSingleObjectDict }
  103. procedure TTestSingleObjectDict.SetUp;
  104. begin
  105. FDict:=TSingleObjectDict.Create([doOwnsValues]);
  106. FList:=TFPList.Create;
  107. inherited SetUp;
  108. end;
  109. procedure TTestSingleObjectDict.TearDown;
  110. Var
  111. I : integer;
  112. A : TObject;
  113. begin
  114. FreeAndNil(FDict);
  115. for I:=0 to FList.Count-1 do
  116. begin
  117. A:=TObject(FList[i]);
  118. A.Free;
  119. end;
  120. FreeAndNil(FList);
  121. inherited TearDown;
  122. end;
  123. procedure TTestSingleObjectDict.TestEmpty;
  124. begin
  125. AssertNotNull('Have object',Dict);
  126. AssertEquals('Have empty object',0,Dict.Count);
  127. end;
  128. procedure TTestSingleObjectDict.DoAdd(aID : Integer);
  129. Var
  130. O : TMyObject;
  131. begin
  132. O:=TMyObject.Create(aID,@DoDestroy);
  133. FList.Add(O);
  134. FDict.Add(aID,O);
  135. end;
  136. procedure TTestSingleObjectDict.DoDestroy(Sender: TObject);
  137. Var
  138. I : Integer;
  139. begin
  140. I:=FList.IndexOf(Sender);
  141. AssertTrue('Have object in list',I<>-1);
  142. FList.Delete(I);
  143. end;
  144. procedure TTestSingleObjectDict.TestFreeOnRemove;
  145. begin
  146. DoAdd(1);
  147. AssertEquals('Have obj',1,FList.Count);
  148. Dict.Remove(1);
  149. AssertEquals('Have no obj',0,FList.Count);
  150. end;
  151. procedure TTestSingleObjectDict.TestNoFreeOnRemove;
  152. begin
  153. Dict.OwnerShips:=[];
  154. DoAdd(1);
  155. AssertEquals('Have obj',1,FList.Count);
  156. Dict.Remove(1);
  157. AssertEquals('Have obj',1,FList.Count);
  158. end;
  159. { TTestDualObjectDict }
  160. procedure TTestDualObjectDict.SetUp;
  161. begin
  162. FDict:=TDualObjectDict.Create([doOwnsKeys,doOwnsValues]);
  163. FList:=TFPList.Create;
  164. inherited SetUp;
  165. end;
  166. procedure TTestDualObjectDict.TearDown;
  167. Var
  168. I : integer;
  169. A : TObject;
  170. begin
  171. FreeAndNil(FDict);
  172. for I:=0 to FList.Count-1 do
  173. begin
  174. A:=TObject(FList[i]);
  175. A.Free;
  176. end;
  177. FreeAndNil(FList);
  178. inherited TearDown;
  179. end;
  180. procedure TTestDualObjectDict.TestEmpty;
  181. begin
  182. AssertNotNull('Have object',Dict);
  183. AssertEquals('Have empty object',0,Dict.Count);
  184. end;
  185. procedure TTestDualObjectDict.DoAdd(aID : Integer);
  186. Var
  187. O1,O10 : TMyObject;
  188. begin
  189. O1:=TMyObject.Create(aID,@DoDestroy);
  190. FList.Add(O1);
  191. O10:=TMyObject.Create(aID*10,@DoDestroy);
  192. FList.Add(O10);
  193. FDict.Add(O1,O10);
  194. end;
  195. procedure TTestDualObjectDict.DoDestroy(Sender: TObject);
  196. Var
  197. I : Integer;
  198. begin
  199. I:=FList.IndexOf(Sender);
  200. AssertTrue('Have object in list',I<>-1);
  201. FList.Delete(I);
  202. end;
  203. procedure TTestDualObjectDict.TestFreeOnRemove;
  204. begin
  205. DoAdd(1);
  206. AssertEquals('Have obj',2,FList.Count);
  207. Dict.Remove(TMyObject(FList[0]));
  208. AssertEquals('Have no obj',0,FList.Count);
  209. end;
  210. procedure TTestDualObjectDict.TestNoFreeOnRemove;
  211. begin
  212. Dict.OwnerShips:=[doOwnsValues];
  213. DoAdd(1);
  214. AssertEquals('Have obj',2,FList.Count);
  215. Dict.Remove(TMyObject(FList[0]));
  216. AssertEquals('Have obj',1,FList.Count);
  217. AssertEquals('Have key',1,TMyObject(Flist[0]).ID);
  218. end;
  219. { TMyObject }
  220. constructor TMyObject.Create(aID: Integer; aOnDestroy: TNotifyEvent);
  221. begin
  222. FOnDestroy:=aOnDestroy;
  223. FID:=AID;
  224. end;
  225. destructor TMyObject.destroy;
  226. begin
  227. if Assigned(FOnDestroy) then
  228. FOnDestroy(Self);
  229. inherited destroy;
  230. end;
  231. { TTestSimpleDictionary }
  232. procedure TTestSimpleDictionary.SetUp;
  233. begin
  234. inherited SetUp;
  235. FDict:=TMySimpleDict.Create;
  236. FCurrentKeyNotify:=0;
  237. FCurrentValueNotify:=0;
  238. FExpectKeys:=[];
  239. FExpectKeyAction:=[];
  240. FExpectValues:=[];
  241. FExpectValueAction:=[];
  242. end;
  243. procedure TTestSimpleDictionary.TearDown;
  244. begin
  245. // So we don't get clear messages
  246. FDict.OnKeyNotify:=Nil;
  247. FDict.OnValueNotify:=Nil;
  248. FreeAndNil(FDict);
  249. inherited TearDown;
  250. end;
  251. procedure TTestSimpleDictionary.TestEmpty;
  252. begin
  253. AssertNotNull('Have dictionary',Dict);
  254. AssertEquals('empty dictionary',0,Dict.Count);
  255. end;
  256. procedure TTestSimpleDictionary.DoAdd(aCount : Integer; aOffset : Integer=0);
  257. Var
  258. I : Integer;
  259. begin
  260. if aOffset=-1 then
  261. aOffset:=Dict.Count;
  262. For I:=aOffset+1 to aOffset+aCount do
  263. Dict.Add(I,IntToStr(i));
  264. end;
  265. procedure TTestSimpleDictionary.TestAdd;
  266. begin
  267. DoAdd(1);
  268. AssertEquals('Count OK',1,Dict.Count);
  269. AssertTrue('Has added value',Dict.ContainsKey(1));
  270. DoAdd(1,1);
  271. AssertEquals('Count OK',2,Dict.Count);
  272. AssertTrue('Has added value',Dict.ContainsKey(2));
  273. end;
  274. procedure TTestSimpleDictionary.TestClear;
  275. begin
  276. DoAdd(3);
  277. AssertEquals('Count OK',3,Dict.Count);
  278. Dict.Clear;
  279. AssertEquals('Count after clear OK',0,Dict.Count);
  280. end;
  281. procedure TTestSimpleDictionary.TestTryGetValue;
  282. Var
  283. I : integer;
  284. SI,A : string;
  285. begin
  286. DoAdd(3);
  287. For I:=1 to 3 do
  288. begin
  289. SI:=IntToStr(I);
  290. AssertTrue('Have value '+SI,Dict.TryGetValue(I,A));
  291. AssertEquals('Value is correct '+SI,SI,A);
  292. end;
  293. AssertFalse('Have no value 4',Dict.TryGetValue(4,A));
  294. end;
  295. procedure TTestSimpleDictionary.DoGetValue(aKey: Integer; Match: String; ExceptionClass: TClass);
  296. Var
  297. EC : TClass;
  298. A,EM : String;
  299. begin
  300. EC:=Nil;
  301. try
  302. A:=Dict.Items[aKey];
  303. except
  304. On E : Exception do
  305. begin
  306. EC:=E.ClassType;
  307. EM:=E.Message;
  308. end
  309. end;
  310. if ExceptionClass=Nil then
  311. begin
  312. if EC<>Nil then
  313. Fail('Got exception '+EC.ClassName+' with message: '+EM);
  314. AssertEquals('Value is correct for '+IntToStr(aKey),Match,A)
  315. end
  316. else
  317. begin
  318. if EC=Nil then
  319. Fail('Expected exception '+ExceptionClass.ClassName+' but got none');
  320. if EC<>ExceptionClass then
  321. Fail('Expected exception class '+ExceptionClass.ClassName+' but got '+EC.ClassName+' with message '+EM);
  322. end;
  323. end;
  324. procedure TTestSimpleDictionary.DoKeyNotify(ASender: TObject; {$ifdef fpc}constref{$else}const{$endif} AItem: Integer; AAction: TCollectionNotification);
  325. begin
  326. // Writeln(FnotifyMessage+' Notification',FCurrentKeyNotify);
  327. AssertSame(FnotifyMessage+' Correct sender', FDict,aSender);
  328. if (FCurrentKeyNotify>=Length(FExpectKeys)) then
  329. Fail(FnotifyMessage+' Too many notificiations');
  330. AssertEquals(FnotifyMessage+' Notification Key no '+IntToStr(FCurrentKeyNotify),FExpectKeys[FCurrentKeyNotify],aItem);
  331. Inc(FCurrentKeyNotify);
  332. end;
  333. procedure TTestSimpleDictionary.DoValueNotify(ASender: TObject; {$ifdef fpc}constref{$else}const{$endif} AItem: String; AAction: TCollectionNotification);
  334. begin
  335. // Writeln(FnotifyMessage+' value Notification',FCurrentValueNotify);
  336. AssertSame(FnotifyMessage+' value Correct sender', FDict,aSender);
  337. if (FCurrentValueNotify>=Length(FExpectValues)) then
  338. Fail(FnotifyMessage+' Too many value notificiations');
  339. AssertEquals(FnotifyMessage+' Notification value no '+IntToStr(FCurrentValueNotify),FExpectValues[FCurrentValueNotify],aItem);
  340. Inc(FCurrentValueNotify);
  341. end;
  342. procedure TTestSimpleDictionary.SetExpectKeys(aMessage: string; AKeys: array of Integer;
  343. AActions: array of TCollectionNotification; DoReverse: Boolean = False);
  344. Var
  345. I,L : integer;
  346. begin
  347. FnotifyMessage:=aMessage;
  348. FCurrentKeyNotify:=0;
  349. L:=Length(aKeys);
  350. AssertEquals('SetExpectkeys: Lengths arrays equal',l,Length(aActions));
  351. SetLength(FExpectKeys,L);
  352. SetLength(FExpectKeyAction,L);
  353. Dec(L);
  354. if DoReverse then
  355. For I:=0 to L do
  356. begin
  357. FExpectKeys[L-i]:=AKeys[i];
  358. FExpectKeyAction[L-i]:=AActions[I];
  359. end
  360. else
  361. For I:=0 to L do
  362. begin
  363. FExpectKeys[i]:=AKeys[i];
  364. FExpectKeyAction[i]:=AActions[I];
  365. end;
  366. end;
  367. procedure TTestSimpleDictionary.SetExpectValues(aMessage: string; AKeys: array of String;
  368. AActions: array of TCollectionNotification; DoReverse: Boolean);
  369. Var
  370. I,L : integer;
  371. begin
  372. FnotifyMessage:=aMessage;
  373. FCurrentValueNotify:=0;
  374. L:=Length(aKeys);
  375. AssertEquals('SetExpectValues: Lengths arrays equal',l,Length(aActions));
  376. SetLength(FExpectValues,L);
  377. SetLength(FExpectValueAction,L);
  378. Dec(L);
  379. if DoReverse then
  380. For I:=0 to L do
  381. begin
  382. FExpectValues[L-i]:=AKeys[i];
  383. FExpectValueAction[L-i]:=AActions[I];
  384. end
  385. else
  386. For I:=0 to L do
  387. begin
  388. FExpectValues[i]:=AKeys[i];
  389. FExpectValueAction[i]:=AActions[I];
  390. end;
  391. end;
  392. procedure TTestSimpleDictionary.TestGetValue;
  393. Var
  394. I : integer;
  395. begin
  396. DoAdd(3);
  397. For I:=1 to 3 do
  398. DoGetValue(I,IntToStr(I));
  399. DoGetValue(4,'4',EDictionary);
  400. end;
  401. procedure TTestSimpleDictionary.TestSetValue;
  402. begin
  403. TestGetValue;
  404. Dict.Items[3]:='Six';
  405. DoGetValue(3,'Six');
  406. end;
  407. procedure TTestSimpleDictionary.DoAdd2;
  408. begin
  409. Dict.Add(2,'A new 2');
  410. end;
  411. procedure TTestSimpleDictionary.DoneExpectKeys;
  412. begin
  413. AssertEquals(FnotifyMessage+' Expected number of keys seen',Length(FExpectKeys),FCurrentKeyNotify);
  414. end;
  415. procedure TTestSimpleDictionary.DoneExpectValues;
  416. begin
  417. AssertEquals(FnotifyMessage+' Expected number of values seen',Length(FExpectValues),FCurrentValueNotify);
  418. end;
  419. procedure TTestSimpleDictionary.TestAddDuplicate;
  420. begin
  421. DoAdd(3);
  422. AssertException('Cannot add duplicate',EDictionary,@DoAdd2);
  423. end;
  424. procedure TTestSimpleDictionary.TestAddOrSet;
  425. begin
  426. DoAdd(3);
  427. Dict.AddOrSetValue(2,'a new 2');
  428. DoGetValue(2,'a new 2');
  429. end;
  430. procedure TTestSimpleDictionary.TestContainsKey;
  431. Var
  432. I : Integer;
  433. begin
  434. DoAdd(3);
  435. For I:=1 to 3 do
  436. AssertTrue('Has '+IntToStr(i),Dict.ContainsKey(I));
  437. AssertFalse('Has not 4',Dict.ContainsKey(4));
  438. end;
  439. procedure TTestSimpleDictionary.TestContainsValue;
  440. Var
  441. I : Integer;
  442. begin
  443. DoAdd(3);
  444. For I:=1 to 3 do
  445. AssertTrue('Has '+IntToStr(i),Dict.ContainsValue(IntToStr(i)));
  446. AssertFalse('Has not 4',Dict.ContainsValue('4'));
  447. end;
  448. procedure TTestSimpleDictionary.TestDelete;
  449. begin
  450. DoAdd(3);
  451. Dict.Remove(2);
  452. AssertEquals('Count',2,Dict.Count);
  453. AssertFalse('Has not 2',Dict.ContainsKey(2));
  454. end;
  455. procedure TTestSimpleDictionary.TestToArray;
  456. Var
  457. {$ifdef fpc}
  458. A : specialize TArray<TMyPair>;
  459. {$else}
  460. A : specialize TArray<TMySimpleDict.TMyPair>;
  461. {$endif}
  462. I : Integer;
  463. SI : String;
  464. begin
  465. DoAdd(3);
  466. A:=Dict.ToArray;
  467. AssertEquals('Length Ok',3,Length(A));
  468. For I:=1 to 3 do
  469. begin
  470. SI:=IntToStr(I);
  471. AssertEquals('key '+SI,I,A[i-1].Key);
  472. AssertEquals('Value '+SI,SI,A[i-1].Value);
  473. end;
  474. end;
  475. procedure TTestSimpleDictionary.TestKeys;
  476. Var
  477. A : Array of Integer;
  478. I : Integer;
  479. SI : String;
  480. begin
  481. DoAdd(3);
  482. A:=Dict.Keys.ToArray;
  483. AssertEquals('Length Ok',3,Length(A));
  484. For I:=1 to 3 do
  485. begin
  486. SI:=IntToStr(I);
  487. AssertEquals('key '+SI,I,A[i-1]);
  488. end;
  489. end;
  490. procedure TTestSimpleDictionary.TestValues;
  491. Var
  492. A : Array of String;
  493. I : Integer;
  494. SI : String;
  495. begin
  496. DoAdd(3);
  497. A:=Dict.Values.ToArray;
  498. AssertEquals('Length Ok',3,Length(A));
  499. For I:=1 to 3 do
  500. begin
  501. SI:=IntToStr(I);
  502. AssertEquals('Value '+SI,SI,A[i-1]);
  503. end;
  504. end;
  505. procedure TTestSimpleDictionary.TestEnumerator;
  506. Var
  507. {$ifdef fpc}
  508. A : TMyPair;
  509. {$else}
  510. A : TMySimpleDict.TMyPair;
  511. {$endif}
  512. I : Integer;
  513. SI : String;
  514. begin
  515. DoAdd(3);
  516. I:=1;
  517. For A in Dict do
  518. begin
  519. SI:=IntToStr(I);
  520. AssertEquals('key '+SI,I,A.Key);
  521. AssertEquals('Value '+SI,SI,A.Value);
  522. Inc(I);
  523. end;
  524. end;
  525. procedure TTestSimpleDictionary.TestNotification;
  526. begin
  527. Dict.OnKeyNotify:=@DoKeyNotify;
  528. SetExpectKeys('Add',[1,2,3],[cnAdded,cnAdded,cnAdded]);
  529. DoAdd(3);
  530. DoneExpectKeys;
  531. end;
  532. procedure TTestSimpleDictionary.TestNotificationDelete;
  533. begin
  534. DoAdd(3);
  535. Dict.OnKeyNotify:=@DoKeyNotify;
  536. SetExpectKeys('Clear',[1,2,3],[cnRemoved,cnRemoved,cnRemoved],{$IFDEF FPC}true{$ELSE}False{$endif});
  537. Dict.Clear;
  538. DoneExpectKeys;
  539. end;
  540. procedure TTestSimpleDictionary.TestValueNotification;
  541. begin
  542. Dict.OnValueNotify:=@DoValueNotify;
  543. SetExpectValues('Add',['1','2','3'],[cnAdded,cnAdded,cnAdded]);
  544. DoAdd(3);
  545. DoneExpectValues;
  546. end;
  547. procedure TTestSimpleDictionary.TestValueNotificationDelete;
  548. begin
  549. DoAdd(3);
  550. Dict.OnValueNotify:=@DoValueNotify;
  551. SetExpectValues('Clear',['1','2','3'],[cnRemoved,cnRemoved,cnRemoved],{$IFDEF FPC}true{$ELSE}False{$endif});
  552. Dict.Clear;
  553. DoneExpectValues;
  554. end;
  555. procedure TTestSimpleDictionary.TestKeyValueNotificationSet;
  556. begin
  557. DoAdd(3);
  558. Dict.OnValueNotify:=@DoValueNotify;
  559. Dict.OnKeyNotify:=@DoKeyNotify;
  560. SetExpectValues('Set',['2','Six'],[cnRemoved,cnAdded]);
  561. SetExpectKeys('Set',[],[]);
  562. Dict[2]:='Six';
  563. DoneExpectKeys;
  564. DoneExpectValues;
  565. end;
  566. begin
  567. RegisterTests([TTestSimpleDictionary,
  568. TTestSingleObjectDict,
  569. TTestDualObjectDict]);
  570. end.