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 assertSameElements for collections #393

Closed
wants to merge 2 commits into from

Conversation

danicheg
Copy link
Contributor

Adding assertSameElements() for comparison elements of collections.
It also might be useful for comparison collections when == equality is not applicable (e.g. Array[A]).
For those collections possible to do plain assertion:

assert(Array() sameElements Array())

but this will lead to a poor error message.

clue: => Any = "collections elements are not the same"
)(implicit loc: Location, ev: B <:< A): Unit = {
StackTraces.dropInside {
if (!obtained.iterator.sameElements(expected.toIterator)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

.toIterator here just for back compat with Scala 2.11.

Copy link
Member

@olafurpg olafurpg left a comment

Choose a reason for hiding this comment

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

Thank you for this contribution! I am personally on the fence about this addition since it's possible to achieve similar functionality with

  • assertEquals(a.toSet b.toSet)
  • assertEquals(a.sorted, b.sorted)

The benefit of those assertions is that they make it clearer whether you're ignoring only the ordering differences, or duplicate elements as well.

However, I'm not opposed to merging this feature if more people think it would be useful. My biggest reservation is that we'll end up with too many assertions. I want to try to keep the number of assertions small.

)
}

test("An assertion fails on collections with different elements".fail) {
Copy link
Member

Choose a reason for hiding this comment

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

It would be good to refactor this test so that every individual assertion is a separate test

def checkFail(obtained, expected) = test(obtained.toString.fail) {
  assertSameElements(obtained, expected)
}

Currently, the test only asserts that at least a single statement in this body throws an exception.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point. Make me known if that PR will have a chance to get merged, then I'll fix that.

/**
* Asserts that two collections contain the same elements.
* It might be useful for comparison collections when `==` equality is not applicable.
* Note that assertion on unsorted collections will produce an unpredictable result.
Copy link
Member

Choose a reason for hiding this comment

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

Can you elaborate on "unpredictable result"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I mean that

val x = List("a" -> 1, "b" -> 2, "c" -> 3, "d" -> 3, "f" -> 4)
val y = Set("a" -> 1, "b" -> 2, "c" -> 3, "d" -> 3, "f" -> 4)
x sameElements y // false

and

val x = List("a" -> 1, "b" -> 2, "c" -> 3, "d" -> 3)
val y = Set("a" -> 1, "b" -> 2, "c" -> 3, "d" -> 3)
x sameElements y // true

a really unpredictable behaviour.

@danicheg
Copy link
Contributor Author

@olafurpg I came to this assertion after the migration of a bunch of libs working with a network where it's common to check some Array[Byte]s. As for me, it's good to have this assertion to not convert Array to Seq and don't use assert on equals check. But I agree that it makes sense to don't procreate too many assertions, as we know, it always ends up badly :)

@olafurpg
Copy link
Member

@danicheg Would it make sense to create a method assertArraySameElements instead? It sounds like this assertion is only relevant for arrays. MUnit already has custom assertions for Double/Float primitives.

@danicheg
Copy link
Contributor Author

@olafurpg as for me, it's more flexible to have that assertion for Iterables, than only for Arrays. Another take is checking elements of sequences (or even Iterables) different types (though I don't endorse it).

@danicheg
Copy link
Contributor Author

@olafurpg yeah, I think it's a great idea. If you agree, I'll do a PR today. And then no needing for the extra assertion, I guess.

@olafurpg
Copy link
Member

@danicheg Thank you for this contribution and bouncing back and forth on ideas. We just merged #395, which improves the error message when an assertion fails on comparison of two arrays with equal values but different references. In the spirit of keeping the number of assertions small, we're not gonna add assertSameElements. Instead, I encourage you to write such an assertion in your own projects or alternatively override def assertEquals to automatically convert array arguments into normal collections.

@olafurpg olafurpg closed this Jul 26, 2021
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