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

Simplify shouldMatchInOrder and shouldMatchEach #3911

Open
gianninia opened this issue Mar 7, 2024 · 0 comments
Open

Simplify shouldMatchInOrder and shouldMatchEach #3911

gianninia opened this issue Mar 7, 2024 · 0 comments
Labels
assertions 🔍 Related to the assertion mechanisms within the testing framework. enhancement ✨ Suggestions for adding new features or improving existing ones.

Comments

@gianninia
Copy link
Contributor

The extension functions shouldMatchInOrder and shouldMatchEach are great to assert collections. However, the signature could be a bit improved in my view. Intuitively, if I want to customize the assertion of the collection elements, I will want to pass the collections and some lambda that receives the actual and expected elements to be asserted.

I mean a signature like this:

fun <T> List<T>.shouldMatchInOrder(expected: List<T>, asserter: (T, T) -> Unit) {}
fun <T> List<T>.shouldMatchEach(expected: List<T>, asserter: (T, T) -> Unit) {}

This allows you to do something like this:

val expectedList = listOf(-1, -2, -3)
val actualList = listOf(1, 3, 4, 5)

actualList.shouldMatchEach(expectedList) { actual, expected ->
    actual shouldBe -expected
}

Instead of:

    actualList.shouldMatchEach(expectedList.map { actual ->
        { expected ->
            actual shouldBe -expected
        }
    })

I mean, looking at both variants when they are there does feel kind of obvious and not so different from each other. But if you have to write something like this for the first time, it does require some elaboration until you get the twist of it, as you don't see this immediately by just looking at the signature. I believe with my suggested signatures it's immediately clear what it's supposed to do.

In my project, I have added the following extension functions to solve this problem. Would you maybe consider adding this to the library?

fun <T> List<T>.shouldMatchInOrder(expected: List<T>, asserter: (T, T) -> Unit) {
    this.shouldMatchInOrder(expected.map { actualElement ->
        { expectedElement: T ->
            asserter(actualElement, expectedElement)
        }
    })
}

fun <T> List<T>.shouldMatchEach(expected: List<T>, asserter: (T, T) -> Unit) {
    this.shouldMatchEach(expected.map { actualElement ->
        { expectedElement: T ->
            asserter(actualElement, expectedElement)
        }
    })
}

I also have overloads for Sequences:

fun <T> Sequence<T>.shouldMatchInOrder(expected: Sequence<T>, asserter: (T, T) -> Unit) = toList().shouldMatchInOrder(expected.toList(), asserter)
fun <T> Sequence<T>.shouldMatchEach(expected: Sequence<T>, asserter: (T, T) -> Unit) = toList().shouldMatchEach(expected.toList(), asserter)

Is there any particular reason why in the library there are overloads for Iterable, Array and List but not for Sequence?

@LeoColman LeoColman added enhancement ✨ Suggestions for adding new features or improving existing ones. assertions 🔍 Related to the assertion mechanisms within the testing framework. labels Mar 7, 2024
gianninia added a commit to gianninia/kotest that referenced this issue Mar 11, 2024
* Added matchEach matcher that receives an expected list and an asserter to verify elements from both lists
* Added shouldMatchEach extensions for List, Iterable and Sequence
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. enhancement ✨ Suggestions for adding new features or improving existing ones.
Projects
None yet
Development

No branches or pull requests

2 participants