From 038fd5414c5dfe3a37b9d3065a38b538c46de079 Mon Sep 17 00:00:00 2001 From: Martin Duhem Date: Wed, 17 Jan 2024 15:19:56 +0100 Subject: [PATCH] Verify only props matching the given TestSelectors Previously, ScalaCheck ignored the selectors that it receives as input in the "root task". This prevented users from running only a subset of properties in a specification by passing their `TestSelector` to ScalaCheck in a `TaskDef`. This patch fixes this by having the root task program the execution of only the requested properties if the `TaskDef` contains only `TestSelector`s. ScalaCheck's behavior remains unchanged if the `TaskDef` contains any other kind of `Selector`. --- .../ScalaCheckFrameworkSpecification.scala | 64 +++++++++++++++++++ .../org/scalacheck/ScalaCheckFramework.scala | 11 +++- 2 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 core/jvm/src/test/scala/org/scalacheck/ScalaCheckFrameworkSpecification.scala diff --git a/core/jvm/src/test/scala/org/scalacheck/ScalaCheckFrameworkSpecification.scala b/core/jvm/src/test/scala/org/scalacheck/ScalaCheckFrameworkSpecification.scala new file mode 100644 index 00000000..d16bc860 --- /dev/null +++ b/core/jvm/src/test/scala/org/scalacheck/ScalaCheckFrameworkSpecification.scala @@ -0,0 +1,64 @@ +/* + * 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 org.scalacheck.Prop.proved +import sbt.testing.{Selector, SuiteSelector, TaskDef, TestSelector} + +object ScalaCheckFrameworkSpecification extends Properties("ScalaCheckFramework") { + + private val firstProp = "ScalaCheckFrameworkHelper.first prop" + private val secondProp = "ScalaCheckFrameworkHelper.second prop" + private val thirdProp = "ScalaCheckFrameworkHelper.third prop" + + property("all props with SuiteSelector") = { + getPropNamesForSelectors(List(new SuiteSelector)) == List(firstProp, secondProp, thirdProp) + getPropNamesForSelectors(List(new SuiteSelector, new TestSelector(firstProp))) == List( + firstProp, + secondProp, + thirdProp) + getPropNamesForSelectors(List(new SuiteSelector, new TestSelector("no matches"))) == List( + firstProp, + secondProp, + thirdProp) + } + + property("only matching props with TestSelector") = { + getPropNamesForSelectors(List(new TestSelector(firstProp))) == List(firstProp) + getPropNamesForSelectors(List(new TestSelector(secondProp))) == List(secondProp) + getPropNamesForSelectors(List(new TestSelector(firstProp), new TestSelector(thirdProp))) == List( + firstProp, + thirdProp) + getPropNamesForSelectors(List(new TestSelector("no matches"))) == Nil + } + + private def getPropNamesForSelectors(selectors: List[Selector]): List[String] = { + val framework = new ScalaCheckFramework() + val runner = framework.runner(Array.empty, Array.empty, getClass.getClassLoader).asInstanceOf[ScalaCheckRunner] + val taskDef = new TaskDef( + classOf[ScalaCheckFrameworkSpecificationHelper].getName, + framework.fingerprints()(0), + true, + selectors.toArray) + val baseTask = runner.rootTask(taskDef) + val newTasks = baseTask.execute(null, null) + val propNames = for { + task <- newTasks + selector <- task.taskDef().selectors() + } yield selector.asInstanceOf[TestSelector].testName() + propNames.toList + } +} + +class ScalaCheckFrameworkSpecificationHelper extends Properties("ScalaCheckFrameworkHelper") { + property("first prop") = proved + property("second prop") = proved + property("third prop") = proved +} diff --git a/core/shared/src/main/scala/org/scalacheck/ScalaCheckFramework.scala b/core/shared/src/main/scala/org/scalacheck/ScalaCheckFramework.scala index 81e96c4f..94969899 100644 --- a/core/shared/src/main/scala/org/scalacheck/ScalaCheckFramework.scala +++ b/core/shared/src/main/scala/org/scalacheck/ScalaCheckFramework.scala @@ -92,8 +92,14 @@ 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] = { + // If the task contains only `TestSelector`s, then run only these props instead of the whole suite. + val propFilter: String => Boolean = + if (td.selectors().forall(_.isInstanceOf[TestSelector])) + td.selectors().collect { case ts: TestSelector => ts.testName() }.toSet + else + Function.const(true) + props.map(_._1).toSet.filter(propFilter).toArray map { name => checkPropTask( new TaskDef( td.fullyQualifiedName(), @@ -102,6 +108,7 @@ private abstract class ScalaCheckRunner extends Runner { Array(new TestSelector(name))), single = true) } + } } def checkPropTask(taskDef: TaskDef, single: Boolean): BaseTask = new BaseTask(taskDef) { self =>