Skip to content

Instantly share code, notes, and snippets.

@xuwei-k
Last active August 29, 2015 14:07
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 xuwei-k/a25ab36bba83fce6b850 to your computer and use it in GitHub Desktop.
Save xuwei-k/a25ab36bba83fce6b850 to your computer and use it in GitHub Desktop.
tab completion for specs2 "ex" parameter
import sbt.complete.Parser
import sbt.complete.DefaultParsers._
import sbinary.DefaultProtocol._
val specs2testNames = TaskKey[Map[String, Set[String]]]("_specs2testNames")
specs2testNames := {
val loader = (testLoader in Test).value
val clazz = Class.forName("org.specs2.FindSpecs2Tests", true, loader)
val method = clazz.getMethod("run", classOf[Array[String]])
val finder = clazz.newInstance()
val testNames = (definedTestNames in Test).value.toArray
// testNames.foreach(println); println;
val names = method.invoke(clazz.newInstance(), testNames).asInstanceOf[Array[Array[String]]]
(testNames, names).zipped.map((k, v) => k -> v.toSet)(collection.breakOut)
}
specs2testNames <<= specs2testNames storeAs specs2testNames triggeredBy (compile in Test)
val specs2only = InputKey[Unit]("specs2only")
val defaultParser: Parser[(String, Seq[String])] =
Space ~> token(StringBasic, "<test class names>") ~ (Space ~> token(StringBasic, "<test name>")).*
def createParser(tests: Map[String, Set[String]]): Parser[(String, Seq[String])] = {
val other = token(StringBasic, _ => true)
tests.filter(_._2.nonEmpty).map{ case (k, v) =>
token(k) ~ (Space ~> v.map(token(_)).reduceOption(_ | _).map(_ | other).getOrElse(other)).*
}.reduceOption(_ | _).map(Space ~> _).getOrElse(defaultParser)
}
specs2only <<= InputTask.createDyn(
Defaults.loadForParser(specs2testNames)(
(state, classes) => classes.fold(defaultParser)(createParser)
)
){
Def.task{ tests: (String, Seq[String]) =>
(testOnly in Test).toTask((" " :: tests._1 :: "--" :: "ex" :: tests._2.toList).mkString(" "))
}
}
package org.specs2
import java.lang.reflect.Modifier
import scala.language.reflectiveCalls
class FindSpecs2Tests {
private def getClassInstance(className: String): Option[Any] = {
val clazz = Class.forName(className)
val mods = clazz.getModifiers
if (!clazz.isInterface && !Modifier.isAbstract(mods)) {
try {
Option(clazz.newInstance())
} catch {
case e: ReflectiveOperationException =>
None
}
} else None
}
private def getObjectInstance(className: String): Any = {
val clazz = Class.forName(className + "$")
clazz.getField("MODULE$").get(null)
}
def run(classes: Array[String]): Array[Array[String]] = try {
val result = classes.map { className =>
try {
val clazz = getClassInstance(className).getOrElse(getObjectInstance(className))
specs2testNames(clazz)
} catch {
case e: ReflectiveOperationException =>
// println(e)
Array[String]()
}
}
// result.foreach { x => if (x.nonEmpty) println((x.size, x.mkString(","))) }; println
result
} catch {
case e: Throwable =>
e.printStackTrace()
Array()
}
def specs2testNames(testClass: Any): Array[String] = {
type FormattedString = Any
type Example = { def desc: FormattedString }
type Fragment = Any
type Fragments = { def middle: Seq[Fragment] }
val collectExample: PartialFunction[Fragment, Example] = {
case obj if obj.getClass.getName == "org.specs2.specification.Example" => obj.asInstanceOf[Example]
}
val fragments = testClass.asInstanceOf[{ def fragments: Fragments }].fragments.middle
fragments.collect(collectExample).map(_.desc.toString).toArray
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment