tccomponent.pp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. unit tccomponent;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, fpcunit, testutils, testregistry;
  6. type
  7. { TEventSink }
  8. TEventSink = Class(TObject)
  9. FEventCount : Integer;
  10. FLastSender : TObject;
  11. Procedure Event(Sender : TObject); virtual;
  12. Procedure ResetEvent;
  13. end;
  14. { TNotification }
  15. TNotification = Class(TCollectionItem)
  16. Public
  17. ASender,
  18. AComponent : TComponent;
  19. AOperation : TOperation;
  20. end;
  21. { TNotificationSink }
  22. TNotificationSink = Class(TObject)
  23. private
  24. Fevents : TCollection;
  25. function GetNot(Index : Integer): TNotification;
  26. Public
  27. Destructor Destroy; override;
  28. procedure Notification(Sender, AComponent: TComponent; Operation: TOperation); virtual;
  29. Procedure Reset;
  30. Function EventCount : Integer;
  31. Property Notifications [Index : Integer] : TNotification Read GetNot;
  32. end;
  33. { TMyComponent }
  34. TNotificationEvent = procedure (Sender : TComponent; AComponent: TComponent; Operation: TOperation) of object;
  35. TMyComponent = Class(TComponent)
  36. private
  37. FOnDestroy: TNotifyEvent;
  38. FOnNotify: TNotificationEvent;
  39. Public
  40. Destructor Destroy; override;
  41. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  42. Property OnDestroy : TNotifyEvent Read FOnDestroy Write FOnDestroy;
  43. Property OnNotification : TNotificationEvent Read FOnNotify Write FOnNotify;
  44. end;
  45. { TTestTComponentBase }
  46. TTestTComponentBase = class(TTestCase)
  47. protected
  48. FRoot : TMyComponent;
  49. Procedure CreateComponents(ACount : Integer);
  50. Procedure CreateComponents(ACount : Integer; Const BaseName : String);
  51. Procedure CreateComponents(ACount : Integer; AClass : TComponentClass);
  52. Procedure CreateComponents(ACount : Integer; AClass : TComponentClass; Const BaseName : String);
  53. procedure SetUp; override;
  54. procedure TearDown; override;
  55. end;
  56. { TTestTComponent }
  57. TTestTComponent = Class(TTestTComponentBase)
  58. private
  59. procedure TestDoubleName;
  60. procedure TestTextName;
  61. procedure TestNumberName;
  62. procedure TestNumberTextName;
  63. Published
  64. Procedure TestCreate;
  65. Procedure TestName;
  66. procedure TestIdentiFierName;
  67. procedure TestIdentiFierNameTwo;
  68. procedure TestIdentiFierNameThree;
  69. procedure TestIdentiFierNameFour;
  70. procedure TestOwner;
  71. procedure TestChildren;
  72. Procedure TestDestroyChild;
  73. Procedure TestDestroyChildren;
  74. Procedure TestUniqueName;
  75. Procedure TestRemoveComponent;
  76. end;
  77. { TTestTComponentNotifies }
  78. TTestTComponentNotifies = Class(TTestTComponentBase)
  79. Protected
  80. N : TNotificationSink;
  81. procedure SetUp; override;
  82. procedure TearDown; override;
  83. Published
  84. Procedure TestInsertNotification;
  85. Procedure TestRemoveNotification;
  86. end;
  87. implementation
  88. procedure TTestTComponentBase.CreateComponents(ACount: Integer);
  89. begin
  90. CreateComponents(ACount,'');
  91. end;
  92. procedure TTestTComponentBase.CreateComponents(ACount: Integer;
  93. const BaseName: String);
  94. begin
  95. CreateComponents(ACount,TMyComponent,BaseName);
  96. end;
  97. procedure TTestTComponentBase.CreateComponents(ACount: Integer;
  98. AClass: TComponentClass);
  99. begin
  100. CreateComponents(ACount,AClass,'');
  101. end;
  102. procedure TTestTComponentBase.CreateComponents(ACount: Integer;
  103. AClass: TComponentClass; const BaseName: String);
  104. Var
  105. I : Integer;
  106. C : TComponent;
  107. begin
  108. For I:=0 to ACount-1 do
  109. begin
  110. C:=TMyComponent.Create(FRoot);
  111. If (BaseName<>'') then
  112. C.Name:=BaseName+IntToStr(I+1);
  113. end;
  114. end;
  115. procedure TTestTComponentBase.SetUp;
  116. begin
  117. FRoot:=TMyComponent.Create(Nil);
  118. FRoot.Name:='Root';
  119. end;
  120. procedure TTestTComponentBase.TearDown;
  121. begin
  122. FreeAndNil(FRoot);
  123. end;
  124. { TTestTComponent }
  125. procedure TTestTComponent.TestCreate;
  126. begin
  127. FreeAndNil(Froot);
  128. FRoot:=TMyComponent.Create(Nil);
  129. AssertEquals('Empty name','',FRoot.Name);
  130. AssertEquals('No owned components',0,FRoot.ComponentCount);
  131. If (FRoot.ComponentState<>[]) then
  132. Fail('Componentstate is not empty');
  133. If (FRoot.Owner<>Nil) then
  134. Fail('Owner is not nil');
  135. end;
  136. procedure TTestTComponent.TestName;
  137. begin
  138. AssertEquals('Name is Root','Root',FRoot.Name);
  139. end;
  140. procedure TTestTComponent.TestOwner;
  141. Var
  142. C : TComponent;
  143. begin
  144. C:=TComponent.Create(FRoot);
  145. If (C.Owner<>FRoot) then
  146. Fail('Owner not saved after create');
  147. end;
  148. procedure TTestTComponent.TestChildren;
  149. begin
  150. CreateComponents(3,'Child');
  151. AssertEquals('Componentcount is 3',3,FRoot.ComponentCount);
  152. AssertEquals('Child component 0 is child1','Child1',FRoot.Components[0].Name);
  153. AssertEquals('Child component 1 is child2','Child2',FRoot.Components[1].Name);
  154. AssertEquals('Child component 2 is child3','Child3',FRoot.Components[2].Name);
  155. end;
  156. procedure TTestTComponent.TestDestroyChild;
  157. Var
  158. S : TEventSink;
  159. begin
  160. CreateComponents(1);
  161. S:=TEventSink.Create;
  162. try
  163. TMyComponent(FRoot.Components[0]).OnDestroy:[email protected];
  164. FreeAndNil(FRoot);
  165. AssertEquals('One child destroyed',1,S.FEventcount);
  166. If (S.FLastSender=Nil) then
  167. Fail('No sender passed');
  168. finally
  169. S.Free;
  170. end;
  171. end;
  172. procedure TTestTComponent.TestDestroyChildren;
  173. Var
  174. S : TEventSink;
  175. I : Integer;
  176. begin
  177. CreateComponents(3);
  178. S:=TEventSink.Create;
  179. try
  180. For I:=0 to 2 do
  181. TMyComponent(FRoot.Components[I]).OnDestroy:[email protected];
  182. FreeAndNil(FRoot);
  183. AssertEquals('One child destroyed',3,S.FEventcount);
  184. If (S.FLastSender=Nil) then
  185. Fail('No sender passed');
  186. finally
  187. S.Free;
  188. end;
  189. end;
  190. procedure TTestTComponent.TestDoubleName;
  191. begin
  192. FRoot.Components[1].Name:='Child1';
  193. end;
  194. procedure TTestTComponent.TestUniqueName;
  195. begin
  196. CreateComponents(3,'Child');
  197. AssertException('Unique name',EComponentError,@TestDoubleName);
  198. end;
  199. procedure TTestTComponent.TestRemoveComponent;
  200. Var
  201. C : TComponent;
  202. begin
  203. CreateComponents(1);
  204. C:=FRoot.Components[0];
  205. FRoot.RemoveComponent(C);
  206. Try
  207. AssertEquals('No components left',0,FRoot.ComponentCount);
  208. AssertSame('Component has no owner',Nil,C.Owner);
  209. Finally
  210. C.Free;
  211. end;
  212. end;
  213. procedure TTestTComponent.TestTextName;
  214. begin
  215. FRoot.Name:='Child 1';
  216. end;
  217. procedure TTestTComponent.TestNumberName;
  218. begin
  219. FRoot.Name:='1';
  220. end;
  221. procedure TTestTComponent.TestNumberTextName;
  222. begin
  223. FRoot.Name:='1Too';
  224. end;
  225. procedure TTestTComponent.TestIdentiFierName;
  226. begin
  227. AssertException('Identifier name',EComponentError,@TestTextName);
  228. end;
  229. procedure TTestTComponent.TestIdentiFierNameTwo;
  230. begin
  231. AssertException('Identifier name',EComponentError,@TestNumberTextName);
  232. end;
  233. procedure TTestTComponent.TestIdentiFierNameThree;
  234. begin
  235. AssertException('Identifier name',EComponentError,@TestNumberName);
  236. end;
  237. procedure TTestTComponent.TestIdentiFierNameFour;
  238. Var
  239. Failed : Boolean;
  240. begin
  241. Failed:=False;
  242. Try
  243. FRoot.Name:='Some1';
  244. except
  245. Failed:=True;
  246. end;
  247. If Failed then
  248. Fail('No identifier ending on 1 accepted ?');
  249. end;
  250. { TMyComponent }
  251. destructor TMyComponent.Destroy;
  252. begin
  253. If Assigned(FOnDestroy) then
  254. FOnDestroy(Self);
  255. inherited Destroy;
  256. end;
  257. procedure TMyComponent.Notification(AComponent: TComponent;
  258. Operation: TOperation);
  259. begin
  260. If Assigned(FOnNotify) then
  261. FOnNotify(Self, AComponent, Operation);
  262. inherited Notification(AComponent, Operation);
  263. end;
  264. { TEventSink }
  265. procedure TEventSink.Event(Sender: TObject);
  266. begin
  267. Inc(FEventCount);
  268. FLastSender:=Sender;
  269. end;
  270. procedure TEventSink.ResetEvent;
  271. begin
  272. FLastSender:=Nil;
  273. FEventCount:=0;
  274. end;
  275. { TNotificationSink }
  276. function TNotificationSink.GetNot(Index : Integer): TNotification;
  277. begin
  278. If Assigned(FEvents) then
  279. Result:=Nil
  280. else
  281. Result:=TNotification(FEvents.Items[Index]);
  282. end;
  283. destructor TNotificationSink.Destroy;
  284. begin
  285. FreeAndNil(FEvents);
  286. inherited Destroy;
  287. end;
  288. procedure TNotificationSink.Notification(Sender, AComponent: TComponent;
  289. Operation: TOperation);
  290. Var
  291. N : TNotification;
  292. begin
  293. If (Fevents=Nil) then
  294. FEvents:=TCollection.Create(TNotification);
  295. N:=FEvents.Add as TNotification;
  296. N.AComponent:=AComponent;
  297. N.ASender:=Sender;
  298. N.AOperation:=Operation;
  299. end;
  300. procedure TNotificationSink.Reset;
  301. begin
  302. FreeAndNil(FEvents);
  303. end;
  304. function TNotificationSink.EventCount: Integer;
  305. begin
  306. If (Fevents<>Nil) then
  307. Result:=FEvents.Count
  308. else
  309. Result:=0;
  310. end;
  311. { TTestTComponentNotifies }
  312. procedure TTestTComponentNotifies.SetUp;
  313. begin
  314. inherited SetUp;
  315. N:=TNotificationSink.Create;
  316. FRoot.OnNotification:[email protected];
  317. end;
  318. procedure TTestTComponentNotifies.TearDown;
  319. begin
  320. FreeAndNil(N);
  321. inherited TearDown;
  322. end;
  323. procedure TTestTComponentNotifies.TestInsertNotification;
  324. Var
  325. C : TComponent;
  326. E : TNotification;
  327. begin
  328. CreateComponents(1);
  329. AssertEquals('One notification received',1,N.EventCount);
  330. E:=N.Notifications[0];
  331. AssertEquals('Insert notification received',Ord(opInsert),Ord(E.AOperation));
  332. end;
  333. procedure TTestTComponentNotifies.TestRemoveNotification;
  334. Var
  335. C : TComponent;
  336. E : TNotification;
  337. begin
  338. CreateComponents(1);
  339. N.Reset;
  340. C:=FRoot.Components[0];
  341. FRoot.RemoveComponent(C);
  342. Try
  343. AssertEquals('One notification received',1,N.EventCount);
  344. E:=N.Notifications[0];
  345. Finally
  346. C.Free;
  347. end;
  348. end;
  349. initialization
  350. RegisterTests([TTestTComponent,TTestTComponentNotifies]);
  351. end.