mirror of https://github.com/sbt/sbt.git
Pick the first test fingerprint for a given suite/class name. Fixes #827.
This drops older code that picked a single fingerprint within a framework. This commit ensures only one name is executed across all frameworks. The precedence is the order that frameworks are declared in Defaults.scala. JUnit should be last because it is common for specs tests to be annotated with @RunWith for Eclipse support. If a distinct fingerprint is not picked, the test will be run by both specs and JUnit. In addition to this main reason, result processing code assumes one result per test class name and would have to be fixed if multiple fingerprints were allowed.
This commit is contained in:
parent
beea6a9b4a
commit
a0e301e3d8
|
|
@ -0,0 +1,6 @@
|
|||
scalaVersion := "2.10.2"
|
||||
|
||||
libraryDependencies += "com.novocode" % "junit-interface" % "0.10-M4" % "test"
|
||||
|
||||
libraryDependencies += "org.specs2" %% "specs2" % "2.1.1" % "test"
|
||||
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
import org.junit.runner.RunWith
|
||||
import org.specs2._
|
||||
|
||||
@RunWith(classOf[org.specs2.runner.JUnitRunner])
|
||||
class B extends Specification
|
||||
{
|
||||
// sequential=true is necessary to get junit in the call stack
|
||||
// otherwise, junit calls specs, which then runs tests on separate threads
|
||||
def is = args(sequential=true) ^ s2"""
|
||||
|
||||
This should
|
||||
fail if 'succeed' file is missing $succeedNeeded
|
||||
not run via JUnit $noJUnit
|
||||
"""
|
||||
|
||||
def succeedNeeded = {
|
||||
val f = new java.io.File("succeed")
|
||||
f.exists must_== true
|
||||
}
|
||||
def noJUnit = {
|
||||
println("Trace: " + RunBy.trace.mkString("\n\t", "\n\t", ""))
|
||||
RunBy.junit must_== false
|
||||
}
|
||||
}
|
||||
|
||||
object RunBy
|
||||
{
|
||||
def trace = (new Exception).getStackTrace.map(_.getClassName)
|
||||
def junit = trace.exists(_.contains("org.junit"))
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
# verify the test runs at all by having it fail
|
||||
$ absent succeed
|
||||
-> test
|
||||
|
||||
# indicate to the test it should succeed
|
||||
# it will fail if run via junit and succeed if run via specs
|
||||
$ touch succeed
|
||||
> test
|
||||
|
|
@ -152,13 +152,19 @@ object TestFramework
|
|||
listeners: Seq[TestReportListener]):
|
||||
(() => Unit, Seq[(String, TestFunction)], TestResult.Value => () => Unit) =
|
||||
{
|
||||
val mappedTests = testMap(frameworks.values.toSeq, tests)
|
||||
val unique = distinctBy(tests)(_.name)
|
||||
val mappedTests = testMap(frameworks.values.toSeq, unique)
|
||||
if(mappedTests.isEmpty)
|
||||
(() => (), Nil, _ => () => () )
|
||||
else
|
||||
createTestTasks(testLoader, runners.map { case (tf, r) => (frameworks(tf), new TestRunner(r, listeners, log))}, mappedTests, tests, log, listeners)
|
||||
createTestTasks(testLoader, runners.map { case (tf, r) => (frameworks(tf), new TestRunner(r, listeners, log))}, mappedTests, unique, log, listeners)
|
||||
}
|
||||
|
||||
private[this] def distinctBy[T, K](in: Seq[T])(f: T => K): Seq[T] =
|
||||
{
|
||||
val seen = new collection.mutable.HashSet[K]
|
||||
in.filter(t => seen.add(f(t)))
|
||||
}
|
||||
private[this] def order(mapped: Map[String, TestFunction], inputs: Seq[TestDefinition]): Seq[(String, TestFunction)] =
|
||||
for( d <- inputs; act <- mapped.get(d.name) ) yield (d.name, act)
|
||||
|
||||
|
|
@ -166,28 +172,15 @@ object TestFramework
|
|||
{
|
||||
import scala.collection.mutable.{HashMap, HashSet, Set}
|
||||
val map = new HashMap[Framework, Set[TestDefinition]]
|
||||
def assignTests()
|
||||
def assignTest(test: TestDefinition)
|
||||
{
|
||||
for(test <- tests if !map.values.exists(_.contains(test)))
|
||||
{
|
||||
def isTestForFramework(framework: Framework) = getFingerprints(framework).exists {t => matches(t, test.fingerprint) }
|
||||
for(framework <- frameworks.find(isTestForFramework))
|
||||
map.getOrElseUpdate(framework, new HashSet[TestDefinition]) += test
|
||||
}
|
||||
def isTestForFramework(framework: Framework) = getFingerprints(framework).exists {t => matches(t, test.fingerprint) }
|
||||
for(framework <- frameworks.find(isTestForFramework))
|
||||
map.getOrElseUpdate(framework, new HashSet[TestDefinition]) += test
|
||||
}
|
||||
if(!frameworks.isEmpty)
|
||||
assignTests()
|
||||
map.toMap transform { (framework, tests) => mergeDuplicates(framework, tests.toSeq) }
|
||||
}
|
||||
private[this] def mergeDuplicates(framework: Framework, tests: Seq[TestDefinition]): Set[TestDefinition] =
|
||||
{
|
||||
val frameworkPrints = framework.fingerprints.reverse
|
||||
def pickOne(prints: Seq[Fingerprint]): Fingerprint =
|
||||
frameworkPrints.find(prints.toSet) getOrElse prints.head
|
||||
val uniqueDefs =
|
||||
for( ((name, explicitlySpecified, selectors), defs) <- tests.groupBy(t => (t.name, t.explicitlySpecified, t.selectors)) ) yield
|
||||
new TestDefinition(name, pickOne(defs.map(_.fingerprint)), explicitlySpecified, selectors)
|
||||
uniqueDefs.toSet
|
||||
for(test <- tests) assignTest(test)
|
||||
map.toMap.mapValues(_.toSet)
|
||||
}
|
||||
|
||||
private def createTestTasks(loader: ClassLoader, runners: Map[Framework, TestRunner], tests: Map[Framework, Set[TestDefinition]], ordered: Seq[TestDefinition], log: Logger, listeners: Seq[TestReportListener]) =
|
||||
|
|
|
|||
Loading…
Reference in New Issue