Thanks to visit codestin.com
Credit goes to github.com

Skip to content
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
26 changes: 19 additions & 7 deletions test/shared/src/main/scala/zio/test/mock/TestClock.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,24 @@ import zio.clock.Clock
import zio.test.mock.TestClock.Data
import java.time.{ Instant, OffsetDateTime }

case class TestClock(ref: Ref[TestClock.Data]) extends Clock.Service[Any] {
case class TestClock(clockState: Ref[TestClock.Data]) extends Clock.Service[Any] {

final def currentTime(unit: TimeUnit): UIO[Long] =
ref.get.map(data => unit.convert(data.currentTimeMillis, TimeUnit.MILLISECONDS))
clockState.get.map(data => unit.convert(data.currentTimeMillis, TimeUnit.MILLISECONDS))

final def currentDateTime: UIO[OffsetDateTime] =
ref.get.map(data => TestClock.offset(data.currentTimeMillis, data.timeZone))
clockState.get.map(data => TestClock.offset(data.currentTimeMillis, data.timeZone))

final val nanoTime: IO[Nothing, Long] =
ref.get.map(_.nanoTime)
clockState.get.map(_.nanoTime)

final def sleep(duration: Duration): UIO[Unit] =
adjust(duration) *> ref.update(data => data.copy(sleeps0 = duration :: data.sleeps0)).unit
adjust(duration) *> clockState.update(data => data.copy(sleeps0 = duration :: data.sleeps0)).unit

val sleeps: UIO[List[Duration]] = ref.get.map(_.sleeps0.reverse)
val sleeps: UIO[List[Duration]] = clockState.get.map(_.sleeps0.reverse)

final def adjust(duration: Duration): UIO[Unit] =
ref.update { data =>
clockState.update { data =>
Data(
data.nanoTime + duration.toNanos,
data.currentTimeMillis + duration.toMillis,
Expand All @@ -51,9 +51,21 @@ case class TestClock(ref: Ref[TestClock.Data]) extends Clock.Service[Any] {
)
}.unit

final def setTime(duration: Duration): UIO[Unit] =
clockState.update(_.copy(nanoTime = duration.toNanos, currentTimeMillis = duration.toMillis)).unit

final def setTimeZone(zone: ZoneId): UIO[Unit] =
clockState.update(_.copy(timeZone = zone)).unit

val timeZone: UIO[ZoneId] =
clockState.get.map(_.timeZone)
}

object TestClock {

def make(data: Data): UIO[TestClock] =
Ref.make(data).map(TestClock(_))

val DefaultData = Data(0, 0, Nil, ZoneId.of("UTC"))

def offset(millis: Long, timeZone: ZoneId): OffsetDateTime =
Expand Down
27 changes: 22 additions & 5 deletions test/shared/src/main/scala/zio/test/mock/TestConsole.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,32 +23,49 @@ import zio.console._
import zio._
import TestConsole.Data

case class TestConsole(ref: Ref[TestConsole.Data]) extends Console.Service[Any] {
case class TestConsole(consoleState: Ref[TestConsole.Data]) extends Console.Service[Any] {

override def putStr(line: String): UIO[Unit] =
ref.update { data =>
consoleState.update { data =>
Data(data.input, data.output :+ line)
}.unit

override def putStrLn(line: String): ZIO[Any, Nothing, Unit] =
ref.update { data =>
consoleState.update { data =>
Data(data.input, data.output :+ s"$line\n")
}.unit

val getStrLn: ZIO[Any, IOException, String] = {
for {
input <- ref.get.flatMap(
input <- consoleState.get.flatMap(
d =>
IO.fromOption(d.input.headOption)
.mapError(_ => new EOFException("There is no more input left to read"))
)
_ <- ref.update { data =>
_ <- consoleState.update { data =>
Data(data.input.tail, data.output)
}
} yield input
}

def feedLines(lines: String*): UIO[Unit] =
consoleState.update(data => data.copy(input = lines.toList ::: data.input)).unit

val output: UIO[Vector[String]] =
Copy link
Member

Choose a reason for hiding this comment

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

This is good. Probably good to add a clearOutput, too, and maybe clearInput.

consoleState.get.map(_.output)

val clearInput: UIO[Unit] =
consoleState.update(data => data.copy(input = List.empty)).unit

val clearOutput: UIO[Unit] =
consoleState.update(data => data.copy(output = Vector.empty)).unit
}

object TestConsole {

def make(data: Data): UIO[TestConsole] =
Ref.make(data).map(TestConsole(_))

val DefaultData: Data = Data(Nil, Vector())

case class Data(input: List[String] = List.empty, output: Vector[String] = Vector.empty)
Expand Down
57 changes: 54 additions & 3 deletions test/shared/src/main/scala/zio/test/mock/TestRandom.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import zio._
import zio.random.Random
import zio.test.mock.TestRandom.Data

final case class TestRandom(ref: Ref[TestRandom.Data]) extends Random.Service[Any] {
final case class TestRandom(randomState: Ref[TestRandom.Data]) extends Random.Service[Any] {

val nextBoolean: UIO[Boolean] = nextRandom(shiftBooleans)

Expand All @@ -44,11 +44,59 @@ final case class TestRandom(ref: Ref[TestRandom.Data]) extends Random.Service[An

def shuffle[A](list: List[A]): UIO[List[A]] = Random.shuffleWith(nextInt, list)

def feedInts(ints: Int*): UIO[Unit] =
randomState.update(data => data.copy(integers = ints.toList ::: data.integers)).unit

def feedBooleans(booleans: Boolean*): UIO[Unit] =
randomState.update(data => data.copy(booleans = booleans.toList ::: data.booleans)).unit

def feedDoubles(doubles: Double*): UIO[Unit] =
randomState.update(data => data.copy(doubles = doubles.toList ::: data.doubles)).unit

def feedFloats(floats: Float*): UIO[Unit] =
randomState.update(data => data.copy(floats = floats.toList ::: data.floats)).unit

def feedLongs(longs: Long*): UIO[Unit] =
randomState.update(data => data.copy(longs = longs.toList ::: data.longs)).unit

def feedChars(chars: Char*): UIO[Unit] =
randomState.update(data => data.copy(chars = chars.toList ::: data.chars)).unit

def feedStrings(strings: String*): UIO[Unit] =
randomState.update(data => data.copy(strings = strings.toList ::: data.strings)).unit

def feedBytes(bytes: Chunk[Byte]*): UIO[Unit] =
randomState.update(data => data.copy(bytes = bytes.toList ::: data.bytes)).unit

val clearInts: UIO[Unit] =
randomState.update(data => data.copy(integers = List.empty)).unit

val clearBooleans: UIO[Unit] =
randomState.update(data => data.copy(booleans = List.empty)).unit

val clearDoubles: UIO[Unit] =
randomState.update(data => data.copy(doubles = List.empty)).unit

val clearFloats: UIO[Unit] =
randomState.update(data => data.copy(floats = List.empty)).unit

val clearLongs: UIO[Unit] =
randomState.update(data => data.copy(longs = List.empty)).unit

val clearChars: UIO[Unit] =
randomState.update(data => data.copy(chars = List.empty)).unit

val clearStrings: UIO[Unit] =
randomState.update(data => data.copy(strings = List.empty)).unit

val clearBytes: UIO[Unit] =
randomState.update(data => data.copy(bytes = List.empty)).unit

private def nextRandom[T](shift: Data => (T, Data)) =
for {
data <- ref.get
data <- randomState.get
(next, shifted) = shift(data)
_ <- ref.update(_ => shifted)
_ <- randomState.update(_ => shifted)
} yield next

private def shiftBooleans(data: Data) =
Expand Down Expand Up @@ -93,6 +141,9 @@ final case class TestRandom(ref: Ref[TestRandom.Data]) extends Random.Service[An
object TestRandom {
val DefaultData: Data = Data()

def make(data: Data): UIO[TestRandom] =
Ref.make(data).map(TestRandom(_))

val defaultInteger = 1
val randomIntegers = defaultInteger :: 2 :: 3 :: 4 :: 5 :: Nil
val defaultBoolean = true
Expand Down
25 changes: 20 additions & 5 deletions test/shared/src/main/scala/zio/test/mock/TestSystem.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,37 @@ package zio.test.mock
import zio.{ Ref, UIO, ZIO }
import zio.system.System

case class TestSystem(ref: Ref[TestSystem.Data]) extends System.Service[Any] {
case class TestSystem(systemState: Ref[TestSystem.Data]) extends System.Service[Any] {

override def env(variable: String): ZIO[Any, SecurityException, Option[String]] =
ref.get.map(_.envs.get(variable))
systemState.get.map(_.envs.get(variable))

override def property(prop: String): ZIO[Any, Throwable, Option[String]] =
ref.get.map(_.properties.get(prop))
systemState.get.map(_.properties.get(prop))

override val lineSeparator: ZIO[Any, Nothing, String] =
ref.get.map(_.lineSeparator)
systemState.get.map(_.lineSeparator)

def putEnv(name: String, value: String): UIO[Unit] =
systemState.update(data => data.copy(envs = data.envs.updated(name, value))).unit

def putProperty(name: String, value: String): UIO[Unit] =
Copy link
Member

Choose a reason for hiding this comment

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

Great, and probably useful to make a clearEnv / clearProperty, as well.

systemState.update(data => data.copy(properties = data.properties.updated(name, value))).unit

def setLineSeparator(lineSep: String): UIO[Unit] =
systemState.update(_.copy(lineSeparator = lineSep)).unit

def clearEnv(variable: String): UIO[Unit] =
systemState.update(data => data.copy(envs = data.envs - variable)).unit

def clearProperty(prop: String): UIO[Unit] =
systemState.update(data => data.copy(properties = data.properties - prop)).unit
}

object TestSystem {
val DefaultData: Data = Data(Map(), Map(), "\n")

def apply(data: Data): UIO[TestSystem] =
def make(data: Data): UIO[TestSystem] =
Ref.make(data).map(TestSystem(_))

case class Data(
Expand Down
Loading