diff --git a/arrow-optics/src/test/kotlin/arrow/optics/GetterTest.kt b/arrow-optics/src/test/kotlin/arrow/optics/GetterTest.kt index 9ec685eb650..26cd5d6e30d 100644 --- a/arrow-optics/src/test/kotlin/arrow/optics/GetterTest.kt +++ b/arrow-optics/src/test/kotlin/arrow/optics/GetterTest.kt @@ -21,7 +21,6 @@ class GetterTest : UnitSpec() { init { val userGetter = userIso.asGetter() - val tokenGetter = tokenIso.asGetter() val length = Getter { it.length } val upper = Getter { it.toUpperCase() } diff --git a/arrow-optics/src/test/kotlin/arrow/optics/IsoTest.kt b/arrow-optics/src/test/kotlin/arrow/optics/IsoTest.kt index bc623f7787b..8295b759d80 100644 --- a/arrow-optics/src/test/kotlin/arrow/optics/IsoTest.kt +++ b/arrow-optics/src/test/kotlin/arrow/optics/IsoTest.kt @@ -1,16 +1,21 @@ package arrow.optics import arrow.core.* +import arrow.data.k import io.kotlintest.KTestJUnitRunner import io.kotlintest.properties.Gen import io.kotlintest.properties.forAll import arrow.instances.StringMonoidInstance +import arrow.syntax.option.some import org.junit.runner.RunWith import arrow.test.UnitSpec import arrow.test.generators.genFunctionAToB import arrow.test.laws.IsoLaws import arrow.test.laws.LensLaws +import arrow.test.laws.OptionalLaws import arrow.test.laws.PrismLaws +import arrow.test.laws.SetterLaws +import arrow.test.laws.TraversalLaws import arrow.typeclasses.Eq @RunWith(KTestJUnitRunner::class) @@ -29,7 +34,7 @@ class IsoTest : UnitSpec() { aGen = TokenGen, bGen = Gen.string(), funcGen = genFunctionAToB(Gen.string()), - EQA = Eq.any(), + EQA = Token.eq(), EQB = Eq.any(), MB = StringMonoidInstance), @@ -41,16 +46,106 @@ class IsoTest : UnitSpec() { EQA = Eq.any(), EQOptionB = Eq.any()), + TraversalLaws.laws( + traversal = tokenIso.asTraversal(), + aGen = TokenGen, + bGen = Gen.string(), + funcGen = genFunctionAToB(Gen.string()), + EQA = Token.eq() + ), + + OptionalLaws.laws( + optional = tokenIso.asOptional(), + aGen = TokenGen, + bGen = Gen.string(), + funcGen = genFunctionAToB(Gen.string()), + EQA = Token.eq() + ), + + SetterLaws.laws( + setter = tokenIso.asSetter(), + aGen = TokenGen, + bGen = Gen.string(), + funcGen = genFunctionAToB(Gen.string()), + EQA = Token.eq() + ), + IsoLaws.laws( iso = tokenIso, aGen = TokenGen, bGen = Gen.string(), funcGen = genFunctionAToB(Gen.string()), - EQA = Eq.any(), + EQA = Token.eq(), EQB = Eq.any(), bMonoid = StringMonoidInstance) ) + "asFold should behave as valid Fold: size" { + forAll(TokenGen) { token -> + tokenIso.asFold().size(token) == 1 + } + } + + "asFold should behave as valid Fold: nonEmpty" { + forAll(TokenGen) { token -> + tokenIso.asFold().nonEmpty(token) + } + } + + "asFold should behave as valid Fold: isEmpty" { + forAll(TokenGen) { token -> + !tokenIso.asFold().isEmpty(token) + } + } + + "asFold should behave as valid Fold: getAll" { + forAll(TokenGen) { token -> + tokenIso.asFold().getAll(token) == listOf(token.value).k() + } + } + + "asFold should behave as valid Fold: combineAll" { + forAll(TokenGen) { token -> + tokenIso.asFold().combineAll(token) == token.value + } + } + + "asFold should behave as valid Fold: fold" { + forAll(TokenGen) { token -> + tokenIso.asFold().fold(token) == token.value + } + } + + "asFold should behave as valid Fold: headOption" { + forAll(TokenGen) { token -> + tokenIso.asFold().headOption(token) == token.value.some() + } + } + + "asFold should behave as valid Fold: lastOption" { + forAll(TokenGen) { token -> + tokenIso.asFold().lastOption(token) == token.value.some() + } + } + + "asGetter should behave as valid Getter: get" { + forAll(TokenGen) { token -> + tokenIso.asGetter().get(token) == tokenGetter.get(token) + } + } + + "asGetter should behave as valid Getter: find" { + forAll(TokenGen, genFunctionAToB(Gen.bool())) { token, p -> + tokenIso.asGetter().find(token, p) == tokenGetter.find(token, p) + } + } + + "asGetter should behave as valid Getter: exist" { + forAll(TokenGen, genFunctionAToB(Gen.bool())) { token, p -> + tokenIso.asGetter().exist(token, p) == tokenGetter.exist(token, p) + } + } + "Lifting a function should yield the same result as not yielding" { forAll(TokenGen, Gen.string(), { token, value -> tokenIso.modify(token) { value } == tokenIso.lift { value }(token) diff --git a/arrow-optics/src/test/kotlin/arrow/optics/TestDomain.kt b/arrow-optics/src/test/kotlin/arrow/optics/TestDomain.kt index 06716617b67..db27233f5e0 100644 --- a/arrow-optics/src/test/kotlin/arrow/optics/TestDomain.kt +++ b/arrow-optics/src/test/kotlin/arrow/optics/TestDomain.kt @@ -4,6 +4,7 @@ import io.kotlintest.properties.Gen import arrow.core.identity import arrow.syntax.either.left import arrow.syntax.either.right +import arrow.typeclasses.Eq sealed class SumType { data class A(val string: String) : SumType() @@ -56,7 +57,13 @@ internal val userSetter: Setter = Setter { s -> { user -> user.copy(token = s(user.token)) } } -internal data class Token(val value: String) +internal data class Token(val value: String) { + companion object { + fun eq() = object : Eq { + override fun eqv(a: Token, b: Token): Boolean = a == b + } + } +} internal object TokenGen : Gen { override fun generate() = Token(Gen.string().generate()) } @@ -66,6 +73,8 @@ internal object UserGen : Gen { override fun generate() = User(TokenGen.generate()) } +internal val tokenGetter: Getter = Getter(Token::value) + internal val userLens: Lens = Lens( { user: User -> user.token }, { token: Token -> { user: User -> user.copy(token = token) } }