From a1e24a3f95d52de624dcf482e5b3968c5c9bb58b Mon Sep 17 00:00:00 2001 From: Ross Boucher Date: Sat, 19 Dec 2009 17:47:02 -0500 Subject: [PATCH] Fix a bug where keyPaths which had a component evaluating to self would send notifications containing the wrong keypath in the observation. Includes test case. --- Foundation/CPKeyValueObserving.j | 4 ++-- Tests/Foundation/CPKVOTest.j | 38 +++++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/Foundation/CPKeyValueObserving.j b/Foundation/CPKeyValueObserving.j index 6a83591d5..37d749a2c 100644 --- a/Foundation/CPKeyValueObserving.j +++ b/Foundation/CPKeyValueObserving.j @@ -510,7 +510,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, - (void)observeValueForKeyPath:(CPString)aKeyPath ofObject:(id)anObject change:(CPDictionary)changes context:(id)aContext { - if (anObject == _object) + if (aKeyPath === _firstPart) { [_observer observeValueForKeyPath:_firstPart ofObject:_object change:changes context:_context]; @@ -523,7 +523,7 @@ var kvoNewAndOld = CPKeyValueObservingOptionNew|CPKeyValueObservingOptionOld, if (_value) [_value addObserver:self forKeyPath:_secondPart options:kvoNewAndOld context:nil]; } - else /* if (anObject == _value || !_value) */ + else { //a is the same, but a.b has changed -- nothing to do but forward this message along [_observer observeValueForKeyPath:_firstPart+"."+aKeyPath ofObject:_object change:changes context:_context]; diff --git a/Tests/Foundation/CPKVOTest.j b/Tests/Foundation/CPKVOTest.j index 2311c387c..9244db558 100644 --- a/Tests/Foundation/CPKVOTest.j +++ b/Tests/Foundation/CPKVOTest.j @@ -172,7 +172,7 @@ { cs101 = [ClassTester new]; bob = [PersonTester new]; - + [cs101 setTeacher:bob]; [cs101 addObserver:self forKeyPath:@"teacher.name" options:0 context:"testMultipartKey"]; @@ -183,12 +183,26 @@ [self assertTrue: _sawObservation message:"Never recieved an observation"]; } +- (void)testMultiPartKeysWhereValuesEvaluateToSelf +{ + focus = [CarTester new]; + bob = [PersonTester new]; + + [bob setValue:focus forKey:"car"]; + + [bob addObserver:self forKeyPath:@"self.car.thisCar.model" options:0 context:"testMultiPartKeysWhereValuesEvaluateToSelf"]; + + [focus setValue:"ford focus" forKey:"model"]; + + [self assertTrue: _sawObservation message:"Never recieved an observation"]; +} + - (void)testThreePartKey { focus = [CarTester new]; cs101 = [ClassTester new]; bob = [PersonTester new]; - + [cs101 setTeacher:bob]; [bob setValue:focus forKey:"car"]; @@ -203,7 +217,7 @@ focus = [CarTester new]; cs101 = [ClassTester new]; bob = [PersonTester new]; - + [cs101 setTeacher:bob]; [focus setValue:"2000" forKey:"year"]; @@ -218,7 +232,7 @@ { cs101 = [ClassTester new]; bob = [PersonTester new]; - + [cs101 setTeacher:bob]; [cs101 addObserver:self forKeyPath:@"teacher.name" options:0 context:"testRemoveMultipartKey"]; @@ -235,7 +249,7 @@ focus = [CarTester new]; cs101 = [ClassTester new]; bob = [PersonTester new]; - + [cs101 setTeacher:bob]; [bob setValue:focus forKey:"car"]; @@ -367,7 +381,7 @@ - (void)testPerformance { bob = [PersonTester new]; - + [bob setValue:"initial bob" forKey:"name"]; var startTime = new Date(); @@ -584,6 +598,13 @@ break; + case "testMultiPartKeysWhereValuesEvaluateToSelf": + + [self assert:aKeyPath equals:"self.car.thisCar.model"]; + [self assert:newValue equals:"ford focus"]; + [self assert:anObject equals:bob]; + break; + default: [self assertFalse:YES message:"unhandled observation, must be an error"]; return; @@ -661,6 +682,11 @@ model = aModel; } +- (void)thisCar +{ + return self; +} + @end @implementation IndirectToManyTester : CPObject