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

Add collection filtering assertions analagous to filterIsInstance #546

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

jzbrooks
Copy link

This would be pretty handy when dealing with collections of sealed typed objects. I'd use it a lot!

- added `doesNotExist` assertions to `Path`.

### Added
- Added `doesNotExist` assertions to `Path`
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved this note into the added section for consistency

*/
inline fun <reified T> Assert<Iterable<*>>.containsInstanceOf(): Assert<List<T>> {
return transform("contains subtype of ${T::class}") { actual ->
actual.filterIsInstance<T>().also {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would use any here so that it returns true as soon as a single instance is found rather that needing to perform a full iteration and allocate a new list.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The sub-list allocation is necessary to provide a way to continue making assertions against the sublist. No?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yeah, I missed the new list was propagated as a return value. I'm a bit hesitant about the API shape using a verb "contains" while the return value is a full filtering.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, agreed. I noticed the having discussion after I pushed this. Would havingInstancesOf be better? Maybe the negation would be doesNotHaveInstancesOf?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I'm a bit torn on whether this makes sense as a dedicated operator since it combines a transform with an assertion in a way that I don't think has precedent from other operators. We'll see what the actual maintainers think, though.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd argue there's precedent with isNotNull. It's a transform and an assertion.

Copy link
Contributor

@JakeWharton JakeWharton Oct 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But it's atomic in nature. You cannot break it down into discrete steps.

Whereas this one is very clearly a filterIsInstance transformation and then an isNotEmpty assertion.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair. I'd find a shorthand for the transformation basically just as helpful.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A transformation without assertion might set a (good) precedent for other collection operators.
@evant, could you weigh in when you have some time?

* ```
*/
inline fun <reified T> Assert<Iterable<*>>.doesNotContainInstanceOf() = given { actual ->
if (actual.filterIsInstance<T>().isNotEmpty()) expected("to contain no instances of ${T::class} but was $actual")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, none here.

@jzbrooks jzbrooks changed the title Add collection filtering assertions analagous to instanceOf Add collection filtering assertions analagous to filterIsInstance Sep 30, 2024
@jzbrooks
Copy link
Author

#554 might be relevant

* ```
*/
inline fun <reified T> Assert<Iterable<*>>.containsInstanceOf(): Assert<List<T>> {
return transform("contains subtype of ${T::class}") { actual ->
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This message should probably just be contains instance of ${T::class} per Liskov.

@jzbrooks
Copy link
Author

Along the lines of the key argument in #557, is there a precedent for or idea of what the negation of having should be called? notHaving?

@jzbrooks
Copy link
Author

Alternatively <T> havingInstancesOf could make sense as just a transformation.

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

Successfully merging this pull request may close these issues.

2 participants