busterjs / referee-combinators

Combinators goes assertion
0 stars 1 forks source link

Ignored failures in combined asserts. #6

Open johlrogge opened 11 years ago

johlrogge commented 11 years ago

Consider this case:

var successfulFetch = composite.assert.anyOf(
   composite.assert.equals("loaded"),
   composite.assert.equals("cached"));

This means that at least one assertion in anyOf must pass, but not all. In the current implementation of combinators this kind of construction can't be created since if, in the example above, if actual is "cached" the first assertion for "loaded" will emit a failure event to referee.

We will need to come up with a better way for sub assertions in combined asserts. I think ultimately one combined assert should only emit one success or failure regardless of it's components.

This will require us to get at the structures passed to add in referee and do our own assertions. This will most probably also be necessary for proper context in messages such as {sub:{name: "expected equal to 'banana' but was 'apple'"}}

meisl commented 11 years ago

Indeed, I already came across this use case in our own tests. What I did was hacking together a temp custom assertion isFunctionOrObject (conventional way). Not a solution of course, just showing the need.

I think this one depends on https://github.com/busterjs/referee-combinators/issues/5 ("don't rely on AssertionError") to be solved, right?

Let's also not forget that OR/ANY is the dual of AND/ALL (~> https://github.com/busterjs/referee-combinators/issues/4).

johlrogge commented 11 years ago

OR/ANY AND/ALL: I Agree, synonyms is a good thing in DSLs. All for that.

You are right about this relying on #5. My lose thoughts on this is that assertions such as attr will not invoke subassertions via referee but directly. (That is why I think we need to get at the actual declaration in referee). I was reading up on parser combinators yesterday. In Scala the implementation returns Success, Failure or Error (pretty familiar for assertion frameworks). Failure and Error contain a message about what went wrong and each status return the actual for chaining [1]. (I would also like to see Pending [or perhaps Deferred can fill this need] as a possible outcome but that is a different discussion). I think it would be good if combinators would allow themselves to be invoked internally as something that returns one of the above mentioned statuses. Theroot assertion is responsible for emitting success or failure to referee with some decent message to go with that. When it comes to combined asserts it would be nice to be able to generate indented messages for easy reading.

[1] As something to debate, all parsers consume part of the incoming on success and return the remaining part. Other results return actual unchained I don't think this is relevant for assertion unless you are actually working with lists where the traversion of the list can be implemented as a combinator that lets subassertions validate or fail elements repeat(any('a', 'b', 'c')); // match any number of "a", "b", "c" in any order or repeat(sequence("a", "b", "c")); // match any number of "a", "b" or "c" sequences or repeat(exactly(2, sequence("a", "b", "c"))); // match exactly 2 "a", "b", "c" sequences etc