Update ChangeLog and fix coding style and leaks in testcases

This commit is contained in:
Hugo Melder 2025-02-04 07:46:34 +01:00 committed by rfm
parent 05628229e4
commit b3d5c20277
3 changed files with 287 additions and 213 deletions

View file

@ -11,9 +11,9 @@
@interface Observee : NSObject
{
NSString *_firstName;
NSString *_middleName;
NSString *_lastName;
NSString *_firstName;
NSString *_middleName;
NSString *_lastName;
}
- (NSString *) firstName;
@ -32,7 +32,7 @@
@interface ObserveeMixed : Observee
{
BOOL _trigger;
BOOL _trigger;
}
- (BOOL) trigger;
@ -42,43 +42,49 @@
@implementation Observee
- (instancetype)init {
self = [super init];
_firstName = _middleName = _lastName = @"";
- (instancetype) init
{
if ((self = [super init]) != nil)
{
_firstName = _middleName = _lastName = @"";
}
return self;
}
- (NSString *) firstName
{
return _firstName;
return _firstName;
}
- (void) setFirstName: (NSString *)name
{
ASSIGN(_firstName, name);
ASSIGN(_firstName, name);
}
- (NSString *) middleName
{
return _middleName;
return _middleName;
}
- (void) setMiddleName: (NSString *)name
{
ASSIGN(_middleName, name);
ASSIGN(_middleName, name);
}
- (NSString *) lastName
{
return _lastName;
return _lastName;
}
- (void) setLastName: (NSString *)name
{
ASSIGN(_lastName, name);
ASSIGN(_lastName, name);
}
- (NSString *) shortFullName {
return [NSString stringWithFormat: @"%@ %@", _firstName, _lastName];
- (NSString *) shortFullName
{
return [NSString stringWithFormat: @"%@ %@", _firstName, _lastName];
}
- (NSString *) fullName {
return [NSString stringWithFormat: @"%@ %@ %@", _firstName, _middleName, _lastName];
- (NSString *) fullName
{
return [NSString stringWithFormat: @"%@ %@ %@",
_firstName, _middleName, _lastName];
}
@end
@ -87,32 +93,32 @@ return [NSString stringWithFormat: @"%@ %@ %@", _firstName, _middleName, _lastNa
- (BOOL) trigger
{
return _trigger;
return _trigger;
}
- (void) setTrigger: (BOOL) trigger
{
_trigger = trigger;
_trigger = trigger;
}
// We expect this function to have priority over the legacy API
+ (NSSet *)keyPathsForValuesAffectingFullName
+ (NSSet *) keyPathsForValuesAffectingFullName
{
return [NSSet setWithObject:@"trigger"];
return [NSSet setWithObject: @"trigger"];
}
@end
@interface Observer : NSObject
{
@public
NSString *lastKeyPath;
id lastObject;
NSDictionary *lastChange;
int notificationCount;
}
@end
@implementation Observer
{
@public
NSString *lastKeyPath;
id lastObject;
NSDictionary *lastChange;
int notificationCount;
}
- (void) resetValues
{
@ -123,13 +129,13 @@ return [NSString stringWithFormat: @"%@ %@ %@", _firstName, _middleName, _lastNa
- (void) resetCounter
{
notificationCount = 0;
notificationCount = 0;
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
- (void) observeValueForKeyPath: (NSString *)keyPath
ofObject: (id)object
change: (NSDictionary *)change
context: (void *)context
{
notificationCount += 1;
lastKeyPath = keyPath;
@ -147,43 +153,49 @@ void simpleDependency(void)
NSArray *keys = [NSArray arrayWithObjects: @"firstName", @"lastName", nil];
[Observee setKeys: keys
triggerChangeNotificationsForDependentKey:@"fullName"];
triggerChangeNotificationsForDependentKey: @"fullName"];
NSSet *s = [Observee keyPathsForValuesAffectingValueForKey:@"fullName"];
NSSet *s = [Observee keyPathsForValuesAffectingValueForKey: @"fullName"];
NSSet *expectedSet = [NSSet setWithArray: keys];
PASS_EQUAL(s, expectedSet, "'keyPathsForValuesAffectingValueForKey:' returns the correct values affecting 'fullName'");
PASS_EQUAL(s, expectedSet, "'keyPathsForValuesAffectingValueForKey:' returns"
" the correct values affecting 'fullName'")
NSKeyValueObservingOptions opts =
NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew;
NSKeyValueObservingOptions opts
= NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew;
[e addObserver:o forKeyPath:@"fullName" options:opts context:NULL];
[e addObserver: o forKeyPath: @"fullName" options: opts context: NULL];
[e setFirstName:@"Hey"];
[e setFirstName: @"Hey"];
PASS_EQUAL(o->lastKeyPath, @"fullName", "last keypath is 'fullName'");
PASS_EQUAL(o->lastObject, e, "last change object is correct");
PASS(o->lastChange != nil, "last change is not nil");
PASS_EQUAL([o->lastChange valueForKey: NSKeyValueChangeNewKey], @"Hey ", "new entry in change dict correct");
PASS_EQUAL([o->lastChange valueForKey: NSKeyValueChangeOldKey], @" ", "old entry in change dict correct");
PASS(o->notificationCount == 1, "notification count is 1");
PASS_EQUAL(o->lastKeyPath, @"fullName", "last keypath is 'fullName'")
PASS_EQUAL(o->lastObject, e, "last change object is correct")
PASS(o->lastChange != nil, "last change is not nil")
PASS_EQUAL([o->lastChange valueForKey: NSKeyValueChangeNewKey], @"Hey ",
"new entry in change dict correct")
PASS_EQUAL([o->lastChange valueForKey: NSKeyValueChangeOldKey], @" ",
"old entry in change dict correct")
PASS(o->notificationCount == 1, "notification count is 1")
[e setMiddleName:@"Not"]; // no change notification
[e setMiddleName: @"Not"]; // no change notification
[e setLastName:@"You"];
PASS_EQUAL(o->lastKeyPath, @"fullName", "last keypath is 'fullName'");
PASS_EQUAL(o->lastObject, e, "last change object is correct");
PASS(o->lastChange != nil, "last change is not nil");
PASS_EQUAL([o->lastChange valueForKey: NSKeyValueChangeNewKey], @"Hey Not You", "new entry in change dict correct");
PASS_EQUAL([o->lastChange valueForKey: NSKeyValueChangeOldKey], @"Hey Not ", "old entry in change dict correct");
PASS(o->notificationCount == 2, "notification count is 2");
[e setLastName: @"You"];
PASS_EQUAL(o->lastKeyPath, @"fullName", "last keypath is 'fullName'")
PASS_EQUAL(o->lastObject, e, "last change object is correct")
PASS(o->lastChange != nil, "last change is not nil")
PASS_EQUAL([o->lastChange valueForKey: NSKeyValueChangeNewKey],
@"Hey Not You", "new entry in change dict correct")
PASS_EQUAL([o->lastChange valueForKey: NSKeyValueChangeOldKey],
@"Hey Not ", "old entry in change dict correct")
PASS(o->notificationCount == 2, "notification count is 2")
[e removeObserver:o forKeyPath:@"fullName"];
[e removeObserver: o forKeyPath: @"fullName"];
[o release];
[e release];
RELEASE(o);
RELEASE(e);
}
void registeringMultipleDependencies(void) {
void registeringMultipleDependencies(void)
{
Observer *o;
Observee *e;
NSArray *arr;
@ -194,72 +206,89 @@ void registeringMultipleDependencies(void) {
arr = [NSArray arrayWithObject: @"firstName"];
[Observee setKeys:arr
triggerChangeNotificationsForDependentKey:@"fullName"];
s = [Observee keyPathsForValuesAffectingValueForKey:@"fullName"];
PASS_EQUAL(s, [NSSet setWithArray: arr], "expecting 'firstName' as affecting key for 'fullName'");
triggerChangeNotificationsForDependentKey: @"fullName"];
s = [Observee keyPathsForValuesAffectingValueForKey: @"fullName"];
PASS_EQUAL(s, [NSSet setWithArray: arr], "expecting 'firstName' as"
" affecting key for 'fullName'")
arr = [NSArray arrayWithObject: @"middleName"];
[Observee setKeys: arr
triggerChangeNotificationsForDependentKey:@"fullName"];
s = [Observee keyPathsForValuesAffectingValueForKey:@"fullName"];
PASS_EQUAL(s, [NSSet setWithArray: arr], "expecting 'middleName' as affecting key for 'fullName'");
triggerChangeNotificationsForDependentKey: @"fullName"];
s = [Observee keyPathsForValuesAffectingValueForKey: @"fullName"];
PASS_EQUAL(s, [NSSet setWithArray: arr], "expecting 'middleName' as"
" affecting key for 'fullName'")
arr = [NSArray arrayWithObjects: @"firstName", @"lastName", nil];
[Observee setKeys:arr
triggerChangeNotificationsForDependentKey:@"shortFullName"];
s = [Observee keyPathsForValuesAffectingValueForKey:@"shortFullName"];
PASS_EQUAL(s, [NSSet setWithArray: arr], "expecting 'firstName' and 'lastName' as affecting key for 'fullName'");
[Observee setKeys: arr
triggerChangeNotificationsForDependentKey: @"shortFullName"];
s = [Observee keyPathsForValuesAffectingValueForKey: @"shortFullName"];
PASS_EQUAL(s, [NSSet setWithArray: arr], "expecting 'firstName' and"
" 'lastName' as affecting key for 'fullName'")
NSKeyValueObservingOptions opts =
NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew;
NSKeyValueObservingOptions opts
= NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew;
[e addObserver:o forKeyPath:@"fullName" options:opts context:NULL];
[e addObserver: o forKeyPath: @"fullName" options: opts context: NULL];
[e setFirstName:@"Hey"];
PASS(o->notificationCount == 0, "no change notification received when modifying firstName");
[e setFirstName: @"Hey"];
PASS(o->notificationCount == 0, "no change notification received when"
" modifying firstName")
[e setMiddleName:@"Not"];
PASS_EQUAL(o->lastKeyPath, @"fullName", "last keypath is 'fullName'");
PASS_EQUAL(o->lastObject, e, "last change object is correct");
PASS(o->lastChange != nil, "last change is not nil");
PASS_EQUAL([o->lastChange valueForKey: NSKeyValueChangeNewKey], @"Hey Not ", "new entry in change dict correct");
PASS_EQUAL([o->lastChange valueForKey: NSKeyValueChangeOldKey], @"Hey ", "old entry in change dict correct");
PASS(o->notificationCount == 1, "change notification received when modifying middleName");
[e setMiddleName: @"Not"];
PASS_EQUAL(o->lastKeyPath, @"fullName", "last keypath is 'fullName'")
PASS_EQUAL(o->lastObject, e, "last change object is correct")
PASS(o->lastChange != nil, "last change is not nil")
PASS_EQUAL([o->lastChange valueForKey: NSKeyValueChangeNewKey],
@"Hey Not ", "new entry in change dict correct")
PASS_EQUAL([o->lastChange valueForKey: NSKeyValueChangeOldKey],
@"Hey ", "old entry in change dict correct")
PASS(o->notificationCount == 1, "change notification received when"
" modifying middleName")
[e setLastName:@"You"];
PASS(o->notificationCount == 1, "no change notification received when modifying lastName");
[e setLastName: @"You"];
PASS(o->notificationCount == 1, "no change notification received when"
" modifying lastName")
[e removeObserver:o forKeyPath:@"fullName"];
[e removeObserver: o forKeyPath: @"fullName"];
[o resetCounter];
[o resetValues];
[e addObserver:o forKeyPath:@"shortFullName" options:opts context:NULL];
[e addObserver: o forKeyPath: @"shortFullName" options: opts context: NULL];
[e setFirstName:@"Hello"];
PASS_EQUAL(o->lastKeyPath, @"shortFullName", "last keypath is 'shortFullName'");
PASS_EQUAL(o->lastObject, e, "last change object is correct");
PASS(o->lastChange != nil, "last change is not nil");
PASS_EQUAL([o->lastChange valueForKey: NSKeyValueChangeNewKey], @"Hello You", "new entry in change dict correct");
PASS_EQUAL([o->lastChange valueForKey: NSKeyValueChangeOldKey], @"Hey You", "old entry in change dict correct");
PASS(o->notificationCount == 1, "change notification received when modifying firstName");
[e setFirstName: @"Hello"];
PASS_EQUAL(o->lastKeyPath, @"shortFullName",
"last keypath is 'shortFullName'")
PASS_EQUAL(o->lastObject, e, "last change object is correct")
PASS(o->lastChange != nil, "last change is not nil")
PASS_EQUAL([o->lastChange valueForKey: NSKeyValueChangeNewKey],
@"Hello You", "new entry in change dict correct")
PASS_EQUAL([o->lastChange valueForKey: NSKeyValueChangeOldKey],
@"Hey You", "old entry in change dict correct")
PASS(o->notificationCount == 1, "change notification received when"
" modifying firstName")
[e setMiddleName:@"Not"];
PASS(o->notificationCount == 1, "no change notification received when modifying middleName");
[e setMiddleName: @"Not"];
PASS(o->notificationCount == 1, "no change notification received when"
" modifying middleName")
[o resetValues];
[e setLastName:@"World"];
PASS_EQUAL(o->lastKeyPath, @"shortFullName", "last keypath is 'shortFullName'");
PASS_EQUAL(o->lastObject, e, "last change object is correct");
PASS(o->lastChange != nil, "last change is not nil");
PASS_EQUAL([o->lastChange valueForKey: NSKeyValueChangeNewKey], @"Hello World", "new entry in change dict correct");
PASS_EQUAL([o->lastChange valueForKey: NSKeyValueChangeOldKey], @"Hello You", "old entry in change dict correct");
PASS(o->notificationCount == 2, "change notification received when modifying lastName");
[e setLastName: @"World"];
PASS_EQUAL(o->lastKeyPath, @"shortFullName",
"last keypath is 'shortFullName'")
PASS_EQUAL(o->lastObject, e, "last change object is correct")
PASS(o->lastChange != nil, "last change is not nil")
PASS_EQUAL([o->lastChange valueForKey: NSKeyValueChangeNewKey],
@"Hello World", "new entry in change dict correct")
PASS_EQUAL([o->lastChange valueForKey: NSKeyValueChangeOldKey],
@"Hello You", "old entry in change dict correct")
PASS(o->notificationCount == 2, "change notification received when"
" modifying lastName")
[e removeObserver:o forKeyPath:@"shortFullName"];
[e removeObserver: o forKeyPath: @"shortFullName"];
[o release];
[e release];
RELEASE(o);
RELEASE(e);
}
void mixedLegacy(void)
@ -269,47 +298,56 @@ void mixedLegacy(void)
NSArray *keys = [NSArray arrayWithObjects: @"firstName", @"lastName", nil];
[ObserveeMixed setKeys:keys
triggerChangeNotificationsForDependentKey:@"fullName"];
[ObserveeMixed setKeys: keys
triggerChangeNotificationsForDependentKey: @"fullName"];
NSSet *s = [ObserveeMixed keyPathsForValuesAffectingValueForKey:@"fullName"];
NSSet *expected = [NSSet setWithObject:@"trigger"];
PASS_EQUAL(s, expected, "newer API has precedence over deprecated API");
NSSet *s = [ObserveeMixed keyPathsForValuesAffectingValueForKey: @"fullName"];
NSSet *expected = [NSSet setWithObject: @"trigger"];
PASS_EQUAL(s, expected, "newer API has precedence over deprecated API")
NSKeyValueObservingOptions opts =
NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew;
NSKeyValueObservingOptions opts
= NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew;
[e addObserver:o forKeyPath:@"fullName" options:opts context:NULL];
[e addObserver: o forKeyPath: @"fullName" options: opts context: NULL];
// No trigger
[e setFirstName:@"Hey"];
[e setMiddleName:@"Not"];
[e setLastName:@"You"];
PASS(o->notificationCount == 0, "no change notification from either firstName, middleName, or lastName");
[e setFirstName: @"Hey"];
[e setMiddleName: @"Not"];
[e setLastName: @"You"];
PASS(o->notificationCount == 0, "no change notification from either"
" firstName, middleName, or lastName")
// Trigger
[e setTrigger:YES];
PASS(o->notificationCount == 1, "change notification from trigger");
[e setTrigger: YES];
PASS(o->notificationCount == 1, "change notification from trigger")
[e removeObserver:o forKeyPath:@"fullName"];
[o release];
[e release];
[e removeObserver: o forKeyPath: @"fullName"];
RELEASE(o);
RELEASE(e);
}
int
main(int argc, char *argv[])
{
START_SET("KVO Legacy Tests")
START_SET("KVO Legacy Tests")
simpleDependency();
registeringMultipleDependencies();
mixedLegacy();
#if defined(__GNUC__)
testHopeful = YES;
#endif
END_SET("KVO Legacy Tests")
simpleDependency();
registeringMultipleDependencies();
mixedLegacy();
return 0;
#if defined(__GNUC__)
testHopeful = YES;
#endif
END_SET("KVO Legacy Tests")
return 0;
}

View file

@ -12,15 +12,16 @@
#import "Testing.h"
/**
* The new KVO implementation for libobjc2/clang, located in Source/NSKVO*, reuses
* or installs a hidden class and subsequently adds the swizzled method to the
* hidden class. Make sure that the invocation mechanism calls the swizzled method.
* The new KVO implementation for libobjc2/clang, located in Source/NSKVO*,
* reuses or installs a hidden class and subsequently adds the swizzled
* method to the hidden class. Make sure that the invocation mechanism calls
* the swizzled method.
*/
@interface Observee : NSObject
{
NSString *_name;
NSString *_derivedName;
NSString *_name;
NSString *_derivedName;
}
- (NSString *) name;
@ -35,38 +36,39 @@
- (NSString *) name
{
return [[_name retain] autorelease];
return AUTORELEASE(RETAIN(_name));
}
- (void) setName: (NSString *)name
{
ASSIGN(_name, name);
}
- (NSString *)derivedName
- (NSString *) derivedName
{
return [NSString stringWithFormat:@"Derived %@", self.name];
return [NSString stringWithFormat: @"Derived %@", [self name]];
}
- (void) setDerivedName: (NSString *)name
{
ASSIGN(_derivedName, name);
ASSIGN(_derivedName, name);
}
+ (NSSet *)keyPathsForValuesAffectingDerivedName
+ (NSSet *) keyPathsForValuesAffectingDerivedName
{
return [NSSet setWithObject:@"name"];
return [NSSet setWithObject: @"name"];
}
- (void) dealloc {
RELEASE(_name);
RELEASE(_derivedName);
[super dealloc];
- (void) dealloc
{
RELEASE(_name);
RELEASE(_derivedName);
DEALLOC
}
@end
@interface TProxy : NSProxy
{
id _proxiedObject;
id _proxiedObject;
}
@end
@ -74,31 +76,31 @@
- (instancetype)initWithProxiedObject:(id)proxiedObject
{
ASSIGN(_proxiedObject, proxiedObject);
return self;
ASSIGN(_proxiedObject, proxiedObject);
return self;
}
- (void)forwardInvocation:(NSInvocation *)invocation
- (void) forwardInvocation: (NSInvocation *)invocation
{
[invocation invokeWithTarget:_proxiedObject];
[invocation invokeWithTarget: _proxiedObject];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
- (NSMethodSignature*) methodSignatureForSelector: (SEL)sel
{
return [_proxiedObject methodSignatureForSelector:sel];
return [_proxiedObject methodSignatureForSelector: sel];
}
- (void) dealloc
{
RELEASE(_proxiedObject);
[super dealloc];
RELEASE(_proxiedObject);
DEALLOC
}
@end
@interface Wrapper : NSObject
{
TProxy *_proxy;
TProxy *_proxy;
}
- (instancetype) initWithProxy: (TProxy *) proxy;
@ -111,105 +113,128 @@
- (instancetype) initWithProxy: (TProxy *) proxy
{
self = [super init];
if (self)
self = [super init];
if (self)
{
_proxy = proxy;
_proxy = proxy;
}
return self;
return self;
}
- (TProxy *) proxy
{
return _proxy;
return _proxy;
}
@end
@interface Observer: NSObject
{
int count;
NSArray *keys;
int count;
NSArray *keys;
}
- (void)runTest;
@end
@implementation Observer
- (void)simpleKeypathTest
- (void) simpleKeypathTest
{
Observee *obj = [[Observee alloc] init];
TProxy *proxy = [[TProxy alloc] initWithProxiedObject:obj];
Observee *obj = [[Observee alloc] init];
TProxy *proxy = [[TProxy alloc] initWithProxiedObject: obj];
keys = [NSArray arrayWithObjects: @"derivedName", @"name", nil];
count = 0;
keys = [NSArray arrayWithObjects: @"derivedName", @"name", nil];
count = 0;
[(Observee *)proxy addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:NULL];
[(Observee *)proxy addObserver:self forKeyPath:@"derivedName" options:NSKeyValueObservingOptionNew context:NULL];
[(Observee *)proxy addObserver: self
forKeyPath: @"name"
options: NSKeyValueObservingOptionNew
context: NULL];
[(Observee *)proxy addObserver: self
forKeyPath: @"derivedName"
options: NSKeyValueObservingOptionNew
context: NULL];
[((Observee *)proxy) setName: @"MOO"];
PASS(count == 2, "Got two change notifications");
[((Observee *)proxy) setName: @"MOO"];
PASS(count == 2, "Got two change notifications");
[obj setName: @"BAH"];
PASS(count == 4, "Got two change notifications");
[obj setName: @"BAH"];
PASS(count == 4, "Got two change notifications");
[(Observee *)proxy removeObserver:self forKeyPath:@"name" context:NULL];
[(Observee *)proxy removeObserver:self forKeyPath:@"derivedName" context:NULL];
[(Observee *)proxy removeObserver: self forKeyPath: @"name" context: NULL];
[(Observee *)proxy removeObserver: self
forKeyPath: @"derivedName"
context: NULL];
[proxy release];
[obj release];
RELEASE(proxy);
RELEASE(obj);
}
- (void)nestedKeypathTest
- (void) nestedKeypathTest
{
Observee *obj = [[Observee alloc] init];
TProxy *proxy = [[TProxy alloc] initWithProxiedObject:obj];
Observee *obj = [[Observee alloc] init];
TProxy *proxy = [[TProxy alloc] initWithProxiedObject: obj];
Wrapper *w = [[Wrapper alloc] initWithProxy: proxy];
keys = [NSArray arrayWithObjects: @"proxy.derivedName", @"proxy.name", nil];
count = 0;
[w addObserver:self forKeyPath:@"proxy.name" options:NSKeyValueObservingOptionNew context:NULL];
[w addObserver:self forKeyPath:@"proxy.derivedName" options:NSKeyValueObservingOptionNew context:NULL];
[w addObserver: self
forKeyPath: @"proxy.name"
options: NSKeyValueObservingOptionNew
context: NULL];
[w addObserver: self
forKeyPath: @"proxy.derivedName"
options: NSKeyValueObservingOptionNew
context: NULL];
[((Observee *)proxy) setName: @"MOO"];
[((Observee *)proxy) setName: @"MOO"];
PASS(count == 2, "Got two change notifications");
[obj setName: @"BAH"];
[obj setName: @"BAH"];
PASS(count == 4, "Got two change notifications");
[w removeObserver:self forKeyPath:@"proxy.name" context:NULL];
[w removeObserver:self forKeyPath:@"proxy.derivedName" context:NULL];
[w removeObserver: self forKeyPath: @"proxy.name" context: NULL];
[w removeObserver: self forKeyPath: @"proxy.derivedName" context: NULL];
[w release];
[proxy release];
[obj release];
RELEASE(w);
RELEASE(proxy);
RELEASE(obj);
count = 0;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
- (void) observeValueForKeyPath: (NSString *)keyPath
ofObject: (id)object
change: (NSDictionary *)change
context: (void *)context
{
count += 1;
switch (count) {
case 1:
PASS_EQUAL(keyPath, [keys objectAtIndex: 0], "change notification for dependent key 'derivedName' is emitted first");
break;
case 2:
PASS_EQUAL(keyPath, [keys objectAtIndex: 1], "'name' change notification for proxy is second");
break;
case 3:
PASS_EQUAL(keyPath, [keys objectAtIndex: 0], "'derivedName' change notification for object is third");
break;
case 4:
PASS_EQUAL(keyPath, [keys objectAtIndex: 1], "'name' change notification for object is fourth");
break;
default:
PASS(0, "unexpected -[Observer observeValueForKeyPath:ofObject:change:context:] callback");
count += 1;
switch (count)
{
case 1:
PASS_EQUAL(keyPath, [keys objectAtIndex: 0],
"change notification for dependent key 'derivedName'"
" is emitted first")
break;
case 2:
PASS_EQUAL(keyPath, [keys objectAtIndex: 1],
"'name' change notification for proxy is second")
break;
case 3:
PASS_EQUAL(keyPath, [keys objectAtIndex: 0],
"'derivedName' change notification for object is third")
break;
case 4:
PASS_EQUAL(keyPath, [keys objectAtIndex: 1],
"'name' change notification for object is fourth")
break;
default:
PASS(0,
"unexpected -[Observer observeValueForKeyPath:ofObject:"
"change:context:] callback")
}
}
@ -218,15 +243,15 @@
int
main(int argc, char *argv[])
{
START_SET("KVO Proxy Tests")
Observer *obs = [Observer new];
START_SET("KVO Proxy Tests")
Observer *obs = [Observer new];
testHopeful = YES;
[obs simpleKeypathTest];
[obs nestedKeypathTest];
testHopeful = NO;
testHopeful = YES;
[obs simpleKeypathTest];
[obs nestedKeypathTest];
testHopeful = NO;
[obs release];
END_SET("KVO Proxy Tests")
return 0;
RELEASE(obs);
END_SET("KVO Proxy Tests")
return 0;
}