Package

cats.effect.laws

util

Permalink

package util

Visibility
  1. Public
  2. All

Type Members

  1. final class TestContext extends ExecutionContext

    Permalink

    A scala.concurrent.ExecutionContext implementation and a provider of cats.effect.Timer instances, that can simulate async boundaries and time passage, useful for testing purposes.

    A scala.concurrent.ExecutionContext implementation and a provider of cats.effect.Timer instances, that can simulate async boundaries and time passage, useful for testing purposes.

    Usage for simulating an ExecutionContext):

    implicit val ec = TestContext()
    
    ec.execute(new Runnable { def run() = println("task1") })
    
    ex.execute(new Runnable {
      def run() = {
        println("outer")
    
        ec.execute(new Runnable {
          def run() = println("inner")
        })
      }
    })
    
    // Nothing executes until `tick` gets called
    ec.tick()
    
    // Testing the resulting state
    assert(ec.state.tasks.isEmpty)
    assert(ec.state.lastReportedFailure == None)

    Our TestContext can also simulate time passage, as we are able to builds a cats.effect.Timer instance for any data type that has a LiftIO instance:

    val ctx = TestContext()
    
    val timer: Timer[IO] = ctx.timer[IO]

    We can now simulate actual time:

    val io = timer.sleep(10.seconds) *> IO(1 + 1)
    val f = io.unsafeToFuture()
    
    // This invariant holds true, because our IO is async
    assert(f.value == None)
    
    // Not yet completed, because this does not simulate time passing:
    ctx.tick()
    assert(f.value == None)
    
    // Simulating time passing:
    ctx.tick(10.seconds)
    assert(f.value == Some(Success(2))

    Simulating time makes this pretty useful for testing race conditions:

    val never = IO.async[Int](_ => {})
    val timeoutError = new TimeoutException
    val timeout = timer.sleep(10.seconds) *> IO.raiseError[Int](timeoutError)
    
    val pair = (never, timeout).parMapN(_ + _)
    
    // Not yet
    ctx.tick()
    assert(f.value == None)
    // Not yet
    ctx.tick(5.seconds)
    assert(f.value == None)
    
    // Good to go:
    ctx.tick(5.seconds)
    assert(f.value, Some(Failure(timeoutError)))
  2. trait TestInstances extends AnyRef

    Permalink

    Defines instances for Future and for IO, meant for law testing by means of TestContext.

    Defines instances for Future and for IO, meant for law testing by means of TestContext.

    The TestContext interpreter is used here for simulating asynchronous execution.

Value Members

  1. object TestContext

    Permalink
  2. object TestInstances extends TestInstances

    Permalink

Ungrouped