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

Equality testing for iterables broken #1727

Closed
U1F984 opened this issue Sep 24, 2020 · 6 comments · Fixed by #1751
Closed

Equality testing for iterables broken #1727

U1F984 opened this issue Sep 24, 2020 · 6 comments · Fixed by #1751
Labels
assertions 🔍 Related to the assertion mechanisms within the testing framework. bug 🐛 Issues that report a problem or error in the code.

Comments

@U1F984
Copy link
Contributor

U1F984 commented Sep 24, 2020

Which version of Kotest are you using
4.2.5

Due to the recent changes from 6bbbfec equality testing for iterables is broken:

listOf("hello") shouldNotBe emptyList<String>() // java.lang.AssertionError: [] should not equal ["hello"]

this is caused by a missing check in IterableEq#checkIterableEquality that the given iterables are the same size. Also, the implementation is not fast because it will create a list in the background (which is then prompty discarded).

A (untested) alternative implementation could look something like this:

    private fun checkIterableEquality(actual: Iterable<*>, expected: Iterable<*>): Throwable? {
        var index = 0
        val actualIterator = actual.iterator()
        val expectedIterator = expected.iterator()
        while (actualIterator.hasNext() && expectedIterator.hasNext()) {
            val t = eq(actualIterator.next(), expectedIterator.next())
            if (t != null) return failure(
                Expected(expected.show()),
                Actual(actual.show()),
                "Elements differ at index $index: "
            )
            index++
        }
        if(actualIterator.hasNext()) {
            return failure(
                Expected(expected.show()),
                Actual(actual.show()),
                "Expected fewer elements"
            )
        }
        if(expectedIterator.hasNext()) {
            return failure(
                Expected(expected.show()),
                Actual(actual.show()),
                "Expected more elements"
            )
        }
        return null
    }
@LeoColman LeoColman added assertions 🔍 Related to the assertion mechanisms within the testing framework. bug 🐛 Issues that report a problem or error in the code. labels Sep 24, 2020
@daviddenton
Copy link

daviddenton commented Sep 27, 2020

Possibly related, but equality of Jackson JsonNode objects are also broken. A JsonNode itself is iterable of its own child nodes, but in the case of something like a TextNode there are no children. So a text value of "value1" should NOT be equal to "value2", but kotest reports it is because it just compares the children.

By the same token any object which is iterable but has state other than its contents will also be inaccurately reported as always equal.

@sksamuel
Copy link
Member

sksamuel commented Oct 4, 2020

Thanks for the bug reports guys. So I believe @Quicksteve your issue is already fixed in master, if you look at the latest implementation, it does basically what you pasted. I'll add another set of test cases for shouldNotBe just to be sure.

@daviddenton that is an excellent observation and something that happened with Path already. I think the safest course of action is to have an accepted list of iterable types that use the IterableEq typeclass - so list, set, etc. And if it's not in that list, then it uses the DefaultEq implementation.

@sksamuel
Copy link
Member

sksamuel commented Oct 4, 2020

Fixed in master, will relaese 4.2.6 with these changes.

sksamuel added a commit that referenced this issue Oct 5, 2020
@sksamuel
Copy link
Member

sksamuel commented Oct 5, 2020

4.2.6 is released.

@TheSench
Copy link

Still seeing JsonNode comparisons not properly detect different values in TextNodes in 5.3.1.

@TheSench
Copy link

TheSench commented Jul 28, 2022

Here's a simple test that reproduces this for me:

@Test
fun `it should return detect differences in values`() {
  val map1 = mapOf("test" to 1)
  val map2 = mapOf("test" to 2)
  val mapper = ObjectMapper()
  val jsonNode1 = mapper.valueToTree<JsonNode>(map1)
  val jsonNode2 = mapper.valueToTree<JsonNode>(map2)

  // Passes
  jsonNode1 shouldBe jsonNode2
  // Fails with:
  // expected:<"{"test":2}"> but was:<"{"test":1}">
  jsonNode1.toString() shouldBe jsonNode2.toString()
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
assertions 🔍 Related to the assertion mechanisms within the testing framework. bug 🐛 Issues that report a problem or error in the code.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants