update task tests

This commit is contained in:
Mark Harrah 2010-06-10 08:19:15 -04:00
parent 647a78467e
commit 4572f1b6ca
9 changed files with 241 additions and 114 deletions

View File

@ -0,0 +1,159 @@
/* sbt -- Simple Build Tool
* Copyright 2010 Mark Harrah
*/
package sbt
import Types._
import Task._
import Execute._
sealed trait Task[+T]
sealed case class Pure[+T](eval: () => T) extends Task[T]
final case class Mapped[+T, In <: MList[Task]](in: In, f: In#Map[Result] => T) extends Task[T]
final case class MapAll[+T, In <: MList[Task]](in: In, f: In#Map[Result]#Raw => T) extends Task[T]
final case class FlatMapAll[+T, In <: MList[Task]](in: In, f: In#Map[Result]#Raw => Task[T]) extends Task[T]
final case class MapFailure[+T, In <: MList[Task]](in: In, f: Seq[Incomplete] => T) extends Task[T]
final case class FlatMapFailure[+T, In <: MList[Task]](in: In, f: Seq[Incomplete] => Task[T]) extends Task[T]
final case class FlatMapped[+T, In <: MList[Task]](in: In, f: In#Map[Result] => Task[T]) extends Task[T]
final case class DependsOn[+T](in: Task[T], deps: Seq[Task[_]]) extends Task[T]
final case class Join[+T, U](in: Seq[Task[U]], f: Seq[U] => Either[Task[T], T]) extends Task[T] { type Uniform = U }
trait MultiInTask[M <: MList[Task]]
{
def flatMap[T](f: M#Map[Result]#Raw => Task[T]): Task[T]
def flatMapR[T](f: M#Map[Result] => Task[T]): Task[T]
def mapH[T](f: M#Map[Result]#Raw => T): Task[T]
def mapR[T](f: M#Map[Result] => T): Task[T]
def flatFailure[T](f: Seq[Incomplete] => Task[T]): Task[T]
def mapFailure[T](f: Seq[Incomplete] => T): Task[T]
}
trait SingleInTask[S]
{
def flatMapR[T](f: Result[S] => Task[T]): Task[T]
def flatMap[T](f: S => Task[T]): Task[T]
def map[T](f: S => T): Task[T]
def mapR[T](f: Result[S] => T): Task[T]
def flatFailure[T](f: Incomplete => Task[T]): Task[T]
def mapFailure[T](f: Incomplete => T): Task[T]
def dependsOn(tasks: Task[_]*): Task[S]
}
trait ForkTask[S, CC[_]]
{
def fork[T](f: S => T): CC[Task[T]]
}
trait JoinTask[S, CC[_]]
{
def join: Task[CC[S]]
def reduce(f: (S,S) => S): Task[S]
}
object Task
{
def pure[T](f: => T): Task[T] = toPure(f _)
def pure[T](name: String, f: => T): Task[T] = new Pure(f _) { override def toString = name }
implicit def toPure[T](f: () => T): Task[T] = new Pure(f)
implicit def toTasks[S](in: Seq[S]): Seq[Task[S]] = in.map(s => pure(s))
implicit def toTasks[S](in: Seq[() => S]): Seq[Task[S]] = in.map(toPure)
implicit def iterableTask[S](in: Seq[S]): ForkTask[S, Seq] = new ForkTask[S, Seq] {
def fork[T](f: S => T): Seq[Task[T]] = in.map(x => pure(x) map f)
}
implicit def joinTasks[S](in: Seq[S]): JoinTask[S, Seq] = joinTasks(toTasks(in))
implicit def joinTasks[S](in: Seq[Task[S]]): JoinTask[S, Seq] = new JoinTask[S, Seq] {
def join: Task[Seq[S]] = new Join(in, (s: Seq[S]) => Right(s) )
//def join[T](f: Iterable[S] => T): Task[Iterable[T]] = new MapAll( MList.fromTCList[Task](in), ml => f(ml.toList))
//def joinR[T](f: Iterable[Result[S]] => T): Task[Iterable[Result[T]]] = new Mapped( MList.fromTCList[Task](in), ml => f(ml.toList))
def reduce(f: (S,S) => S): Task[S] = Task.reduce(in.toIndexedSeq, f)
}
implicit def multInputTask[M <: MList[Task]](ml: M): MultiInTask[M] = new MultiInTask[M] {
def flatMap[T](f: M#Map[Result]#Raw => Task[T]): Task[T] = new FlatMapAll(ml, f)
def flatMapR[T](f: M#Map[Result] => Task[T]): Task[T] = new FlatMapped(ml, f)
def mapH[T](f: M#Map[Result]#Raw => T): Task[T] = new MapAll(ml, f)
def mapR[T](f: M#Map[Result] => T): Task[T] = new Mapped(ml, f)
def flatFailure[T](f: Seq[Incomplete] => Task[T]): Task[T] = new FlatMapFailure(ml, f)
def mapFailure[T](f: Seq[Incomplete] => T): Task[T] = new MapFailure(ml, f)
}
implicit def singleInputTask[S](in: Task[S]): SingleInTask[S] = new SingleInTask[S] {
private val ml = in :^: MNil
private def headM = (_: ml.Map[Result]).head
private def headH = (_: S :+: HNil).head
private def headS = (_: Seq[Incomplete]).head
def flatMapR[T](f: Result[S] => Task[T]): Task[T] = new FlatMapped[T, ml.type](ml, f headM)
def flatMap[T](f: S => Task[T]): Task[T] = new FlatMapAll[T, ml.type](ml, f headH)
def map[T](f: S => T): Task[T] = new MapAll[T, ml.type](ml, f headH)
def mapR[T](f: Result[S] => T): Task[T] = new Mapped[T, ml.type](ml, f headM)
def flatFailure[T](f: Incomplete => Task[T]): Task[T] = new FlatMapFailure(ml, f headS)
def mapFailure[T](f: Incomplete => T): Task[T] = new MapFailure(ml, f headS)
def dependsOn(tasks: Task[_]*): Task[S] = new DependsOn(in, tasks)
}
implicit val taskToNode = new (Task ~> NodeT[Task]#Apply) {
def apply[T](t: Task[T]): Node[Task, T] = t match {
case Pure(eval) => toNode[T, MNil](MNil, _ => Right(eval()) )
case Mapped(in, f) => toNode[T, in.type](in, right f )
case MapAll(in, f) => toNode[T, in.type](in, right (f compose allM) )
case MapFailure(in, f) => toNode[T, in.type](in, right (f compose failuresM))
case FlatMapped(in, f) => toNode[T, in.type](in, left f )
case FlatMapAll(in, f) => toNode[T, in.type](in, left (f compose allM) )
case FlatMapFailure(in, f) => toNode[T, in.type](in, left (f compose failuresM))
case DependsOn(in, tasks) => join[T, Any](tasks, (_: Seq[Result[_]]) => Left(in))
case j@ Join(in, f) => join[T, j.Uniform](in, f compose all)
}
}
def join[T, D](tasks: Seq[Task[D]], f: Seq[Result[D]] => Either[Task[T], T]): Node[Task, T] = new Node[Task, T] {
type Mixed = MNil
val mixedIn = MNil
type Uniform = D
val uniformIn = tasks
def work(mixed: MNil, uniform: Seq[Result[Uniform]]) = {
val inc = failures(uniform)
if(inc.isEmpty) f(uniform) else throw Incomplete(causes = inc)
}
}
def toNode[T, In <: MList[Task]](in: In, f: In#Map[Result] => Either[Task[T], T]): Node[Task, T] = new Node[Task, T] {
type Mixed = In
val mixedIn = in
type Uniform = Nothing
val uniformIn = Nil
def work(results: Mixed#Map[Result], units: Seq[Result[Uniform]]) = f(results)
}
def allM[In <: MList[Result]]: In => In#Raw = in =>
{
val incs = failuresM(in)
if(incs.isEmpty) in.down(Result.tryValue) else throw Incomplete(causes = incs)
}
def all[D]: Seq[Result[D]] => Seq[D] = in =>
{
val incs = failures(in)
if(incs.isEmpty) in.map(Result.tryValue.apply[D]) else throw Incomplete(causes = incs)
}
def failuresM[In <: MList[Result]]: In => Seq[Incomplete] = x => failures[Any](x.toList)
def failures[A]: Seq[Result[A]] => Seq[Incomplete] = _.collect { case Inc(i) => i }
def run[T](root: Task[T], checkCycles: Boolean, maxWorkers: Int): Result[T] =
{
val (service, shutdown) = CompletionService[Task[_], Completed](maxWorkers)
val x = new Execute[Task](checkCycles)(taskToNode)
try { x.run(root)(service) } finally { shutdown() }
}
def tryRun[T](root: Task[T], checkCycles: Boolean, maxWorkers: Int): T =
run(root, checkCycles, maxWorkers) match {
case Value(v) => v
case Inc(i) => throw i
}
def reduce[S](i: IndexedSeq[Task[S]], f: (S, S) => S): Task[S] =
i match
{
case Seq() => error("Cannot reduce empty sequence")
case Seq(x) => x
case Seq(x, y) => reducePair(x, y, f)
case z =>
val (a, b) = i.splitAt(i.size / 2)
reducePair( reduce(a, f), reduce(b, f), f )
}
def reducePair[S](a: Task[S], b: Task[S], f: (S, S) => S): Task[S] =
(a :^: b :^: MNil) mapH { case x :+: y :+: HNil => f(x,y) }
}

View File

@ -1,44 +1,49 @@
import xsbt._
/* sbt -- Simple Build Tool
* Copyright 2009, 2010 Mark Harrah
*/
package sbt
import org.scalacheck._
import Prop._
import TaskGen._
import Task._
object TaskRunnerSpec extends Properties("TaskRunner")
object ExecuteSpec extends Properties("Execute")
{
val iGen = Arbitrary.arbInt.arbitrary
property("evaluates simple task") = forAll(iGen, MaxWorkersGen) { (i: Int, workers: Int) =>
("Workers: " + workers) |:
checkResult(TaskRunner(Task(i), workers), i)
checkResult(tryRun(pure(i), false, workers), i)
}
property("evaluates simple static graph") = forAll(iGen, MaxWorkersGen) { (i: Int, workers: Int) =>
// no direct dependencies currently
/*property("evaluates simple static graph") = forAll(iGen, MaxWorkersGen) { (i: Int, workers: Int) =>
("Workers: " + workers) |:
{
def result = TaskRunner(Task(i) dependsOn(Task(false),Task("a")), workers)
def result = tryRun(Task(i) dependsOn(pure(false),pure("a")), false, workers)
checkResult(result, i)
}
}
}*/
property("evaluates simple mapped task") = forAll(iGen, MaxTasksGen, MaxWorkersGen) { (i: Int, times: Int, workers: Int) =>
("Workers: " + workers) |: ("Value: " + i) |: ("Times: " + times) |:
{
def result = TaskRunner(Task(i).map(_*times), workers)
def result = tryRun(pure(i).map(_*times), false, workers)
checkResult(result, i*times)
}
}
property("evaluates chained mapped task") = forAllNoShrink(iGen, Gen.choose(0, 1000), MaxWorkersGen) { (i: Int, times: Int, workers: Int) =>
property("evaluates chained mapped task") = forAllNoShrink(iGen, MaxTasksGen, MaxWorkersGen) { (i: Int, times: Int, workers: Int) =>
("Workers: " + workers) |: ("Value: " + i) |: ("Times: " + times) |:
{
val initial = Task(0) map(identity[Int])
val initial = pure(0) map(identity[Int])
def task = ( initial /: (0 until times) )( (t,ignore) => t.map(_ + i))
checkResult(TaskRunner(task, workers), i*times)
checkResult(tryRun(task, false, workers), i*times)
}
}
property("evaluates simple bind") = forAll(iGen, MaxTasksGen, MaxWorkersGen) { (i: Int, times: Int, workers: Int) =>
("Workers: " + workers) |: ("Value: " + i) |: ("Times: " + times) |:
{
def result = TaskRunner(Task(i).bind(x => Task(x*times)), workers)
def result = tryRun(pure(i).flatMap(x => pure(x*times)), false, workers)
checkResult(result, i*times)
}
}

View File

@ -1,11 +1,16 @@
/* sbt -- Simple Build Tool
* Copyright 2009 Mark Harrah
*/
package sbt
import org.scalacheck._
import Gen.choose
object TaskGen
{
// upper bounds to make the tests finish in reasonable time
val MaxTasks = 10000
val MaxWorkers = 257
val MaxTasks = 100
val MaxWorkers = 29
val MaxJoin = 100
val MaxTasksGen = choose(0, MaxTasks)

View File

@ -1,8 +1,9 @@
import xsbt._
package sbt
import org.scalacheck._
import Prop._
import TaskGen._
import Task._
object TaskRunnerCircularTest extends Properties("TaskRunner Circular")
{
@ -10,32 +11,33 @@ object TaskRunnerCircularTest extends Properties("TaskRunner Circular")
property("Allows references to completed tasks") = forAllNoShrink(MaxTasksGen, MaxWorkersGen) { allowedReference _ }
final def allowedReference(intermediate: Int, workers: Int) =
{
val top = Task(intermediate) named("top")
val top = pure("top", intermediate)
def iterate(task: Task[Int]): Task[Int] =
task bind { t =>
task flatMap { t =>
if(t <= 0)
top
else
iterate(Task(t-1) named (t-1).toString)
iterate(pure((t-1).toString, t-1) )
}
try { checkResult(TaskRunner(iterate(top), workers), intermediate) }
catch { case e: CircularDependency => ("Unexpected exception: " + e) |: false }
try { checkResult(tryRun(iterate(top), true, workers), intermediate) }
catch { case i: Incomplete if cyclic(i) => ("Unexpected cyclic exception: " + i) |: false }
}
final def checkCircularReferences(intermediate: Int, workers: Int) =
{
lazy val top = iterate(Task(intermediate) named"bottom", intermediate)
lazy val top = iterate(pure("bottom", intermediate), intermediate)
def iterate(task: Task[Int], i: Int): Task[Int] =
{
lazy val it: Task[Int] =
task bind { t =>
task flatMap { t =>
if(t <= 0)
top
else
iterate(Task(t-1) named (t-1).toString, i-1)
} named("it_" + i)
iterate(pure((t-1).toString, t-1), i-1)
}
it
}
try { TaskRunner(top, workers); false }
catch { case TasksFailed(failures) => failures.exists(_.exception.isInstanceOf[CircularDependency]) }
try { tryRun(top, true, workers); false }
catch { case i: Incomplete => cyclic(i) }
}
def cyclic(i: Incomplete) = Incomplete.allExceptions(i).exists(_.isInstanceOf[Execute[Task]#CyclicException[_]])
}

View File

@ -1,22 +1,22 @@
import xsbt._
import sbt._
import org.scalacheck._
import Prop._
import Task._
import TaskGen._
import Math.abs
import math.abs
object TaskRunnerForkTest extends Properties("TaskRunner Fork")
{
property("fork m tasks and wait for all to complete") = forAll(MaxTasksGen, MaxWorkersGen) { (m: Int, workers: Int) =>
val values = (0 until m).toList
checkResult(TaskRunner(values.fork(f => () ).join.map(_.toList),workers), values)
checkResult(tryRun(values.fork(f => () ).join.map(_.toList),false, workers), values)
true
}
property("Fork and reduce 2") = forAll(MaxTasksGen, MaxWorkersGen) { (m: Int, workers: Int) =>
(m > 1) ==> {
val task = (0 to m) fork {_ * 10} reduce{_ + _}
checkResult(TaskRunner(task, workers), 5*(m+1)*m)
checkResult(tryRun(task, false, workers), 5*(m+1)*m)
}
}
property("Double join") = forAll(MaxJoinGen, MaxJoinGen, MaxWorkersGen) { (a: Int, b: Int, workers: Int) =>
@ -25,13 +25,13 @@ object TaskRunnerForkTest extends Properties("TaskRunner Fork")
}
def runDoubleJoin(a: Int, b: Int, workers: Int)
{
def inner(i: Int) = List.range(0, b).map(j => Task(j) named(j.toString)).join.named("Join " + i)
TaskRunner( List.range(0,a).map(inner).join.named("Outermost join"), workers)
def inner(i: Int) = List.range(0, b).map(j => pure(j.toString, j)).join
tryRun( List.range(0,a).map(inner).join, false, workers)
}
property("fork and reduce") = forAll(TaskListGen, MaxWorkersGen) { (m: List[Int], workers: Int) =>
(!m.isEmpty) ==> {
val expected = m.reduceLeft(_+_)
checkResult(TaskRunner( m.reduce(_ + _), workers), expected)
checkResult(tryRun( m.reduce(_ + _), false, workers), expected)
}
}
}

View File

@ -4,60 +4,22 @@
package sbt
import Types._
import Node._
import Task._
import Execute._
sealed trait Task[+T]
sealed case class Pure[+T](eval: () => T) extends Task[T]
sealed case class Mapped[+T, In <: MList[Task]](in: In, f: In#Map[Result] => T) extends Task[T]
sealed case class MapAll[+T, In <: MList[Task]](in: In, f: In#Map[Result]#Raw => T) extends Task[T]
sealed case class FlatMapAll[+T, In <: MList[Task]](in: In, f: In#Map[Result]#Raw => Task[T]) extends Task[T]
sealed case class FlatMapped[+T, In <: MList[Task]](in: In, f: In#Map[Result] => Task[T]) extends Task[T]
object Task
{
implicit val taskToNode = new (Task ~> NodeT[Task]#Apply) {
def apply[T](t: Task[T]): Node[Task, T] = t match {
case Pure(eval) => toNode[T, MNil](MNil, _ => Right(eval()) )
case Mapped(in, f) => toNode[T, in.type](in, right f )
case MapAll(in, f) => toNode[T, in.type](in, right (f compose all) )
case FlatMapAll(in, f) => toNode[T, in.type](in, left (f compose all) )
case FlatMapped(in, f) => toNode[T, in.type](in, left f )
}
}
def toNode[T, In <: MList[Task]](in: In, f: In#Map[Result] => Either[Task[T], T]): Node[Task, T] = new Node[Task, T] {
type Inputs = In
val inputs = in
def unitDependencies = Nil
def work(results: Results, units: UnitResults[Task]) = f(results)
}
def pure[T](name: String)(f: => T): Pure[T] = new Pure(f _) { override def toString = name }
def mapped[T, In0 <: MList[Task]](name: String)(in0: In0)(f0: In0#Map[Result] => T): Mapped[T, In0] = new Mapped(in0, f0) { override def toString = name }
def flat[T, In0 <: MList[Task]](name: String)(in0: In0)(f0: In0#Map[Result] => Task[T]): FlatMapped[T, In0] = new FlatMapped(in0, f0) { override def toString = name }
def mapAll[T, In0 <: MList[Task]](name: String)(in0: In0)(f0: In0#Map[Result]#Raw => T): MapAll[T, In0] = new MapAll(in0, f0) { override def toString = name }
def flatAll[T, In0 <: MList[Task]](name: String)(in0: In0)(f0: In0#Map[Result]#Raw => Task[T]): FlatMapAll[T, In0] = new FlatMapAll(in0, f0) { override def toString = name }
def all[In <: MList[Result]]: In => In#Raw = in =>
{
val incs = in.toList.collect { case Inc(i) => i }
if(incs.isEmpty) in.down(Result.tryValue) else throw Incomplete(causes = incs)
}
}
object Test
{
val a = pure("a")(3)
val b = pure[Boolean]("b")(error("test"))
val b2 = pure("b2")(true)
val c = pure("x")("asdf")
val a = pure(3)
val b = pure[Boolean](error("test"))
val b2 = pure(true)
val c = pure("asdf")
val i3 = a :^: b :^: c :^: MNil
val i32 = a :^: b2 :^: c :^: MNil
val fh= (_: Int :+: Boolean :+: String :+: HNil) match
{ case aa :+: bb :+: cc :+: HNil => aa + " " + bb + " " + cc }
val h1 = mapAll("h1")(i3)(fh)
val h2 = mapAll("h2")(i32)(fh)
val h1 = i3 mapH fh
val h2 = i32 mapH fh
val f: i3.Map[Result] => Any = {
case Value(aa) :^: Value(bb) :^: Value(cc) :^: MNil => aa + " " + bb + " " + cc
@ -65,41 +27,24 @@ object Test
val cs = x.toList.collect { case Inc(x) => x } // workaround for double definition bug
throw Incomplete(causes = cs)
}
val d2 = mapped("d2")(i32)(f)
val d2 = i32 mapR f
val f2: i3.Map[Result] => Task[Any] = {
case Value(aa) :^: Value(bb) :^: Value(cc) :^: MNil => new Pure(() => aa + " " + bb + " " + cc)
case x => d3
}
lazy val d = flat("d")(i3)(f2)
lazy val d = i3 flatMapR f2
val f3: i3.Map[Result] => Task[Any] = {
case Value(aa) :^: Value(bb) :^: Value(cc) :^: MNil => new Pure(() => aa + " " + bb + " " + cc)
case x => d2
}
lazy val d3= flat("d3")(i3)(f3)
lazy val d3= i3 flatMapR f3
def d4(i: Int): Task[Int] = flat("d4")(MNil){ _ => val x = math.random; if(x < 0.01) pure(x.toString)(i); else d4(i+1) }
lazy val pureEval =
new (Pure ~> Result) {
def apply[T](p: Pure[T]): Result[T] =
try { Value(p.eval()) }
catch { case e: Exception => throw Incomplete(Incomplete.Error, directCause = Some(e)) }
}
lazy val resultA = d.f( d.in.map(pureEval) )
def execute[T](root: Task[T]) = {
val (service, shutdown) = CompletionService[Task[_], Completed](2)
implicit val wrapped = CompletionService.manage(service)(x => println("Starting: " + x), x => println("Finished: " + x) )
val x = new Execute[Task](true)(taskToNode)
try { x.run(root) } finally { shutdown(); println(x.dump) }
}
def d4(i: Int): Task[Int] = MNil flatMap { _ => val x = math.random; if(x < 0.01) pure(i); else d4(i+1) }
def go()
{
def run[T](root: Task[T]) =
println("Result : " + execute(root))
println("Result : " + Task.run(root, true, 2))
run(a)
run(b)

View File

@ -1,8 +1,9 @@
import xsbt._
import sbt._
import org.scalacheck._
import Prop._
import TaskGen._
import Task._
object TaskRunnerCallTest extends Properties("TaskRunner Call")
{
@ -11,7 +12,7 @@ object TaskRunnerCallTest extends Properties("TaskRunner Call")
val f = fibDirect(i)
("Workers: " + workers) |: ("i: " + i) |: ("fib(i): " + f) |:
{
def result = TaskRunner( fibTask(i), workers)
def result = tryRun( fibTask(i), false, workers)
checkResult(result, f)
}
}
@ -23,11 +24,11 @@ object TaskRunnerCallTest extends Properties("TaskRunner Call")
(index, x1, x2) =>
{
if(index == i)
Task(x2)
pure(x2)
else
iterate( (index+1, x2, x1+x2) )
}
def iterate(iteration: (Int,Int,Int)) = Task( iteration ) bind Function.tupled(next)
def iterate(iteration: (Int,Int,Int)) = pure( iteration ) flatMap next.tupled
iterate( (1, 0, 1) )
}
final def fibDirect(i: Int): Int =

View File

@ -1,8 +1,13 @@
import xsbt._
/* sbt -- Simple Build Tool
* Copyright 2009, 2010 Mark Harrah
*/
package sbt
import org.scalacheck._
import Prop._
import TaskGen._
import Task._
import Types._
object TaskRunnerSortTest extends Properties("TaskRunnerSort")
{
@ -12,31 +17,33 @@ object TaskRunnerSortTest extends Properties("TaskRunnerSort")
java.util.Arrays.sort(sorted)
("Workers: " + workers) |: ("Array: " + a.toList) |:
{
def result = TaskRunner( sort(a.toArray), if(workers > 0) workers else 1)
def result = tryRun( sort(a.toSeq), false, if(workers > 0) workers else 1)
checkResult(result.toList, sorted.toList)
}
}
final def sortDirect(a: RandomAccessSeq[Int]): RandomAccessSeq[Int] =
final def sortDirect(a: Seq[Int]): Seq[Int] =
{
if(a.length < 2)
a
else
{
val pivot = a(0)
val (lt,gte) = a.projection.drop(1).partition(_ < pivot)
val (lt,gte) = a.view.drop(1).partition(_ < pivot)
sortDirect(lt) ++ List(pivot) ++ sortDirect(gte)
}
}
final def sort(a: RandomAccessSeq[Int]): Task[RandomAccessSeq[Int]] =
final def sort(a: Seq[Int]): Task[Seq[Int]] =
{
if(a.length < 200)
Task(sortDirect(a))
pure(sortDirect(a))
else
{
Task(a) bind { a =>
pure(a) flatMap { a =>
val pivot = a(0)
val (lt,gte) = a.projection.drop(1).partition(_ < pivot)
(sort(lt), sort(gte)) map { _ ++ List(pivot) ++ _ }
val (lt,gte) = a.view.drop(1).partition(_ < pivot)
sort(lt) :^: sort(gte) :^: MNil mapH {
case l :+: g :+: HNil => l ++ List(pivot) ++ g
}
}
}
}

View File

@ -1,4 +1,7 @@
package xsbt
/* sbt -- Simple Build Tool
* Copyright 2009 Mark Harrah
*/
package sbt
import org.scalacheck.Prop._
@ -14,8 +17,8 @@ object checkResult
}
catch
{
case TasksFailed(failures) =>
failures.foreach(f => f.exception.printStackTrace)
case i: Incomplete =>
println(Incomplete.show(i, true))
"One or more tasks failed" |: false
case e =>
e.printStackTrace