Skip to content

Instantly share code, notes, and snippets.

@jrudolph
Last active October 23, 2019 08:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jrudolph/190eb628b16fa3bc1e6de42f3835be96 to your computer and use it in GitHub Desktop.
Save jrudolph/190eb628b16fa3bc1e6de42f3835be96 to your computer and use it in GitHub Desktop.
sbt camel case and dot expanding testOnly see https://asciinema.org/a/276464?t=20 for a demo
// copy into project
import sbt._
import Keys._
import Def._
import sbt.Def
import sbt.Defaults.allTestGroupsTask
import sbt.Defaults.loadForParser
import sbt.Project.inConfig
import sbt.internal.util.complete.DefaultParsers
import sbt.internal.util.complete.Parser
import sbt.librarymanagement.Configurations.Test
import sjsonnew.BasicJsonProtocol._
object BetterTestOnly extends AutoPlugin {
override def trigger: PluginTrigger = allRequirements
override def projectSettings: Seq[Def.Setting[_]] = inConfig(Test) {
Seq(
testOnly := inputTests(testOnly).evaluated
)
}
def inputTests(key: InputKey[_]): Initialize[InputTask[Unit]] =
inputTests0.mapReferenced(Def.mapScope(_ in key.key))
private[this] lazy val inputTests0: Initialize[InputTask[Unit]] = {
val parser = loadForParser(definedTestNames)((s, i) => testOnlyParser(s, i getOrElse Nil))
Def.inputTaskDyn {
val (selected, frameworkOptions) = parser.parsed
val s = streams.value
val filter = testFilter.value
val config = testExecution.value
implicit val display = Project.showContextKey(state.value)
val modifiedOpts = Tests.Filters(filter(selected)) +: Tests.Argument(frameworkOptions: _*) +: config.options
val newConfig = config.copy(options = modifiedOpts)
val output = allTestGroupsTask(
s,
loadedTestFrameworks.value,
testLoader.value,
testGrouping.value,
newConfig,
fullClasspath.value,
testForkedParallel.value,
javaOptions.value
)
val taskName = display.show(Keys.resolvedScoped.value)
val trl = testResultLogger.value
val processed = output.map(out => trl.run(s.log, out, taskName))
processed
}
}
def testOnlyParser: (State, Seq[String]) => Parser[(Seq[String], Seq[String])] = {
(state, tests) =>
import DefaultParsers._
val selectTests = distinctParser(tests.toSet, false)
val options = (token(Space) ~> token("--") ~> spaceDelimited("<option>")) ?? Nil
selectTests ~ options
}
private def distinctParser(exs: Set[String], raw: Boolean): Parser[Seq[String]] = {
import DefaultParsers._, Parser.and
def filterQuery(query: String): String => Boolean = {
val reg =
query
.replaceAll("([A-Z])", "[^A-Z]*$1")
.replaceAll("\\.", "[^.]*\\\\.")
println(s"regexp: [$reg]")
ex => reg.r.findAllMatchIn(ex).nonEmpty
}
val base = token(Space) ~> token(NotSpaceClass.+.map(_.mkString) examples exs) <~ Space
base flatMap { ex =>
println(s"Looking for [$ex]")
val matching = if (ex.length >= 3) exs.filter(filterQuery(ex)) else Nil
if (matching.nonEmpty) {
println(s"Found: $matching")
val next = matching.map(m => token(Parser.literal("(") ~> m <~ ")")).reduce(_ | _)
next.map(_ :: Nil)
} else
Parser.failure("No matching test found")
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment