Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom matcher behaves differently than built in matcher under async #125

Open
iosdev-republicofapps opened this issue Jan 9, 2015 · 0 comments

Comments

@iosdev-republicofapps
Copy link
Contributor

Hi,

First, I love Expecta, thanks so much for your hard work!

Here's what I'm trying to do:

@interface Person : NSObject
@property (nonatomic, copy) NSString *surname;
@end

// Person.surname starts out as nil.  I want to test an async process that eventually
// (after say 0.1s) sets Person.surname to some non-nil value.
Person *person = [[Person alloc] init];

// I tried this but it barfed with:
//  nil/null is not an instance of NSString or NSFastEnumeration
expect(person.name).will.contain(@"foo");

// I know nil is not an instance of NSString or NSFastEnumeration.  That's because
// person.name is nil when the expect method is invoked.  But person.name will
// become non-nil after the async process finishes.

// OK, so I went in to EXPMatchers+contain.m in the Expecta source and changed
BOOL actualIsCompatible = [actual isKindOfClass:[NSString class]] || [actual conformsToProtocol:@protocol(NSFastEnumeration)];

// ... to
BOOL actualIsCompatible = YES;

// Now if I run, the test passes as desired.
// I know this change was potentially unsafe if actual is non-nil and not an NSString
// or NSFastEnumeration, but I'm just hacking to make things work for my one test
// case first before finding a better solution ...

// OK, so now I copy EXPMatchers+contain.[h, m] verbatim and make my own version called
// EXPMatchers+containEventually.[h, m] (and I replace "contain" with "containEventually"
// everywhere in these two files.
// I drop these in my own source tree, not the Expecta tree, and include them in my test file.

// Now, you would think that
expect(person.name).will.containEventually(@"foo");

// ... would behave identically to my modified contain from the Expecta source because
// it's exactly the same code, except that "contain" has been replaced by "containEventually"
// ...

// ... but it doesn't.  Somehow the same exact (line-for-line) code that works when
// compiled inside the Expecta source behaves differently when included directly
// in my project ...

Any ideas?

What I need to test is the following:

  • That a value that is currently nil will eventually, when it gets set to non-nil, contain some value "foo"
  • When expect(value) is invoked, value is nil, but it will become non-nil later due to an async process

How can I test this?

Thanks!

NOTE: If I put an NSLog statement in the match invocation in the modified contain and containEventually .m files, I can see that match gets called repeatedly. The values passed are actual == nil many times. Eventually, the regular contain gets an actual != nil. The containEventually never does ... I don't understand why. Hope that helps.

NOTE 2: This doesn't happen with expect(person.name).will.equal(@"foo") (in that case the transition from nil to foo is handled as expected) - it only happens with contain, not equal. Does that help?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant