All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.spingo.scoped_fixtures.ScopedFixtures.scala Maven / Gradle / Ivy

The newest version!
package com.spingo.scoped_fixtures

import org.scalatest.{Suite, Status, Args}
import ScopedFixtures._

object ScopedFixtures {
  type ScopedFn[T] = (T => Status) => Status
  sealed abstract class ScopedFixtureException(message: String) extends Exception(message)
  class InvalidForwardReference(fixtureType: TestFixture[Any]) extends ScopedFixtureException(s"Forward referencing of non-lazy ${fixtureType.name}")
  class ReadOutsideOfTestAttempt(fixtureType: TestFixture[Any]) extends ScopedFixtureException(s"Invalid attempt to resolve ${fixtureType.name} outside of a test")
  class DeclarationOutsideOfTestAttempt() extends ScopedFixtureException(s"Defining scoped variables outside of a test is not allowed")
}

trait TestFixture[+T] {
  def name: String = getClass.getSimpleName
  protected def instance: T
  protected val insideTestScope: () => Boolean

  def apply() = {
    if (insideTestScope())
      instance
    else
      throw(new ReadOutsideOfTestAttempt(this))
  }

  def aroundTest(body: () => Status): Status
}

class ScopedFixture[T]( protected val insideTestScope: () => Boolean, scopedGetter: ScopedFn[T] ) extends TestFixture[T] {
  private [this] var _initialized = false
  private [this] var _instance: T = _
  def instance: T = {
    if (!_initialized)
      throw(new InvalidForwardReference(this))
    else
      _instance
  }

  override def aroundTest(body: () => Status) = {
    scopedGetter({ value: T =>
      _initialized = true
      _instance = value
      val status = body()
      _initialized = false
      status
    })
  }
}

class LazyFixture[T](protected val insideTestScope: () => Boolean, getter: => T) extends TestFixture[T] {
  private class LazyGetter {
    lazy val value: T = getter
  }

  private [this] var _lazyGetter: LazyGetter = _
  def instance = _lazyGetter.value

  override def aroundTest(body: () => Status) = {
    _lazyGetter = new LazyGetter
    body()
  }
}

class EagerFixture[T]( protected val insideTestScope: () => Boolean, getter: => T) extends TestFixture[T] {
  private [this] var _initialized = false
  private [this] var _instance: T = _
  def instance = if (!_initialized)
    throw(new InvalidForwardReference(this))
  else
    _instance

  override def aroundTest(body: () => Status) = {
    _instance = getter
    _initialized = true
    val status = body()
    _initialized = false
    status
  }
}

trait ScopedFixtures extends Suite {
  private var insideTestScope = false
  private val insideTestScopeGetter = () => insideTestScope
  private [this] var fixtures = List.empty[TestFixture[Any]]
  private def registeringFixture[T](fixture: TestFixture[T]): TestFixture[T] = synchronized {
    fixtures = fixture :: fixtures
    fixture
  }


  object ScopedFixture {
    def apply[T]( fn: ScopedFn[T] ) = registeringFixture {
      new ScopedFixture[T](insideTestScopeGetter, fn)
    }
  }

  object LazyFixture {
    def apply[T]( getter: => T) = registeringFixture {
      new LazyFixture[T](insideTestScopeGetter, getter)
    }
  }
  object EagerFixture {
    def apply[T]( fn: => T) = registeringFixture {
      new EagerFixture[T](insideTestScopeGetter, fn)
    }
  }

  abstract protected override def runTest(testName: String, args: Args): Status = {
    def iterate(fns: List[TestFixture[Any]]): Status = {
      fns match {
        case head :: tail =>
          head.aroundTest { () => iterate(tail) }
        case Nil =>
          super.runTest(testName, args)
      }
    }
    insideTestScope = true
    val status = iterate(fixtures.reverse)
    insideTestScope = false
    status
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy