Skip to content

Add CollectionSubject.offset() #41

@rickeylev

Description

@rickeylev

A case that came out of testifying the cc rules that Pedro ran into was needing to verify the last element of a collection. The position mattered because it was checking the linker args, which is important in C++.

He was also checking the collection contains some other values, so the resulting code to do that and check the last element was cumbersome. Something like:

libs = <construct libs>

expect.that_collection(libs).contains_at_least(...)
expect.where(...).that_str(libs[-1]).equals(...)

This would be slightly more ergonomic by having a contains_at method, which checks both the value and offset:

libs = expect.that_collect(<construct libs>)
libs.contains_at_least(...)
libs.offset(-1).equals(...)

This allows an error message like:

expected: foo
got: bar
where
  offset=-1
  within list:
    0: a
    1: bar

(A nicer message like "got wrong value at offset -1" would require some changes to how context is recorded and displayed, which would be nice, but out of scope for this FR)

The name can be bikeshed a bit:

  • index(): not an option; lists already have an index function which return the position of
    the argument, so using that name with a different behavior would be confusing
  • element_at(): slightly more fluenty, but much longer than offset
  • offset(): short, and relatively clear
  • get(): analogous to Java lists and maps. But could be confused with maps, and not really
    a common term for getting an element from a list.

There were a couple other ideas to solve this problem; I'll note them for completeness:

  • contains_at() method: it doesn't compose as well; checking that the string matched
    e.g. "foo_*.o" would be a bit more cumbersome. I'll note that having offset() makes
    implementing a convenience contains_at() very simple.
  • A way to include the position when checking, similar to how DictSubject.contains_exactly()
    includes checking the keys. Maybe a CollectionSubject.items() method, or an include_offset
    arg for contains_at_least(), or an foo.enumerated() method? And then you assert on the 2-tuples of (position, value).

Another idea was a specialized contains_at() method, but this doesn't compose as well. In Pedro's case, he was using equals, but it's easy to imagine needing to match a pattern like "foo_*.o" or some such.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions