Skip to content

Commit

Permalink
Merge pull request #16 from scottweaver/zio-2.0-RC4
Browse files Browse the repository at this point in the history
[WIP] First pass at ZIO 2.0 RC4 compatibility.
  • Loading branch information
vigoo committed Apr 9, 2022
2 parents 00df7e8 + 9633576 commit e437c0a
Show file tree
Hide file tree
Showing 25 changed files with 1,526 additions and 765 deletions.
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ addCommandAlias(
";mockNative/compile"
)

val zioVersion = "2.0.0-RC3"
val zioVersion = "2.0.0-RC5"

lazy val root = (project in file("."))
.aggregate(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ import zio.test.Assertion
import zio.{Clock, Console, ZIO}

import java.io.IOException
import zio.test.{Spec, TestFailure, TestSuccess}
import zio.test._

object ComposedEmptyMockSpec extends ZIOBaseSpec with MockSpecUtils[ComposedEmptyMockSpecCompat.Environment] {
object ComposedEmptyMockSpec extends ZIOBaseSpec {

import Assertion._
import Expectation._
import MockException._
import testing._

def branchingProgram(predicate: Boolean): ZIO[Console with Clock, IOException, Unit] =
def branchingProgram(predicate: Boolean): ZIO[Any, IOException, Unit] =
ZIO
.succeed(predicate)
.flatMap {
Expand All @@ -22,47 +23,48 @@ object ComposedEmptyMockSpec extends ZIOBaseSpec with MockSpecUtils[ComposedEmpt
}
.unit

def spec: Spec[Any, TestFailure[Any], TestSuccess] = suite("ComposedEmptyMockSpec")(
def spec = suite("ComposedEmptyMockSpec")(
suite("expect no calls on empty mocks")(
testValue("should succeed when no calls on Console")(
MockConsole.empty ++ MockClock.NanoTime(value(42L)),
branchingProgram(false),
isUnit
), {
test("should succeed when no calls on Console") {
branchingProgram(false).as(assertTrue(true))
} @@ TestAspects.withEnv(
(MockConsole.empty ++ MockClock.NanoTime(value(42L))).build
),
test("should fail when call on Console happened") {
type M = Capability[Console, Unit, IOException, String]
type X = UnexpectedCallException[Console, Unit, IOException, String]

testDied("should fail when call on Console happened")(
MockConsole.empty ++ MockClock.NanoTime(value(42L)),
branchingProgram(true),
isSubtype[X](
hasField[X, M]("capability", _.capability, equalTo(MockConsole.ReadLine)) &&
hasField[X, Any]("args", _.args, equalTo(()))
swapFailure(branchingProgram(true)).map { e =>
assert(e)(
isSubtype[X](
hasField[X, M]("capability", _.capability, equalTo(MockConsole.ReadLine)) &&
hasField[X, Any]("args", _.args, equalTo(()))
)
)
)
},
testValue("should succeed when no calls on Clock")(
MockClock.empty ++ MockConsole.ReadLine(value("foo")),
branchingProgram(true),
isUnit
), {
}
} @@ TestAspects.withEnv(
(MockConsole.empty ++ MockClock.empty).build
),
test("should succeed when no calls on Clock") {
branchingProgram(true).as(assertTrue(true))
} @@ TestAspects.withEnv(
(MockClock.empty ++ MockConsole.ReadLine(value("foo"))).build
),
test("should fail when call on Clock happened") {

type M = Capability[Clock, Unit, Nothing, Long]
type X = UnexpectedCallException[Clock, Unit, Nothing, Long]

testDied("should fail when call on Clock happened")(
MockClock.empty ++ MockConsole.ReadLine(value("foo")),
branchingProgram(false),
isSubtype[X](
hasField[X, M]("capability", _.capability, equalTo(MockClock.NanoTime)) &&
hasField[X, Any]("args", _.args, equalTo(()))
swapFailure(branchingProgram(false)).map { e =>
assert(e)(
isSubtype[X](
hasField[X, M]("capability", _.capability, equalTo(MockClock.NanoTime)) &&
hasField[X, Any]("args", _.args, equalTo(()))
)
)
)
}
}
} @@ TestAspects.withEnv(
(MockClock.empty ++ MockConsole.empty).build
)
)
)
}

object ComposedEmptyMockSpecCompat {
type Environment = Console with Clock
}
73 changes: 25 additions & 48 deletions mock-tests/shared/src/test/scala/zio/mock/ComposedMockSpec.scala
Original file line number Diff line number Diff line change
@@ -1,62 +1,39 @@
package zio.mock

import zio._
import zio.test.{Assertion, assertM}

import java.io.IOException
import zio.test._

object ComposedMockSpec extends ZIOBaseSpec {

import Assertion._
import Expectation._

private def testValueComposed[R1: EnvironmentTag, E, A](name: String)(
mock: ULayer[R1],
app: ZIO[R1, E, A],
check: Assertion[A]
) = test(name) {
val result = ZIO.scoped[Any](mock.build.flatMap(app.provideEnvironment(_)))
assertM(result)(check)
}

def spec = suite("ComposedMockSpec")(
suite("mocking composed environments")(
{
val cmd1 = MockClock.NanoTime(value(42L))
val cmd2 = MockConsole.PrintLine(equalTo("42"), unit)
val composed = cmd1 ++ cmd2

val program =
for {
time <- Clock.nanoTime
_ <- Console.printLine(time.toString)
} yield ()

testValueComposed[Clock with Console, IOException, Unit]("Console with Clock")(
composed,
program,
isUnit
)
}, {
val cmd1 = MockRandom.NextInt(value(42))
val cmd2 = MockClock.Sleep(equalTo(42.seconds))
val cmd3 = MockSystem.Property(equalTo("foo"), value(None))
val cmd4 = MockConsole.PrintLine(equalTo("None"), unit)

val composed = cmd1 ++ cmd2 ++ cmd3 ++ cmd4

val program =
for {
n <- Random.nextInt
_ <- Clock.sleep(n.seconds)
v <- System.property("foo")
_ <- Console.printLine(v.toString)
} yield ()

testValueComposed[Random with Clock with System with Console, Throwable, Unit](
"Random with Clock with System with Console"
)(composed, program, isUnit)
}
test("Console with Clock") {
for {
time <- Clock.nanoTime
_ <- Console.printLine(time.toString)
} yield (assertTrue(true))

} @@ TestAspects.withExpectationsAsEnv(
MockClock.NanoTime(value(42L)) ++
MockConsole.PrintLine(equalTo("42"), unit)
),
test("Random with Clock with System with Console") {

for {
n <- Random.nextInt
_ <- Clock.sleep(n.seconds)
v <- System.property("foo")
_ <- Console.printLine(v.toString)
} yield (assertTrue(true))
} @@ TestAspects.withExpectationsAsEnv(
MockRandom.NextInt(value(42)) ++
MockClock.Sleep(equalTo(42.seconds)) ++
MockSystem.Property(equalTo("foo"), value(None)) ++
MockConsole.PrintLine(equalTo("None"), unit)
)
)
)
}
32 changes: 17 additions & 15 deletions mock-tests/shared/src/test/scala/zio/mock/EmptyMockSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,35 @@ import zio.mock.internal.MockException
import zio.test.Assertion

import java.io.IOException
import zio.test.{Spec, TestFailure, TestSuccess}
import zio.test._
import testing._

object EmptyMockSpec extends ZIOBaseSpec with MockSpecUtils[Console] {
object EmptyMockSpec extends ZIOBaseSpec {

import Assertion._
import MockException._

def spec: Spec[Any, TestFailure[Any], TestSuccess] = suite("EmptyMockSpec")(
def spec = suite("EmptyMockSpec")(
suite("expect no calls on empty mocks")(
testValue("should succeed when no call")(
MockConsole.empty,
ZIO.when(false)(Console.printLine("foo")).unit,
isUnit
), {
test("should succeed when no call") {
ZIO.when(false)(Console.printLine("foo")).as(assertTrue(true))
},
test("should fail when call happened") {

type M = Capability[Console, Any, IOException, Unit]
type X = UnexpectedCallException[Console, Any, IOException, Unit]

testDied("should fail when call happened")(
MockConsole.empty,
ZIO.when(true)(Console.printLine("foo")),
isSubtype[X](
hasField[X, M]("capability", _.capability, equalTo(MockConsole.PrintLine)) &&
hasField[X, Any]("args", _.args, equalTo("foo"))
swapFailure(ZIO.when(true)(Console.printLine("foo"))).map { e =>
assert(e)(
isSubtype[X](
hasField[X, M]("capability", _.capability, equalTo(MockConsole.PrintLine)) &&
hasField[X, Any]("args", _.args, equalTo("foo"))
)
)
)
}
}
) @@ TestAspects.withEnv(
MockConsole.empty.build
)
)
}
18 changes: 10 additions & 8 deletions mock-tests/shared/src/test/scala/zio/mock/MockSpecUtils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package zio.mock
import zio._
import zio.mock.module.T22
import zio.test.{Assertion, Live, ZSpec, assertM, test}
import testing._

trait MockSpecUtils[R] {

Expand Down Expand Up @@ -49,16 +50,17 @@ trait MockSpecUtils[R] {
app: ZIO[R, E, A],
check: Assertion[Throwable]
): ZSpec[Any, Any] = test(name) {

val result: IO[Any, Throwable] =
ZIO
.scoped {
mock.build
.flatMap(app.provideEnvironment(_))
}
.orElse(ZIO.unit)
.absorb
.flip
swapFailure(
ZIO
.scoped {
mock.build
.flatMap(app.provideEnvironment(_))
}
)

assertM(result)(check)
}

}
105 changes: 44 additions & 61 deletions mock-tests/shared/src/test/scala/zio/mock/MockTestReporterSpec.scala
Original file line number Diff line number Diff line change
@@ -1,72 +1,55 @@
package zio.mock

import zio.Scope
import zio.mock.ReportingTestUtils._
import zio.test.Assertion._
import zio.test.TestAspect._
import zio.test._

object MockTestReporterSpec extends ZIOBaseSpec {

def spec: ZSpec[
Annotations
with Live
with Sized
with TestClock
with TestConfig
with TestConsole
with TestRandom
with TestSystem
with Scope,
Any
] =
def spec =
suite("MockTestReporterSpec")(
test("correctly reports a successful test") {
assertM(runLog(test1))(equalTo(test1Expected.mkString + reportStats(1, 0, 0)))
},
test("correctly reports a failed test") {
assertM(runLog(test3))(equalTo(test3Expected.mkString + "\n" + reportStats(0, 0, 1)))
},
test("correctly reports an error in a test") {
for {
log <- runLog(test4)
} yield assertTrue(log.contains("Test 4 Fail"))
},
test("correctly reports successful test suite") {
assertM(runLog(suite1))(equalTo(suite1Expected.mkString + reportStats(2, 0, 0)))
},
test("correctly reports failed test suite") {
assertM(runLog(suite2))(equalTo(suite2Expected.mkString + "\n" + reportStats(2, 0, 1)))
},
test("correctly reports multiple test suites") {
assertM(runLog(suite3))(equalTo(suite3Expected.mkString + "\n" + reportStats(4, 0, 2)))
},
test("correctly reports empty test suite") {
assertM(runLog(suite4))(equalTo(suite4Expected.mkString + "\n" + reportStats(2, 0, 1)))
},
test("correctly reports failure of simple assertion") {
assertM(runLog(test5))(equalTo(test5Expected.mkString + "\n" + reportStats(0, 0, 1)))
},
test("correctly reports multiple nested failures") {
assertM(runLog(test6))(equalTo(test6Expected.mkString + "\n" + reportStats(0, 0, 1)))
},
test("correctly reports labeled failures") {
assertM(runLog(test7))(equalTo(test7Expected.mkString + "\n" + reportStats(0, 0, 1)))
},
test("correctly reports negated failures") {
assertM(runLog(test8))(equalTo(test8Expected.mkString + "\n" + reportStats(0, 0, 1)))
},
test("correctly reports mock failure of invalid call") {
runLog(mock1).map(str => assertTrue(str == mock1Expected.mkString + reportStats(0, 0, 1)))
},
test("correctly reports mock failure of unmet expectations") {
runLog(mock2).map(str => assertTrue(str == mock2Expected.mkString + reportStats(0, 0, 1)))
},
test("correctly reports mock failure of unexpected call") {
assertM(runLog(mock3))(equalTo(mock3Expected.mkString + reportStats(0, 0, 1)))
},
test("correctly reports mock failure of invalid range") {
assertM(runLog(mock4))(equalTo(mock4Expected.mkString + reportStats(0, 0, 1)))
}
suite("reports")(
test("a successful test") {
runLog(test1).map(res => assertTrue(test1Expected == res))
},
test("a failed test") {
runLog(test3).map(res => test3Expected.map(expected => assertTrue(res.contains(expected))).reduce(_ && _))
},
test("an error in a test") {
runLog(test4).map(log => assertTrue(log.contains("Test 4 Fail")))
} @@ ignore,
test("successful test suite") {
runLog(suite1).map(res => suite1Expected.map(expected => assertTrue(res.contains(expected))).reduce(_ && _))
},
test("failed test suite") {
runLog(suite2).map(res => suite2Expected.map(expected => assertTrue(res.contains(expected))).reduce(_ && _))
},
test("multiple test suites") {
runLog(suite3).map(res => suite3Expected.map(expected => assertTrue(res.contains(expected))).reduce(_ && _))
},
test("empty test suite") {
runLog(suite4).map(res => suite4Expected.map(expected => assertTrue(res.contains(expected))).reduce(_ && _))
},
test("failure of simple assertion") {
runLog(test5).map(res => test5Expected.map(expected => assertTrue(res.contains(expected))).reduce(_ && _))
},
test("multiple nested failures") {
runLog(test6).map(res => test6Expected.map(expected => assertTrue(res.contains(expected))).reduce(_ && _))
},
test("labeled failures") {
runLog(test7).map(res => test7Expected.map(expected => assertTrue(res.contains(expected))).reduce(_ && _))
},
test("labeled failures for assertTrue") {
for {
log <- runLog(test9)
} yield assertTrue(log.contains("""?? "third""""), log.contains("""?? "fourth""""))
},
test("negated failures") {
runLog(test8).map(res => test8Expected.map(expected => assertTrue(res.contains(expected))).reduce(_ && _))
}
// test("correctly reports mock failure of invalid call") {
// runLog(mock1).map(str => assertTrue(str == mock1Expected.mkString + reportStats(0, 0, 1)))
// }
)
) @@ silent
}
Loading

0 comments on commit e437c0a

Please sign in to comment.