mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2026-01-07 19:01:07 +01:00
438 lines
9.0 KiB
ObjectPascal
438 lines
9.0 KiB
ObjectPascal
unit tccomponent;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, fpcunit, testregistry;
|
|
|
|
type
|
|
|
|
{ TEventSink }
|
|
|
|
TEventSink = Class(TObject)
|
|
FEventCount : Integer;
|
|
FLastSender : TObject;
|
|
Procedure Event(Sender : TObject); virtual;
|
|
Procedure ResetEvent;
|
|
end;
|
|
|
|
{ TNotification }
|
|
|
|
TNotification = Class(TCollectionItem)
|
|
Public
|
|
ASender,
|
|
AComponent : TComponent;
|
|
AOperation : TOperation;
|
|
end;
|
|
|
|
{ TNotificationSink }
|
|
|
|
TNotificationSink = Class(TObject)
|
|
private
|
|
Fevents : TCollection;
|
|
function GetNot(Index : Integer): TNotification;
|
|
Public
|
|
Destructor Destroy; override;
|
|
procedure Notification(Sender, AComponent: TComponent; Operation: TOperation); virtual;
|
|
Procedure Reset;
|
|
Function EventCount : Integer;
|
|
Property Notifications [Index : Integer] : TNotification Read GetNot;
|
|
end;
|
|
|
|
{ TMyComponent }
|
|
|
|
TNotificationEvent = procedure (Sender : TComponent; AComponent: TComponent; Operation: TOperation) of object;
|
|
|
|
TMyComponent = Class(TComponent)
|
|
private
|
|
FOnDestroy: TNotifyEvent;
|
|
FOnNotify: TNotificationEvent;
|
|
Public
|
|
Destructor Destroy; override;
|
|
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
Property OnDestroy : TNotifyEvent Read FOnDestroy Write FOnDestroy;
|
|
Property OnNotification : TNotificationEvent Read FOnNotify Write FOnNotify;
|
|
end;
|
|
|
|
{ TTestTComponentBase }
|
|
|
|
TTestTComponentBase = class(TTestCase)
|
|
protected
|
|
FRoot : TMyComponent;
|
|
Procedure CreateComponents(ACount : Integer);
|
|
Procedure CreateComponents(ACount : Integer; Const BaseName : String);
|
|
Procedure CreateComponents(ACount : Integer; AClass : TComponentClass);
|
|
Procedure CreateComponents(ACount : Integer; AClass : TComponentClass; Const BaseName : String);
|
|
procedure SetUp; override;
|
|
procedure TearDown; override;
|
|
end;
|
|
|
|
{ TTestTComponent }
|
|
|
|
TTestTComponent = Class(TTestTComponentBase)
|
|
private
|
|
procedure TestDoubleName;
|
|
procedure TestTextName;
|
|
procedure TestNumberName;
|
|
procedure TestNumberTextName;
|
|
Published
|
|
Procedure TestCreate;
|
|
Procedure TestName;
|
|
procedure TestIdentiFierName;
|
|
procedure TestIdentiFierNameTwo;
|
|
procedure TestIdentiFierNameThree;
|
|
procedure TestIdentiFierNameFour;
|
|
procedure TestOwner;
|
|
procedure TestChildren;
|
|
Procedure TestDestroyChild;
|
|
Procedure TestDestroyChildren;
|
|
Procedure TestUniqueName;
|
|
Procedure TestRemoveComponent;
|
|
end;
|
|
|
|
{ TTestTComponentNotifies }
|
|
|
|
TTestTComponentNotifies = Class(TTestTComponentBase)
|
|
Protected
|
|
N : TNotificationSink;
|
|
procedure SetUp; override;
|
|
procedure TearDown; override;
|
|
Published
|
|
Procedure TestInsertNotification;
|
|
Procedure TestRemoveNotification;
|
|
end;
|
|
|
|
|
|
implementation
|
|
|
|
procedure TTestTComponentBase.CreateComponents(ACount: Integer);
|
|
begin
|
|
CreateComponents(ACount,'');
|
|
end;
|
|
|
|
procedure TTestTComponentBase.CreateComponents(ACount: Integer;
|
|
const BaseName: String);
|
|
begin
|
|
CreateComponents(ACount,TMyComponent,BaseName);
|
|
end;
|
|
|
|
procedure TTestTComponentBase.CreateComponents(ACount: Integer;
|
|
AClass: TComponentClass);
|
|
begin
|
|
CreateComponents(ACount,AClass,'');
|
|
end;
|
|
|
|
procedure TTestTComponentBase.CreateComponents(ACount: Integer;
|
|
AClass: TComponentClass; const BaseName: String);
|
|
|
|
Var
|
|
I : Integer;
|
|
C : TComponent;
|
|
|
|
begin
|
|
For I:=0 to ACount-1 do
|
|
begin
|
|
C:=TMyComponent.Create(FRoot);
|
|
If (BaseName<>'') then
|
|
C.Name:=BaseName+IntToStr(I+1);
|
|
end;
|
|
end;
|
|
|
|
procedure TTestTComponentBase.SetUp;
|
|
begin
|
|
FRoot:=TMyComponent.Create(Nil);
|
|
FRoot.Name:='Root';
|
|
end;
|
|
|
|
procedure TTestTComponentBase.TearDown;
|
|
begin
|
|
FreeAndNil(FRoot);
|
|
end;
|
|
|
|
{ TTestTComponent }
|
|
|
|
procedure TTestTComponent.TestCreate;
|
|
begin
|
|
FreeAndNil(Froot);
|
|
FRoot:=TMyComponent.Create(Nil);
|
|
AssertEquals('Empty name','',FRoot.Name);
|
|
AssertEquals('No owned components',0,FRoot.ComponentCount);
|
|
If (FRoot.ComponentState<>[]) then
|
|
Fail('Componentstate is not empty');
|
|
If (FRoot.Owner<>Nil) then
|
|
Fail('Owner is not nil');
|
|
end;
|
|
|
|
procedure TTestTComponent.TestName;
|
|
begin
|
|
AssertEquals('Name is Root','Root',FRoot.Name);
|
|
end;
|
|
|
|
procedure TTestTComponent.TestOwner;
|
|
|
|
Var
|
|
C : TComponent;
|
|
|
|
begin
|
|
C:=TComponent.Create(FRoot);
|
|
If (C.Owner<>FRoot) then
|
|
Fail('Owner not saved after create');
|
|
end;
|
|
|
|
procedure TTestTComponent.TestChildren;
|
|
begin
|
|
CreateComponents(3,'Child');
|
|
AssertEquals('Componentcount is 3',3,FRoot.ComponentCount);
|
|
AssertEquals('Child component 0 is child1','Child1',FRoot.Components[0].Name);
|
|
AssertEquals('Child component 1 is child2','Child2',FRoot.Components[1].Name);
|
|
AssertEquals('Child component 2 is child3','Child3',FRoot.Components[2].Name);
|
|
end;
|
|
|
|
procedure TTestTComponent.TestDestroyChild;
|
|
|
|
Var
|
|
S : TEventSink;
|
|
|
|
begin
|
|
CreateComponents(1);
|
|
S:=TEventSink.Create;
|
|
try
|
|
TMyComponent(FRoot.Components[0]).OnDestroy:=@S.Event;
|
|
FreeAndNil(FRoot);
|
|
AssertEquals('One child destroyed',1,S.FEventcount);
|
|
If (S.FLastSender=Nil) then
|
|
Fail('No sender passed');
|
|
finally
|
|
S.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TTestTComponent.TestDestroyChildren;
|
|
|
|
Var
|
|
S : TEventSink;
|
|
I : Integer;
|
|
|
|
begin
|
|
CreateComponents(3);
|
|
S:=TEventSink.Create;
|
|
try
|
|
For I:=0 to 2 do
|
|
TMyComponent(FRoot.Components[I]).OnDestroy:=@S.Event;
|
|
FreeAndNil(FRoot);
|
|
AssertEquals('One child destroyed',3,S.FEventcount);
|
|
If (S.FLastSender=Nil) then
|
|
Fail('No sender passed');
|
|
finally
|
|
S.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TTestTComponent.TestDoubleName;
|
|
|
|
begin
|
|
FRoot.Components[1].Name:='Child1';
|
|
end;
|
|
|
|
procedure TTestTComponent.TestUniqueName;
|
|
begin
|
|
CreateComponents(3,'Child');
|
|
AssertException('Unique name',EComponentError,@TestDoubleName);
|
|
end;
|
|
|
|
procedure TTestTComponent.TestRemoveComponent;
|
|
|
|
Var
|
|
C : TComponent;
|
|
|
|
begin
|
|
CreateComponents(1);
|
|
C:=FRoot.Components[0];
|
|
FRoot.RemoveComponent(C);
|
|
Try
|
|
AssertEquals('No components left',0,FRoot.ComponentCount);
|
|
AssertSame('Component has no owner',Nil,C.Owner);
|
|
Finally
|
|
C.Free;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TTestTComponent.TestTextName;
|
|
|
|
begin
|
|
FRoot.Name:='Child 1';
|
|
end;
|
|
|
|
procedure TTestTComponent.TestNumberName;
|
|
begin
|
|
FRoot.Name:='1';
|
|
end;
|
|
|
|
procedure TTestTComponent.TestNumberTextName;
|
|
begin
|
|
FRoot.Name:='1Too';
|
|
end;
|
|
|
|
procedure TTestTComponent.TestIdentiFierName;
|
|
begin
|
|
AssertException('Identifier name',EComponentError,@TestTextName);
|
|
end;
|
|
|
|
procedure TTestTComponent.TestIdentiFierNameTwo;
|
|
|
|
begin
|
|
AssertException('Identifier name',EComponentError,@TestNumberTextName);
|
|
end;
|
|
|
|
procedure TTestTComponent.TestIdentiFierNameThree;
|
|
begin
|
|
AssertException('Identifier name',EComponentError,@TestNumberName);
|
|
end;
|
|
|
|
procedure TTestTComponent.TestIdentiFierNameFour;
|
|
|
|
Var
|
|
Failed : Boolean;
|
|
|
|
begin
|
|
Failed:=False;
|
|
Try
|
|
FRoot.Name:='Some1';
|
|
except
|
|
Failed:=True;
|
|
end;
|
|
If Failed then
|
|
Fail('No identifier ending on 1 accepted ?');
|
|
end;
|
|
|
|
{ TMyComponent }
|
|
|
|
destructor TMyComponent.Destroy;
|
|
begin
|
|
If Assigned(FOnDestroy) then
|
|
FOnDestroy(Self);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TMyComponent.Notification(AComponent: TComponent;
|
|
Operation: TOperation);
|
|
begin
|
|
If Assigned(FOnNotify) then
|
|
FOnNotify(Self, AComponent, Operation);
|
|
inherited Notification(AComponent, Operation);
|
|
end;
|
|
|
|
{ TEventSink }
|
|
|
|
procedure TEventSink.Event(Sender: TObject);
|
|
begin
|
|
Inc(FEventCount);
|
|
FLastSender:=Sender;
|
|
end;
|
|
|
|
procedure TEventSink.ResetEvent;
|
|
begin
|
|
FLastSender:=Nil;
|
|
FEventCount:=0;
|
|
end;
|
|
|
|
{ TNotificationSink }
|
|
|
|
function TNotificationSink.GetNot(Index : Integer): TNotification;
|
|
begin
|
|
If Assigned(FEvents) then
|
|
Result:=TNotification(FEvents.Items[Index])
|
|
else
|
|
Result:=Nil;
|
|
end;
|
|
|
|
destructor TNotificationSink.Destroy;
|
|
begin
|
|
FreeAndNil(FEvents);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TNotificationSink.Notification(Sender, AComponent: TComponent;
|
|
Operation: TOperation);
|
|
|
|
Var
|
|
N : TNotification;
|
|
|
|
begin
|
|
If (Fevents=Nil) then
|
|
FEvents:=TCollection.Create(TNotification);
|
|
N:=FEvents.Add as TNotification;
|
|
N.AComponent:=AComponent;
|
|
N.ASender:=Sender;
|
|
N.AOperation:=Operation;
|
|
end;
|
|
|
|
procedure TNotificationSink.Reset;
|
|
begin
|
|
FreeAndNil(FEvents);
|
|
end;
|
|
|
|
function TNotificationSink.EventCount: Integer;
|
|
begin
|
|
If (Fevents<>Nil) then
|
|
Result:=FEvents.Count
|
|
else
|
|
Result:=0;
|
|
end;
|
|
|
|
{ TTestTComponentNotifies }
|
|
|
|
procedure TTestTComponentNotifies.SetUp;
|
|
begin
|
|
inherited SetUp;
|
|
N:=TNotificationSink.Create;
|
|
FRoot.OnNotification:=@N.Notification;
|
|
end;
|
|
|
|
procedure TTestTComponentNotifies.TearDown;
|
|
begin
|
|
FreeAndNil(N);
|
|
inherited TearDown;
|
|
end;
|
|
|
|
procedure TTestTComponentNotifies.TestInsertNotification;
|
|
|
|
Var
|
|
E : TNotification;
|
|
|
|
begin
|
|
CreateComponents(1);
|
|
AssertEquals('One notification received',1,N.EventCount);
|
|
E:=N.Notifications[0];
|
|
AssertEquals('Insert notification received',Ord(opInsert),Ord(E.AOperation));
|
|
end;
|
|
|
|
procedure TTestTComponentNotifies.TestRemoveNotification;
|
|
|
|
Var
|
|
C : TComponent;
|
|
E : TNotification;
|
|
|
|
begin
|
|
CreateComponents(1);
|
|
N.Reset;
|
|
C:=FRoot.Components[0];
|
|
FRoot.RemoveComponent(C);
|
|
Try
|
|
AssertEquals('One notification received',1,N.EventCount);
|
|
E:=N.Notifications[0];
|
|
Finally
|
|
C.Free;
|
|
end;
|
|
end;
|
|
|
|
|
|
initialization
|
|
|
|
RegisterTests([TTestTComponent,TTestTComponentNotifies]);
|
|
end.
|
|
|