Skip to content

Commit da9cb92

Browse files
committed
- when Selectors supplied include only TestSelectors and TestWildcardSelectors, filter properties to run by matching their names against the Selectors;
- added a test that actually runs ScalaCheck via the `SBT Test Interface` and demonstrates the (now correct) treatment of the `Selector`s; - test also demonstrates two unfixable infidelities in the treatment of the nested properties; - thankfully, ScalaCheck's implementation of `sbt.testing.Framework` is, unlike in some other test frameworks, shared between the platforms (JVM, Scala.js, Scala Native), so the fixes do not have to be replicated for each platform, but: - the test needs to supply a `testClassLoader: ClassLoader` parameter when calling `sbt.testing.Framework.runner()`; on platforms other than JVM, `getClass.getClassLoader` is not available, so `Platform.getClassLoader: ClassLoader` method was added to every `Platform`; on platforms other than the JVM, it returns `null`, which is fine since on those platforms `sbt.testing.Framework.runner()` ignores the `testClassLoader` parameter anyway. fixes #1105
1 parent c9aa8d3 commit da9cb92

File tree

5 files changed

+122
-2
lines changed

5 files changed

+122
-2
lines changed

core/js/src/main/scala/org/scalacheck/Platform.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,6 @@ private[scalacheck] object Platform {
4646
}
4747

4848
type EnableReflectiveInstantiation = scala.scalajs.reflect.annotation.EnableReflectiveInstantiation
49+
50+
def getClassLoader: ClassLoader = null
4951
}

core/jvm/src/main/scala/org/scalacheck/Platform.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,6 @@ private[scalacheck] object Platform {
7373
Class.forName(name + "$", true, loader).getField("MODULE$").get(null)
7474

7575
class EnableReflectiveInstantiation extends scala.annotation.Annotation
76+
77+
def getClassLoader: ClassLoader = getClass.getClassLoader
7678
}

core/native/src/main/scala/org/scalacheck/Platform.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,6 @@ private[scalacheck] object Platform {
4646
}
4747

4848
type EnableReflectiveInstantiation = scala.scalanative.reflect.annotation.EnableReflectiveInstantiation
49+
50+
def getClassLoader: ClassLoader = null
4951
}

core/shared/src/main/scala/org/scalacheck/ScalaCheckFramework.scala

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,24 @@ private abstract class ScalaCheckRunner extends Runner {
9292
}
9393

9494
def rootTask(td: TaskDef): BaseTask = new BaseTask(td) {
95-
def execute(handler: EventHandler, loggers: Array[Logger]): Array[Task] =
96-
props.map(_._1).toSet.toArray map { name =>
95+
def execute(handler: EventHandler, loggers: Array[Logger]): Array[Task] = {
96+
val isTestsOnly: Boolean = td.selectors().forall(selector =>
97+
selector.isInstanceOf[TestSelector] ||
98+
selector.isInstanceOf[TestWildcardSelector])
99+
100+
val prefix: String = properties.map(properties => s"${properties.name}.").getOrElse("")
101+
def isIncluded(name: String): Boolean = !isTestsOnly || td.selectors().exists {
102+
case s: TestWildcardSelector => name.contains(s.testWildcard())
103+
// For TestSelector, exact comparison with both the full name and the name with
104+
// the suite prefix (properties.name) stripped off works for non-nested suite,
105+
// but results in a false negative for nested suites: test "A.B.test" can not be
106+
// selected by its short name "test";
107+
// instead, selected test name is matched using `endsWith`.
108+
case s: TestSelector => name.endsWith(s.testName())
109+
case _ => false
110+
}
111+
112+
props.map(_._1).toSet.filter(isIncluded).toArray map { name =>
97113
checkPropTask(
98114
new TaskDef(
99115
td.fullyQualifiedName(),
@@ -102,6 +118,7 @@ private abstract class ScalaCheckRunner extends Runner {
102118
Array(new TestSelector(name))),
103119
single = true)
104120
}
121+
}
105122
}
106123

107124
def checkPropTask(taskDef: TaskDef, single: Boolean): BaseTask = new BaseTask(taskDef) { self =>
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* ScalaCheck
3+
* Copyright (c) 2007-2021 Rickard Nilsson. All rights reserved.
4+
* http://www.scalacheck.org
5+
*
6+
* This software is released under the terms of the Revised BSD License.
7+
* There is NO WARRANTY. See the file LICENSE for the full text.
8+
*/
9+
10+
package org.scalacheck
11+
12+
import sbt.testing.{
13+
Event,
14+
EventHandler,
15+
Framework,
16+
Selector,
17+
SuiteSelector,
18+
Task,
19+
TaskDef,
20+
TestSelector,
21+
TestWildcardSelector
22+
}
23+
24+
object SbtFixture extends Properties("SbtFixture") {
25+
property("success") = Prop.passed
26+
}
27+
28+
object SbtNestingFixture extends Properties("SbtNestingFixture") {
29+
include(SbtFixture)
30+
}
31+
32+
object SbtSpecification extends Properties("Sbt") {
33+
property("suite") = run(Array(new SuiteSelector)) == List("SbtFixture.success")
34+
35+
property("exact") = run(Array(new TestSelector("success"))) == List("SbtFixture.success")
36+
property("exactFull") = run(Array(new TestSelector("SbtFixture.success"))) == List("SbtFixture.success")
37+
property("exactMissing") = run(Array(new TestSelector("nonexistent"))) == List.empty
38+
39+
property("wildcard") = run(Array(new TestWildcardSelector("succ"))) == List("SbtFixture.success")
40+
property("wildcardFull") = run(Array(new TestWildcardSelector("xture.succ"))) == List("SbtFixture.success")
41+
property("wildcardMissing") = run(Array(new TestWildcardSelector("prev"))) == List.empty
42+
43+
property("nestedFull") = run(
44+
Array(new TestSelector("SbtNestingFixture.SbtFixture.success")),
45+
"org.scalacheck.SbtNestingFixture") == List("SbtNestingFixture.SbtFixture.success")
46+
47+
property("nestedMedium") = run(
48+
Array(new TestSelector("SbtFixture.success")),
49+
"org.scalacheck.SbtNestingFixture") == List("SbtNestingFixture.SbtFixture.success")
50+
51+
property("nestedShort") = run(
52+
Array(new TestSelector("success")),
53+
"org.scalacheck.SbtNestingFixture") == List("SbtNestingFixture.SbtFixture.success")
54+
55+
// Since ScalaCheck does not keep track what class/object a property belongs to,
56+
// the following two issues concerning nested properties can not be fixed:
57+
//
58+
// When `explicitlySpecified = true`, properties from objects other than the one being run
59+
// should *not* run (and the outcome should be `List.empty`) - but they do.
60+
//
61+
// When a property from an object other than the one being run *does* run,
62+
// its status should be reported with a `NestedTestSelector`
63+
// where `suiteId` names the object that the property belongs to -
64+
// but it is reported with a `TestSelector`.
65+
66+
property("nestedShouldRunAndDoes") = run(
67+
Array(new SuiteSelector),
68+
fullyQualifiedName = "org.scalacheck.SbtNestingFixture",
69+
explicitlySpecified = false
70+
) == List("SbtNestingFixture.SbtFixture.success")
71+
72+
property("nestedShouldNotRunButDoes") = run(
73+
Array(new SuiteSelector),
74+
fullyQualifiedName = "org.scalacheck.SbtNestingFixture",
75+
explicitlySpecified = true
76+
) == List("SbtNestingFixture.SbtFixture.success") // should be List.empty
77+
78+
// run using SBT Test Interface
79+
def run(
80+
selectors: Array[Selector],
81+
fullyQualifiedName: String = "org.scalacheck.SbtFixture",
82+
explicitlySpecified: Boolean = false
83+
): List[String] = {
84+
val framework: Framework = new ScalaCheckFramework
85+
var ran: List[String] = List.empty
86+
val eventHandler: EventHandler =
87+
(event: Event) => ran = ran :+ event.selector().asInstanceOf[TestSelector].testName()
88+
def execute(tasks: Array[Task]): Unit = tasks.foreach(task => execute(task.execute(eventHandler, Array.empty)))
89+
execute(framework.runner(Array.empty, Array.empty, Platform.getClassLoader).tasks(Array(new TaskDef(
90+
fullyQualifiedName,
91+
framework.fingerprints()(2), // object ... extends org.scalacheck.Properties
92+
explicitlySpecified,
93+
selectors
94+
))))
95+
ran
96+
}
97+
}

0 commit comments

Comments
 (0)