Skip to content

Increase Fidelity of the sbt.testing.Framework Implementation #1107

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions core/js/src/main/scala/org/scalacheck/Platform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,6 @@ private[scalacheck] object Platform {
}

type EnableReflectiveInstantiation = scala.scalajs.reflect.annotation.EnableReflectiveInstantiation

def getClassLoader: ClassLoader = null
}
2 changes: 2 additions & 0 deletions core/jvm/src/main/scala/org/scalacheck/Platform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,6 @@ private[scalacheck] object Platform {
Class.forName(name + "$", true, loader).getField("MODULE$").get(null)

class EnableReflectiveInstantiation extends scala.annotation.Annotation

def getClassLoader: ClassLoader = getClass.getClassLoader
}
2 changes: 2 additions & 0 deletions core/native/src/main/scala/org/scalacheck/Platform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,6 @@ private[scalacheck] object Platform {
}

type EnableReflectiveInstantiation = scala.scalanative.reflect.annotation.EnableReflectiveInstantiation

def getClassLoader: ClassLoader = null
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,23 @@ private abstract class ScalaCheckRunner extends Runner {
}

def rootTask(td: TaskDef): BaseTask = new BaseTask(td) {
def execute(handler: EventHandler, loggers: Array[Logger]): Array[Task] =
props.map(_._1).toSet.toArray map { name =>
def execute(handler: EventHandler, loggers: Array[Logger]): Array[Task] = {
val isTestsOnly: Boolean = td.selectors().forall(selector =>
selector.isInstanceOf[TestSelector] ||
selector.isInstanceOf[TestWildcardSelector])

def isIncluded(name: String): Boolean = !isTestsOnly || td.selectors().exists {
case s: TestWildcardSelector => name.contains(s.testWildcard())
// For TestSelector, exact comparison with both the full name and the name with
// the suite prefix (properties.name) stripped off works for non-nested suite,
// but results in a false negative for nested suites: test "A.B.test" can not be
// selected by its short name "test";
// instead, selected test name is matched using `endsWith`.
case s: TestSelector => name.endsWith(s.testName())
case _ => false
}

props.map(_._1).toSet.filter(isIncluded).toArray map { name =>
checkPropTask(
new TaskDef(
td.fullyQualifiedName(),
Expand All @@ -102,6 +117,7 @@ private abstract class ScalaCheckRunner extends Runner {
Array(new TestSelector(name))),
single = true)
}
}
}

def checkPropTask(taskDef: TaskDef, single: Boolean): BaseTask = new BaseTask(taskDef) { self =>
Expand Down
97 changes: 97 additions & 0 deletions core/shared/src/test/scala/org/scalacheck/SbtSpecification.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* ScalaCheck
* Copyright (c) 2007-2021 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.{
Event,
EventHandler,
Framework,
Selector,
SuiteSelector,
Task,
TaskDef,
TestSelector,
TestWildcardSelector
}

object SbtFixture extends Properties("SbtFixture") {
property("success") = Prop.passed
}

object SbtNestingFixture extends Properties("SbtNestingFixture") {
include(SbtFixture)
}

object SbtSpecification extends Properties("Sbt") {
property("suite") = run(Array(new SuiteSelector)) == List("SbtFixture.success")

property("exact") = run(Array(new TestSelector("success"))) == List("SbtFixture.success")
property("exactFull") = run(Array(new TestSelector("SbtFixture.success"))) == List("SbtFixture.success")
property("exactMissing") = run(Array(new TestSelector("nonexistent"))) == List.empty

property("wildcard") = run(Array(new TestWildcardSelector("succ"))) == List("SbtFixture.success")
property("wildcardFull") = run(Array(new TestWildcardSelector("xture.succ"))) == List("SbtFixture.success")
property("wildcardMissing") = run(Array(new TestWildcardSelector("prev"))) == List.empty

property("nestedFull") = run(
Array(new TestSelector("SbtNestingFixture.SbtFixture.success")),
"org.scalacheck.SbtNestingFixture") == List("SbtNestingFixture.SbtFixture.success")

property("nestedMedium") = run(
Array(new TestSelector("SbtFixture.success")),
"org.scalacheck.SbtNestingFixture") == List("SbtNestingFixture.SbtFixture.success")

property("nestedShort") = run(
Array(new TestSelector("success")),
"org.scalacheck.SbtNestingFixture") == List("SbtNestingFixture.SbtFixture.success")

// Since ScalaCheck does not keep track what class/object a property belongs to,
// the following two issues concerning nested properties can not be fixed:
//
// When `explicitlySpecified = true`, properties from objects other than the one being run
// should *not* run (and the outcome should be `List.empty`) - but they do.
//
// When a property from an object other than the one being run *does* run,
// its status should be reported with a `NestedTestSelector`
// where `suiteId` names the object that the property belongs to -
// but it is reported with a `TestSelector`.

property("nestedShouldRunAndDoes") = run(
Array(new SuiteSelector),
fullyQualifiedName = "org.scalacheck.SbtNestingFixture",
explicitlySpecified = false
) == List("SbtNestingFixture.SbtFixture.success")

property("nestedShouldNotRunButDoes") = run(
Array(new SuiteSelector),
fullyQualifiedName = "org.scalacheck.SbtNestingFixture",
explicitlySpecified = true
) == List("SbtNestingFixture.SbtFixture.success") // should be List.empty

// run using SBT Test Interface
def run(
selectors: Array[Selector],
fullyQualifiedName: String = "org.scalacheck.SbtFixture",
explicitlySpecified: Boolean = false
): List[String] = {
val framework: Framework = new ScalaCheckFramework
var ran: List[String] = List.empty
val eventHandler: EventHandler =
(event: Event) => ran = ran :+ event.selector().asInstanceOf[TestSelector].testName()
def execute(tasks: Array[Task]): Unit = tasks.foreach(task => execute(task.execute(eventHandler, Array.empty)))
execute(framework.runner(Array.empty, Array.empty, Platform.getClassLoader).tasks(Array(new TaskDef(
fullyQualifiedName,
framework.fingerprints()(2), // object ... extends org.scalacheck.Properties
explicitlySpecified,
selectors
))))
ran
}
}