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

org.scalacheck.ScalaCheckFramework.scala Maven / Gradle / Ivy

/*-------------------------------------------------------------------------*\
**  ScalaCheck                                                             **
**  Copyright (c) 2007-2016 Rickard Nilsson. All rights reserved.          **
**  http://www.scalacheck.org                                              **
**                                                                         **
**  This software is released under the terms of the Revised BSD License.  **
**  There is NO WARRANTY. See the file LICENSE for the full text.          **
\*------------------------------------------------------------------------ */

package org.scalacheck

import sbt.testing._
import scala.language.reflectiveCalls
import java.util.concurrent.atomic.AtomicInteger

private abstract class ScalaCheckRunner extends Runner {

  val args: Array[String]
  val loader: ClassLoader
  val params: Test.Parameters

  val successCount = new AtomicInteger(0)
  val failureCount = new AtomicInteger(0)
  val errorCount = new AtomicInteger(0)
  val testCount = new AtomicInteger(0)

  def deserializeTask(task: String, deserializer: String => TaskDef) = {
    val taskDef = deserializer(task)
    val countTestSelectors = taskDef.selectors.toSeq.count {
      case _:TestSelector => true
      case _ => false
    }
    if (countTestSelectors == 0) rootTask(taskDef)
    else checkPropTask(taskDef)
  }

  def serializeTask(task: Task, serializer: TaskDef => String) =
    serializer(task.taskDef)

  def tasks(taskDefs: Array[TaskDef]): Array[Task] = taskDefs.map(rootTask)

  abstract class BaseTask(override val taskDef: TaskDef) extends Task {
    val tags: Array[String] = Array()

    val props: Seq[(String,Prop)] = {
      val fp = taskDef.fingerprint.asInstanceOf[SubclassFingerprint]
      val obj = if (fp.isModule) Platform.loadModule(taskDef.fullyQualifiedName,loader)
                else Platform.newInstance(taskDef.fullyQualifiedName, loader)(Seq())
      obj match {
        case props: Properties => props.properties
        case prop: Prop => Seq("" -> prop)
      }
    }

    def log(loggers: Array[Logger], ok: Boolean, msg: String) =
      loggers foreach { l =>
        val logstr =
          if(!l.ansiCodesSupported) msg
          else s"${if (ok) Console.GREEN else Console.RED}$msg${Console.RESET}"
        l.info(logstr)
      }

    def execute(handler: EventHandler, loggers: Array[Logger],
      continuation: Array[Task] => Unit
    ): Unit  = continuation(execute(handler,loggers))
  }

  def rootTask(td: TaskDef) = new BaseTask(td) {
    def execute(handler: EventHandler, loggers: Array[Logger]): Array[Task] =
      props.map(_._1).toSet.toArray map { name =>
        checkPropTask(new TaskDef(td.fullyQualifiedName, td.fingerprint,
          td.explicitlySpecified, Array(new TestSelector(name)))
        )
      }
  }

  def checkPropTask(taskDef: TaskDef) = new BaseTask(taskDef) {
    val names = taskDef.selectors flatMap {
      case ts: TestSelector => Array(ts.testName)
      case _ => Array.empty[String]
    }

    def execute(handler: EventHandler, loggers: Array[Logger]): Array[Task] =
      names flatMap { name =>
        import util.Pretty.{pretty, Params}

        for ((`name`, prop) <- props) {
          val result = Test.check(params, prop)

          val event = new Event {
            val status = result.status match {
              case Test.Passed => Status.Success
              case _:Test.Proved => Status.Success
              case _:Test.Failed => Status.Failure
              case Test.Exhausted => Status.Failure
              case _:Test.PropException => Status.Error
            }
            val throwable = result.status match {
              case Test.PropException(_, e, _) => new OptionalThrowable(e)
              case _:Test.Failed => new OptionalThrowable(
                new Exception(pretty(result, Params(0)))
              )
              case _ => new OptionalThrowable()
            }
            val fullyQualifiedName = taskDef.fullyQualifiedName
            val selector = new TestSelector(name)
            val fingerprint = taskDef.fingerprint
            val duration = -1L
          }

          handler.handle(event)

          event.status match {
            case Status.Success => successCount.incrementAndGet()
            case Status.Error => errorCount.incrementAndGet()
            case Status.Skipped => errorCount.incrementAndGet()
            case Status.Failure => failureCount.incrementAndGet()
            case _ => failureCount.incrementAndGet()
          }
          testCount.incrementAndGet()

          // TODO Stack traces should be reported through event
          val verbosityOpts = Set("-verbosity", "-v")
          val verbosity =
            args.grouped(2).filter(twos => verbosityOpts(twos.head))
            .toSeq.headOption.map(_.last).map(_.toInt).getOrElse(0)
          val s = if (result.passed) "+" else "!"
          val n = if (name.isEmpty) taskDef.fullyQualifiedName else name
          val logMsg = s"$s $n: ${pretty(result, Params(verbosity))}"
          log(loggers, result.passed, logMsg)
        }

        Array.empty[Task]
      }
  }

}

final class ScalaCheckFramework extends Framework {

  private def mkFP(mod: Boolean, cname: String, noArgCons: Boolean = true) =
    new SubclassFingerprint {
      def superclassName(): String = cname
      val isModule = mod
      def requireNoArgConstructor(): Boolean = noArgCons
    }

  val name = "ScalaCheck"

  def fingerprints: Array[Fingerprint] = Array(
    mkFP(false, "org.scalacheck.Properties"),
    mkFP(false, "org.scalacheck.Prop"),
    mkFP(true, "org.scalacheck.Properties"),
    mkFP(true, "org.scalacheck.Prop")
  )

  def runner(_args: Array[String], _remoteArgs: Array[String],
    _loader: ClassLoader
  ): Runner = new ScalaCheckRunner {

    val args = _args
    val remoteArgs = _remoteArgs
    val loader = _loader
    val (prms,unknownArgs) = Test.cmdLineParser.parseParams(args)
    val params = prms.withTestCallback(new Test.TestCallback {})
                     .withCustomClassLoader(Some(loader))

    def receiveMessage(msg: String): Option[String] = msg(0) match {
      case 'd' =>
        val Array(t,s,f,e) = msg.tail.split(',')
        testCount.addAndGet(t.toInt)
        successCount.addAndGet(s.toInt)
        failureCount.addAndGet(f.toInt)
        errorCount.addAndGet(e.toInt)
        None
    }

    def done = if (testCount.get > 0) {
      val heading = if (testCount.get == successCount.get) "Passed" else "Failed"
      s"$heading: Total $testCount, " +
      s"Failed $failureCount, Errors $errorCount, Passed $successCount" +
      (if(unknownArgs.isEmpty) "" else
      s"\nWarning: Unknown ScalaCheck args provided: ${unknownArgs.mkString(" ")}")
    } else ""

  }

  def slaveRunner(_args: Array[String], _remoteArgs: Array[String],
    _loader: ClassLoader, send: String => Unit
  ): Runner = new ScalaCheckRunner {
    val args = _args
    val remoteArgs = _remoteArgs
    val loader = _loader
    val params = Test.cmdLineParser.parseParams(args)._1
                   .withTestCallback(new Test.TestCallback {})
                   .withCustomClassLoader(Some(loader))

    def receiveMessage(msg: String) = None

    def done = {
      send(s"d$testCount,$successCount,$failureCount,$errorCount")
      ""
    }

  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy