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

matcher to check if array contains an object matching a block #95

Open
ahti opened this issue Mar 31, 2014 · 6 comments
Open

matcher to check if array contains an object matching a block #95

ahti opened this issue Mar 31, 2014 · 6 comments

Comments

@ahti
Copy link

ahti commented Mar 31, 2014

I recently wrote some code like this:

expect([array[0] someProperty]).to.equal(@"a");
expect([array[0] otherProperty]).to.equal(@1);

expect([array[1] someProperty]).to.equal(@"b");
expect([array[1] otherProperty]).to.equal(@2);

Now, I really don't care for the order of the elements of array, but couldn't find a better expecta-ish way to confirm both objects are present in the array.

I think for things like this, it would be nice to have a matcher that would make the code above a bit like this:

expect(array).to.containElementPassing(^(id o){
    expect([o someProperty]).to.equal(@"a");
    expect([o otherProperty]).to.equal(@1);
});

expect(array).to.containElementPassing(^(id o){
    expect([o someProperty]).to.equal(@"b");
    expect([o otherProperty]).to.equal(@2);
});

I'm not sure it could be implemented like this, and would also be happy if the block just returns a BOOL and that is what is used.

If something like this does make it into Expecta, it would also be nice to have something like containOnlyElementsPassing(). (Basically rubys all? and any?)

@ollieatkinson
Copy link
Contributor

You can probably use #90 and the equal or contains matchers dependent on your requirements. Is this what you are looking for?

@ahti
Copy link
Author

ahti commented Mar 31, 2014

Not exactly. The problem with using #90 and equal or contains is that they still only allow assertions about the elements in the array. I need to check properties of the elements in the array.

I do however like the idea of using any matcher on the elements of an array, and #90 would be of help if there were a matcher that tests wether an object conforms to a block-test. (And if any-semantics would be implemented).

If this block-test only returns a BOOL this matcher should be easy to implement, and my example would become something like this:

expect(array).elements.any.passTest(^BOOL(id o){
    return [[o someProperty] isEqual:@"a"]
           && [[o otherProperty] isEqual:@1];
}

But it would (imho) be nicer if we could get something like this:

expect(array).elements.any.passTest(^(id o){
    expect([o someProperty]).to.equal(@"a");
    expect([o otherProperty]).to.equal(@1);
}

So the test-block itself doesn't return anything, but uses expect(...) itself.

Depending on the internal workings of Expecta (which I don't have the faintest idea about) the difficulty of implementing this might be somewhere between pretty easy and very hard.

@paulsamuels
Copy link
Contributor

For accessing properties you could easily just use KVC to get the properties

expect([array valueForKey:@"someProperty"]).elements.to.equal(@"a");
expect([array valueForKey:@"otherProperty"]).elements.to.equal(@1);

I think the second example would require a lot of additional complexity.


Shameless plug if you want to look at the inner workings and implement things yourself you could start by reading this for an introduction on how matchers work http://paul-samuels.com/blog/2014/03/16/how-does-it-work-expecta/

@ahti
Copy link
Author

ahti commented Apr 1, 2014

@paulsamuels that's almost what I need, but (aside from not looking that elegant, ymmv) has one flaw:

When I want to test wether the array contains two objects, each having specific properties, say object a with properties {x: 1, y:1} and object b with properties {x: 2, y: 2}, the valueForKey approach would also pass for an array like this: [{x: 1, y: 2}, {x: 2, y: 1}], so while it comes close, it does not do exactly what I want.

I'll take a look at your article and see what I can do :)

@paulsamuels
Copy link
Contributor

In that case the elements approach wouldn't work anyway as you have different expectations for each element in the array. Could you provide an example of how you would want that to work with multiple conditions

@ahti
Copy link
Author

ahti commented Apr 1, 2014

an example yould be this comment, assert that any of the elements in the array passes the matcher, then assert any element passes another matcher

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

No branches or pull requests

4 participants