← Back to team overview

testtools-dev team mailing list archive

Re: [Merge] lp:~jml/testtools/dict-matcher into lp:testtools

 

On 7 August 2012 20:48, Robert Collins <robertc@xxxxxxxxxxxxxxxxx> wrote:
> + " 'baz': 'qux' matches Equals('qux'),\n"
> 487
>
> So this shows equal keyvalues? Would it be nicer to elide them entirely?
>

That's the expected error message for a mismatch of
Not(Equals('qux')).  I agree that it's confusing, but that's a problem
with Not().

It already elides matching key values.

>
> The SuperDict / SubDict thing weirds me out.
>
> IIUC:
> self.assertThat({'a': 'b'}, SubDict({'a': 'b'}))
>
> will pass, as written.
>

That won't pass. That will raise an error.

This will pass:
  self.assertThat({'a': 'b'}, SubDict({'a': Equals('b')})

Looking at that spelling, I agree it's hard to understand. They could
definitely use better names.

I wanted to have something like Dict, but that didn't exist on strict
key equality.

> But
>
> self.assertThat({'a': 'b'}, Contains({}))
>
> is an existing matcher that is easier to read and seems to do the same job.
>

It doesn't do the same job. It fails on two counts::
  - Contains just does an 'x in y' check. '{} in {'a': 'b'}' raises an error.
  - SubDict has matchers for values. This is important and useful. One
could say, e.g.,
      self.assertThat(employee_dict, SubDict({'email':
Contains('canonical.com'), 'title': Not(Contains('engineer'))})

i.e. it enables
http://bazaar.launchpad.net/~jml/treeshape/matchers/view/head:/treeshape/_matchers.py#L65

> I guess I'd like SubDict and SuperDict to be more clear about whether their constructor is the thing that should be a superdict or a subdict, and I'd love it if the simpler Contains were the goto thing here.

I think the way to achieve the first bit is to name them better.  A
more natural English reading for assertThat(foo, SubDict(bar)) would
help a lot.  Perhaps ContainsDict?

> ContainsAll also looks redundantish here.
>

That's closer to redundant, as it's basically a subset matcher.

Even so, assertThat({1: 'cat', 2: 'dog', 3: 'bear'}, ContainsAll({1:
'foo', 2: 'bar'})) passes. That is, it just matches keys. The mismatch
just tells you the key you are missing, rather than the key and value.

Contrariwise, SubDict requires the values of the specified keys to
match the specified matchers. If a needed key is not found, the error
includes both the key and the value that it needs.

> tl;dr - I think we need to do some orthogonalising and deduplicating.

I think a large source of the general redundancy is that Python has
quite a few data structures, and there are actually many different
things that one is interested per data structure (dict: keys, values;
lists: subset, subsequence, subset but caring about duplicates, maybe
more).

Another source is that you are supposed to write, say::
  self.assertThat(observed, Contains(expected))

And although if you needed to check for a super-set rather than subset
you could _technically_ write::
  self.assertThat(expected, Contains(observed))

You will often get confusing errors. In particular, 'actual' and
'reference' will be lies.

I've got no idea how I'd orthogonalize this patch without doing a deep
dive on the existing matchers. I do think that deep dive has to happen
soon, though I'm loath to block my patch on it. It's already quite
deep down the yak stack.

jml

-- 
https://code.launchpad.net/~jml/testtools/dict-matcher/+merge/118567
Your team testtools developers is subscribed to branch lp:testtools.


References