📄 xpobservertests.pas
字号:
'2: subject rc after first observer added again');
CheckEquals(2, FObserver.RefCount,
'2: observer rc after attempting to add itself again');
CheckEquals(1, ASubject.ObserverCount,
'2: observer count after first observer added again');
ASubject := nil;
CheckEquals(1, FObserver.RefCount, 'observer rc after subject is destroyed');
end;
procedure TXPSubjectTests.TestCreate;
var
ASubject: IXPCrackedSubject;
begin
ASubject := TCrackedSubject.Create;
CheckEquals(1, ASubject.RefCount, 'sole reference on construction');
end;
procedure TXPSubjectTests.TestDeleteObserver;
var
ASubject: IXPCrackedSubject;
begin
ASubject := TCrackedSubject.Create;
CheckEquals(1, ASubject.RefCount, 'sole reference on construction');
CheckEquals(0, ASubject.Count, 'empty observer count on construction');
Check(not ASubject.DeleteObserver(nil), 'delete nil observer on empty');
FObserver.Subject := ASubject;
CheckEquals(2, ASubject.RefCount, 'subject rc after assignment');
Check(ASubject.InsertObserver(0, FObserver, ASubject),
'insert observer into subject');
CheckEquals(2, FObserver.RefCount, 'observer rc after registration');
Check(not ASubject.DeleteObserver(nil), 'delete nil observer on non-empty');
CheckEquals(2, FObserver.RefCount, 'observer rc after delete nil observer');
Check(not ASubject.DeleteObserver(FObserver, pointer(1)),
'delete observer with wrong context');
CheckEquals(2, FObserver.RefCount,
'observer rc after delete observer with wrong context');
Check(ASubject.DeleteObserver(FObserver),
'delete observer with right context');
CheckEquals(1, FObserver.RefCount,
'observer rc after delete observer with right context');
CheckEquals(1, ASubject.RefCount,
'subject rc after delete observer callback');
Check(not ASubject.DeleteObserver(FObserver),
'delete deleted observer with right context');
Check(not ASubject.DeleteObserver(nil),
'delete nil observer on empty after filling');
end;
procedure TXPSubjectTests.TestDeleteObservers;
var
ASubject: IXPCrackedSubject;
begin
ASubject := TCrackedSubject.Create;
CheckEquals(1, ASubject.RefCount, 'sole reference on construction');
CheckEquals(0, ASubject.Count, 'empty observer count on construction');
ASubject.DeleteObservers;
CheckEquals(1, ASubject.RefCount,
'rc after delete observers without observers');
CheckEquals(0, ASubject.Count,
'observer count after delete observers without observers');
FObserver.Subject := ASubject;
Check(ASubject.InsertObserver(0, FObserver, ASubject),
'insert observer into subject');
CheckEquals(2, FObserver.RefCount,
'observer rc after registration');
FObserver2.Subject := ASubject;
Check(ASubject.InsertObserver(0, FObserver2, ASubject),
'insert observer 2 into subject');
CheckEquals(2, FObserver2.RefCount, 'observer 2 rc after registration');
FObserver3.Subject := ASubject;
Check(ASubject.InsertObserver(0, FObserver3, ASubject),
'insert observer 3 into subject');
CheckEquals(2, FObserver3.RefCount, 'observer 3 rc after registration');
CheckEquals(3, ASubject.Count, 'observer count after 3 registrations');
CheckEquals(4, ASubject.RefCount, 'subject rc after 3 registrations');
ASubject.DeleteObservers;
CheckEquals(0, ASubject.Count, 'observer count after delete observers');
CheckEquals(1, ASubject.RefCount, 'subject rc after delete observers');
CheckEquals(1, FObserver.RefCount, 'observer rc after delete observers');
CheckEquals(1, FObserver2.RefCount, 'observer 2 rc after delete observers');
CheckEquals(1, FObserver3.RefCount, 'observer 3 rc after delete observers');
end;
procedure TXPSubjectTests.TestInsertObserver;
var
ASubject: IXPCrackedSubject;
begin
ASubject := TCrackedSubject.Create;
CheckEquals(1, ASubject.RefCount, 'sole reference on construction');
CheckEquals(0, ASubject.Count, 'empty observer count on construction');
CheckEquals(1, FObserver.RefCount, 'rc observer on construction');
FObserver.Subject := ASubject;
CheckEquals(2, ASubject.RefCount, 'subject rc after assignment');
CheckEquals(1, FObserver.RefCount, 'observer rc after assignment');
Check(not ASubject.InsertObserver(-1, FObserver, ASubject),
'insert lower bound error');
Check(not ASubject.InsertObserver(1, FObserver, ASubject),
'insert upper bound error');
Check(ASubject.InsertObserver(0, FObserver, ASubject),
'insert into empty subject');
CheckEquals(1, ASubject.Count, 'observer count after registration');
CheckEquals(2, FObserver.RefCount, 'observer rc after registration');
FObserver2.Subject := ASubject;
CheckEquals(3, ASubject.RefCount, 'subject rc after second assignment');
CheckEquals(1, FObserver2.RefCount, 'observer2 rc after assignment');
Check(not ASubject.InsertObserver(-1, FObserver2, ASubject),
'insert 2 lower bound error');
Check(not ASubject.InsertObserver(2, FObserver2, ASubject),
'insert 2 upper bound error');
Check(ASubject.InsertObserver(0, FObserver2, ASubject),
'insert into start of non-empty subject');
CheckEquals(2, ASubject.Count, 'observer count after second registration');
CheckEquals(2, FObserver2.RefCount, 'observer2 rc after registration');
FObserver3.Subject := ASubject;
CheckEquals(4, ASubject.RefCount, 'subject rc after third assignment');
CheckEquals(1, FObserver3.RefCount, 'observer3 rc after assignment');
Check(not ASubject.InsertObserver(-1, FObserver3, ASubject),
'insert 3 lower bound error');
Check(not ASubject.InsertObserver(3, FObserver3, ASubject),
'insert 3 upper bound error');
Check(ASubject.InsertObserver(2, FObserver3, ASubject),
'insert into end of non-empty subject');
CheckEquals(3, ASubject.Count,
'observer count after third registration');
CheckEquals(2, FObserver2.RefCount, 'observer3 rc after registration');
FObserver4.Subject := ASubject;
CheckEquals(5, ASubject.RefCount, 'subject rc after fourth assignment');
CheckEquals(1, FObserver4.RefCount, 'observer4 rc after assignment');
Check(not ASubject.InsertObserver(-1, FObserver4, ASubject),
'insert 4 lower bound error');
Check(not ASubject.InsertObserver(4, FObserver4, ASubject),
'insert 4 upper bound error');
Check(ASubject.InsertObserver(2, FObserver4, ASubject),
'insert into middle of non-empty subject');
CheckEquals(4, ASubject.Count,
'observer count after fourth registration');
CheckEquals(2, FObserver4.RefCount, 'observer4 rc after registration');
Check(not ASubject.InsertObserver(-1, FObserver3, ASubject),
'insert 5 lower bound error with current member');
Check(not ASubject.InsertObserver(5, FObserver3, ASubject),
'insert 5 upper bound error with current member');
Check(not ASubject.InsertObserver(0, FObserver3, ASubject),
'insert 5 at 0 with found current member');
Check(not ASubject.InsertObserver(1, FObserver3, ASubject),
'insert 5 at 1 with found current member');
Check(not ASubject.InsertObserver(2, FObserver3, ASubject),
'insert 5 at 2 with found current member');
Check(not ASubject.InsertObserver(3, FObserver3, ASubject),
'insert 5 at 3 with found current member');
Check(not ASubject.InsertObserver(4, FObserver3, ASubject),
'insert 5 at 4 with found current member');
ASubject := nil;
CheckEquals(1, FObserver.RefCount, 'observer 1 rc after subject nil''d');
CheckEquals(1, FObserver2.RefCount, 'observer 2 rc after subject nil''d');
CheckEquals(1, FObserver3.RefCount, 'observer 3 rc after subject nil''d');
CheckEquals(1, FObserver4.RefCount, 'observer 4 rc after subject nil''d');
end;
procedure TXPSubjectTests.TestObserverCount;
var
ASubject: IXPCrackedSubject;
begin
ASubject := TCrackedSubject.Create;
CheckEquals(0, ASubject.ObserverCount,
'empty observer count on construction');
CheckEquals(1, FObserver.RefCount, 'observer rc before acquiring subject');
FObserver.Subject := ASubject;
Check(ASubject.AddObserver(FObserver, ASubject),
'1: adding first observer to subject') ;
CheckEquals(2, ASubject.RefCount, '1: subject rc after first observer');
CheckEquals(2, FObserver.RefCount, '1: observer rc after acquiring subject');
CheckEquals(1, ASubject.ObserverCount,
'1: observer count after first observer');
CheckEquals(1, FObserver2.RefCount,
'1: observer rc before acquiring subject');
FObserver2.Subject := ASubject;
Check(ASubject.AddObserver(FObserver2, ASubject),
'1: adding second observer to subject');
CheckEquals(3, ASubject.RefCount, '1: subject rc after second observer');
CheckEquals(2, FObserver2.RefCount,
'1: second observer rc after acquiring subject');
CheckEquals(2, ASubject.ObserverCount,
'1: observer count after second observer');
Check(ASubject.DeleteObserver(FObserver2),
'1: deleting second observer from subject');
CheckEquals(2, ASubject.RefCount,
'1: subject rc after deleting second observer');
CheckEquals(1, FObserver2.RefCount,
'1: second observer rc after detaching from subject');
CheckEquals(1, ASubject.ObserverCount,
'1: observer count after deleting second observer');
CheckEquals(2, FObserver.RefCount,
'1: observer rc after detaching first observer from subject');
Check(ASubject.DeleteObserver(FObserver),
'1: deleting second observer from subject');
CheckEquals(1, ASubject.RefCount,
'1: subject rc after deleting first observer');
CheckEquals(1, FObserver.RefCount,
'1: first observer rc after detaching from subject');
CheckEquals(0, ASubject.ObserverCount,
'1: observer count after deleting first observer');
CheckEquals(1, FObserver2.RefCount,
'1: second observer rc after first observer detached from subject');
// Repeat but reverse removal order
FObserver.Subject := ASubject;
Check(ASubject.AddObserver(FObserver, ASubject),
'2: adding first observer to subject');
CheckEquals(2, ASubject.RefCount, '2: subject rc after first observer');
CheckEquals(2, FObserver.RefCount, '2: observer rc after acquiring subject');
CheckEquals(1, ASubject.ObserverCount,
'2: observer count after first observer');
CheckEquals(1, FObserver2.RefCount,
'2: observer rc before acquiring subject');
FObserver2.Subject := ASubject;
Check(ASubject.AddObserver(FObserver2, ASubject),
'2: adding second observer to subject');
CheckEquals(3, ASubject.RefCount, '2: subject rc after second observer');
CheckEquals(2, FObserver2.RefCount,
'2: second observer rc after acquiring subject');
CheckEquals(2, ASubject.ObserverCount,
'2: observer count after second observer');
Check(ASubject.DeleteObserver(FObserver),
'2: deleting first observer from subject');
CheckEquals(2, ASubject.RefCount,
'2: subject rc after deleting first observer');
CheckEquals(1, FObserver.RefCount,
'2: observer rc after detaching from subject');
CheckEquals(1, ASubject.ObserverCount,
'2: observer count after deleting first observer');
CheckEquals(2, FObserver2.RefCount,
'2: second observer rc after first observer detached from subject');
Check(ASubject.DeleteObserver(FObserver2),
'2: deleting second observer from subject');
CheckEquals(1, ASubject.RefCount,
'2: subject rc after deleting second observer');
CheckEquals(1, FObserver2.RefCount,
'2: second observer rc after detaching from subject');
CheckEquals(0, ASubject.ObserverCount,
'2: observer count after deleting second observer');
CheckEquals(1, FObserver.RefCount,
'2: first observer rc after detaching second observer from subject');
// Try repeated deletion
Check(not ASubject.DeleteObserver(FObserver2),
'2: deleting second observer (again) from subject');
CheckEquals(1, ASubject.RefCount,
'2: subject rc after second attempt to delete second observer');
CheckEquals(1, FObserver2.RefCount,
'2: second observer rc after second attempt to detach from subject');
CheckEquals(0, ASubject.ObserverCount,
'2: observer count after attempting second deletion of second observer');
CheckEquals(1, FObserver.RefCount,
'2: observer rc after attempting to detach second observer from subject');
end;
procedure TXPSubjectTests.SetUp;
begin
inherited;
FObserver := TCrackedObserver.Create;
FObserver2 := TCrackedObserver.Create;
FObserver3 := TCrackedObserver.Create;
FObserver4 := TCrackedObserver.Create;
end;
procedure TXPSubjectTests.TearDown;
begin
FObserver := nil;
FObserver2 := nil;
FObserver3 := nil;
FObserver4 := nil;
inherited;
end;
procedure TXPSubjectTests.TestGetObserver;
var
ASubject: IXPCrackedSubject;
begin
ASubject := TCrackedSubject.Create;
CheckEquals(1, ASubject.RefCount, 'subject rc count on construction');
CheckEquals(0, ASubject.ObserverCount,
'empty observer count on construction');
Check(ASubject.Observers[0] = nil, 'observers[0] on empty subject');
CheckEquals(1, ASubject.RefCount,
'subject rc count after observers[0] on empty subject');
Check(ASubject.Observers[-1] = nil, 'observers[-1] on empty subject');
CheckEquals(1, ASubject.RefCount,
'subject rc count after observers[-1] on empty subject');
Check(ASubject.Observers[1] = nil, 'observers[1] on empty subject');
CheckEquals(1, ASubject.RefCount,
'subject rc count after observers[1] on empty subject');
// Add an observer
CheckEquals(1, FObserver.RefCount, 'observer rc before acquiring subject');
FObserver.Subject := ASubject;
Check(ASubject.AddObserver(FObserver, ASubject),
'1: adding first observer to subject') ;
CheckEquals(2, ASubject.RefCount, '1: subject rc after first observer');
CheckEquals(2, FObserver.RefCount, '1: observer rc after acquiring subject');
CheckEquals(1, ASubject.ObserverCount,
'1: observer count after first observer');
Check(ASubject.Observers[0] <> nil, 'observers[0] non-nil on empty subject');
// temporary interface created in above comparison not released until
// procedure scope exited
CheckEquals(3, FObserver.RefCount,
'observer rc after observers[0] non-nil comparison');
CheckEquals(1, FObserver2.RefCount, 'observer 2 rc before re-assignment');
FObserver2 := FObserver;
// temporary still present in rc after copy
CheckEquals(4, FObserver2.RefCount, 'observer 2 rc after re-assignment');
CheckEquals(4, FObserver.RefCount, 'observer rc after copying to observer 2');
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -