tcgenericstack.pp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. unit tcgenericstack;
  2. {$mode objfpc}
  3. interface
  4. uses
  5. fpcunit, testregistry, Classes, SysUtils, Generics.Defaults, Generics.Collections;
  6. Type
  7. TMySimpleStack = Class(Specialize TStack<String>);
  8. {$IFDEF FPC}
  9. EList = EListError;
  10. {$ENDIF}
  11. { TTestSimpleStack }
  12. TTestSimpleStack = Class(TTestCase)
  13. Private
  14. FStack : TMySimpleStack;
  15. FnotifyMessage : String;
  16. FCurrentValueNotify : Integer;
  17. FExpectValues : Array of String;
  18. FExpectValueAction: Array of TCollectionNotification;
  19. procedure DoAdd(aCount: Integer);
  20. procedure DoAdd2;
  21. Procedure DoneExpectValues;
  22. procedure DoGetValue(Match: String; ExceptionClass: TClass=nil);
  23. procedure DoValueNotify(ASender: TObject; {$ifdef fpc}constref{$else}const{$endif} AItem: String; AAction: TCollectionNotification);
  24. Public
  25. Procedure SetExpectValues(aMessage : string; AKeys : Array of String; AActions : Array of TCollectionNotification; DoReverse : Boolean = False);
  26. Procedure SetUp; override;
  27. Procedure TearDown; override;
  28. Property Stack : TMySimpleStack Read FStack;
  29. Published
  30. Procedure TestEmpty;
  31. Procedure TestAdd;
  32. Procedure TestClear;
  33. Procedure TestGetValue;
  34. Procedure TestPeek;
  35. Procedure TestPop;
  36. Procedure TestToArray;
  37. Procedure TestEnumerator;
  38. procedure TestValueNotification;
  39. procedure TestValueNotificationDelete;
  40. end;
  41. { TMyObject }
  42. TMyObject = Class(TObject)
  43. Private
  44. fOnDestroy : TNotifyEvent;
  45. FID : Integer;
  46. public
  47. Constructor Create(aID : Integer; aOnDestroy : TNotifyEvent);
  48. destructor destroy; override;
  49. Property ID : Integer Read FID;
  50. end;
  51. TSingleObjectStack = Class(Specialize TObjectStack<TMyObject>);
  52. { TTestSingleObjectStack }
  53. TTestSingleObjectStack = Class(TTestCase)
  54. private
  55. FOStack: TSingleObjectStack;
  56. FList : TFPList;
  57. procedure DoAdd(aID: Integer);
  58. procedure DoDestroy(Sender: TObject);
  59. Public
  60. Procedure SetUp; override;
  61. Procedure TearDown; override;
  62. Property Stack : TSingleObjectStack Read FOStack;
  63. Published
  64. Procedure TestEmpty;
  65. Procedure TestFreeOnPop;
  66. Procedure TestNoFreeOnPop;
  67. end;
  68. implementation
  69. { TTestSingleObjectStack }
  70. procedure TTestSingleObjectStack.SetUp;
  71. begin
  72. FOStack:=TSingleObjectStack.Create(True);
  73. FList:=TFPList.Create;
  74. inherited SetUp;
  75. end;
  76. procedure TTestSingleObjectStack.TearDown;
  77. Var
  78. I : integer;
  79. A : TObject;
  80. begin
  81. FreeAndNil(FOStack);
  82. for I:=0 to FList.Count-1 do
  83. begin
  84. A:=TObject(FList[i]);
  85. A.Free;
  86. end;
  87. FreeAndNil(FList);
  88. inherited TearDown;
  89. end;
  90. procedure TTestSingleObjectStack.TestEmpty;
  91. begin
  92. AssertNotNull('Have object',Stack);
  93. AssertEquals('Have empty object',0,Stack.Count);
  94. end;
  95. procedure TTestSingleObjectStack.DoAdd(aID : Integer);
  96. Var
  97. O : TMyObject;
  98. begin
  99. O:=TMyObject.Create(aID,@DoDestroy);
  100. FOStack.Push(O);
  101. FList.Add(O);
  102. end;
  103. procedure TTestSingleObjectStack.DoDestroy(Sender: TObject);
  104. Var
  105. I : Integer;
  106. begin
  107. I:=FList.IndexOf(Sender);
  108. AssertTrue('Have object in Stack',I<>-1);
  109. FList.Delete(I);
  110. end;
  111. procedure TTestSingleObjectStack.TestFreeOnPop;
  112. begin
  113. DoAdd(1);
  114. AssertEquals('Have obj',1,FList.Count);
  115. Stack.Pop;
  116. AssertEquals('Have no obj',0,FList.Count);
  117. end;
  118. procedure TTestSingleObjectStack.TestNoFreeOnPop;
  119. begin
  120. Stack.OwnsObjects:=False;
  121. DoAdd(1);
  122. AssertEquals('Have obj',1,FList.Count);
  123. Stack.Pop;
  124. AssertEquals('Have obj',1,FList.Count);
  125. end;
  126. { TMyObject }
  127. constructor TMyObject.Create(aID: Integer; aOnDestroy: TNotifyEvent);
  128. begin
  129. FOnDestroy:=aOnDestroy;
  130. FID:=AID;
  131. end;
  132. destructor TMyObject.destroy;
  133. begin
  134. if Assigned(FOnDestroy) then
  135. FOnDestroy(Self);
  136. inherited destroy;
  137. end;
  138. { TTestSimpleStack }
  139. procedure TTestSimpleStack.SetUp;
  140. begin
  141. inherited SetUp;
  142. FStack:=TMySimpleStack.Create;
  143. FCurrentValueNotify:=0;
  144. FExpectValues:=[];
  145. FExpectValueAction:=[];
  146. end;
  147. procedure TTestSimpleStack.TearDown;
  148. begin
  149. // So we don't get clear messages
  150. FStack.OnNotify:=Nil;
  151. FreeAndNil(FStack);
  152. inherited TearDown;
  153. end;
  154. procedure TTestSimpleStack.TestEmpty;
  155. begin
  156. AssertNotNull('Have dictionary',Stack);
  157. AssertEquals('empty dictionary',0,Stack.Count);
  158. end;
  159. procedure TTestSimpleStack.DoAdd(aCount : Integer);
  160. Var
  161. I : Integer;
  162. begin
  163. For I:=1 to aCount do
  164. Stack.Push(IntToStr(i));
  165. end;
  166. procedure TTestSimpleStack.TestAdd;
  167. begin
  168. DoAdd(1);
  169. AssertEquals('Count OK',1,Stack.Count);
  170. DoAdd(1);
  171. AssertEquals('Count OK',2,Stack.Count);
  172. end;
  173. procedure TTestSimpleStack.TestClear;
  174. begin
  175. DoAdd(3);
  176. AssertEquals('Count OK',3,Stack.Count);
  177. Stack.Clear;
  178. AssertEquals('Count after clear OK',0,Stack.Count);
  179. end;
  180. procedure TTestSimpleStack.DoGetValue(Match: String; ExceptionClass: TClass);
  181. Var
  182. EC : TClass;
  183. A,EM : String;
  184. begin
  185. EC:=Nil;
  186. try
  187. A:=Stack.Pop;
  188. except
  189. On E : Exception do
  190. begin
  191. EC:=E.ClassType;
  192. EM:=E.Message;
  193. end
  194. end;
  195. if ExceptionClass=Nil then
  196. begin
  197. if EC<>Nil then
  198. Fail('Got exception '+EC.ClassName+' with message: '+EM);
  199. AssertEquals('Value is correct',Match,A)
  200. end
  201. else
  202. begin
  203. if EC=Nil then
  204. Fail('Expected exception '+ExceptionClass.ClassName+' but got none');
  205. if EC<>ExceptionClass then
  206. Fail('Expected exception class '+ExceptionClass.ClassName+' but got '+EC.ClassName+' with message '+EM);
  207. end;
  208. end;
  209. procedure TTestSimpleStack.DoValueNotify(ASender: TObject; {$ifdef fpc}constref{$else}const{$endif} AItem: String; AAction: TCollectionNotification);
  210. begin
  211. // Writeln(FnotifyMessage+' value Notification',FCurrentValueNotify);
  212. AssertSame(FnotifyMessage+' value Correct sender', FStack,aSender);
  213. if (FCurrentValueNotify>=Length(FExpectValues)) then
  214. Fail(FnotifyMessage+' Too many value notificiations');
  215. AssertEquals(FnotifyMessage+' Notification value no '+IntToStr(FCurrentValueNotify),FExpectValues[FCurrentValueNotify],aItem);
  216. Inc(FCurrentValueNotify);
  217. end;
  218. procedure TTestSimpleStack.SetExpectValues(aMessage: string; AKeys: array of String;
  219. AActions: array of TCollectionNotification; DoReverse: Boolean);
  220. Var
  221. I,L : integer;
  222. begin
  223. FnotifyMessage:=aMessage;
  224. FCurrentValueNotify:=0;
  225. L:=Length(aKeys);
  226. AssertEquals('SetExpectValues: Lengths arrays equal',l,Length(aActions));
  227. SetLength(FExpectValues,L);
  228. SetLength(FExpectValueAction,L);
  229. Dec(L);
  230. if DoReverse then
  231. For I:=0 to L do
  232. begin
  233. FExpectValues[L-i]:=AKeys[i];
  234. FExpectValueAction[L-i]:=AActions[I];
  235. end
  236. else
  237. For I:=0 to L do
  238. begin
  239. FExpectValues[i]:=AKeys[i];
  240. FExpectValueAction[i]:=AActions[I];
  241. end;
  242. end;
  243. procedure TTestSimpleStack.TestGetValue;
  244. Var
  245. I : integer;
  246. begin
  247. DoAdd(3);
  248. For I:=3 downto 1 do
  249. DoGetValue(IntToStr(I));
  250. DoGetValue('4',EArgumentOutOfRangeException);
  251. end;
  252. procedure TTestSimpleStack.TestPeek;
  253. Var
  254. I : integer;
  255. begin
  256. DoAdd(3);
  257. For I:=3 downto 1 do
  258. begin
  259. AssertEquals('Peek ',IntToStr(I),FStack.Peek);
  260. DoGetValue(IntToStr(I));
  261. end;
  262. end;
  263. procedure TTestSimpleStack.DoAdd2;
  264. begin
  265. Stack.Push('A new 2');
  266. end;
  267. procedure TTestSimpleStack.DoneExpectValues;
  268. begin
  269. AssertEquals(FnotifyMessage+' Expected number of values seen',Length(FExpectValues),FCurrentValueNotify);
  270. end;
  271. procedure TTestSimpleStack.TestPop;
  272. Var
  273. I : Integer;
  274. SI : String;
  275. begin
  276. DoAdd(3);
  277. For I:=3 downto 1 do
  278. begin
  279. SI:=IntToStr(I);
  280. AssertEquals('Value '+SI,SI,FStack.Pop);
  281. end;
  282. AssertEquals('Count',0,Stack.Count);
  283. end;
  284. procedure TTestSimpleStack.TestToArray;
  285. Var
  286. A : specialize TArray<String>;
  287. I : Integer;
  288. SI : String;
  289. begin
  290. DoAdd(3);
  291. A:=Stack.ToArray;
  292. AssertEquals('Length Ok',3,Length(A));
  293. For I:=1 to 3 do
  294. begin
  295. SI:=IntToStr(I);
  296. AssertEquals('Value '+SI,SI,A[i-1]);
  297. end;
  298. end;
  299. procedure TTestSimpleStack.TestEnumerator;
  300. Var
  301. A : String;
  302. I : Integer;
  303. SI : String;
  304. begin
  305. DoAdd(3);
  306. I:=1;
  307. For A in Stack do
  308. begin
  309. SI:=IntToStr(i);
  310. AssertEquals('Value '+SI,SI,A);
  311. Inc(I);
  312. end;
  313. end;
  314. procedure TTestSimpleStack.TestValueNotification;
  315. begin
  316. Stack.OnNotify:=@DoValueNotify;
  317. SetExpectValues('Add',['1','2','3'],[cnAdded,cnAdded,cnAdded]);
  318. DoAdd(3);
  319. DoneExpectValues;
  320. end;
  321. procedure TTestSimpleStack.TestValueNotificationDelete;
  322. begin
  323. DoAdd(3);
  324. Stack.OnNotify:=@DoValueNotify;
  325. SetExpectValues('Clear',['3','2','1'],[cnRemoved,cnRemoved,cnRemoved],False);
  326. Stack.Clear;
  327. DoneExpectValues;
  328. end;
  329. begin
  330. RegisterTests([ TTestSimpleStack,TTestSingleObjectStack]);
  331. end.