Skip to content
This repository has been archived by the owner on Feb 24, 2021. It is now read-only.

Cleanup fx tests #90

Merged
merged 9 commits into from
Mar 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,24 @@ import arrow.core.extensions.either.eq.eq
import arrow.core.extensions.eq
import arrow.core.internal.AtomicRefW
import arrow.core.right
import arrow.core.test.UnitSpec
import arrow.core.test.generators.throwable
import arrow.core.test.laws.equalUnderTheLaw
import arrow.fx.ForIO
import arrow.fx.IO
import arrow.fx.extensions.exitcase.eq.eq
import arrow.fx.extensions.fx
import arrow.fx.extensions.io.applicative.applicative
import arrow.fx.extensions.io.applicativeError.attempt
import arrow.fx.extensions.io.async.effectMap
import arrow.fx.handleErrorWith
import arrow.fx.extensions.io.bracket.onCancel
import arrow.fx.extensions.io.concurrent.waitFor
import arrow.fx.fix
import arrow.fx.handleErrorWith
import arrow.fx.typeclasses.Duration
import arrow.fx.typeclasses.ExitCase
import arrow.fx.typeclasses.milliseconds
import arrow.fx.typeclasses.seconds
import arrow.test.UnitSpec
import arrow.test.generators.throwable
import arrow.test.laws.equalUnderTheLaw
import arrow.test.laws.shouldBeEq
import arrow.fx.test.laws.shouldBeEq
import arrow.typeclasses.Eq
import arrow.typeclasses.EqK
import io.kotlintest.fail
Expand Down
26 changes: 13 additions & 13 deletions arrow-fx-reactor/src/test/kotlin/arrow/fx/FluxKTest.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package arrow.fx

import arrow.Kind
import arrow.core.test.UnitSpec
import arrow.core.test.generators.GenK
import arrow.core.test.generators.throwable
import arrow.fx.reactor.FluxK
import arrow.fx.reactor.FluxKOf
import arrow.fx.reactor.ForFluxK
Expand All @@ -15,11 +18,8 @@ import arrow.fx.reactor.fix
import arrow.fx.reactor.k
import arrow.fx.reactor.value
import arrow.fx.typeclasses.ExitCase
import arrow.test.UnitSpec
import arrow.test.generators.GenK
import arrow.test.generators.throwable
import arrow.test.laws.AsyncLaws
import arrow.test.laws.TimerLaws
import arrow.fx.test.laws.AsyncLaws
import arrow.fx.test.laws.TimerLaws
import arrow.typeclasses.Eq
import arrow.typeclasses.EqK
import io.kotlintest.matchers.startWith
Expand Down Expand Up @@ -154,12 +154,12 @@ class FluxKTest : UnitSpec() {

"FluxK should cancel KindConnection on dispose" {
Promise.uncancellable<ForFluxK, Unit>(FluxK.async()).flatMap { latch ->
FluxK {
FluxK.async<Unit> { conn, _ ->
conn.push(latch.complete(Unit))
}.flux.subscribe().dispose()
}.flatMap { latch.get() }
}.value()
FluxK {
FluxK.async<Unit> { conn, _ ->
conn.push(latch.complete(Unit))
}.flux.subscribe().dispose()
}.flatMap { latch.get() }
}.value()
.test()
.expectNext(Unit)
.expectComplete()
Expand All @@ -183,8 +183,8 @@ class FluxKTest : UnitSpec() {

"KindConnection can cancel upstream" {
FluxK.async<Unit> { connection, _ ->
connection.cancel().value().subscribe()
}.value()
connection.cancel().value().subscribe()
}.value()
.test()
.expectError(ConnectionCancellationException::class)
}
Expand Down
8 changes: 4 additions & 4 deletions arrow-fx-reactor/src/test/kotlin/arrow/fx/MonoKTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ import arrow.fx.reactor.k
import arrow.fx.reactor.unsafeRunSync
import arrow.fx.reactor.value
import arrow.fx.typeclasses.ExitCase
import arrow.test.UnitSpec
import arrow.test.generators.GenK
import arrow.test.laws.AsyncLaws
import arrow.test.laws.TimerLaws
import arrow.core.test.UnitSpec
import arrow.core.test.generators.GenK
import arrow.fx.test.laws.AsyncLaws
import arrow.fx.test.laws.TimerLaws
import arrow.typeclasses.Eq
import arrow.typeclasses.EqK
import io.kotlintest.matchers.startWith
Expand Down
22 changes: 11 additions & 11 deletions arrow-fx-rx2/src/test/kotlin/arrow/fx/FlowableKTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package arrow.fx

import arrow.Kind
import arrow.core.Try
import arrow.core.test.generators.GenK
import arrow.core.test.laws.MonadFilterLaws
import arrow.core.test.laws.TraverseLaws
import arrow.fx.rx2.FlowableK
import arrow.fx.rx2.FlowableKOf
import arrow.fx.rx2.ForFlowableK
Expand All @@ -23,11 +26,8 @@ import arrow.fx.rx2.fix
import arrow.fx.rx2.k
import arrow.fx.rx2.value
import arrow.fx.typeclasses.ExitCase
import arrow.test.generators.GenK
import arrow.test.laws.AsyncLaws
import arrow.test.laws.ConcurrentLaws
import arrow.test.laws.MonadFilterLaws
import arrow.test.laws.TraverseLaws
import arrow.fx.test.laws.AsyncLaws
import arrow.fx.test.laws.ConcurrentLaws
import arrow.typeclasses.Eq
import arrow.typeclasses.EqK
import io.kotlintest.properties.Gen
Expand Down Expand Up @@ -153,12 +153,12 @@ class FlowableKTests : RxJavaSpec() {

"FlowableK should cancel KindConnection on dispose" {
Promise.uncancellable<ForFlowableK, Unit>(FlowableK.async()).flatMap { latch ->
FlowableK {
FlowableK.cancellable<Unit>(fa = {
latch.complete(Unit)
}).flowable.subscribe().dispose()
}.flatMap { latch.get() }
}.value()
FlowableK {
FlowableK.cancellable<Unit>(fa = {
latch.complete(Unit)
}).flowable.subscribe().dispose()
}.flatMap { latch.get() }
}.value()
.test()
.assertValue(Unit)
.awaitTerminalEvent(100, TimeUnit.MILLISECONDS)
Expand Down
6 changes: 3 additions & 3 deletions arrow-fx-rx2/src/test/kotlin/arrow/fx/MaybeKTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ import arrow.fx.rx2.k
import arrow.fx.rx2.unsafeRunSync
import arrow.fx.rx2.value
import arrow.fx.typeclasses.ExitCase
import arrow.test.generators.GenK
import arrow.test.generators.throwable
import arrow.test.laws.ConcurrentLaws
import arrow.core.test.generators.GenK
import arrow.core.test.generators.throwable
import arrow.fx.test.laws.ConcurrentLaws
import arrow.typeclasses.Eq
import arrow.typeclasses.EqK
import io.kotlintest.properties.Gen
Expand Down
6 changes: 3 additions & 3 deletions arrow-fx-rx2/src/test/kotlin/arrow/fx/ObservableKTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ import arrow.fx.rx2.fix
import arrow.fx.rx2.k
import arrow.fx.rx2.value
import arrow.fx.typeclasses.ExitCase
import arrow.test.generators.GenK
import arrow.test.generators.throwable
import arrow.test.laws.ConcurrentLaws
import arrow.core.test.generators.GenK
import arrow.core.test.generators.throwable
import arrow.fx.test.laws.ConcurrentLaws
import arrow.typeclasses.Eq
import arrow.typeclasses.EqK
import io.kotlintest.properties.Gen
Expand Down
2 changes: 1 addition & 1 deletion arrow-fx-rx2/src/test/kotlin/arrow/fx/RxJavaSpec.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package arrow.fx

import arrow.test.UnitSpec
import arrow.core.test.UnitSpec
import io.kotlintest.Spec
import io.reactivex.plugins.RxJavaPlugins

Expand Down
14 changes: 7 additions & 7 deletions arrow-fx-rx2/src/test/kotlin/arrow/fx/SingleKTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ import arrow.fx.rx2.k
import arrow.fx.rx2.unsafeRunSync
import arrow.fx.rx2.value
import arrow.fx.typeclasses.ExitCase
import arrow.test.generators.GenK
import arrow.test.generators.throwable
import arrow.test.laws.ConcurrentLaws
import arrow.test.laws.forFew
import arrow.core.test.generators.GenK
import arrow.core.test.generators.throwable
import arrow.fx.test.laws.ConcurrentLaws
import arrow.fx.test.laws.forFew
import arrow.typeclasses.Eq
import arrow.typeclasses.EqK
import io.kotlintest.properties.Gen
Expand Down Expand Up @@ -55,9 +55,9 @@ class SingleKTests : RxJavaSpec() {
"Multi-thread Singles finish correctly" {
forFew(10, Gen.choose(10L, 50)) { delay ->
SingleK.fx {
val a = Single.timer(delay, TimeUnit.MILLISECONDS).k().bind()
a
}.value()
val a = Single.timer(delay, TimeUnit.MILLISECONDS).k().bind()
a
}.value()
.test()
.awaitDone(delay + awaitDelay, TimeUnit.MILLISECONDS)
.assertTerminated()
Expand Down
9 changes: 3 additions & 6 deletions arrow-fx-test/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
plugins {
id "maven-publish"
id "base"
id "org.jetbrains.kotlin.jvm"
id "org.jetbrains.kotlin.kapt"
Expand All @@ -8,15 +9,11 @@ plugins {
}

apply from: "$SUBPROJECT_CONF"
apply from: "$PUBLISH_CONF"

dependencies {
compile project(":arrow-fx")
compile "io.arrow-kt:arrow-core-test:$VERSION_NAME", excludeArrow
compile "io.arrow-kt:arrow-mtl:$VERSION_NAME", excludeArrow
compile "io.arrow-kt:arrow-mtl-data:$VERSION_NAME", excludeArrow
compile "io.arrow-kt:arrow-free:$VERSION_NAME", excludeArrow
compile "io.arrow-kt:arrow-free-data:$VERSION_NAME", excludeArrow
compile "io.arrow-kt:arrow-recursion-data:$VERSION_NAME", excludeArrow
api "io.arrow-kt:arrow-core-test:$VERSION_NAME", excludeArrow
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$KOTLIN_VERSION"
compile "org.jetbrains.kotlinx:kotlinx-coroutines-core:$KOTLINX_COROUTINES_VERSION"
Copy link
Member

Choose a reason for hiding this comment

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

Created #93 for the removal of this dependency. This is low priority so not blocking for 0.10.x

testRuntime "org.junit.vintage:junit-vintage-engine:$JUNIT_VINTAGE_VERSION"
Expand Down
65 changes: 65 additions & 0 deletions arrow-fx-test/src/main/kotlin/arrow/fx/test/eq/EqK.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package arrow.fx.test.eq

import arrow.Kind
import arrow.core.extensions.either.eq.eq
import arrow.fx.DecisionPartialOf
import arrow.fx.ForIO
import arrow.fx.IO
import arrow.fx.Schedule
import arrow.fx.extensions.io.applicative.applicative
import arrow.fx.extensions.io.applicativeError.attempt
import arrow.fx.extensions.io.concurrent.waitFor
import arrow.fx.fix
import arrow.fx.typeclasses.Duration
import arrow.fx.typeclasses.Fiber
import arrow.fx.typeclasses.FiberOf
import arrow.fx.typeclasses.FiberPartialOf
import arrow.fx.typeclasses.fix
import arrow.fx.typeclasses.seconds
import arrow.typeclasses.Eq
import arrow.typeclasses.EqK

fun <A> IO.Companion.eq(EQA: Eq<A> = Eq.any(), timeout: Duration = 5.seconds): Eq<Kind<ForIO, A>> = Eq { a, b ->
arrow.core.Either.eq(Eq.any(), EQA).run {
IO.applicative().mapN(a.attempt(), b.attempt()) { (a, b) -> a.eqv(b) }
.waitFor(timeout)
.unsafeRunSync()
}
}

fun IO.Companion.eqK() = object : EqK<ForIO> {
override fun <A> Kind<ForIO, A>.eqK(other: Kind<ForIO, A>, EQ: Eq<A>): Boolean = eq(EQ).run {
fix().eqv(other.fix())
}
}

fun <F, A> Fiber.Companion.eq(EQ: Eq<Kind<F, A>>): Eq<FiberOf<F, A>> = object : Eq<FiberOf<F, A>> {
override fun FiberOf<F, A>.eqv(b: FiberOf<F, A>): Boolean = EQ.run {
fix().join().eqv(b.fix().join())
}
}

fun Fiber.Companion.eqK() = object : EqK<FiberPartialOf<ForIO>> {
override fun <A> Kind<FiberPartialOf<ForIO>, A>.eqK(other: Kind<FiberPartialOf<ForIO>, A>, EQ: Eq<A>): Boolean =
IO.eq<A>().run {
fix().join().eqv(other.fix().join())
}
}

/**
* Comparing Throwable is not safe due to their structure (stacktrace),
* so we structurally compare type and message instead.
*/
fun throwableEq() = Eq { a: Throwable, b ->
a::class == b::class && a.message == b.message
}

fun Schedule.Decision.Companion.eqK(): EqK<DecisionPartialOf<Any?>> = object : EqK<DecisionPartialOf<Any?>> {
override fun <A> Kind<DecisionPartialOf<Any?>, A>.eqK(other: Kind<DecisionPartialOf<Any?>, A>, EQ: Eq<A>): Boolean =
(fix() to other.fix()).let { (l, r) ->
l.cont == r.cont &&
l.delay.nanoseconds == r.delay.nanoseconds &&
// don't force end result if we don't continue as it may contain Nothing
(if (l.cont) EQ.run { l.finish.value().eqv(r.finish.value()) } else true)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package arrow.fx.test.generators

import arrow.Kind
import arrow.core.Eval
import arrow.core.test.generators.GenK
import arrow.core.test.generators.intSmall
import arrow.core.test.generators.throwable
import arrow.fx.DecisionPartialOf
import arrow.fx.ForIO
import arrow.fx.IO
import arrow.fx.Schedule
import arrow.fx.typeclasses.Fiber
import arrow.fx.typeclasses.FiberPartialOf
import arrow.fx.typeclasses.nanoseconds
import arrow.typeclasses.Applicative
import arrow.typeclasses.ApplicativeError
import io.kotlintest.properties.Gen
import java.util.concurrent.TimeUnit

fun <F, A, E> Gen<E>.raiseError(AP: ApplicativeError<F, E>): Gen<Kind<F, A>> =
map { AP.raiseError<A>(it) }

fun Gen.Companion.timeUnit(): Gen<TimeUnit> = Gen.from(TimeUnit.values())

fun IO.Companion.genK() = object : GenK<ForIO> {
override fun <A> genK(gen: Gen<A>): Gen<Kind<ForIO, A>> = Gen.oneOf(
gen.map(IO.Companion::just),
Gen.throwable().map(IO.Companion::raiseError)
)
}

fun <F> Fiber.Companion.genK(A: Applicative<F>) = object : GenK<FiberPartialOf<F>> {
override fun <A> genK(gen: Gen<A>): Gen<Kind<FiberPartialOf<F>, A>> = gen.map {
Fiber(A.just(it), A.just(Unit))
}
}

fun Schedule.Decision.Companion.genK(): GenK<DecisionPartialOf<Any?>> = object : GenK<DecisionPartialOf<Any?>> {
override fun <A> genK(gen: Gen<A>): Gen<Kind<DecisionPartialOf<Any?>, A>> =
Gen.bind(
Gen.bool(),
Gen.intSmall(),
gen
) { cont, delay, res -> Schedule.Decision(cont, delay.nanoseconds, 0 as Any?, Eval.now(res)) }
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
package arrow.test.laws
package arrow.fx.test.laws

import arrow.Kind
import arrow.core.Either
import arrow.core.Left
import arrow.core.Right
import arrow.core.extensions.eq
import arrow.core.internal.AtomicBooleanW
import arrow.core.test.generators.GenK
import arrow.core.test.generators.applicativeError
import arrow.core.test.generators.either
import arrow.core.test.generators.functionAToB
import arrow.core.test.generators.functionToA
import arrow.core.test.generators.intSmall
import arrow.core.test.generators.throwable
import arrow.core.test.laws.Law
import arrow.fx.Promise
import arrow.fx.typeclasses.Async
import arrow.fx.typeclasses.ExitCase
import arrow.test.generators.GenK
import arrow.test.generators.applicativeError
import arrow.test.generators.either
import arrow.test.generators.functionAToB
import arrow.test.generators.functionToA
import arrow.test.generators.intSmall
import arrow.test.generators.throwable
import arrow.typeclasses.Apply
import arrow.typeclasses.Eq
import arrow.typeclasses.EqK
Expand Down Expand Up @@ -186,9 +187,9 @@ object AsyncLaws {
forFew(5, Gen.intSmall()) { threadId1: Int ->
val ctx = newSingleThreadContext(threadId1.toString())
fx.async {
continueOn(ctx)
getCurrentThread()
}
continueOn(ctx)
getCurrentThread()
}
.equalUnderTheLaw(fx.async { ctx.shift().bind(); getCurrentThread() }, EQ)
}

Expand Down
Loading