Skip to content

Commit

Permalink
Added support for excluding tests.
Browse files Browse the repository at this point in the history
The way this works is mutually exclusive with defining a subset of tests
that only should run.

It hooks into the same bsp API with the logic inverted. Instead of
saying run only these test that come from the user through the cli we
say run all tets besides the ones the user specified in the cli
  • Loading branch information
KristianAN committed Aug 7, 2024
1 parent 8a94a46 commit e07f58f
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 25 deletions.
7 changes: 4 additions & 3 deletions bleep-cli/src/scala/bleep/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ object Main {
.orNone
.map(started.chosenTestProjects)

val testSuites: Opts[Option[NonEmptyList[String]]] = Opts.options[String]("test-only", "Test only a subset of test suites", "o").orNone
val testSuitesOnly: Opts[Option[NonEmptyList[String]]] = Opts.options[String]("only", "Test only a subset of test suites", "o").orNone
val testSuitesExclude: Opts[Option[NonEmptyList[String]]] = Opts.options[String]("exclude", "Test only a subset of test suites", "x").orNone

val hasSourcegenProjectNames: Opts[Array[model.CrossProjectName]] =
Opts
Expand Down Expand Up @@ -174,8 +175,8 @@ object Main {
(watch, hasSourcegenProjectNames).mapN { case (watch, projectNames) => commands.SourceGen(watch, projectNames) }
),
Opts.subcommand("test", "test projects")(
(watch, testProjectNames, testSuites).mapN { case (watch, projectNames, testSuites) =>
commands.Test(watch, projectNames, testSuites)
(watch, testProjectNames, testSuitesOnly, testSuitesExclude).mapN { case (watch, projectNames, testSuitesOnly, testSuitesExclude) =>
commands.Test(watch, projectNames, testSuitesOnly, testSuitesExclude)
}
),
Opts.subcommand("list-tests", "list tests in projects")(
Expand Down
9 changes: 7 additions & 2 deletions bleep-core/src/scala/bleep/Commands.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,13 @@ class Commands(started: Started) {
): Unit =
force(commands.Run(project, maybeOverriddenMain, args, raw, watch))

def test(projects: List[model.CrossProjectName], watch: Boolean = false, classes: Option[NonEmptyList[String]]): Unit =
force(commands.Test(watch, projects.toArray, classes))
def test(
projects: List[model.CrossProjectName],
watch: Boolean = false,
testOnlyClasses: Option[NonEmptyList[String]],
testExcludeClasses: Option[NonEmptyList[String]]
): Unit =
force(commands.Test(watch, projects.toArray, testOnlyClasses, testExcludeClasses))

def script(name: model.ScriptName, args: List[String], watch: Boolean = false): Unit =
force(commands.Script(name, args, watch))
Expand Down
70 changes: 50 additions & 20 deletions bleep-core/src/scala/bleep/commands/Test.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,24 @@ import bloop.rifle.BuildServer
import cats.data.NonEmptyList
import bleep.BleepException.TestSuitesNotFound

case class Test(watch: Boolean, projects: Array[model.CrossProjectName], testSuites: Option[NonEmptyList[String]])
extends BleepCommandRemote(watch)
case class Test(
watch: Boolean,
projects: Array[model.CrossProjectName],
testSuitesOnly: Option[NonEmptyList[String]],
testSuitesExclude: Option[NonEmptyList[String]]
) extends BleepCommandRemote(watch)
with BleepCommandRemote.OnlyChanged {

private def isSameSuite(fromBuild: String, fromCli: String) = {
val fromBuildFqn = fromBuild.split('.')
val fromCliFqn = fromCli.split('.')
fromBuildFqn.sameElements(fromCliFqn) || fromBuildFqn.last == fromCliFqn.last
}

private def intersectTestSuites(fromBuild: List[String], fromCli: List[String]): List[String] =
fromBuild.filter { fullyQualifiedCls =>
fromCli.exists { fromCliCls =>
val fromBuildFqn = fullyQualifiedCls.split('.')
val fromCliFqn = fromCliCls.split('.')
fromBuildFqn.sameElements(fromCliFqn) || fromBuildFqn.last == fromCliFqn.last
isSameSuite(fullyQualifiedCls, fromCliCls)
}
}

Expand All @@ -33,25 +41,47 @@ case class Test(watch: Boolean, projects: Array[model.CrossProjectName], testSui
DoSourceGen(started, bloop, watchableProjects(started)).flatMap { _ =>
val targets = BleepCommandRemote.buildTargets(started.buildPaths, projects)
val tests = bloop.buildTargetScalaTestClasses(new bsp4j.ScalaTestClassesParams(targets)).get()
val testClasses: List[String] = tests.getItems().asScala.flatMap(_.getClasses.asScala).toList
val testClassesUnfiltered: List[String] = tests.getItems().asScala.flatMap(_.getClasses.asScala).toList

val testClasses = testSuitesExclude.map { exclude =>
val filtered = testClassesUnfiltered
.filter(fromBuildCls => exclude.toList.find(fromCliCls => isSameSuite(fromBuildCls, fromCliCls)).isDefined)
if (filtered.nonEmpty) testClassesUnfiltered.diff(filtered) else List.empty
}

val testParams = new bsp4j.TestParams(targets)

val hasSuites: Boolean = testSuites
.map { classes =>
val testClassesData = new bsp4j.ScalaTestSuites(
intersectTestSuites(testClasses, classes.toList)
.map(cls => new bsp4j.ScalaTestSuiteSelection(cls, List.empty[String].asJava))
.asJava,
List.empty[String].asJava,
List.empty[String].asJava
)
testParams.setData(testClassesData)
testParams.setDataKind(bsp4j.TestParamsDataKind.SCALA_TEST_SUITES_SELECTION)
val hasSuites: Boolean =
testClasses match {
case None =>
testSuitesOnly
.map { classes =>
val testClassesData = new bsp4j.ScalaTestSuites(
intersectTestSuites(testClassesUnfiltered, classes.toList)
.map(cls => new bsp4j.ScalaTestSuiteSelection(cls, List.empty[String].asJava))
.asJava,
List.empty[String].asJava,
List.empty[String].asJava
)
testParams.setData(testClassesData)
testParams.setDataKind(bsp4j.TestParamsDataKind.SCALA_TEST_SUITES_SELECTION)

!testClassesData.getSuites().isEmpty
!testClassesData.getSuites().isEmpty
}
.getOrElse(true)
case Some(value) =>
if (value.isEmpty) false
else {
val testClassesData = new bsp4j.ScalaTestSuites(
value.map(suite => new bsp4j.ScalaTestSuiteSelection(suite, List.empty[String].asJava)).asJava,
List.empty[String].asJava,
List.empty[String].asJava
)
testParams.setData(testClassesData)
testParams.setDataKind(bsp4j.TestParamsDataKind.SCALA_TEST_SUITES_SELECTION)
true
}
}
.getOrElse(true)

if (hasSuites) {
val result = bloop.buildTargetTest(testParams).get()
Expand All @@ -65,7 +95,7 @@ case class Test(watch: Boolean, projects: Array[model.CrossProjectName], testSui
Left(new BspCommandFailed("tests", projects, BspCommandFailed.StatusCode(errorCode)))
}
} else {
Left(new TestSuitesNotFound(testSuites.map(_.toList).getOrElse(List.empty[String])))
Left(new TestSuitesNotFound(testSuitesOnly.map(_.toList).getOrElse(List.empty[String])))
}
}
}

0 comments on commit e07f58f

Please sign in to comment.