Skip to content

Commit

Permalink
added infrastruture for running grouped tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
rssh committed Mar 23, 2012
1 parent 50380ba commit 57fcb8f
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 2 deletions.
Expand Up @@ -108,7 +108,9 @@ trait FeatureSpec[T <: FixtureStateTypes] extends fixture.Suite
**/
def fixtureStateTypes: T

protected override lazy val internalSpec = new InternalFeatureSpec[T](this);

protected override lazy val internalSpec: InternalFeatureSpec[T] = new InternalFeatureSpec[T](this);


override def withFixture(test: OneArgTest): Unit =
throw new IllegalStateException("You can't call withFixture diretly in managedfixture");
Expand Down
17 changes: 16 additions & 1 deletion src/main/scala/org/scalatest/managedfixture/FlatSpec.scala
Expand Up @@ -202,7 +202,17 @@ trait FlatSpec[T <: FixtureStateTypes] extends Suite with ShouldVerb with MustVe


// here we recreate internal suite and will be pass to one all 'real' functionality.
private[scalatest] lazy val internalSpec = new InternalFlatSpec(this);
private[scalatest] lazy val internalSpec: InternalFlatSpec[T] =
if (this.isInstanceOf[Grouped]) {
if (GroupSpecConstructorKluge.currentOwner!=None) {
GroupSpecConstructorKluge.currentOwner.value.get.asInstanceOf[FlatSpecGroup[T]].internalSpec;
} else {
// it was called outside group, create internal constructor
new InternalFlatSpec(this);
}
} else {
new InternalFlatSpec(this);
}

implicit protected def info: Informer = internalSpec._info;

Expand Down Expand Up @@ -380,10 +390,15 @@ trait FlatSpec[T <: FixtureStateTypes] extends Suite with ShouldVerb with MustVe

override def run(testName: Option[String], reporter: Reporter, stopper: Stopper, filter: Filter,
configMap: Map[String, Any], distributor: Option[Distributor], tracker: Tracker) {
if (isGrouped) {
this.asInstanceOf[Grouped].checkGroupExists( classOf[FlatSpecGroup[_]] );
}
internalSpec.run(testName, reporter, stopper, filter, configMap, distributor, tracker);
}

protected val behave = new BehaveWord

private def isGrouped: Boolean = this.isInstanceOf[Grouped];
}

private[scalatest] object FlatSpecConstructorKluge
Expand Down
21 changes: 21 additions & 0 deletions src/main/scala/org/scalatest/managedfixture/FlatSpecGroup.scala
@@ -0,0 +1,21 @@
package org.scalatest.managedfixture


import scala.util.DynamicVariable
import org.scalatest._
import ua.gradsoft.managedfixture._


abstract class FlatSpecGroup[T <: FixtureStateTypes] extends FlatSpec[T]
with SpecGroup
{

override def run(testName: Option[String], reporter: Reporter, stopper: Stopper, filter: Filter,
configMap: Map[String, Any], distributor: Option[Distributor], tracker: Tracker) {
collectGrouped(classOf[FlatSpec[T]]);
internalSpec.run(testName, reporter, stopper, filter, configMap, distributor, tracker);
}

}


35 changes: 35 additions & 0 deletions src/main/scala/org/scalatest/managedfixture/Grouped.scala
@@ -0,0 +1,35 @@
package org.scalatest.managedfixture

import ua.gradsoft.managedfixture._

trait Grouped {



/**
* check - are we have instance of clazz somewhere in our package structure
* upper to current class.
* [todo - check same fixture state types (?)]
*/
def checkGroupExists(clazz:Class[_]):Boolean =
{
val pkg = clazz.getPackage();
val components = pkg.getName().split('.');
if (components.length > 1) {
var i=components.length;
var isFound = false;
while( i > 0 && !isFound ) {
isFound = ! ( ReflectionUtils.findClasses(components.take(i).mkString("."),
{ (x: Class[_]) =>
!(classOf[FlatSpecGroup[_]].isAssignableFrom(x))
}, false) );
}
isFound;
}else{
false
}
}

def mark(owner:SpecGroup):Unit = {}

}
39 changes: 39 additions & 0 deletions src/main/scala/org/scalatest/managedfixture/SpecGroup.scala
@@ -0,0 +1,39 @@
package org.scalatest.managedfixture

import ua.gradsoft.managedfixture._
import scala.util.DynamicVariable

trait SpecGroup
{

def checkClass[T](cl:Class[T]): Boolean
= true;

def checkObject(x:AnyRef): Boolean
= true;

private[scalatest] def collectGrouped[T](cl:Class[T]):Boolean =
{
ReflectionUtils.findClasses(this.getClass().getPackage().getName,
{
(x:Class[_]) =>
if (x.isInstanceOf[Grouped] && x.isInstanceOf[T]) {
if (checkClass(x)) {
GroupSpecConstructorKluge.currentOwner.withValue(Some(this)) {
val obj = x.newInstance().asInstanceOf[Grouped];
obj.mark(this);
}
}
}
true
},
true);
}


}

private[scalatest] object GroupSpecConstructorKluge
{
val currentOwner = new DynamicVariable[Option[SpecGroup]](None);
}
67 changes: 67 additions & 0 deletions src/main/scala/ua/gradsoft/managedfixture/ReflectionUtils.scala
@@ -0,0 +1,67 @@
package ua.gradsoft.managedfixture

import java.io._
import java.util.zip._

/**
* helper class, which simplicify work with reflection
*/
object ReflectionUtils {


def findClasses(packageName:String, testFun: Class[_]=>Boolean, recursive:Boolean):Boolean =
{
val e = classLoader.getResources(packageName);
var more = true;
while(e.hasMoreElements && more) {
val url = e.nextElement();
more = forClassesInDir(packageName,url.getFile, testFun, recursive);
}
more
}

private[this] def forClassesInDir(pkgName:String, dir:String, fun: Class[_]=>Boolean, recursive: Boolean):Boolean =
{
var more = true;
if (dir.startsWith("file:") && dir.contains("!") ) {
val jar = new java.net.URL(dir.split("!")(0));
val zip = new ZipInputStream(jar.openStream());
var zipEntry = zip.getNextEntry;
while(zipEntry!=null && more) {
val className = zipEntry.getName.replaceAll("[$].*", "").replaceAll("[.]class","").replace('/', '.');
val c = Class.forName(className);
more = fun(c)
zipEntry = zip.getNextEntry;
}
} else {
var fd = new File(dir);
if (fd.exists) {
for(f <- fd.listFiles) {
var fname = f.getName;
if (fname.endsWith(".class")) {
val className = pkgName+"."+ fname.substring(0, fname.length-6);
val c = Class.forName(className);
more = fun(c);
} else if (f.isDirectory() && recursive) {
more = forClassesInDir(pkgName+"."+f.getName(),dir+"/"+f.getName,fun,recursive)
}
if (!more) {
return false;
}
}
}
}
more;
}

private[this] def classLoader: ClassLoader =
{
Option(Thread.currentThread().getContextClassLoader()) match {
case Some(x) => x
case None => this.getClass.getClassLoader();
}
}



}

0 comments on commit 57fcb8f

Please sign in to comment.