Skip to content

Commit

Permalink
Merge pull request #707 from ceedubs/statet-tests
Browse files Browse the repository at this point in the history
Add some StateT/State tests
  • Loading branch information
stew committed Dec 4, 2015
2 parents f5972f5 + e4e4618 commit 7891cd8
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 19 deletions.
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ lazy val freeJVM = free.jvm
lazy val freeJS = free.js

lazy val state = crossProject.crossType(CrossType.Pure)
.dependsOn(macros, core, free, tests % "test-internal -> test")
.dependsOn(macros, core, free % "compile-internal;test-internal -> test", tests % "test-internal -> test")
.settings(moduleName := "cats-state")
.settings(catsSettings:_*)
.jsSettings(commonJsSettings:_*)
Expand Down
38 changes: 26 additions & 12 deletions free/src/test/scala/cats/free/FreeTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,11 @@ package free
import cats.arrow.NaturalTransformation
import cats.tests.CatsSuite
import cats.laws.discipline.{MonadTests, SerializableTests}
import cats.laws.discipline.arbitrary.function0Arbitrary
import org.scalacheck.{Arbitrary, Gen}

class FreeTests extends CatsSuite {

implicit def freeArbitrary[F[_], A](implicit F: Arbitrary[F[A]], A: Arbitrary[A]): Arbitrary[Free[F, A]] =
Arbitrary(
Gen.oneOf(
A.arbitrary.map(Free.pure[F, A]),
F.arbitrary.map(Free.liftF[F, A])))

implicit def freeEq[S[_]: Monad, A](implicit SA: Eq[S[A]]): Eq[Free[S, A]] =
new Eq[Free[S, A]] {
def eqv(a: Free[S, A], b: Free[S, A]): Boolean =
SA.eqv(a.runM(identity), b.runM(identity))
}
import FreeTests._

checkAll("Free[Option, ?]", MonadTests[Free[Option, ?]].monad[Int, Int, Int])
checkAll("Monad[Free[Option, ?]]", SerializableTests.serializable(Monad[Free[Option, ?]]))
Expand Down Expand Up @@ -51,3 +41,27 @@ class FreeTests extends CatsSuite {
assert(10000 == a(0).foldMap(runner))
}
}

object FreeTests extends FreeTestsInstances {
import cats.std.function._

implicit def trampolineArbitrary[A:Arbitrary]: Arbitrary[Trampoline[A]] =
freeArbitrary[Function0, A]

implicit def trampolineEq[A:Eq]: Eq[Trampoline[A]] =
freeEq[Function0, A]
}

sealed trait FreeTestsInstances {
implicit def freeArbitrary[F[_], A](implicit F: Arbitrary[F[A]], A: Arbitrary[A]): Arbitrary[Free[F, A]] =
Arbitrary(
Gen.oneOf(
A.arbitrary.map(Free.pure[F, A]),
F.arbitrary.map(Free.liftF[F, A])))

implicit def freeEq[S[_]: Monad, A](implicit SA: Eq[S[A]]): Eq[Free[S, A]] =
new Eq[Free[S, A]] {
def eqv(a: Free[S, A], b: Free[S, A]): Boolean =
SA.eqv(a.runM(identity), b.runM(identity))
}
}
2 changes: 2 additions & 0 deletions laws/src/main/scala/cats/laws/discipline/Arbitrary.scala
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ object arbitrary extends ArbitraryInstances0 {
implicit def showArbitrary[A: Arbitrary]: Arbitrary[Show[A]] =
Arbitrary(Show.fromToString[A])

implicit def function0Arbitrary[A: Arbitrary]: Arbitrary[() => A] =
Arbitrary(getArbitrary[A].map(() => _))
}

private[discipline] sealed trait ArbitraryInstances0 {
Expand Down
58 changes: 53 additions & 5 deletions state/src/test/scala/cats/state/StateTTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cats
package state

import cats.tests.CatsSuite
import cats.free.FreeTests._
import cats.laws.discipline.{MonadStateTests, MonoidKTests, SerializableTests}
import cats.laws.discipline.eq._
import org.scalacheck.{Arbitrary, Gen}
Expand Down Expand Up @@ -39,18 +40,65 @@ class StateTTests extends CatsSuite {
}
}

test("runEmpty, runEmptyS, and runEmptyA consistent"){
forAll { (f: StateT[List, Long, Int]) =>
(f.runEmptyS zip f.runEmptyA) should === (f.runEmpty)
}
}

test("modify identity is a noop"){
forAll { (f: StateT[List, Long, Int]) =>
f.modify(identity) should === (f)
}
}

test("modify modifies state"){
forAll { (f: StateT[List, Long, Int], g: Long => Long, initial: Long) =>
f.modify(g).runS(initial) should === (f.runS(initial).map(g))
}
}

test("modify doesn't affect A value"){
forAll { (f: StateT[List, Long, Int], g: Long => Long, initial: Long) =>
f.modify(g).runA(initial) should === (f.runA(initial))
}
}

test("State.modify equivalent to get then set"){
forAll { (f: Long => Long) =>
val s1 = for {
l <- State.get[Long]
_ <- State.set(f(l))
} yield ()

val s2 = State.modify(f)

s1 should === (s2)
}
}

checkAll("StateT[Option, Int, Int]", MonadStateTests[StateT[Option, Int, ?], Int].monadState[Int, Int, Int])
checkAll("MonadState[StateT[Option, ?, ?], Int]", SerializableTests.serializable(MonadState[StateT[Option, Int, ?], Int]))

checkAll("State[Long, ?]", MonadStateTests[State[Long, ?], Long].monadState[Int, Int, Int])
checkAll("MonadState[State[Long, ?], Long]", SerializableTests.serializable(MonadState[State[Long, ?], Long]))
}

object StateTTests {
object StateTTests extends StateTTestsInstances {
implicit def stateEq[S:Eq:Arbitrary, A:Eq]: Eq[State[S, A]] =
stateTEq[free.Trampoline, S, A]

implicit def stateArbitrary[F[_]: Applicative, S, A](implicit F: Arbitrary[S => F[(S, A)]]): Arbitrary[StateT[F, S, A]] =
implicit def stateArbitrary[S: Arbitrary, A: Arbitrary]: Arbitrary[State[S, A]] =
stateTArbitrary[free.Trampoline, S, A]

val add1: State[Int, Int] = State(n => (n + 1, n))
}

sealed trait StateTTestsInstances {
implicit def stateTArbitrary[F[_]: Applicative, S, A](implicit F: Arbitrary[S => F[(S, A)]]): Arbitrary[StateT[F, S, A]] =
Arbitrary(F.arbitrary.map(f => StateT(f)))

implicit def stateEq[F[_], S, A](implicit S: Arbitrary[S], FSA: Eq[F[(S, A)]], F: FlatMap[F]): Eq[StateT[F, S, A]] =
implicit def stateTEq[F[_], S, A](implicit S: Arbitrary[S], FSA: Eq[F[(S, A)]], F: FlatMap[F]): Eq[StateT[F, S, A]] =
Eq.by[StateT[F, S, A], S => F[(S, A)]](state =>
s => state.run(s))

val add1: State[Int, Int] = State(n => (n + 1, n))
}
1 change: 0 additions & 1 deletion tests/src/test/scala/cats/tests/FunctionTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import cats.laws.discipline.arbitrary._
import algebra.laws.GroupLaws

class FunctionTests extends CatsSuite {
implicit def ev0[A: Arbitrary]: Arbitrary[() => A] = Arbitrary(Arbitrary.arbitrary[A].map { a => () => a })
checkAll("Function0[Int]", BimonadTests[Function0].bimonad[Int, Int, Int])
checkAll("Bimonad[Function0]", SerializableTests.serializable(Bimonad[Function0]))

Expand Down

0 comments on commit 7891cd8

Please sign in to comment.