erikdoe/ocmock — pull request #21 by itsthejb (2012-10-08 09:07:07+00:00)
Title: "Property chaining" functionality

In the past I've had a lot of trouble creating mocks for objects with deep property hierarchies:

```
object.someProperty.anotherProperty.another.value
```

At present, this means creating mocks for all the intervening objects when I'm only actually interested in stubbing the final property. With the functionality I've implemented here, all of the middle objects can be automatically generated as ```OCChainTampolineProxy``` objects, which can return a specific object (another trampoline or a *real* mock) on a particular selector.

[This test](https://github.com/itsthejb/ocmock/blob/feature/property-chaining/Source/OCMockTests/OCMockObjectTests.m#L840-848) illustrates best;

```
- (void)testValueWithStubbedPropertyChain
{
mock = [OCMockObject mockForClass:[NSBundle class]];
NSUInteger length = 100;
[[[mock stub] andReturnValue:OCMOCK_VALUE(length)] chainedPropertyWithPath:@"bundleURL.absoluteString.length"
terminalObjectClass:[NSString class]];
NSBundle *castedBundle = (NSBundle*) mock;
STAssertEquals(length, castedBundle.bundleURL.absoluteString.length, @"Didn't return the stubbed value");
}
```

**Notes**

* Implementation is currently rather incomplete, since the chain isn't clever enough to allow tacking on to existing stubs. For example;

```
- (void)testStubAnotherPropertyOnChain
{
mock = [OCMockObject mockForClass:[NSBundle class]];
NSUInteger length = 100;
[[[mock stub] andReturnValue:OCMOCK_VALUE(length)] chainedPropertyWithPath:@"bundleURL.absoluteString.length"
terminalObjectClass:[NSString class]];
[[[mock stub] andReturn:@"foo"] chainedPropertyWithPath:@"bundleURL.absoluteString.lowercaseString"
terminalObjectClass:[NSString class]];

NSBundle *castedBundle = (NSBundle*) mock;
STAssertEquals(length, castedBundle.bundleURL.absoluteString.length, @"Didn't return the stubbed value");
STAssertEqualObjects(@"foo", castedBundle.bundleURL.absoluteString.lowercaseString, @"Didn't return the stubbed value");
}
```

Won't work since the second call with throw away the previous chain (or worse). I think that the current implementation of the chain building currently makes this rather hard to add...

* A little hacky at the moment, since I didn't want to touch too much of the existing framework.
* ```OCChainTampolineProxy``` is quite nice, but the creation of the chain in ```-chainedPropertyWithPath:terminalObjectClass:``` isn't so elegant. It does work, at least!

I thought I should at least issue this PR now to get some feedback on the idea. I can then work on it further.