From d502987386491d916c694b593746b7ebab69fea4 Mon Sep 17 00:00:00 2001 From: Alphonse Bendt Date: Mon, 6 Mar 2023 22:59:33 +0100 Subject: [PATCH 1/9] improve IterableTest coverage this adds a couple of tests to IterableTest to improve test coverage for functions in Iterable --- .../kotlin/arrow/core/IterableTest.kt | 836 ++++++++++-------- 1 file changed, 461 insertions(+), 375 deletions(-) diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt index 83e1c161984..fafbc073f44 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt @@ -2,9 +2,11 @@ package arrow.core import arrow.core.test.either import arrow.core.test.functionAToB +import arrow.core.test.ior import arrow.core.test.option import arrow.typeclasses.Semigroup import io.kotest.core.spec.style.StringSpec +import io.kotest.matchers.collections.shouldBeEmpty import io.kotest.matchers.collections.shouldContainExactly import io.kotest.matchers.nulls.shouldBeNull import io.kotest.matchers.nulls.shouldNotBeNull @@ -14,6 +16,7 @@ import io.kotest.property.arbitrary.boolean import io.kotest.property.arbitrary.int import io.kotest.property.arbitrary.list import io.kotest.property.arbitrary.orNull +import io.kotest.property.arbitrary.pair import io.kotest.property.arbitrary.string import io.kotest.property.checkAll import kotlin.math.max @@ -71,483 +74,566 @@ class IterableTest : StringSpec({ } shouldBe Either.Left("failfailfail") } - "traverse Either stack-safe" { - // also verifies result order and execution order (l to r) + "traverse Either stack-safe" { + // also verifies result order and execution order (l to r) + val acc = mutableListOf() + val res = (0..20_000).traverse { a -> + acc.add(a) + Either.Right(a) + } + res shouldBe Either.Right(acc) + res shouldBe Either.Right((0..20_000).toList()) + } + + "traverse Either short-circuit" { + checkAll(Arb.list(Arb.int())) { ints -> val acc = mutableListOf() - val res = (0..20_000).traverse { a -> - acc.add(a) - Either.Right(a) + val evens = ints.traverse { + if (it % 2 == 0) { + acc.add(it) + Either.Right(it) + } else Either.Left(it) } - res shouldBe Either.Right(acc) - res shouldBe Either.Right((0..20_000).toList()) - } - - "traverse Either short-circuit" { - checkAll(Arb.list(Arb.int())) { ints -> - val acc = mutableListOf() - val evens = ints.traverse { - if (it % 2 == 0) { - acc.add(it) - Either.Right(it) - } else Either.Left(it) - } - acc shouldBe ints.takeWhile { it % 2 == 0 } - when (evens) { - is Either.Right -> evens.value shouldBe ints - is Either.Left -> evens.value shouldBe ints.first { it % 2 != 0 } - } + acc shouldBe ints.takeWhile { it % 2 == 0 } + when (evens) { + is Either.Right -> evens.value shouldBe ints + is Either.Left -> evens.value shouldBe ints.first { it % 2 != 0 } } } + } - "sequenceEither should be consistent with traverse Either" { - checkAll(Arb.list(Arb.int())) { ints -> - ints.map { it.right() }.sequence() shouldBe ints.traverse { it.right() } - } + "sequenceEither should be consistent with traverse Either" { + checkAll(Arb.list(Arb.int())) { ints -> + ints.map { it.right() }.sequence() shouldBe ints.traverse { it.right() } } + } + + "traverse Result stack-safe" { + // also verifies result order and execution order (l to r) + val acc = mutableListOf() + val res = (0..20_000).traverse { a -> + acc.add(a) + Result.success(a) + } + res shouldBe Result.success(acc) + res shouldBe Result.success((0..20_000).toList()) + } - "traverse Result stack-safe" { - // also verifies result order and execution order (l to r) + "traverse Result short-circuit" { + checkAll(Arb.list(Arb.int())) { ints -> val acc = mutableListOf() - val res = (0..20_000).traverse { a -> - acc.add(a) - Result.success(a) - } - res shouldBe Result.success(acc) - res shouldBe Result.success((0..20_000).toList()) - } - - "traverse Result short-circuit" { - checkAll(Arb.list(Arb.int())) { ints -> - val acc = mutableListOf() - val evens = ints.traverse { - if (it % 2 == 0) { - acc.add(it) - Result.success(it) - } else Result.failure(RuntimeException()) - } - acc shouldBe ints.takeWhile { it % 2 == 0 } - evens.fold( - { it shouldBe ints }, - { } - ) - } + val evens = ints.traverse { + if (it % 2 == 0) { + acc.add(it) + Result.success(it) + } else Result.failure(RuntimeException()) + } + acc shouldBe ints.takeWhile { it % 2 == 0 } + evens.fold( + { it shouldBe ints }, + { } + ) } + } - "sequence Result should be consistent with traverse Result" { - checkAll(Arb.list(Arb.int())) { ints -> - ints.map { Result.success(it) }.sequence() shouldBe ints.traverse { Result.success(it) } - } + "sequence Result should be consistent with traverse Result" { + checkAll(Arb.list(Arb.int())) { ints -> + ints.map { Result.success(it) }.sequence() shouldBe ints.traverse { Result.success(it) } } + } - "traverse Option is stack-safe" { - // also verifies result order and execution order (l to r) + "traverse Option is stack-safe" { + // also verifies result order and execution order (l to r) + val acc = mutableListOf() + val res = (0..20_000).traverse { a: Int -> + acc.add(a) + Some(a) + } + res shouldBe Some(acc) + res shouldBe Some((0..20_000).toList()) + } + + "traverse Option short-circuits" { + checkAll(Arb.list(Arb.int())) { ints -> val acc = mutableListOf() - val res = (0..20_000).traverse { a: Int -> - acc.add(a) - Some(a) - } - res shouldBe Some(acc) - res shouldBe Some((0..20_000).toList()) - } - - "traverse Option short-circuits" { - checkAll(Arb.list(Arb.int())) { ints -> - val acc = mutableListOf() - val evens = ints.traverse { - (it % 2 == 0).maybe { - acc.add(it) - it - } + val evens = ints.traverse { + (it % 2 == 0).maybe { + acc.add(it) + it } - acc shouldBe ints.takeWhile { it % 2 == 0 } - evens.fold({ Unit }) { it shouldBe ints } } + acc shouldBe ints.takeWhile { it % 2 == 0 } + evens.fold({ Unit }) { it shouldBe ints } } + } - "sequence Option yields some when all entries in the list are some" { - checkAll(Arb.list(Arb.int())) { ints -> - val evens = ints.map { (it % 2 == 0).maybe { it } }.sequence() - evens.fold({ Unit }) { it shouldBe ints } - } + "sequence Option yields some when all entries in the list are some" { + checkAll(Arb.list(Arb.int())) { ints -> + val evens = ints.map { (it % 2 == 0).maybe { it } }.sequence() + evens.fold({ Unit }) { it shouldBe ints } } + } - "sequence Option should be consistent with traverse Option" { - checkAll(Arb.list(Arb.int())) { ints -> - ints.map { Some(it) }.sequence() shouldBe ints.traverse { Some(it) } - } + "sequence Option should be consistent with traverse Option" { + checkAll(Arb.list(Arb.int())) { ints -> + ints.map { Some(it) }.sequence() shouldBe ints.traverse { Some(it) } } + } - "traverse Nullable is stack-safe" { - // also verifies result order and execution order (l to r) - val acc = mutableListOf() - val res = (0..20_000).traverse { a: Int -> - acc.add(a) - a - } - res.shouldNotBeNull() shouldBe acc - res.shouldNotBeNull() shouldBe (0..20_000).toList() - } - - "traverse Nullable short-circuits" { - checkAll(Arb.list(Arb.int())) { ints -> - val acc = mutableListOf() - val evens = ints.traverse { - if (it % 2 == 0) { - acc.add(it) - it - } else { - null - } - } - - val expected = ints.takeWhile { it % 2 == 0 } - acc shouldBe expected + "traverse Nullable is stack-safe" { + // also verifies result order and execution order (l to r) + val acc = mutableListOf() + val res = (0..20_000).traverse { a: Int -> + acc.add(a) + a + } + res.shouldNotBeNull() shouldBe acc + res.shouldNotBeNull() shouldBe (0..20_000).toList() + } - if (ints.any { it % 2 != 0 }) { - evens.shouldBeNull() + "traverse Nullable short-circuits" { + checkAll(Arb.list(Arb.int())) { ints -> + val acc = mutableListOf() + val evens = ints.traverse { + if (it % 2 == 0) { + acc.add(it) + it } else { - evens.shouldNotBeNull() shouldContainExactly expected + null } } - } - "sequence Nullable yields some when all entries in the list are not null" { - checkAll(Arb.list(Arb.int())) { ints -> - val evens = ints.map { if (it % 2 == 0) it else null }.sequence() + val expected = ints.takeWhile { it % 2 == 0 } + acc shouldBe expected - if (ints.any { it % 2 != 0 }) { - evens.shouldBeNull() - } else { - evens.shouldNotBeNull() shouldContainExactly ints.takeWhile { it % 2 == 0 } - } + if (ints.any { it % 2 != 0 }) { + evens.shouldBeNull() + } else { + evens.shouldNotBeNull() shouldContainExactly expected } } + } + + "sequence Nullable yields some when all entries in the list are not null" { + checkAll(Arb.list(Arb.int())) { ints -> + val evens = ints.map { if (it % 2 == 0) it else null }.sequence() - "sequence Nullable should be consistent with travers Nullable" { - checkAll(Arb.list(Arb.int())) { ints -> - ints.map { it as Int? }.sequence() shouldBe ints.traverse { it as Int? } + if (ints.any { it % 2 != 0 }) { + evens.shouldBeNull() + } else { + evens.shouldNotBeNull() shouldContainExactly ints.takeWhile { it % 2 == 0 } } } + } - "traverse Validated stack-safe" { - // also verifies result order and execution order (l to r) - val acc = mutableListOf() - val res = (0..20_000).traverse(Semigroup.string()) { - acc.add(it) - Validated.Valid(it) - } - res shouldBe Validated.Valid(acc) - res shouldBe Validated.Valid((0..20_000).toList()) + "sequence Nullable should be consistent with travers Nullable" { + checkAll(Arb.list(Arb.int())) { ints -> + ints.map { it as Int? }.sequence() shouldBe ints.traverse { it as Int? } + } + } + + "traverse Validated stack-safe" { + // also verifies result order and execution order (l to r) + val acc = mutableListOf() + val res = (0..20_000).traverse(Semigroup.string()) { + acc.add(it) + Validated.Valid(it) } + res shouldBe Validated.Valid(acc) + res shouldBe Validated.Valid((0..20_000).toList()) + } - "traverse Validated acumulates" { - checkAll(Arb.list(Arb.int())) { ints -> - val res: ValidatedNel> = - ints.map { i -> if (i % 2 == 0) Valid(i) else Invalid(nonEmptyListOf(i)) } - .sequence() + "traverse Validated acumulates" { + checkAll(Arb.list(Arb.int())) { ints -> + val res: ValidatedNel> = + ints.map { i -> if (i % 2 == 0) Valid(i) else Invalid(nonEmptyListOf(i)) } + .sequence() - val expected: ValidatedNel> = ints.filterNot { it % 2 == 0 } - .toNonEmptyListOrNull()?.invalid() ?: Valid(ints.filter { it % 2 == 0 }) + val expected: ValidatedNel> = ints.filterNot { it % 2 == 0 } + .toNonEmptyListOrNull()?.invalid() ?: Valid(ints.filter { it % 2 == 0 }) - res shouldBe expected - } + res shouldBe expected } + } - "sequence Validated should be consistent with traverse Validated" { - checkAll(Arb.list(Arb.int())) { ints -> - ints.map { it.valid() }.sequence(Semigroup.string()) shouldBe - ints.traverse(Semigroup.string()) { it.valid() } - } + "sequence Validated should be consistent with traverse Validated" { + checkAll(Arb.list(Arb.int())) { ints -> + ints.map { it.valid() }.sequence(Semigroup.string()) shouldBe + ints.traverse(Semigroup.string()) { it.valid() } } + } - "sequence Either traverse Nullable interoperate - and proof map + sequence equality with traverse" { - checkAll( - Arb.list(Arb.int()), - Arb.functionAToB?>(Arb.either(Arb.string(), Arb.int()).orNull()) - ) { ints, f -> + "sequence Either traverse Nullable interoperate - and proof map + sequence equality with traverse" { + checkAll( + Arb.list(Arb.int()), + Arb.functionAToB?>(Arb.either(Arb.string(), Arb.int()).orNull()) + ) { ints, f -> - val res: Either>? = - ints.traverse(f)?.sequence() + val res: Either>? = + ints.traverse(f)?.sequence() - val expected: Either>? = - ints.map(f).sequence()?.sequence() + val expected: Either>? = + ints.map(f).sequence()?.sequence() - res shouldBe expected - } + res shouldBe expected } + } - "zip3" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b, c -> - val result = a.zip(b, c, ::Triple) - val expected = a.zip(b, ::Pair).zip(c) { (a, b), c -> Triple(a, b, c) } - result shouldBe expected - } + "zip3" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b, c -> + val result = a.zip(b, c, ::Triple) + val expected = a.zip(b, ::Pair).zip(c) { (a, b), c -> Triple(a, b, c) } + result shouldBe expected } + } - "zip4" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int()), Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b, c, d -> - val result = a.zip(b, c, d, ::Tuple4) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + "zip4" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int()), Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b, c, d -> + val result = a.zip(b, c, d, ::Tuple4) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - result shouldBe expected - } + result shouldBe expected + } + } + + "zip5" { + checkAll( + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()) + ) { a, b, c, d, e -> + val result = a.zip(b, c, d, e, ::Tuple5) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } + + result shouldBe expected } + } - "zip5" { - checkAll( - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()) - ) { a, b, c, d, e -> - val result = a.zip(b, c, d, e, ::Tuple5) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } - - result shouldBe expected - } + "zip6" { + checkAll( + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()) + ) { a, b, c, d, e, f -> + val result = a.zip(b, c, d, e, f, ::Tuple6) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } + .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } + + result shouldBe expected } + } - "zip6" { - checkAll( - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()) - ) { a, b, c, d, e, f -> - val result = a.zip(b, c, d, e, f, ::Tuple6) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } - .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } - - result shouldBe expected - } + "zip7" { + checkAll( + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()) + ) { a, b, c, d, e, f, g -> + val result = a.zip(b, c, d, e, f, g, ::Tuple7) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } + .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } + .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } + + result shouldBe expected } + } - "zip7" { - checkAll( - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()) - ) { a, b, c, d, e, f, g -> - val result = a.zip(b, c, d, e, f, g, ::Tuple7) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } - .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } - .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } - - result shouldBe expected - } + "zip8" { + checkAll( + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()) + ) { a, b, c, d, e, f, g, h -> + val result = a.zip(b, c, d, e, f, g, h, ::Tuple8) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } + .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } + .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } + .zip(h) { (a, b, c, d, e, f, g), h -> Tuple8(a, b, c, d, e, f, g, h) } + + result shouldBe expected } + } - "zip8" { - checkAll( - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()) - ) { a, b, c, d, e, f, g, h -> - val result = a.zip(b, c, d, e, f, g, h, ::Tuple8) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } - .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } - .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } - .zip(h) { (a, b, c, d, e, f, g), h -> Tuple8(a, b, c, d, e, f, g, h) } - - result shouldBe expected - } + "zip9" { + checkAll( + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()) + ) { a, b, c, d, e, f, g, h, i -> + val result = a.zip(b, c, d, e, f, g, h, i, ::Tuple9) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } + .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } + .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } + .zip(h) { (a, b, c, d, e, f, g), h -> Tuple8(a, b, c, d, e, f, g, h) } + .zip(i) { (a, b, c, d, e, f, g, h), i -> Tuple9(a, b, c, d, e, f, g, h, i) } + + result shouldBe expected } + } - "zip9" { - checkAll( - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()) - ) { a, b, c, d, e, f, g, h, i -> - val result = a.zip(b, c, d, e, f, g, h, i, ::Tuple9) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } - .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } - .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } - .zip(h) { (a, b, c, d, e, f, g), h -> Tuple8(a, b, c, d, e, f, g, h) } - .zip(i) { (a, b, c, d, e, f, g, h), i -> Tuple9(a, b, c, d, e, f, g, h, i) } - - result shouldBe expected - } + "zip10" { + checkAll( + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()) + ) { a, b, c, d, e, f, g, h, i, j -> + val result = a.zip(b, c, d, e, f, g, h, i, j, ::Tuple10) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } + .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } + .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } + .zip(h) { (a, b, c, d, e, f, g), h -> Tuple8(a, b, c, d, e, f, g, h) } + .zip(i) { (a, b, c, d, e, f, g, h), i -> Tuple9(a, b, c, d, e, f, g, h, i) } + .zip(j) { (a, b, c, d, e, f, g, h, i), j -> Tuple10(a, b, c, d, e, f, g, h, i, j) } + + result shouldBe expected } + } - "zip10" { - checkAll( - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()) - ) { a, b, c, d, e, f, g, h, i, j -> - val result = a.zip(b, c, d, e, f, g, h, i, j, ::Tuple10) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } - .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } - .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } - .zip(h) { (a, b, c, d, e, f, g), h -> Tuple8(a, b, c, d, e, f, g, h) } - .zip(i) { (a, b, c, d, e, f, g, h), i -> Tuple9(a, b, c, d, e, f, g, h, i) } - .zip(j) { (a, b, c, d, e, f, g, h, i), j -> Tuple10(a, b, c, d, e, f, g, h, i, j) } - - result shouldBe expected - } + "can align lists with different lengths" { + checkAll(Arb.list(Arb.boolean()), Arb.list(Arb.boolean())) { a, b -> + a.align(b).size shouldBe max(a.size, b.size) } - "can align lists with different lengths" { - checkAll(Arb.list(Arb.boolean()), Arb.list(Arb.boolean())) { a, b -> - a.align(b).size shouldBe max(a.size, b.size) + checkAll(Arb.list(Arb.boolean()), Arb.list(Arb.boolean())) { a, b -> + a.align(b).take(min(a.size, b.size)).forEach { + it.isBoth shouldBe true } + } - checkAll(Arb.list(Arb.boolean()), Arb.list(Arb.boolean())) { a, b -> - a.align(b).take(min(a.size, b.size)).forEach { - it.isBoth shouldBe true + checkAll(Arb.list(Arb.boolean()), Arb.list(Arb.boolean())) { a, b -> + a.align(b).drop(min(a.size, b.size)).forEach { + if (a.size < b.size) { + it.isRight shouldBe true + } else { + it.isLeft shouldBe true } } + } + } - checkAll(Arb.list(Arb.boolean()), Arb.list(Arb.boolean())) { a, b -> - a.align(b).drop(min(a.size, b.size)).forEach { - if (a.size < b.size) { - it.isRight shouldBe true - } else { - it.isLeft shouldBe true - } - } - } + "leftPadZip (with map)" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> + val left = a.map { it } + List(max(0, b.count() - a.count())) { null } + val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + + val result = a.leftPadZip(b) { a, b -> a to b } + + result shouldBe left.zip(right) { l, r -> l to r }.filter { it.second != null } } + } - "leftPadZip (with map)" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> - val left = a.map { it } + List(max(0, b.count() - a.count())) { null } - val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + "leftPadZip (without map)" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> + val left = a.map { it } + List(max(0, b.count() - a.count())) { null } + val right = b.map { it } + List(max(0, a.count() - b.count())) { null } - val result = a.leftPadZip(b) { a, b -> a to b } + val result = a.leftPadZip(b) - result shouldBe left.zip(right) { l, r -> l to r }.filter { it.second != null } - } + result shouldBe left.zip(right) { l, r -> l to r }.filter { it.second != null } } + } - "leftPadZip (without map)" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> - val left = a.map { it } + List(max(0, b.count() - a.count())) { null } - val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + "rightPadZip (without map)" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> + val left = a.map { it } + List(max(0, b.count() - a.count())) { null } + val right = b.map { it } + List(max(0, a.count() - b.count())) { null } - val result = a.leftPadZip(b) + val result = a.rightPadZip(b) - result shouldBe left.zip(right) { l, r -> l to r }.filter { it.second != null } - } + result shouldBe left.zip(right) { l, r -> l to r }.filter { it.first != null } + result.map { it.first } shouldBe a } + } - "rightPadZip (without map)" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> - val left = a.map { it } + List(max(0, b.count() - a.count())) { null } - val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + "rightPadZip (with map)" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> + val left = a.map { it } + List(max(0, b.count() - a.count())) { null } + val right = b.map { it } + List(max(0, a.count() - b.count())) { null } - val result = a.rightPadZip(b) + val result = a.rightPadZip(b) { a, b -> a to b } - result shouldBe left.zip(right) { l, r -> l to r }.filter { it.first != null } - result.map { it.first } shouldBe a - } + result shouldBe left.zip(right) { l, r -> l to r }.filter { it.first != null } + result.map { it.first } shouldBe a } + } - "rightPadZip (with map)" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> - val left = a.map { it } + List(max(0, b.count() - a.count())) { null } - val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + "padZip" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> + val left = a.map { it } + List(max(0, b.count() - a.count())) { null } + val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + a.padZip(b) { l, r -> Ior.fromNullables(l, r) } shouldBe left.zip(right) { l, r -> Ior.fromNullables(l, r) } + } + } - val result = a.rightPadZip(b) { a, b -> a to b } + "padZipWithNull" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> + val left = a.map { it } + List(max(0, b.count() - a.count())) { null } + val right = b.map { it } + List(max(0, a.count() - b.count())) { null } - result shouldBe left.zip(right) { l, r -> l to r }.filter { it.first != null } - result.map { it.first } shouldBe a - } + a.padZip(b) shouldBe left.zip(right) { l, r -> l to r } } + } - "padZip" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> - val left = a.map { it } + List(max(0, b.count() - a.count())) { null } - val right = b.map { it } + List(max(0, a.count() - b.count())) { null } - a.padZip(b) { l, r -> Ior.fromNullables(l, r) } shouldBe left.zip(right) { l, r -> Ior.fromNullables(l, r) } - } + "filterOption" { + checkAll(Arb.list(Arb.option(Arb.int()))) { listOfOption -> + listOfOption.filterOption() shouldBe listOfOption.mapNotNull { it.orNull() } } + } - "padZipWithNull" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> - val left = a.map { it } + List(max(0, b.count() - a.count())) { null } - val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + "flattenOption" { + checkAll(Arb.list(Arb.option(Arb.int()))) { listOfOption -> + listOfOption.flattenOption() shouldBe listOfOption.mapNotNull { it.orNull() } + } + } - a.padZip(b) shouldBe left.zip(right) { l, r -> l to r } + "separateEither" { + checkAll(Arb.list(Arb.int())) { ints -> + val list = ints.map { + if (it % 2 == 0) it.left() + else it.right() } + list.separateEither() shouldBe ints.partition { it % 2 == 0 } } + } - "filterOption" { - checkAll(Arb.list(Arb.option(Arb.int()))) { listOfOption -> - listOfOption.filterOption() shouldBe listOfOption.mapNotNull { it.orNull() } + "separateValidated" { + checkAll(Arb.list(Arb.int())) { ints -> + val list = ints.map { + if (it % 2 == 0) it.invalid() + else it.valid() } + list.separateValidated() shouldBe ints.partition { it % 2 == 0 } } + } - "flattenOption" { - checkAll(Arb.list(Arb.option(Arb.int()))) { listOfOption -> - listOfOption.flattenOption() shouldBe listOfOption.mapNotNull { it.orNull() } - } + "unzip is the inverse of zip" { + checkAll(Arb.list(Arb.int())) { xs -> + + val zipped = xs.zip(xs) + val ls = zipped.unzip() + val rs = xs to xs + + ls shouldBe rs + } + } + + "unzip(fn)" { + checkAll(Arb.list(Arb.pair(Arb.int(), Arb.string()))) { xs -> + xs.unzip { it } shouldBe xs.unzip() + } + } + + "zip is the inverse of unzip" { + checkAll(Arb.list(Arb.pair(Arb.int(), Arb.string()))) { xs -> + val (l, r) = xs.unzip() + + l.zip(r) shouldBe xs + } + } + + "unalign is the inverse of align" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.string())) { a, b -> + a.align(b).unalign() shouldBe (a to b) + } + } + + "align is the inverse of unalign" { + checkAll(Arb.list(Arb.ior(Arb.int(0 .. 1), Arb.string(1)), 0 .. 10)) { xs -> + val (a, b) = xs.unalign() + a.align(b) shouldBe xs + } + } + + "unalign(fn)" { + checkAll(Arb.list(Arb.ior(Arb.int(), Arb.string()))) { xs -> + xs.unalign { it } shouldBe xs.unalign() } + } + + "salign" { + checkAll(Arb.list(Arb.int())) { xs -> + xs.salign(Semigroup.int(), xs) shouldBe xs.map { it + it } + } + } - "separateEither" { - checkAll(Arb.list(Arb.int())) { ints -> - val list = ints.map { - if (it % 2 == 0) it.left() - else it.right() + "reduceOrNull is compatible with reduce from stdlib" { + checkAll(Arb.list(Arb.string())) { xs -> + + val rs = xs.reduceOrNull({ it }) { a, b -> + a + b + } + + if (xs.isEmpty()) { + rs.shouldBeNull() + } else { + rs shouldBe xs.reduce { + a,b -> a +b } - list.separateEither() shouldBe ints.partition { it % 2 == 0 } } } + } + + "reduceRightNull is compatible with reduce from stdlib" { + checkAll(Arb.list(Arb.string())) { xs -> - "separateValidated" { - checkAll(Arb.list(Arb.int())) { ints -> - val list = ints.map { - if (it % 2 == 0) it.invalid() - else it.valid() + val rs = xs.reduceRightNull({ it }) { a, b -> + a + b + } + + if (xs.isEmpty()) { + rs.shouldBeNull() + } else { + rs shouldBe xs.reduceRight { + a,b -> a +b } - list.separateValidated() shouldBe ints.partition { it % 2 == 0 } } } - + } }) From 828810f342e997456bf6608fb529a97d34357100 Mon Sep 17 00:00:00 2001 From: Alphonse Bendt Date: Mon, 6 Mar 2023 23:02:53 +0100 Subject: [PATCH 2/9] formatting --- .../kotlin/arrow/core/IterableTest.kt | 759 +++++++++--------- 1 file changed, 379 insertions(+), 380 deletions(-) diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt index fafbc073f44..4380b677eaa 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt @@ -6,7 +6,6 @@ import arrow.core.test.ior import arrow.core.test.option import arrow.typeclasses.Semigroup import io.kotest.core.spec.style.StringSpec -import io.kotest.matchers.collections.shouldBeEmpty import io.kotest.matchers.collections.shouldContainExactly import io.kotest.matchers.nulls.shouldBeNull import io.kotest.matchers.nulls.shouldNotBeNull @@ -74,484 +73,484 @@ class IterableTest : StringSpec({ } shouldBe Either.Left("failfailfail") } - "traverse Either stack-safe" { - // also verifies result order and execution order (l to r) - val acc = mutableListOf() - val res = (0..20_000).traverse { a -> - acc.add(a) - Either.Right(a) - } - res shouldBe Either.Right(acc) - res shouldBe Either.Right((0..20_000).toList()) - } - - "traverse Either short-circuit" { - checkAll(Arb.list(Arb.int())) { ints -> + "traverse Either stack-safe" { + // also verifies result order and execution order (l to r) val acc = mutableListOf() - val evens = ints.traverse { - if (it % 2 == 0) { - acc.add(it) - Either.Right(it) - } else Either.Left(it) + val res = (0..20_000).traverse { a -> + acc.add(a) + Either.Right(a) } - acc shouldBe ints.takeWhile { it % 2 == 0 } - when (evens) { - is Either.Right -> evens.value shouldBe ints - is Either.Left -> evens.value shouldBe ints.first { it % 2 != 0 } + res shouldBe Either.Right(acc) + res shouldBe Either.Right((0..20_000).toList()) + } + + "traverse Either short-circuit" { + checkAll(Arb.list(Arb.int())) { ints -> + val acc = mutableListOf() + val evens = ints.traverse { + if (it % 2 == 0) { + acc.add(it) + Either.Right(it) + } else Either.Left(it) + } + acc shouldBe ints.takeWhile { it % 2 == 0 } + when (evens) { + is Either.Right -> evens.value shouldBe ints + is Either.Left -> evens.value shouldBe ints.first { it % 2 != 0 } + } } } - } - "sequenceEither should be consistent with traverse Either" { - checkAll(Arb.list(Arb.int())) { ints -> - ints.map { it.right() }.sequence() shouldBe ints.traverse { it.right() } - } - } - - "traverse Result stack-safe" { - // also verifies result order and execution order (l to r) - val acc = mutableListOf() - val res = (0..20_000).traverse { a -> - acc.add(a) - Result.success(a) + "sequenceEither should be consistent with traverse Either" { + checkAll(Arb.list(Arb.int())) { ints -> + ints.map { it.right() }.sequence() shouldBe ints.traverse { it.right() } + } } - res shouldBe Result.success(acc) - res shouldBe Result.success((0..20_000).toList()) - } - "traverse Result short-circuit" { - checkAll(Arb.list(Arb.int())) { ints -> + "traverse Result stack-safe" { + // also verifies result order and execution order (l to r) val acc = mutableListOf() - val evens = ints.traverse { - if (it % 2 == 0) { - acc.add(it) - Result.success(it) - } else Result.failure(RuntimeException()) - } - acc shouldBe ints.takeWhile { it % 2 == 0 } - evens.fold( - { it shouldBe ints }, - { } - ) - } - } - - "sequence Result should be consistent with traverse Result" { - checkAll(Arb.list(Arb.int())) { ints -> - ints.map { Result.success(it) }.sequence() shouldBe ints.traverse { Result.success(it) } + val res = (0..20_000).traverse { a -> + acc.add(a) + Result.success(a) + } + res shouldBe Result.success(acc) + res shouldBe Result.success((0..20_000).toList()) + } + + "traverse Result short-circuit" { + checkAll(Arb.list(Arb.int())) { ints -> + val acc = mutableListOf() + val evens = ints.traverse { + if (it % 2 == 0) { + acc.add(it) + Result.success(it) + } else Result.failure(RuntimeException()) + } + acc shouldBe ints.takeWhile { it % 2 == 0 } + evens.fold( + { it shouldBe ints }, + { } + ) + } } - } - "traverse Option is stack-safe" { - // also verifies result order and execution order (l to r) - val acc = mutableListOf() - val res = (0..20_000).traverse { a: Int -> - acc.add(a) - Some(a) + "sequence Result should be consistent with traverse Result" { + checkAll(Arb.list(Arb.int())) { ints -> + ints.map { Result.success(it) }.sequence() shouldBe ints.traverse { Result.success(it) } + } } - res shouldBe Some(acc) - res shouldBe Some((0..20_000).toList()) - } - "traverse Option short-circuits" { - checkAll(Arb.list(Arb.int())) { ints -> + "traverse Option is stack-safe" { + // also verifies result order and execution order (l to r) val acc = mutableListOf() - val evens = ints.traverse { - (it % 2 == 0).maybe { - acc.add(it) - it + val res = (0..20_000).traverse { a: Int -> + acc.add(a) + Some(a) + } + res shouldBe Some(acc) + res shouldBe Some((0..20_000).toList()) + } + + "traverse Option short-circuits" { + checkAll(Arb.list(Arb.int())) { ints -> + val acc = mutableListOf() + val evens = ints.traverse { + (it % 2 == 0).maybe { + acc.add(it) + it + } } + acc shouldBe ints.takeWhile { it % 2 == 0 } + evens.fold({ Unit }) { it shouldBe ints } } - acc shouldBe ints.takeWhile { it % 2 == 0 } - evens.fold({ Unit }) { it shouldBe ints } } - } - - "sequence Option yields some when all entries in the list are some" { - checkAll(Arb.list(Arb.int())) { ints -> - val evens = ints.map { (it % 2 == 0).maybe { it } }.sequence() - evens.fold({ Unit }) { it shouldBe ints } - } - } - "sequence Option should be consistent with traverse Option" { - checkAll(Arb.list(Arb.int())) { ints -> - ints.map { Some(it) }.sequence() shouldBe ints.traverse { Some(it) } + "sequence Option yields some when all entries in the list are some" { + checkAll(Arb.list(Arb.int())) { ints -> + val evens = ints.map { (it % 2 == 0).maybe { it } }.sequence() + evens.fold({ Unit }) { it shouldBe ints } + } } - } - "traverse Nullable is stack-safe" { - // also verifies result order and execution order (l to r) - val acc = mutableListOf() - val res = (0..20_000).traverse { a: Int -> - acc.add(a) - a + "sequence Option should be consistent with traverse Option" { + checkAll(Arb.list(Arb.int())) { ints -> + ints.map { Some(it) }.sequence() shouldBe ints.traverse { Some(it) } + } } - res.shouldNotBeNull() shouldBe acc - res.shouldNotBeNull() shouldBe (0..20_000).toList() - } - "traverse Nullable short-circuits" { - checkAll(Arb.list(Arb.int())) { ints -> - val acc = mutableListOf() - val evens = ints.traverse { - if (it % 2 == 0) { - acc.add(it) - it - } else { - null - } + "traverse Nullable is stack-safe" { + // also verifies result order and execution order (l to r) + val acc = mutableListOf() + val res = (0..20_000).traverse { a: Int -> + acc.add(a) + a } + res.shouldNotBeNull() shouldBe acc + res.shouldNotBeNull() shouldBe (0..20_000).toList() + } + + "traverse Nullable short-circuits" { + checkAll(Arb.list(Arb.int())) { ints -> + val acc = mutableListOf() + val evens = ints.traverse { + if (it % 2 == 0) { + acc.add(it) + it + } else { + null + } + } - val expected = ints.takeWhile { it % 2 == 0 } - acc shouldBe expected + val expected = ints.takeWhile { it % 2 == 0 } + acc shouldBe expected - if (ints.any { it % 2 != 0 }) { - evens.shouldBeNull() - } else { - evens.shouldNotBeNull() shouldContainExactly expected + if (ints.any { it % 2 != 0 }) { + evens.shouldBeNull() + } else { + evens.shouldNotBeNull() shouldContainExactly expected + } } } - } - "sequence Nullable yields some when all entries in the list are not null" { - checkAll(Arb.list(Arb.int())) { ints -> - val evens = ints.map { if (it % 2 == 0) it else null }.sequence() + "sequence Nullable yields some when all entries in the list are not null" { + checkAll(Arb.list(Arb.int())) { ints -> + val evens = ints.map { if (it % 2 == 0) it else null }.sequence() - if (ints.any { it % 2 != 0 }) { - evens.shouldBeNull() - } else { - evens.shouldNotBeNull() shouldContainExactly ints.takeWhile { it % 2 == 0 } + if (ints.any { it % 2 != 0 }) { + evens.shouldBeNull() + } else { + evens.shouldNotBeNull() shouldContainExactly ints.takeWhile { it % 2 == 0 } + } } } - } - "sequence Nullable should be consistent with travers Nullable" { - checkAll(Arb.list(Arb.int())) { ints -> - ints.map { it as Int? }.sequence() shouldBe ints.traverse { it as Int? } + "sequence Nullable should be consistent with travers Nullable" { + checkAll(Arb.list(Arb.int())) { ints -> + ints.map { it as Int? }.sequence() shouldBe ints.traverse { it as Int? } + } } - } - "traverse Validated stack-safe" { - // also verifies result order and execution order (l to r) - val acc = mutableListOf() - val res = (0..20_000).traverse(Semigroup.string()) { - acc.add(it) - Validated.Valid(it) + "traverse Validated stack-safe" { + // also verifies result order and execution order (l to r) + val acc = mutableListOf() + val res = (0..20_000).traverse(Semigroup.string()) { + acc.add(it) + Validated.Valid(it) + } + res shouldBe Validated.Valid(acc) + res shouldBe Validated.Valid((0..20_000).toList()) } - res shouldBe Validated.Valid(acc) - res shouldBe Validated.Valid((0..20_000).toList()) - } - "traverse Validated acumulates" { - checkAll(Arb.list(Arb.int())) { ints -> - val res: ValidatedNel> = - ints.map { i -> if (i % 2 == 0) Valid(i) else Invalid(nonEmptyListOf(i)) } - .sequence() + "traverse Validated acumulates" { + checkAll(Arb.list(Arb.int())) { ints -> + val res: ValidatedNel> = + ints.map { i -> if (i % 2 == 0) Valid(i) else Invalid(nonEmptyListOf(i)) } + .sequence() - val expected: ValidatedNel> = ints.filterNot { it % 2 == 0 } - .toNonEmptyListOrNull()?.invalid() ?: Valid(ints.filter { it % 2 == 0 }) + val expected: ValidatedNel> = ints.filterNot { it % 2 == 0 } + .toNonEmptyListOrNull()?.invalid() ?: Valid(ints.filter { it % 2 == 0 }) - res shouldBe expected + res shouldBe expected + } } - } - "sequence Validated should be consistent with traverse Validated" { - checkAll(Arb.list(Arb.int())) { ints -> - ints.map { it.valid() }.sequence(Semigroup.string()) shouldBe - ints.traverse(Semigroup.string()) { it.valid() } + "sequence Validated should be consistent with traverse Validated" { + checkAll(Arb.list(Arb.int())) { ints -> + ints.map { it.valid() }.sequence(Semigroup.string()) shouldBe + ints.traverse(Semigroup.string()) { it.valid() } + } } - } - "sequence Either traverse Nullable interoperate - and proof map + sequence equality with traverse" { - checkAll( - Arb.list(Arb.int()), - Arb.functionAToB?>(Arb.either(Arb.string(), Arb.int()).orNull()) - ) { ints, f -> + "sequence Either traverse Nullable interoperate - and proof map + sequence equality with traverse" { + checkAll( + Arb.list(Arb.int()), + Arb.functionAToB?>(Arb.either(Arb.string(), Arb.int()).orNull()) + ) { ints, f -> - val res: Either>? = - ints.traverse(f)?.sequence() + val res: Either>? = + ints.traverse(f)?.sequence() - val expected: Either>? = - ints.map(f).sequence()?.sequence() + val expected: Either>? = + ints.map(f).sequence()?.sequence() - res shouldBe expected + res shouldBe expected + } } - } - "zip3" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b, c -> - val result = a.zip(b, c, ::Triple) - val expected = a.zip(b, ::Pair).zip(c) { (a, b), c -> Triple(a, b, c) } - result shouldBe expected + "zip3" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b, c -> + val result = a.zip(b, c, ::Triple) + val expected = a.zip(b, ::Pair).zip(c) { (a, b), c -> Triple(a, b, c) } + result shouldBe expected + } } - } - "zip4" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int()), Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b, c, d -> - val result = a.zip(b, c, d, ::Tuple4) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + "zip4" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int()), Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b, c, d -> + val result = a.zip(b, c, d, ::Tuple4) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - result shouldBe expected + result shouldBe expected + } } - } - "zip5" { - checkAll( - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()) - ) { a, b, c, d, e -> - val result = a.zip(b, c, d, e, ::Tuple5) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } - - result shouldBe expected + "zip5" { + checkAll( + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()) + ) { a, b, c, d, e -> + val result = a.zip(b, c, d, e, ::Tuple5) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } + + result shouldBe expected + } } - } - "zip6" { - checkAll( - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()) - ) { a, b, c, d, e, f -> - val result = a.zip(b, c, d, e, f, ::Tuple6) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } - .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } - - result shouldBe expected + "zip6" { + checkAll( + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()) + ) { a, b, c, d, e, f -> + val result = a.zip(b, c, d, e, f, ::Tuple6) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } + .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } + + result shouldBe expected + } } - } - "zip7" { - checkAll( - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()) - ) { a, b, c, d, e, f, g -> - val result = a.zip(b, c, d, e, f, g, ::Tuple7) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } - .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } - .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } - - result shouldBe expected + "zip7" { + checkAll( + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()) + ) { a, b, c, d, e, f, g -> + val result = a.zip(b, c, d, e, f, g, ::Tuple7) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } + .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } + .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } + + result shouldBe expected + } } - } - "zip8" { - checkAll( - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()) - ) { a, b, c, d, e, f, g, h -> - val result = a.zip(b, c, d, e, f, g, h, ::Tuple8) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } - .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } - .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } - .zip(h) { (a, b, c, d, e, f, g), h -> Tuple8(a, b, c, d, e, f, g, h) } - - result shouldBe expected + "zip8" { + checkAll( + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()) + ) { a, b, c, d, e, f, g, h -> + val result = a.zip(b, c, d, e, f, g, h, ::Tuple8) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } + .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } + .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } + .zip(h) { (a, b, c, d, e, f, g), h -> Tuple8(a, b, c, d, e, f, g, h) } + + result shouldBe expected + } } - } - "zip9" { - checkAll( - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()) - ) { a, b, c, d, e, f, g, h, i -> - val result = a.zip(b, c, d, e, f, g, h, i, ::Tuple9) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } - .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } - .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } - .zip(h) { (a, b, c, d, e, f, g), h -> Tuple8(a, b, c, d, e, f, g, h) } - .zip(i) { (a, b, c, d, e, f, g, h), i -> Tuple9(a, b, c, d, e, f, g, h, i) } - - result shouldBe expected + "zip9" { + checkAll( + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()) + ) { a, b, c, d, e, f, g, h, i -> + val result = a.zip(b, c, d, e, f, g, h, i, ::Tuple9) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } + .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } + .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } + .zip(h) { (a, b, c, d, e, f, g), h -> Tuple8(a, b, c, d, e, f, g, h) } + .zip(i) { (a, b, c, d, e, f, g, h), i -> Tuple9(a, b, c, d, e, f, g, h, i) } + + result shouldBe expected + } } - } - "zip10" { - checkAll( - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()), - Arb.list(Arb.int()) - ) { a, b, c, d, e, f, g, h, i, j -> - val result = a.zip(b, c, d, e, f, g, h, i, j, ::Tuple10) - val expected = a.zip(b, ::Pair) - .zip(c) { (a, b), c -> Triple(a, b, c) } - .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } - .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } - .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } - .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } - .zip(h) { (a, b, c, d, e, f, g), h -> Tuple8(a, b, c, d, e, f, g, h) } - .zip(i) { (a, b, c, d, e, f, g, h), i -> Tuple9(a, b, c, d, e, f, g, h, i) } - .zip(j) { (a, b, c, d, e, f, g, h, i), j -> Tuple10(a, b, c, d, e, f, g, h, i, j) } - - result shouldBe expected + "zip10" { + checkAll( + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()), + Arb.list(Arb.int()) + ) { a, b, c, d, e, f, g, h, i, j -> + val result = a.zip(b, c, d, e, f, g, h, i, j, ::Tuple10) + val expected = a.zip(b, ::Pair) + .zip(c) { (a, b), c -> Triple(a, b, c) } + .zip(d) { (a, b, c), d -> Tuple4(a, b, c, d) } + .zip(e) { (a, b, c, d), e -> Tuple5(a, b, c, d, e) } + .zip(f) { (a, b, c, d, e), f -> Tuple6(a, b, c, d, e, f) } + .zip(g) { (a, b, c, d, e, f), g -> Tuple7(a, b, c, d, e, f, g) } + .zip(h) { (a, b, c, d, e, f, g), h -> Tuple8(a, b, c, d, e, f, g, h) } + .zip(i) { (a, b, c, d, e, f, g, h), i -> Tuple9(a, b, c, d, e, f, g, h, i) } + .zip(j) { (a, b, c, d, e, f, g, h, i), j -> Tuple10(a, b, c, d, e, f, g, h, i, j) } + + result shouldBe expected + } } - } - "can align lists with different lengths" { - checkAll(Arb.list(Arb.boolean()), Arb.list(Arb.boolean())) { a, b -> - a.align(b).size shouldBe max(a.size, b.size) - } + "can align lists with different lengths" { + checkAll(Arb.list(Arb.boolean()), Arb.list(Arb.boolean())) { a, b -> + a.align(b).size shouldBe max(a.size, b.size) + } - checkAll(Arb.list(Arb.boolean()), Arb.list(Arb.boolean())) { a, b -> - a.align(b).take(min(a.size, b.size)).forEach { - it.isBoth shouldBe true + checkAll(Arb.list(Arb.boolean()), Arb.list(Arb.boolean())) { a, b -> + a.align(b).take(min(a.size, b.size)).forEach { + it.isBoth shouldBe true + } } - } - checkAll(Arb.list(Arb.boolean()), Arb.list(Arb.boolean())) { a, b -> - a.align(b).drop(min(a.size, b.size)).forEach { - if (a.size < b.size) { - it.isRight shouldBe true - } else { - it.isLeft shouldBe true + checkAll(Arb.list(Arb.boolean()), Arb.list(Arb.boolean())) { a, b -> + a.align(b).drop(min(a.size, b.size)).forEach { + if (a.size < b.size) { + it.isRight shouldBe true + } else { + it.isLeft shouldBe true + } } } } - } - "leftPadZip (with map)" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> - val left = a.map { it } + List(max(0, b.count() - a.count())) { null } - val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + "leftPadZip (with map)" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> + val left = a.map { it } + List(max(0, b.count() - a.count())) { null } + val right = b.map { it } + List(max(0, a.count() - b.count())) { null } - val result = a.leftPadZip(b) { a, b -> a to b } + val result = a.leftPadZip(b) { a, b -> a to b } - result shouldBe left.zip(right) { l, r -> l to r }.filter { it.second != null } + result shouldBe left.zip(right) { l, r -> l to r }.filter { it.second != null } + } } - } - "leftPadZip (without map)" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> - val left = a.map { it } + List(max(0, b.count() - a.count())) { null } - val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + "leftPadZip (without map)" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> + val left = a.map { it } + List(max(0, b.count() - a.count())) { null } + val right = b.map { it } + List(max(0, a.count() - b.count())) { null } - val result = a.leftPadZip(b) + val result = a.leftPadZip(b) - result shouldBe left.zip(right) { l, r -> l to r }.filter { it.second != null } + result shouldBe left.zip(right) { l, r -> l to r }.filter { it.second != null } + } } - } - "rightPadZip (without map)" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> - val left = a.map { it } + List(max(0, b.count() - a.count())) { null } - val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + "rightPadZip (without map)" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> + val left = a.map { it } + List(max(0, b.count() - a.count())) { null } + val right = b.map { it } + List(max(0, a.count() - b.count())) { null } - val result = a.rightPadZip(b) + val result = a.rightPadZip(b) - result shouldBe left.zip(right) { l, r -> l to r }.filter { it.first != null } - result.map { it.first } shouldBe a + result shouldBe left.zip(right) { l, r -> l to r }.filter { it.first != null } + result.map { it.first } shouldBe a + } } - } - "rightPadZip (with map)" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> - val left = a.map { it } + List(max(0, b.count() - a.count())) { null } - val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + "rightPadZip (with map)" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> + val left = a.map { it } + List(max(0, b.count() - a.count())) { null } + val right = b.map { it } + List(max(0, a.count() - b.count())) { null } - val result = a.rightPadZip(b) { a, b -> a to b } + val result = a.rightPadZip(b) { a, b -> a to b } - result shouldBe left.zip(right) { l, r -> l to r }.filter { it.first != null } - result.map { it.first } shouldBe a + result shouldBe left.zip(right) { l, r -> l to r }.filter { it.first != null } + result.map { it.first } shouldBe a + } } - } - "padZip" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> - val left = a.map { it } + List(max(0, b.count() - a.count())) { null } - val right = b.map { it } + List(max(0, a.count() - b.count())) { null } - a.padZip(b) { l, r -> Ior.fromNullables(l, r) } shouldBe left.zip(right) { l, r -> Ior.fromNullables(l, r) } + "padZip" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> + val left = a.map { it } + List(max(0, b.count() - a.count())) { null } + val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + a.padZip(b) { l, r -> Ior.fromNullables(l, r) } shouldBe left.zip(right) { l, r -> Ior.fromNullables(l, r) } + } } - } - "padZipWithNull" { - checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> - val left = a.map { it } + List(max(0, b.count() - a.count())) { null } - val right = b.map { it } + List(max(0, a.count() - b.count())) { null } + "padZipWithNull" { + checkAll(Arb.list(Arb.int()), Arb.list(Arb.int())) { a, b -> + val left = a.map { it } + List(max(0, b.count() - a.count())) { null } + val right = b.map { it } + List(max(0, a.count() - b.count())) { null } - a.padZip(b) shouldBe left.zip(right) { l, r -> l to r } + a.padZip(b) shouldBe left.zip(right) { l, r -> l to r } + } } - } - "filterOption" { - checkAll(Arb.list(Arb.option(Arb.int()))) { listOfOption -> - listOfOption.filterOption() shouldBe listOfOption.mapNotNull { it.orNull() } + "filterOption" { + checkAll(Arb.list(Arb.option(Arb.int()))) { listOfOption -> + listOfOption.filterOption() shouldBe listOfOption.mapNotNull { it.orNull() } + } } - } - "flattenOption" { - checkAll(Arb.list(Arb.option(Arb.int()))) { listOfOption -> - listOfOption.flattenOption() shouldBe listOfOption.mapNotNull { it.orNull() } + "flattenOption" { + checkAll(Arb.list(Arb.option(Arb.int()))) { listOfOption -> + listOfOption.flattenOption() shouldBe listOfOption.mapNotNull { it.orNull() } + } } - } - "separateEither" { - checkAll(Arb.list(Arb.int())) { ints -> - val list = ints.map { - if (it % 2 == 0) it.left() - else it.right() + "separateEither" { + checkAll(Arb.list(Arb.int())) { ints -> + val list = ints.map { + if (it % 2 == 0) it.left() + else it.right() + } + list.separateEither() shouldBe ints.partition { it % 2 == 0 } } - list.separateEither() shouldBe ints.partition { it % 2 == 0 } } - } - "separateValidated" { - checkAll(Arb.list(Arb.int())) { ints -> - val list = ints.map { - if (it % 2 == 0) it.invalid() - else it.valid() + "separateValidated" { + checkAll(Arb.list(Arb.int())) { ints -> + val list = ints.map { + if (it % 2 == 0) it.invalid() + else it.valid() + } + list.separateValidated() shouldBe ints.partition { it % 2 == 0 } } - list.separateValidated() shouldBe ints.partition { it % 2 == 0 } } - } "unzip is the inverse of zip" { checkAll(Arb.list(Arb.int())) { xs -> @@ -614,7 +613,7 @@ class IterableTest : StringSpec({ rs.shouldBeNull() } else { rs shouldBe xs.reduce { - a,b -> a +b + a,b -> a +b } } } From c46f9c3aeb4a656f1a2ec374fcce2ef0652125cc Mon Sep 17 00:00:00 2001 From: Alphonse Bendt Date: Mon, 6 Mar 2023 23:13:18 +0100 Subject: [PATCH 3/9] remove limit --- .../arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt index 4380b677eaa..e26c588efa0 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt @@ -584,7 +584,7 @@ class IterableTest : StringSpec({ } "align is the inverse of unalign" { - checkAll(Arb.list(Arb.ior(Arb.int(0 .. 1), Arb.string(1)), 0 .. 10)) { xs -> + checkAll(Arb.list(Arb.ior(Arb.int(), Arb.string()))) { xs -> val (a, b) = xs.unalign() a.align(b) shouldBe xs } From 5b5bc4e8f59ec3a573d61b127a94023b2f61f3a3 Mon Sep 17 00:00:00 2001 From: Alphonse Bendt Date: Mon, 6 Mar 2023 23:15:13 +0100 Subject: [PATCH 4/9] fix Arb.ior --- .../kotlin/arrow/core/test/GeneratorTest.kt | 25 +++++++++++++++++++ .../kotlin/arrow/core/test/Generators.kt | 14 +++++++---- 2 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/GeneratorTest.kt diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/GeneratorTest.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/GeneratorTest.kt new file mode 100644 index 00000000000..6f3e75ce437 --- /dev/null +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/GeneratorTest.kt @@ -0,0 +1,25 @@ +package arrow.core.test + +import io.kotest.core.spec.style.StringSpec +import io.kotest.inspectors.forAtLeastOne +import io.kotest.matchers.booleans.shouldBeTrue +import io.kotest.property.Arb +import io.kotest.property.arbitrary.int +import io.kotest.property.arbitrary.list +import io.kotest.property.arbitrary.next +import io.kotest.property.arbitrary.string + +class GeneratorTest : StringSpec({ + "Arb.ior should generate left, right & both" { + Arb.list(Arb.ior(Arb.string(), Arb.int())).next() + .forAtLeastOne { + it.isRight.shouldBeTrue() + } + .forAtLeastOne { + it.isBoth.shouldBeTrue() + } + .forAtLeastOne { + it.isLeft.shouldBeTrue() + } + } +}) diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/Generators.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/Generators.kt index 226ef102150..c952be60b4b 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/Generators.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/Generators.kt @@ -37,13 +37,13 @@ import kotlin.coroutines.startCoroutine // copied from kotest-extensions-arrow -fun Arb.Companion.nonEmptyList(arb: Arb, range: IntRange = 0 .. 100): Arb> = +fun Arb.Companion.nonEmptyList(arb: Arb, range: IntRange = 0..100): Arb> = Arb.bind(arb, Arb.list(arb, range), ::NonEmptyList) -fun Arb.Companion.nonEmptySet(arb: Arb, range: IntRange = 0 .. 100): Arb> = - Arb.set(arb, max(range.first, 1) .. range.last).map { it.toNonEmptySetOrNull()!! } +fun Arb.Companion.nonEmptySet(arb: Arb, range: IntRange = 0..100): Arb> = + Arb.set(arb, max(range.first, 1)..range.last).map { it.toNonEmptySetOrNull()!! } -fun Arb.Companion.sequence(arb: Arb, range: IntRange = 0 .. 100): Arb> = +fun Arb.Companion.sequence(arb: Arb, range: IntRange = 0..100): Arb> = Arb.list(arb, range).map { it.asSequence() } fun Arb.Companion.functionAToB(arb: Arb): Arb<(A) -> B> = @@ -85,7 +85,11 @@ fun Arb.eval(): Arb> = map { Eval.now(it) } private fun Arb.alignWith(arbB: Arb, transform: (Ior) -> R): Arb = - Arb.bind(this, arbB) { a, b -> transform(Ior.Both(a, b)) } + Arb.choice( + this.map { Ior.Left(it) }, + Arb.bind(this, arbB) { a, b -> Ior.Both(a, b) }, + arbB.map { Ior.Right(it) } + ).map(transform) fun Arb.Companion.suspendFunThatReturnsEitherAnyOrAnyOrThrows(): Arb Either> = choice( From 2ff8f16c149a8ebb73dce84bc74ebca1eb6ba844 Mon Sep 17 00:00:00 2001 From: Alphonse Bendt Date: Mon, 6 Mar 2023 23:20:34 +0100 Subject: [PATCH 5/9] format --- .../src/commonTest/kotlin/arrow/core/test/Generators.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/Generators.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/Generators.kt index c952be60b4b..0be3946dd36 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/Generators.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/Generators.kt @@ -37,13 +37,13 @@ import kotlin.coroutines.startCoroutine // copied from kotest-extensions-arrow -fun Arb.Companion.nonEmptyList(arb: Arb, range: IntRange = 0..100): Arb> = +fun Arb.Companion.nonEmptyList(arb: Arb, range: IntRange = 0 .. 100): Arb> = Arb.bind(arb, Arb.list(arb, range), ::NonEmptyList) -fun Arb.Companion.nonEmptySet(arb: Arb, range: IntRange = 0..100): Arb> = - Arb.set(arb, max(range.first, 1)..range.last).map { it.toNonEmptySetOrNull()!! } +fun Arb.Companion.nonEmptySet(arb: Arb, range: IntRange = 0 .. 100): Arb> = + Arb.set(arb, max(range.first, 1) .. range.last).map { it.toNonEmptySetOrNull()!! } -fun Arb.Companion.sequence(arb: Arb, range: IntRange = 0..100): Arb> = +fun Arb.Companion.sequence(arb: Arb, range: IntRange = 0 .. 100): Arb> = Arb.list(arb, range).map { it.asSequence() } fun Arb.Companion.functionAToB(arb: Arb): Arb<(A) -> B> = From dd7fa352a1ca3c47e4a4523e8a102b4aca3467e3 Mon Sep 17 00:00:00 2001 From: Alphonse Bendt Date: Tue, 7 Mar 2023 13:21:36 +0100 Subject: [PATCH 6/9] revert Arb.alignwith behaviour deprecate unalign function introduce separateIor function --- .../commonMain/kotlin/arrow/core/Iterable.kt | 34 ++++++++++++++----- .../kotlin/arrow/core/test/GeneratorTest.kt | 25 -------------- .../kotlin/arrow/core/test/Generators.kt | 6 +--- 3 files changed, 26 insertions(+), 39 deletions(-) delete mode 100644 arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/GeneratorTest.kt diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Iterable.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Iterable.kt index 89015278700..1dd6849a19f 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Iterable.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Iterable.kt @@ -732,7 +732,7 @@ public inline fun Iterable.align(b: Iterable, fa: (Ior) -> first.hasNext() && second.hasNext() -> Ior.Both(first.next(), second.next()) first.hasNext() -> first.next().leftIor() second.hasNext() -> second.next().rightIor() - else -> throw IllegalStateException("this should never happen") + else -> throw AssertionError("this should never happen") } add(fa(element)) } @@ -832,14 +832,11 @@ public inline fun Iterable.unzip(fc: (C) -> Pair): Pair */ -public fun Iterable>.unalign(): Pair, List> = - fold(emptyList() to emptyList()) { (l, r), x -> - x.fold( - { l + it to r }, - { l to r + it }, - { a, b -> l + a to r + b } - ) - } +@Deprecated( + "The current unalign function is renamed to seperateIor, and a new unalign function is going to be added to Arrow 2.0.0.", + ReplaceWith("separateIor()", "arrow.core.separateIor") +) +public fun Iterable>.unalign(): Pair, List> = separateIor() /** * after applying the given function, splits the resulting union shaped structure into its components parts @@ -859,9 +856,28 @@ public fun Iterable>.unalign(): Pair, List> = * ``` * */ +@Deprecated( + "The current unalign function is renamed to seperateIor, and a new unalign function is going to be added to Arrow 2.0.0.", + ReplaceWith("map(fa).separateIor()", "arrow.core.separateIor") +) public inline fun Iterable.unalign(fa: (C) -> Ior): Pair, List> = map(fa).unalign() +/** + * Separate the inner [Ior] values into a pair of Lists. + * + * @receiver Iterable of Ior + * @return a tuple containing a List with the left side value from the[Ior.Left] and [Ior.Both] values and another List with the right side value from the [Ior.Right] and [Ior.Both] values. + */ +public fun Iterable>.separateIor(): Pair, List> = + fold(emptyList() to emptyList()) { (l, r), x -> + x.fold( + { l + it to r }, + { l to r + it }, + { a, b -> l + a to r + b } + ) + } + @Deprecated("use fold instead", ReplaceWith("fold(MA)", "arrow.core.fold")) public fun Iterable.combineAll(MA: Monoid): A = fold(MA) diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/GeneratorTest.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/GeneratorTest.kt deleted file mode 100644 index 6f3e75ce437..00000000000 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/GeneratorTest.kt +++ /dev/null @@ -1,25 +0,0 @@ -package arrow.core.test - -import io.kotest.core.spec.style.StringSpec -import io.kotest.inspectors.forAtLeastOne -import io.kotest.matchers.booleans.shouldBeTrue -import io.kotest.property.Arb -import io.kotest.property.arbitrary.int -import io.kotest.property.arbitrary.list -import io.kotest.property.arbitrary.next -import io.kotest.property.arbitrary.string - -class GeneratorTest : StringSpec({ - "Arb.ior should generate left, right & both" { - Arb.list(Arb.ior(Arb.string(), Arb.int())).next() - .forAtLeastOne { - it.isRight.shouldBeTrue() - } - .forAtLeastOne { - it.isBoth.shouldBeTrue() - } - .forAtLeastOne { - it.isLeft.shouldBeTrue() - } - } -}) diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/Generators.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/Generators.kt index 0be3946dd36..226ef102150 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/Generators.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/test/Generators.kt @@ -85,11 +85,7 @@ fun Arb.eval(): Arb> = map { Eval.now(it) } private fun Arb.alignWith(arbB: Arb, transform: (Ior) -> R): Arb = - Arb.choice( - this.map { Ior.Left(it) }, - Arb.bind(this, arbB) { a, b -> Ior.Both(a, b) }, - arbB.map { Ior.Right(it) } - ).map(transform) + Arb.bind(this, arbB) { a, b -> transform(Ior.Both(a, b)) } fun Arb.Companion.suspendFunThatReturnsEitherAnyOrAnyOrThrows(): Arb Either> = choice( From d758a73501a496811dbef5840b825e48fecdae7b Mon Sep 17 00:00:00 2001 From: Alphonse Bendt Date: Tue, 7 Mar 2023 13:22:08 +0100 Subject: [PATCH 7/9] typo --- .../arrow-core/src/commonMain/kotlin/arrow/core/Iterable.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Iterable.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Iterable.kt index 1dd6849a19f..e9fb37103d6 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Iterable.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Iterable.kt @@ -833,7 +833,7 @@ public inline fun Iterable.unzip(fc: (C) -> Pair): Pair */ @Deprecated( - "The current unalign function is renamed to seperateIor, and a new unalign function is going to be added to Arrow 2.0.0.", + "The current unalign function is renamed to separateIor, and a new unalign function is going to be added to Arrow 2.0.0.", ReplaceWith("separateIor()", "arrow.core.separateIor") ) public fun Iterable>.unalign(): Pair, List> = separateIor() @@ -857,7 +857,7 @@ public fun Iterable>.unalign(): Pair, List> = separa * */ @Deprecated( - "The current unalign function is renamed to seperateIor, and a new unalign function is going to be added to Arrow 2.0.0.", + "The current unalign function is renamed to separateIor, and a new unalign function is going to be added to Arrow 2.0.0.", ReplaceWith("map(fa).separateIor()", "arrow.core.separateIor") ) public inline fun Iterable.unalign(fa: (C) -> Ior): Pair, List> = From 7d870fb6a5b24299976c331b27b5dc4c4856ad26 Mon Sep 17 00:00:00 2001 From: Alphonse Bendt Date: Tue, 7 Mar 2023 13:28:02 +0100 Subject: [PATCH 8/9] fix api check --- arrow-libs/core/arrow-core/api/arrow-core.api | 1 + 1 file changed, 1 insertion(+) diff --git a/arrow-libs/core/arrow-core/api/arrow-core.api b/arrow-libs/core/arrow-core/api/arrow-core.api index f8817c5e542..d44fb57f716 100644 --- a/arrow-libs/core/arrow-core/api/arrow-core.api +++ b/arrow-libs/core/arrow-core/api/arrow-core.api @@ -648,6 +648,7 @@ public final class arrow/core/IterableKt { public static final fun rightPadZip (Ljava/lang/Iterable;Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;)Ljava/util/List; public static final fun salign (Ljava/lang/Iterable;Larrow/typeclasses/Semigroup;Ljava/lang/Iterable;)Ljava/lang/Iterable; public static final fun separateEither (Ljava/lang/Iterable;)Lkotlin/Pair; + public static final fun separateIor (Ljava/lang/Iterable;)Lkotlin/Pair; public static final fun separateValidated (Ljava/lang/Iterable;)Lkotlin/Pair; public static final fun sequence (Ljava/lang/Iterable;)Larrow/core/Either; public static final fun sequence (Ljava/lang/Iterable;)Larrow/core/Option; From 58e9755156278afa04c076f2c541a2df796d5011 Mon Sep 17 00:00:00 2001 From: Alphonse Bendt Date: Tue, 7 Mar 2023 23:38:57 +0100 Subject: [PATCH 9/9] review changes * revert exception type * remove test that tests stdlib `zip` function --- .../src/commonMain/kotlin/arrow/core/Iterable.kt | 2 +- .../src/commonTest/kotlin/arrow/core/IterableTest.kt | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Iterable.kt b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Iterable.kt index adb022c1e8c..7ba652f7075 100644 --- a/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Iterable.kt +++ b/arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/Iterable.kt @@ -777,7 +777,7 @@ public inline fun Iterable.align(b: Iterable, fa: (Ior) -> first.hasNext() && second.hasNext() -> Ior.Both(first.next(), second.next()) first.hasNext() -> first.next().leftIor() second.hasNext() -> second.next().rightIor() - else -> throw AssertionError("this should never happen") + else -> throw IllegalStateException("this should never happen") } add(fa(element)) } diff --git a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt index 13c25f6e59f..ce052f3513a 100644 --- a/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt +++ b/arrow-libs/core/arrow-core/src/commonTest/kotlin/arrow/core/IterableTest.kt @@ -570,14 +570,6 @@ class IterableTest : StringSpec({ } } - "zip is the inverse of unzip" { - checkAll(Arb.list(Arb.pair(Arb.int(), Arb.string()))) { xs -> - val (l, r) = xs.unzip() - - l.zip(r) shouldBe xs - } - } - "unalign is the inverse of align" { checkAll(Arb.list(Arb.int()), Arb.list(Arb.string())) { a, b -> a.align(b).unalign() shouldBe (a to b)