Merge pull request #1316 from sbt/wip/fix-broken-build

This doesn't quite fix the build, but gets closer
This commit is contained in:
eugene yokota 2014-05-07 12:23:09 -04:00
commit d198ea4099
64 changed files with 3655 additions and 3726 deletions

View File

@ -1,17 +1,24 @@
language: scala
script:
- sbt "scripted $SCRIPTED_TEST"
- sbt "$SCRIPTED_TEST"
env:
- SCRIPTED_TEST=actions/*
- SCRIPTED_TEST=api/*
- SCRIPTED_TEST=compiler-project/*
- SCRIPTED_TEST=dependency-management/*
- SCRIPTED_TEST=java/*
- SCRIPTED_TEST=package/*
- SCRIPTED_TEST=reporter/*
- SCRIPTED_TEST=run/*
- SCRIPTED_TEST=source-dependencies/*
- SCRIPTED_TEST=tests/*
- SCRIPTED_TEST="scripted actions/*"
- SCRIPTED_TEST="scripted api/*"
- SCRIPTED_TEST="scripted compiler-project/*""
- SCRIPTED_TEST="scripted dependency-management/*1of2"
- SCRIPTED_TEST="scripted dependency-management/*2of2"
- SCRIPTED_TEST="scripted java/*"
- SCRIPTED_TEST="scripted package/*"
- SCRIPTED_TEST="scripted project/*"
- SCRIPTED_TEST="scripted reporter/*"
- SCRIPTED_TEST="scripted run/*"
- SCRIPTED_TEST="scripted source-dependencies/*1of3"
- SCRIPTED_TEST="scripted source-dependencies/*2of3"
- SCRIPTED_TEST="scripted source-dependencies/*3of3"
- SCRIPTED_TEST="scripted tests/*"
- SCRIPTED_TEST="all launcher/test main-settings/test main/test ivy/test logic/test completion/test"
- SCRIPTED_TEST="all actions/test classpath/test collections/test incremental-compiler/test logging/test run/test task-system/test"
# TODO - we'd like to actually test everything, but the process library has a deadlock right now
jdk:
- openjdk6
notifications:

View File

@ -3,7 +3,7 @@ package sbt
import java.io.File
import Types.:+:
object CacheTest// extends Properties("Cache test")
object CacheTest // extends Properties("Cache test")
{
val lengthCache = new File("/tmp/length-cache")
val cCache = new File("/tmp/c-cache")
@ -12,8 +12,7 @@ object CacheTest// extends Properties("Cache test")
import FileInfo.hash._
import Ordering._
import sbinary.DefaultProtocol.FileFormat
def test
{
def test {
lazy val create = new File("test")
val length = cached(lengthCache) {
@ -25,7 +24,7 @@ object CacheTest// extends Properties("Cache test")
val c = cached(cCache) { (in: (File :+: Long :+: HNil)) =>
val file :+: len :+: HNil = in
println("File: " + file + " (" + file.exists + "), length: " + len)
(len+1) :+: file :+: HNil
(len + 1) :+: file :+: HNil
}
c(create :+: fileLength :+: HNil)
}

View File

@ -24,7 +24,7 @@ class NameHashingSpecification extends Specification {
val nameHashes2 = nameHashing.nameHashes(api2)
assertNameHashEqualForRegularName("Bar", nameHashes1, nameHashes2)
assertNameHashEqualForRegularName("foo", nameHashes1, nameHashes2)
nameHashes1.regularMembers.map(_.name).toSeq must not contain("bar")
nameHashes1.regularMembers.map(_.name).toSeq must not contain ("bar")
nameHashes2.regularMembers.map(_.name).toSeq must contain("bar")
}

View File

@ -8,7 +8,6 @@ import org.scalacheck._
import Gen._
import Prop._
object AnalysisTest extends Properties("Analysis") {
// Merge and split a hard-coded trivial example.
property("Simple Merge and Split") = {
@ -27,7 +26,7 @@ object AnalysisTest extends Properties("Analysis") {
a = a.addProduct(aScala, f("A$.class"), exists, "A$")
a = a.addSource(aScala, aSource, exists, Nil, Nil, sourceInfos)
a = a.addBinaryDep(aScala, f("x.jar"), "x", exists)
a = a.addExternalDep(aScala, "C", cSource, inherited=false)
a = a.addExternalDep(aScala, "C", cSource, inherited = false)
// b
var b = Analysis.Empty
@ -36,7 +35,7 @@ object AnalysisTest extends Properties("Analysis") {
b = b.addSource(bScala, bSource, exists, Nil, Nil, sourceInfos)
b = b.addBinaryDep(bScala, f("x.jar"), "x", exists)
b = b.addBinaryDep(bScala, f("y.jar"), "y", exists)
b = b.addExternalDep(bScala, "A", aSource, inherited=true)
b = b.addExternalDep(bScala, "A", aSource, inherited = true)
// ab
var ab = Analysis.Empty
@ -49,7 +48,7 @@ object AnalysisTest extends Properties("Analysis") {
ab = ab.addBinaryDep(aScala, f("x.jar"), "x", exists)
ab = ab.addBinaryDep(bScala, f("x.jar"), "x", exists)
ab = ab.addBinaryDep(bScala, f("y.jar"), "y", exists)
ab = ab.addExternalDep(aScala, "C", cSource, inherited=false)
ab = ab.addExternalDep(aScala, "C", cSource, inherited = false)
val split: Map[String, Analysis] = ab.groupBy({ f: File => f.getName.substring(0, 1) })
@ -67,7 +66,7 @@ object AnalysisTest extends Properties("Analysis") {
// Mustn't shrink, as the default Shrink[Int] doesn't respect the lower bound of choose(), which will cause
// a divide-by-zero error masking the original error.
property("Complex Merge and Split") = forAllNoShrink(genAnalysis, choose(1, 10)) { (analysis: Analysis, numSplits: Int) =>
val grouped: Map[Int, Analysis] = analysis.groupBy({ f: File => abs(f.hashCode()) % numSplits})
val grouped: Map[Int, Analysis] = analysis.groupBy({ f: File => abs(f.hashCode()) % numSplits })
def getGroup(i: Int): Analysis = grouped.getOrElse(i, Analysis.Empty)
val splits = (Range(0, numSplits) map getGroup).toList

View File

@ -11,7 +11,6 @@ import sbt.Relation
import xsbti.api._
import xsbti.SafeLazy
/**
* Scalacheck generators for Analysis objects and their substructures.
* Fairly complex, as Analysis has interconnected state that can't be
@ -38,7 +37,7 @@ object TestCaseGenerators {
n <- choose(3, maxPathSegmentLen) // Segments have at least 3 characters.
c <- alphaChar
cs <- listOfN(n - 1, alphaNumChar)
} yield (c::cs).mkString
} yield (c :: cs).mkString
def genFile: Gen[File] = for {
n <- choose(2, maxPathLen) // Paths have at least 2 segments.
@ -69,7 +68,7 @@ object TestCaseGenerators {
lzy(new Structure(lzy(Array()), lzy(Array()), lzy(Array()))), Array(), Array(),
name, new Public(), new Modifiers(false, false, false, false, false, false, false), Array())
private [this] def lzy[T <: AnyRef](x: T) = SafeLazy.strict(x)
private[this] def lzy[T <: AnyRef](x: T) = SafeLazy.strict(x)
def genNameHash(defn: String): Gen[xsbti.api._internalOnly_NameHash] =
value(new xsbti.api._internalOnly_NameHash(defn, defn.hashCode()))
@ -98,11 +97,11 @@ object TestCaseGenerators {
def genSource(defns: Seq[String]): Gen[Source] = for {
startTime <- arbitrary[Long]
hashLen <- choose(10, 20) // Requred by SameAPI to be > 0.
hash <- Gen.containerOfN[Array,Byte](hashLen, arbitrary[Byte])
hash <- Gen.containerOfN[Array, Byte](hashLen, arbitrary[Byte])
apiHash <- arbitrary[Int]
hasMacro <- arbitrary[Boolean]
nameHashes <- genNameHashes(defns)
} yield new Source(new Compilation(startTime, Array()), hash, new SourceAPI(Array(), Array(defns map makeDefinition:_*)), apiHash, nameHashes, hasMacro)
} yield new Source(new Compilation(startTime, Array()), hash, new SourceAPI(Array(), Array(defns map makeDefinition: _*)), apiHash, nameHashes, hasMacro)
def genSources(all_defns: Seq[Seq[String]]): Gen[Seq[Source]] = Gen.sequence[List, Source](all_defns.map(genSource))
@ -127,7 +126,7 @@ object TestCaseGenerators {
internal <- listOfN(srcs.length, someOf(srcs)) // Internal dep targets must come from list of sources.
external <- genStringRelation(srcs)
} yield Relations.makeSource( // Ensure that we don't generate a dep of some file on itself.
Relation.reconstruct((srcs zip (internal map { _.toSet } ) map {case (a, b) => (a, b - a) }).toMap),
Relation.reconstruct((srcs zip (internal map { _.toSet }) map { case (a, b) => (a, b - a) }).toMap),
external)
def genSubRSource(src: Relations.Source): Gen[Relations.Source] = for {
@ -144,7 +143,7 @@ object TestCaseGenerators {
publicInherited <- genSubRSource(direct)
classes <- genStringRelation(srcs)
} yield Relations.make(srcProd, binaryDep, direct, publicInherited , classes)
} yield Relations.make(srcProd, binaryDep, direct, publicInherited, classes)
def genAnalysis: Gen[Analysis] = for {
rels <- genRelations

View File

@ -78,9 +78,10 @@ class ScalaCompilerForUnitTesting(nameHashing: Boolean = false) {
val memberRefDeps = memberRefFileDeps map { case (src, target) => toSymbols(src, target) }
val inheritanceDeps = inheritanceFileDeps map { case (src, target) => toSymbols(src, target) }
def pairsToMultiMap[A, B](pairs: Seq[(A, B)]): Map[A, Set[B]] = {
import scala.collection.mutable.{HashMap, MultiMap}
import scala.collection.mutable.{ HashMap, MultiMap }
val emptyMultiMap = new HashMap[A, scala.collection.mutable.Set[B]] with MultiMap[A, B]
val multiMap = pairs.foldLeft(emptyMultiMap) { case (acc, (key, value)) =>
val multiMap = pairs.foldLeft(emptyMultiMap) {
case (acc, (key, value)) =>
acc.addBinding(key, value)
}
// convert all collections to immutable variants
@ -116,9 +117,10 @@ class ScalaCompilerForUnitTesting(nameHashing: Boolean = false) {
val compiler = prepareCompiler(classesDir, analysisCallback, classesDir.toString)
val files = for((compilationUnit, unitId) <- groupedSrcs.zipWithIndex) yield {
val files = for ((compilationUnit, unitId) <- groupedSrcs.zipWithIndex) yield {
val run = new compiler.Run
val srcFiles = compilationUnit.toSeq.zipWithIndex map { case (src, i) =>
val srcFiles = compilationUnit.toSeq.zipWithIndex map {
case (src, i) =>
val fileName = s"Test-$unitId-$i.scala"
prepareSrcFile(temp, fileName, src)
}

View File

@ -3,12 +3,11 @@ package sbt
import java.io.File
import org.specs2._
import mutable.Specification
import IO.{createDirectory, delete, touch, withTemporaryDirectory}
import IO.{ createDirectory, delete, touch, withTemporaryDirectory }
import org.apache.ivy.util.ChecksumHelper
import IfMissing.Fail
object ComponentManagerTest extends Specification
{
object ComponentManagerTest extends Specification {
val TestID = "manager-test"
"Component manager" should {
"throw an exception if 'file' is called for a non-existing component" in {
@ -17,7 +16,7 @@ object ComponentManagerTest extends Specification
"throw an exception if 'file' is called for an empty component" in {
withManager { manager =>
manager.define(TestID, Nil)
( manager.file(TestID)(Fail) ) must throwA[InvalidComponent]
(manager.file(TestID)(Fail)) must throwA[InvalidComponent]
}
}
"return the file for a single-file component" in {
@ -30,7 +29,7 @@ object ComponentManagerTest extends Specification
"throw an exception if 'file' is called for multi-file component" in {
withManager { manager =>
defineFiles(manager, TestID, "a", "b")
( manager.file(TestID)(Fail) ) must throwA[InvalidComponent]
(manager.file(TestID)(Fail)) must throwA[InvalidComponent]
}
}
"return the files for a multi-file component" in {
@ -53,26 +52,24 @@ object ComponentManagerTest extends Specification
withTemporaryDirectory { ivyHome =>
withManagerHome(ivyHome) { definingManager =>
val hash = defineFile(definingManager, TestID, "a")
try
{
try {
definingManager.cache(TestID)
withManagerHome(ivyHome) { usingManager =>
checksum(usingManager.file(TestID)(Fail)) must beEqualTo(hash)
}
}
finally { definingManager.clearCache(TestID) }
} finally { definingManager.clearCache(TestID) }
}
}
}
}
private def checksum(files: Iterable[File]): Seq[String] = files.map(checksum).toSeq
private def checksum(file: File): String = if(file.exists) ChecksumHelper.computeAsString(file, "sha1") else ""
private def checksum(file: File): String = if (file.exists) ChecksumHelper.computeAsString(file, "sha1") else ""
private def defineFile(manager: ComponentManager, id: String, name: String): String = createFile(manager, id, name)(checksum)
private def defineFiles(manager: ComponentManager, id: String, names: String*): Seq[String] = createFiles(manager, id, names : _*)(checksum)
private def defineFiles(manager: ComponentManager, id: String, names: String*): Seq[String] = createFiles(manager, id, names: _*)(checksum)
private def createFile[T](manager: ComponentManager, id: String, name: String)(f: File => T): T = createFiles(manager, id, name)(files => f(files.toList.head))
private def createFiles[T](manager: ComponentManager, id: String, names: String*)(f: Seq[File] => T): T =
withTemporaryDirectory { dir =>
val files = names.map(name => new File(dir, name) )
val files = names.map(name => new File(dir, name))
files.foreach(writeRandomContent)
manager.define(id, files)
f(files)

View File

@ -4,8 +4,7 @@ import java.io.File
import org.specs2._
import mutable.Specification
object CrossVersionTest extends Specification
{
object CrossVersionTest extends Specification {
"Cross version" should {
"return sbt API for xyz as None" in {
CrossVersion.sbtApiVersion("xyz") must_== None

View File

@ -4,10 +4,9 @@ import java.io.File
import org.specs2._
import mutable.Specification
object MakePomTest extends Specification
{
object MakePomTest extends Specification {
val mp = new MakePom(ConsoleLogger())
import mp.{makeDependencyVersion=>v}
import mp.{ makeDependencyVersion => v }
"MakePom makeDependencyVersion" should {
"Handle .+ in versions" in {
v("1.+") must_== "[1,2)"

View File

@ -3,13 +3,12 @@ package xsbt.boot
import org.scalacheck._
import Prop._
object CacheTest extends Properties("Cache")
{
implicit val functions: Arbitrary[Int => Int] = Arbitrary { Gen.oneOf( Seq(identity[Int], i => -i, i=>i/2, i => i+1) ) }
object CacheTest extends Properties("Cache") {
implicit val functions: Arbitrary[Int => Int] = Arbitrary { Gen.oneOf(Seq(identity[Int], i => -i, i => i / 2, i => i + 1)) }
property("Cache") = Prop.forAll { (key: Int, keys: List[Int], map: Int => Int) =>
val cache = new Cache( (i: Int, _: Unit) => map(i) )
val cache = new Cache((i: Int, _: Unit) => map(i))
def toProperty(key: Int) = ("Key " + key) |: ("Value: " + map(key)) |: (cache.apply(key, ()) == map(key))
Prop.all( keys.map(toProperty) : _*)
Prop.all(keys.map(toProperty): _*)
}
}

View File

@ -1,15 +1,14 @@
package xsbt.boot
import java.io.{File,InputStream}
import java.io.{ File, InputStream }
import java.net.URL
import java.util.Properties
import xsbti._
import org.specs2._
import mutable.Specification
import sbt.IO.{createDirectory, touch,withTemporaryDirectory}
import sbt.IO.{ createDirectory, touch, withTemporaryDirectory }
object ConfigurationParserTest extends Specification
{
object ConfigurationParserTest extends Specification {
"Configuration Parser" should {
"Correctly parse bootOnly" in {

View File

@ -1,21 +1,20 @@
package xsbt.boot
import org.scalacheck._
import Prop.{Exception => _,_}
import Prop.{ Exception => _, _ }
object EnumerationTest extends Properties("Enumeration")
{
property("MultiEnum.toValue") = checkToValue(MultiEnum, multiElements : _*)
property("MultiEnum.elements") = checkElements(MultiEnum, multiElements : _*)
object EnumerationTest extends Properties("Enumeration") {
property("MultiEnum.toValue") = checkToValue(MultiEnum, multiElements: _*)
property("MultiEnum.elements") = checkElements(MultiEnum, multiElements: _*)
property("EmptyEnum.toValue") = checkToValue(EmptyEnum)
property("EmptyEnum.elements") = EmptyEnum.elements.isEmpty
property("SingleEnum.toValue") = checkToValue( SingleEnum, singleElements )
property("SingleEnum.elements") = checkElements( SingleEnum,singleElements )
property("SingleEnum.toValue") = checkToValue(SingleEnum, singleElements)
property("SingleEnum.elements") = checkElements(SingleEnum, singleElements)
def singleElements = ("A", SingleEnum.a)
def multiElements =
{
import MultiEnum.{a,b,c}
import MultiEnum.{ a, b, c }
List(("A" -> a), ("B" -> b), ("C" -> c))
}
@ -23,7 +22,7 @@ object EnumerationTest extends Properties("Enumeration")
{
val elements = enum.elements
("elements: " + elements) |:
( mapped.forall{ case (s,v) => elements.contains(v) } && (elements.length == mapped.length) )
(mapped.forall { case (s, v) => elements.contains(v) } && (elements.length == mapped.length))
}
def checkToValue(enum: Enumeration, mapped: (String, Enumeration#Value)*) =
{
@ -33,22 +32,20 @@ object EnumerationTest extends Properties("Enumeration")
def valid(s: String, expected: Enumeration#Value) =
("valueOf(" + s + ")") |:
("Expected " + expected) |:
( enum.toValue(s) == expected )
val map = Map( mapped : _*)
Prop.forAll( (s: String) =>
(enum.toValue(s) == expected)
val map = Map(mapped: _*)
Prop.forAll((s: String) =>
map.get(s) match {
case Some(v) => valid(s, v)
case None => invalid(s)
} )
})
}
object MultiEnum extends Enumeration
{
object MultiEnum extends Enumeration {
val a = value("A")
val b = value("B")
val c = value("C")
}
object SingleEnum extends Enumeration
{
object SingleEnum extends Enumeration {
val a = value("A")
}
object EmptyEnum extends Enumeration

View File

@ -2,20 +2,19 @@ package xsbt.boot
import org.scalacheck._
object ListMapProperties extends Properties("ListMap")
{
implicit val genListMap = Arbitrary ( for(list <- Arbitrary.arbitrary[List[(Int,Int)]]) yield ListMap(list : _*) )
object ListMapProperties extends Properties("ListMap") {
implicit val genListMap = Arbitrary(for (list <- Arbitrary.arbitrary[List[(Int, Int)]]) yield ListMap(list: _*))
property("ListMap from List contains all members of that List") = Prop.forAll { (list: List[(Int,Int)]) =>
val map = ListMap(list : _*)
property("ListMap from List contains all members of that List") = Prop.forAll { (list: List[(Int, Int)]) =>
val map = ListMap(list: _*)
list forall { entry => map contains entry._1 }
}
property("contains added entry") = Prop.forAll { (map: ListMap[Int,Int], key: Int, value: Int) =>
{ (map + (key, value) ) contains(key) } &&
{ (map + (key, value) )(key) == value } &&
{ (map + (key, value) ).get(key) == Some(value) }
property("contains added entry") = Prop.forAll { (map: ListMap[Int, Int], key: Int, value: Int) =>
{ (map + (key, value)) contains (key) } &&
{ (map + (key, value))(key) == value } &&
{ (map + (key, value)).get(key) == Some(value) }
}
property("remove") = Prop.forAll { (map: ListMap[Int,Int], key: Int) =>
property("remove") = Prop.forAll { (map: ListMap[Int, Int], key: Int) =>
{ Prop.throws(classOf[Exception])((map - key)(key)) } &&
{ !(map - key).contains(key) } &&
{ (map - key).get(key).isEmpty }
@ -27,8 +26,7 @@ object ListMapProperties extends Properties("ListMap")
}
}
object ListMapEmpty extends Properties("ListMap.empty")
{
object ListMapEmpty extends Properties("ListMap.empty") {
import ListMap.empty
property("isEmpty") = empty.isEmpty
property("toList.isEmpty") = empty.toList.isEmpty

View File

@ -5,10 +5,11 @@ import Prop._
import java.io.File
import sbt.IO.withTemporaryDirectory
/** These mainly test that things work in the uncontested case and that no OverlappingFileLockExceptions occur.
* There is no real locking testing, just the coordination of locking.*/
object LocksTest extends Properties("Locks")
{
/**
* These mainly test that things work in the uncontested case and that no OverlappingFileLockExceptions occur.
* There is no real locking testing, just the coordination of locking.
*/
object LocksTest extends Properties("Locks") {
property("Lock in nonexisting directory") = spec {
withTemporaryDirectory { dir =>
val lockFile = new File(dir, "doesntexist/lock")
@ -36,11 +37,11 @@ object LocksTest extends Properties("Locks")
property("Contested single lock") = spec {
withTemporaryDirectory { dir =>
val lockFile = new File(dir, "lock")
forkFold(2000){i => Locks(lockFile, callTrue) }
forkFold(2000) { i => Locks(lockFile, callTrue) }
}
}
private def spec(f: => Boolean): Prop = Prop { _ => Result(if(f) True else False) }
private def spec(f: => Boolean): Prop = Prop { _ => Result(if (f) True else False) }
private def call[T](impl: => T) = new java.util.concurrent.Callable[T] { def call = impl }
private def callLocked(lockFile: File) = call { Locks(lockFile, callTrue) }

View File

@ -1,28 +1,27 @@
package xsbt.boot
import java.io.File
import java.util.Arrays.{equals => arrEquals}
import java.util.Arrays.{ equals => arrEquals }
import org.scalacheck._
object PreTest extends Properties("Pre")
{
object PreTest extends Properties("Pre") {
import Pre._
property("isEmpty") = Prop.forAll( (s: String) => (s.isEmpty == isEmpty(s)) )
property("isNonEmpty") = Prop.forAll( (s: String) => (isEmpty(s) != isNonEmpty(s)) )
property("isEmpty") = Prop.forAll((s: String) => (s.isEmpty == isEmpty(s)))
property("isNonEmpty") = Prop.forAll((s: String) => (isEmpty(s) != isNonEmpty(s)))
property("assert true") = { assert(true); true }
property("assert false") = Prop.throws(classOf[AssertionError])(assert(false))
property("assert true with message") = Prop.forAll { (s: String) => assert(true, s); true }
property("assert false with message") = Prop.forAll( (s: String) => Prop.throws(classOf[AssertionError] )(assert(false, s)) )
property("require false") = Prop.forAll( (s: String) => Prop.throws(classOf[IllegalArgumentException])(require(false, s)) )
property("assert false with message") = Prop.forAll((s: String) => Prop.throws(classOf[AssertionError])(assert(false, s)))
property("require false") = Prop.forAll((s: String) => Prop.throws(classOf[IllegalArgumentException])(require(false, s)))
property("require true") = Prop.forAll { (s: String) => require(true, s); true }
property("error") = Prop.forAll( (s: String) => Prop.throws(classOf[BootException])(error(s)) )
property("toBoolean") = Prop.forAll( (s: String) => trap(toBoolean(s)) == trap(java.lang.Boolean.parseBoolean(s)) )
property("toArray") = Prop.forAll( (list: List[Int]) => arrEquals(list.toArray, toArray(list)) )
property("toArray") = Prop.forAll( (list: List[String]) => objArrEquals(list.toArray, toArray(list)) )
property("error") = Prop.forAll((s: String) => Prop.throws(classOf[BootException])(error(s)))
property("toBoolean") = Prop.forAll((s: String) => trap(toBoolean(s)) == trap(java.lang.Boolean.parseBoolean(s)))
property("toArray") = Prop.forAll((list: List[Int]) => arrEquals(list.toArray, toArray(list)))
property("toArray") = Prop.forAll((list: List[String]) => objArrEquals(list.toArray, toArray(list)))
property("concat") = Prop.forAll(genFiles, genFiles) { (a: Array[File], b: Array[File]) => (a ++ b) sameElements concat(a, b) }
property("array") = Prop.forAll(genFiles) { (a: Array[File]) => array(a.toList : _*) sameElements Array(a: _*) }
property("array") = Prop.forAll(genFiles) { (a: Array[File]) => array(a.toList: _*) sameElements Array(a: _*) }
implicit lazy val arbFile: Arbitrary[File] = Arbitrary { for(i <- Arbitrary.arbitrary[Int] ) yield new File(i.toString) }
implicit lazy val arbFile: Arbitrary[File] = Arbitrary { for (i <- Arbitrary.arbitrary[Int]) yield new File(i.toString) }
implicit lazy val genFiles: Gen[Array[File]] = Arbitrary.arbitrary[Array[File]]
def trap[T](t: => T): Option[T] = try { Some(t) } catch { case e: Exception => None }

View File

@ -1,21 +1,22 @@
package xsbt.boot
import java.io.{File,InputStream}
import java.io.{ File, InputStream }
import java.net.URL
import java.util.Properties
import xsbti._
import org.specs2._
import mutable.Specification
import LaunchTest._
import sbt.IO.{createDirectory, touch,withTemporaryDirectory}
import sbt.IO.{ createDirectory, touch, withTemporaryDirectory }
object ScalaProviderTest extends Specification
{
object ScalaProviderTest extends Specification {
"Launch" should {
"provide ClassLoader for Scala 2.8.0" in { checkScalaLoader("2.8.0") }
//"provide ClassLoader for Scala 2.8.0" in { checkScalaLoader("2.8.0") }
"provide ClassLoader for Scala 2.8.2" in { checkScalaLoader("2.8.2") }
"provide ClassLoader for Scala 2.9.0" in { checkScalaLoader("2.9.0") }
"provide ClassLoader for Scala 2.9.2" in { checkScalaLoader("2.9.2") }
"provide ClassLoader for Scala 2.10.4" in { checkScalaLoader("2.10.4") }
"provide ClassLoader for Scala 2.11.0" in { checkScalaLoader("2.11.0") }
}
"Launch" should {
@ -58,7 +59,7 @@ object ScalaProviderTest extends Specification
testResources.foreach(resource => touch(new File(resourceDirectory, resource.replace('/', File.separatorChar))))
Array(resourceDirectory)
}
private def checkScalaLoader(version: String): Unit = withLauncher( checkLauncher(version, mapScalaVersion(version)) )
private def checkScalaLoader(version: String): Unit = withLauncher(checkLauncher(version, mapScalaVersion(version)))
private def checkLauncher(version: String, versionValue: String)(launcher: Launcher): Unit =
{
val provider = launcher.getScala(version)
@ -69,8 +70,7 @@ object ScalaProviderTest extends Specification
}
private def tryScala(loader: ClassLoader): Unit = Class.forName("scala.Product", false, loader).getClassLoader must be(loader)
}
object LaunchTest
{
object LaunchTest {
def testApp(main: String): Application = testApp(main, Array[File]())
def testApp(main: String, extra: Array[File]): Application = Application("org.scala-sbt", "launch-test", new Explicit(AppVersion), main, Nil, CrossValue.Disabled, extra)
import Predefined._
@ -82,7 +82,7 @@ object LaunchTest
val finalStyle = Set("2.9.1", "2.9.0-1", "2.9.0", "2.8.2", "2.8.1", "2.8.0")
def unmapScalaVersion(versionNumber: String) = versionNumber.stripSuffix(".final")
def mapScalaVersion(versionNumber: String) = if(finalStyle(versionNumber)) versionNumber + ".final" else versionNumber
def mapScalaVersion(versionNumber: String) = if (finalStyle(versionNumber)) versionNumber + ".final" else versionNumber
def getScalaVersion: String = getScalaVersion(getClass.getClassLoader)
def getScalaVersion(loader: ClassLoader): String = getProperty(loader, "library.properties", "version.number")

View File

@ -1,17 +1,16 @@
package xsbt.boot
import java.io.{File,InputStream}
import java.io.{ File, InputStream }
import java.net.URL
import java.util.Properties
import xsbti._
import org.specs2._
import mutable.Specification
import LaunchTest._
import sbt.IO.{createDirectory, touch,withTemporaryDirectory}
import sbt.IO.{ createDirectory, touch, withTemporaryDirectory }
import java.net.URI
object ServerLocatorTest extends Specification
{
object ServerLocatorTest extends Specification {
"ServerLocator" should {
// TODO - Maybe use scalacheck to randomnly generate URIs
"read and write server URI properties" in {

View File

@ -6,8 +6,7 @@ import Configuration._
import java.io.File
import java.net.URI
object URITests extends Properties("URI Tests")
{
object URITests extends Properties("URI Tests") {
// Need a platform-specific root, otherwise URI will not be absolute (e.g. if we use a "/a/b/c" path in Windows)
// Note:
// If I use "C:" instead of "/C:", then isAbsolute == true for the resulting URI, but resolve is broken:

View File

@ -1,12 +1,11 @@
package xsbt.boot
import org.scalacheck._
import Prop._
import org.scalacheck._
import Prop._
object VersionParts extends Properties("VersionParts")
{
object VersionParts extends Properties("VersionParts") {
property("Valid version, no qualifier") = Prop.forAll { (x0: Int, y0: Int, z0: Int) =>
val (x,y,z) = (norm(x0), norm(y0), norm(z0))
val (x, y, z) = (norm(x0), norm(y0), norm(z0))
val str = s"$x.$y.$z"
val expected =
s"$x.$y.$z" ::
@ -17,7 +16,7 @@ object VersionParts extends Properties("VersionParts")
}
property("Valid version with qualifier") = Prop.forAll { (x0: Int, y0: Int, z0: Int, q0: String) =>
val (x,y,z,q) = (norm(x0), norm(y0), norm(z0), normS(q0))
val (x, y, z, q) = (norm(x0), norm(y0), norm(z0), normS(q0))
val str = s"$x.$y.$z-$q"
val expected =
s"$x.$y.$z-$q" ::
@ -29,14 +28,14 @@ object VersionParts extends Properties("VersionParts")
}
property("Invalid version") = Prop.forAll { (x0: Int, y0: Int, z0: Int, q0: String) =>
val (x,y,z,q) = (norm(x0), norm(y0), norm(z0), normS(q0))
val (x, y, z, q) = (norm(x0), norm(y0), norm(z0), normS(q0))
val strings =
x.toString ::
s"$x.$y" ::
s"$x.$y-$q" ::
s"$x.$y.$z.$q" ::
Nil
all(strings.map(str => check(str, Configuration.noMatchParts)) : _*)
all(strings.map(str => check(str, Configuration.noMatchParts)): _*)
}
private[this] def check(versionString: String, expectedParts: List[String]) =
@ -51,13 +50,13 @@ object VersionParts extends Properties("VersionParts")
// Make `i` non-negative
private[this] def norm(i: Int): Int =
if(i == Int.MinValue) Int.MaxValue else math.abs(i)
if (i == Int.MinValue) Int.MaxValue else math.abs(i)
// Make `s` non-empty and suitable for java.util.regex input
private[this] def normS(s: String): String =
{
val filtered = s filter validChar
if(filtered.isEmpty) "q" else filtered
if (filtered.isEmpty) "q" else filtered
}
// strip whitespace and characters not supported by Pattern

View File

@ -1,43 +1,42 @@
package sbt
package compiler
import scala.language.reflectiveCalls
import org.scalacheck._
import Prop._
import scala.tools.nsc.reporters.StoreReporter
import scala.language.reflectiveCalls
import org.scalacheck._
import Prop._
import scala.tools.nsc.reporters.StoreReporter
object EvalTest extends Properties("eval")
{
object EvalTest extends Properties("eval") {
private[this] val reporter = new StoreReporter
import reporter.{ERROR,Info,Severity}
import reporter.{ ERROR, Info, Severity }
private[this] val eval = new Eval(_ => reporter, None)
property("inferred integer") = forAll{ (i: Int) =>
property("inferred integer") = forAll { (i: Int) =>
val result = eval.eval(i.toString)
(label("Value", value(result)) |: (value(result) == i)) &&
(label("Type", value(result)) |: (result.tpe == IntType)) &&
(label("Files", result.generated) |: (result.generated.isEmpty))
}
property("explicit integer") = forAll{ (i: Int) =>
property("explicit integer") = forAll { (i: Int) =>
val result = eval.eval(i.toString, tpeName = Some(IntType))
(label("Value", value(result)) |: (value(result) == i)) &&
(label("Type", result.tpe) |: (result.tpe == IntType)) &&
(label("Files", result.generated) |: (result.generated.isEmpty))
}
property("type mismatch") = forAll{ (i: Int, l: Int) =>
property("type mismatch") = forAll { (i: Int, l: Int) =>
val line = math.abs(l)
val src = "mismatch"
throws(classOf[RuntimeException])(eval.eval(i.toString, tpeName =Some(BooleanType), line = line, srcName = src)) &&
hasErrors(line+1, src)
throws(classOf[RuntimeException])(eval.eval(i.toString, tpeName = Some(BooleanType), line = line, srcName = src)) &&
hasErrors(line + 1, src)
}
property("backed local class") = forAll{ (i: Int) =>
property("backed local class") = forAll { (i: Int) =>
IO.withTemporaryDirectory { dir =>
val eval = new Eval(_ => reporter, backing = Some(dir))
val result = eval.eval(local(i))
val v = value(result).asInstanceOf[{def i: Int}].i
val v = value(result).asInstanceOf[{ def i: Int }].i
(label("Value", v) |: (v == i)) &&
(label("Type", result.tpe) |: (result.tpe == LocalType)) &&
(label("Files", result.generated) |: (!result.generated.isEmpty))
@ -65,14 +64,13 @@ val p = {
label("Val names", res.valNames) |: (res.valNames.toSet == ValTestNames)
}
property("explicit import") = forAll(testImport("import math.abs" :: Nil))
property("wildcard import") = forAll(testImport("import math._" :: Nil))
property("comma-separated imports") = forAll(testImport("import util._, math._, xml._" :: Nil))
property("multiple imports") = forAll(testImport("import util._" :: "import math._" :: "import xml._" :: Nil))
private[this] def testImport(imports: Seq[String]): Int => Prop = i =>
value(eval.eval("abs("+i+")", new EvalImports(imports.zipWithIndex, "imp"))) == math.abs(i)
value(eval.eval("abs(" + i + ")", new EvalImports(imports.zipWithIndex, "imp"))) == math.abs(i)
private[this] def local(i: Int) = "{ class ETest(val i: Int); new ETest(" + i + ") }"
val LocalType = "AnyRef{val i: Int}"
@ -82,7 +80,7 @@ val p = {
{
val is = reporter.infos
("Has errors" |: (!is.isEmpty)) &&
all(is.toSeq.map(validPosition(line,src)) :_*)
all(is.toSeq.map(validPosition(line, src)): _*)
}
private[this] def validPosition(line: Int, src: String)(i: Info) =
{

View File

@ -1,8 +1,7 @@
package sbt
package std
import complete.{DefaultParsers, Parsers}
import complete.{ DefaultParsers, Parsers }
/*object UseTask
{
@ -18,12 +17,11 @@ package std
if(y.value) z else x
}
}*/
object Assign
{
object Assign {
import java.io.File
import Def.{inputKey,settingKey,taskKey}
import Def.{Initialize,macroValueT,parserToInput}
// import UseTask.{x,y,z,a,set,plain}
import Def.{ inputKey, settingKey, taskKey }
import Def.{ Initialize, macroValueT, parserToInput }
// import UseTask.{x,y,z,a,set,plain}
val ak = taskKey[Int]("a")
val bk = taskKey[Seq[Int]]("b")
@ -37,11 +35,11 @@ object Assign
val name = settingKey[String]("name")
val dummyt = taskKey[complete.Parser[String]]("dummyt")
val dummys = settingKey[complete.Parser[String]]("dummys")
val dummy3 = settingKey[complete.Parser[(String,Int)]]("dummy3")
val dummy3 = settingKey[complete.Parser[(String, Int)]]("dummy3")
val tsk: complete.Parser[Task[String]] = ???
val itsk: Initialize[InputTask[Int]] = ???
/* def azy = sk.value
/* def azy = sk.value
def azy2 = appmacro.Debug.checkWild(Def.task{ sk.value.size })
@ -59,9 +57,9 @@ object Assign
val is = Seq(
mk := 3,
name := "asdf",
tk := (math.random*1000).toInt,
tk := (math.random * 1000).toInt,
isk := dummys.value.parsed // should not compile: cannot use a task to define the parser
// ik := { if( tsk.parsed.value == "blue") tk.value else mk.value }
// ik := { if( tsk.parsed.value == "blue") tk.value else mk.value }
)
val it1 = Def.inputTask {
@ -75,7 +73,7 @@ object Assign
tsk.parsed.value + itsk.parsed.value.toString + isk.value
}
// should not compile: cannot use a task to define the parser
/* val it4 = Def.inputTask {
/* val it4 = Def.inputTask {
dummyt.value.parsed
}*/
// should compile: can use a setting to define the parser
@ -86,7 +84,7 @@ object Assign
val d3 = dummy3.parsed
val x = d3._1
val i = d3._2
Def.task { tk.value + i}
Def.task { tk.value + i }
}
val it7 = Def.inputTask {

View File

@ -1,17 +1,16 @@
package sbt
import Project._
import Types.{idFun,some}
import TestBuild._
import Project._
import Types.{ idFun, some }
import TestBuild._
import java.io.File
import java.net.URI
import org.scalacheck._
import Prop._
import Gen._
import java.io.File
import java.net.URI
import org.scalacheck._
import Prop._
import Gen._
object Delegates extends Properties("delegates")
{
object Delegates extends Properties("delegates") {
property("generate non-empty configs") = forAll { (c: Seq[Config]) => !c.isEmpty }
property("generate non-empty tasks") = forAll { (t: Seq[Taskk]) => !t.isEmpty }
@ -43,33 +42,32 @@ object Delegates extends Properties("delegates")
def allAxes(f: (Scope, Seq[Scope], Scope => ScopeAxis[_]) => Prop): Prop = forAll { (keys: Keys) =>
allDelegates(keys) { (s, ds) =>
all( f(s, ds, _.project), f(s, ds, _.config), f(s, ds, _.task), f(s, ds, _.extra) )
all(f(s, ds, _.project), f(s, ds, _.config), f(s, ds, _.task), f(s, ds, _.extra))
}
}
def allDelegates(keys: Keys)(f: (Scope, Seq[Scope]) => Prop): Prop = all( keys.scopes map { scope =>
def allDelegates(keys: Keys)(f: (Scope, Seq[Scope]) => Prop): Prop = all(keys.scopes map { scope =>
val delegates = keys.env.delegates(scope)
("Scope: " + Scope.display(scope, "_")) |:
("Delegates:\n\t" + delegates.map( scope => Scope.display(scope, "_") ).mkString("\n\t")) |:
("Delegates:\n\t" + delegates.map(scope => Scope.display(scope, "_")).mkString("\n\t")) |:
f(scope, delegates)
} : _*)
}: _*)
def alwaysGlobal(s: Scope, ds: Seq[Scope], axis: Scope => ScopeAxis[_]): Prop =
(axis(s) != Global) ||
all( ds map { d => (axis(d) == Global) : Prop } : _*)
all(ds map { d => (axis(d) == Global): Prop }: _*)
def globalCombinations(s: Scope, ds: Seq[Scope], axis: Scope => ScopeAxis[_]): Prop =
{
val value = axis(s)
val mods = List[Scope => Scope](_.copy(project = Global), _.copy(config = Global), _.copy(task = Global), _.copy(extra = Global) )
val mods = List[Scope => Scope](_.copy(project = Global), _.copy(config = Global), _.copy(task = Global), _.copy(extra = Global))
val modAndIdent = mods.map(_ :: idFun[Scope] :: Nil)
def loop(cur: Scope, acc: List[Scope], rem: List[Seq[Scope => Scope]]): Seq[Scope] =
rem match
{
rem match {
case Nil => acc
case x :: xs => x flatMap { mod =>
val s = mod(cur)
loop(s, s :: acc, xs)
}
}
all( loop(s, Nil, modAndIdent).map( ds contains _ : Prop) : _*)
all(loop(s, Nil, modAndIdent).map(ds contains _: Prop): _*)
}
}

View File

@ -1,19 +1,20 @@
package sbt
import Def.{displayFull,displayMasked,ScopedKey}
import java.net.URI
import TestBuild._
import complete._
import Def.{ displayFull, displayMasked, ScopedKey }
import java.net.URI
import TestBuild._
import complete._
import org.scalacheck._
import Gen._
import Prop._
import Arbitrary.arbBool
import org.scalacheck._
import Gen._
import Prop._
import Arbitrary.arbBool
/** Tests that the scoped key parser in Act can correctly parse a ScopedKey converted by Def.show*Key.
* This includes properly resolving omitted components.*/
object ParseKey extends Properties("Key parser test")
{
/**
* Tests that the scoped key parser in Act can correctly parse a ScopedKey converted by Def.show*Key.
* This includes properly resolving omitted components.
*/
object ParseKey extends Properties("Key parser test") {
final val MaxKeys = 5
final val MaxScopedKeys = 100
@ -21,7 +22,7 @@ object ParseKey extends Properties("Key parser test")
property("An explicitly specified axis is always parsed to that explicit value") =
forAllNoShrink(structureDefinedKey) { (skm: StructureKeyMask) =>
import skm.{structure, key, mask}
import skm.{ structure, key, mask }
val expected = resolve(structure, key, mask)
val string = displayMasked(key, mask)
@ -32,7 +33,7 @@ object ParseKey extends Properties("Key parser test")
property("An unspecified project axis resolves to the current project") =
forAllNoShrink(structureDefinedKey) { (skm: StructureKeyMask) =>
import skm.{structure, key}
import skm.{ structure, key }
val mask = skm.mask.copy(project = false)
val string = displayMasked(key, mask)
@ -48,7 +49,7 @@ object ParseKey extends Properties("Key parser test")
property("An unspecified task axis resolves to Global") =
forAllNoShrink(structureDefinedKey) { (skm: StructureKeyMask) =>
import skm.{structure, key}
import skm.{ structure, key }
val mask = skm.mask.copy(task = false)
val string = displayMasked(key, mask)
@ -62,7 +63,7 @@ object ParseKey extends Properties("Key parser test")
property("An unspecified configuration axis resolves to the first configuration directly defining the key or else Global") =
forAllNoShrink(structureDefinedKey) { (skm: StructureKeyMask) =>
import skm.{structure, key}
import skm.{ structure, key }
val mask = ScopeMask(config = false)
val string = displayMasked(key, mask)
val resolvedConfig = Resolve.resolveConfig(structure.extra, key.key, mask)(key.scope).config
@ -77,11 +78,10 @@ object ParseKey extends Properties("Key parser test")
}
lazy val structureDefinedKey: Gen[StructureKeyMask] = structureKeyMask { s =>
for( scope <- TestBuild.scope(s.env); key <- oneOf(s.allAttributeKeys.toSeq)) yield ScopedKey(scope, key)
for (scope <- TestBuild.scope(s.env); key <- oneOf(s.allAttributeKeys.toSeq)) yield ScopedKey(scope, key)
}
def structureKeyMask(genKey: Structure => Gen[ScopedKey[_]])(implicit maskGen: Gen[ScopeMask], structureGen: Gen[Structure]): Gen[StructureKeyMask] =
for(mask <- maskGen; structure <- structureGen; key <- genKey(structure)) yield
new StructureKeyMask(structure, key, mask)
for (mask <- maskGen; structure <- structureGen; key <- genKey(structure)) yield new StructureKeyMask(structure, key, mask)
final class StructureKeyMask(val structure: Structure, val key: ScopedKey[_], val mask: ScopeMask)
def resolve(structure: Structure, key: ScopedKey[_], mask: ScopeMask): ScopedKey[_] =
@ -95,7 +95,7 @@ object ParseKey extends Properties("Key parser test")
case Right(sk) => Project.equal(sk, expected, mask)
}
def parse(structure: Structure, s: String)(f: Either[String,ScopedKey[_]] => Prop): Prop =
def parse(structure: Structure, s: String)(f: Either[String, ScopedKey[_]] => Prop): Prop =
{
val parser = makeParser(structure)
val parsed = DefaultParsers.result(parser, s).left.map(_().toString)
@ -108,12 +108,12 @@ object ParseKey extends Properties("Key parser test")
def genStructure(implicit genEnv: Gen[Env]): Gen[Structure] =
structureGenF { (scopes: Seq[Scope], env: Env, current: ProjectRef) =>
val settings = for(scope <- scopes; t <- env.tasks) yield Def.setting(ScopedKey(scope, t.key), Def.value(""))
val settings = for (scope <- scopes; t <- env.tasks) yield Def.setting(ScopedKey(scope, t.key), Def.value(""))
TestBuild.structure(env, settings, current)
}
def structureGenF(f: (Seq[Scope], Env, ProjectRef) => Structure)(implicit genEnv: Gen[Env]): Gen[Structure] =
structureGen( (s,e,p) => Gen.value(f(s,e,p)))
structureGen((s, e, p) => Gen.value(f(s, e, p)))
def structureGen(f: (Seq[Scope], Env, ProjectRef) => Gen[Structure])(implicit genEnv: Gen[Env]): Gen[Structure] =
for {
env <- genEnv
@ -121,9 +121,8 @@ object ParseKey extends Properties("Key parser test")
scopes <- pickN(loadFactor, env.allFullScopes)
current <- oneOf(env.allProjects.unzip._1)
structure <- f(scopes, env, current)
} yield
structure
} yield structure
def pickN[T](load: Double, from: Seq[T]): Gen[Seq[T]] =
pick( (load*from.size).toInt, from )
pick((load * from.size).toInt, from)
}

View File

@ -1,12 +1,11 @@
package sbt
import org.scalacheck._
import Prop._
import Project.project
import java.io.File
import org.scalacheck._
import Prop._
import Project.project
import java.io.File
class ProjectDefs
{
class ProjectDefs {
lazy val p = project
val x = project
@ -21,15 +20,14 @@ class ProjectDefs
lazy val aa: Project = project
}
object ProjectMacro extends Properties("ProjectMacro")
{
object ProjectMacro extends Properties("ProjectMacro") {
lazy val pd = new ProjectDefs
import pd._
def secure(f: => Prop): Prop = try {
Prop.secure(f)
} catch { case e: Throwable =>
} catch {
case e: Throwable =>
e.printStackTrace
throw e
}
@ -64,4 +62,3 @@ object ProjectMacro extends Properties("ProjectMacro")
(p.base.getName == dir)
}
}

View File

@ -1,18 +1,17 @@
package sbt
import org.scalacheck._
import Gen.{listOf}
import Gen.{ listOf }
import Prop._
import Tags._
object TagsTest extends Properties("Tags")
{
object TagsTest extends Properties("Tags") {
final case class Size(value: Int)
def tagMap: Gen[TagMap] = for(ts <- listOf(tagAndFrequency)) yield ts.toMap
def tagAndFrequency: Gen[(Tag, Int)] = for(t <- tag; count <- Arbitrary.arbitrary[Int]) yield (t, count)
def tag: Gen[Tag] = for(s <- Gen.alphaStr if !s.isEmpty) yield Tag(s)
def size: Gen[Size] = for(i <- Arbitrary.arbitrary[Int] if i != Int.MinValue) yield Size(math.abs(i))
def tagMap: Gen[TagMap] = for (ts <- listOf(tagAndFrequency)) yield ts.toMap
def tagAndFrequency: Gen[(Tag, Int)] = for (t <- tag; count <- Arbitrary.arbitrary[Int]) yield (t, count)
def tag: Gen[Tag] = for (s <- Gen.alphaStr if !s.isEmpty) yield Tag(s)
def size: Gen[Size] = for (i <- Arbitrary.arbitrary[Int] if i != Int.MinValue) yield Size(math.abs(i))
implicit def aTagMap = Arbitrary(tagMap)
implicit def aTagAndFrequency = Arbitrary(tagAndFrequency)
@ -27,7 +26,7 @@ object TagsTest extends Properties("Tags")
val absSize = size.value
val tm2: TagMap = tm.updated(etag, absSize).updated(Tags.All, tm.getOrElse(Tags.All, 0) + absSize)
(s"TagMap: $tm2") |:
( excl(etag)(tm2) == (absSize <= 1) )
(excl(etag)(tm2) == (absSize <= 1))
}
property("exclusive always allows a group of size one") = forAll { (etag: Tag, mapTag: Tag) =>

View File

@ -1,20 +1,19 @@
package sbt
import Def.{ScopedKey, Setting}
import Types.{const,idFun,some}
import complete.Parser
import Def.{ ScopedKey, Setting }
import Types.{ const, idFun, some }
import complete.Parser
import java.io.File
import java.net.URI
import org.scalacheck._
import Prop._
import Gen._
import Arbitrary.arbBool
import java.io.File
import java.net.URI
import org.scalacheck._
import Prop._
import Gen._
import Arbitrary.arbBool
// Notes:
// Generator doesn't produce cross-build project dependencies or do anything with the 'extra' axis
object TestBuild
{
object TestBuild {
val MaxTasks = 6
val MaxProjects = 7
val MaxConfigs = 5
@ -30,27 +29,23 @@ object TestBuild
val MaxDepsGen = chooseShrinkable(0, MaxDeps)
def chooseShrinkable(min: Int, max: Int): Gen[Int] =
sized( sz => choose(min, (max min sz) max 1) )
sized(sz => choose(min, (max min sz) max 1))
implicit val cGen = Arbitrary { genConfigs(idGen, MaxDepsGen, MaxConfigsGen) }
implicit val tGen = Arbitrary { genTasks(idGen, MaxDepsGen, MaxTasksGen) }
final class Keys(val env: Env, val scopes: Seq[Scope])
{
final class Keys(val env: Env, val scopes: Seq[Scope]) {
override def toString = env + "\n" + scopes.mkString("Scopes:\n\t", "\n\t", "")
lazy val delegated = scopes map env.delegates
}
final case class Structure(env: Env, current: ProjectRef, data: Settings[Scope], keyIndex: KeyIndex, keyMap: Map[String, AttributeKey[_]])
{
final case class Structure(env: Env, current: ProjectRef, data: Settings[Scope], keyIndex: KeyIndex, keyMap: Map[String, AttributeKey[_]]) {
override def toString = env.toString + "\n" + "current: " + current + "\nSettings:\n\t" + showData + keyMap.keys.mkString("All keys:\n\t", ", ", "")
def showKeys(map: AttributeMap): String = map.keys.mkString("\n\t ",",", "\n")
def showKeys(map: AttributeMap): String = map.keys.mkString("\n\t ", ",", "\n")
def showData: String =
{
val scopeStrings =
for( (scope, map) <- data.data ) yield
(Scope.display(scope, "<key>"), showKeys(map))
for ((scope, map) <- data.data) yield (Scope.display(scope, "<key>"), showKeys(map))
scopeStrings.toSeq.sorted.map(t => t._1 + t._2).mkString("\n\t")
}
val extra: BuildUtil[Proj] =
@ -62,39 +57,35 @@ object TestBuild
lazy val allAttributeKeys: Set[AttributeKey[_]] = data.data.values.flatMap(_.keys).toSet
lazy val (taskAxes, globalTaskAxis, onlyTaskAxis, multiTaskAxis) =
{
import collection.{breakOut, mutable}
import collection.{ breakOut, mutable }
import mutable.HashSet
// task axis of Scope is set to Global and the value of the second map is the original task axis
val taskAxesMappings =
for( (scope, keys) <- data.data.toIterable; key <- keys.keys ) yield
(ScopedKey(scope.copy(task = Global), key), scope.task) : (ScopedKey[_], ScopeAxis[AttributeKey[_]])
for ((scope, keys) <- data.data.toIterable; key <- keys.keys) yield (ScopedKey(scope.copy(task = Global), key), scope.task): (ScopedKey[_], ScopeAxis[AttributeKey[_]])
val taskAxes = Relation.empty ++ taskAxesMappings
val global = new HashSet[ScopedKey[_]]
val single = new HashSet[ScopedKey[_]]
val multi = new HashSet[ScopedKey[_]]
for( (skey, tasks) <- taskAxes.forwardMap)
{
for ((skey, tasks) <- taskAxes.forwardMap) {
def makeKey(task: ScopeAxis[AttributeKey[_]]) = ScopedKey(skey.scope.copy(task = task), skey.key)
val hasGlobal = tasks(Global)
if(hasGlobal)
if (hasGlobal)
global += skey
else
{
else {
val keys = tasks map makeKey
if( keys.size == 1)
if (keys.size == 1)
single ++= keys
else if(keys.size > 1)
else if (keys.size > 1)
multi ++= keys
}
}
(taskAxes, global.toSet, single.toSet, multi.toSet)
}
}
final class Env(val builds: Seq[Build], val tasks: Seq[Taskk])
{
override def toString = "Env:\n "+ " Tasks:\n " + tasks.mkString("\n ") +"\n" + builds.mkString("\n ")
final class Env(val builds: Seq[Build], val tasks: Seq[Taskk]) {
override def toString = "Env:\n " + " Tasks:\n " + tasks.mkString("\n ") + "\n" + builds.mkString("\n ")
val root = builds.head
val buildMap = mapBy(builds)(_.uri)
val taskMap = mapBy(tasks)(getKey)
@ -123,51 +114,45 @@ object TestBuild
(ref, p) <- (Global, root.root) +: allProjects.map { case (ref, p) => (Select(ref), p) }
t <- Global +: tasks.map(t => Select(t.key))
c <- Global +: p.configurations.map(c => Select(ConfigKey(c.name)))
} yield
Scope(project = ref, config = c, task = t, extra = Global)
} yield Scope(project = ref, config = c, task = t, extra = Global)
}
def getKey: Taskk => AttributeKey[_] = _.key
def toConfigKey: Config => ConfigKey = c => ConfigKey(c.name)
final class Build(val uri: URI, val projects: Seq[Proj])
{
final class Build(val uri: URI, val projects: Seq[Proj]) {
override def toString = "Build " + uri.toString + " :\n " + projects.mkString("\n ")
val allProjects = projects map { p => (ProjectRef(uri, p.id), p) }
val root = projects.head
val projectMap = mapBy(projects)(_.id)
}
final class Proj(val id: String, val delegates: Seq[ProjectRef], val configurations: Seq[Config])
{
final class Proj(val id: String, val delegates: Seq[ProjectRef], val configurations: Seq[Config]) {
override def toString = "Project " + id + "\n Delegates:\n " + delegates.mkString("\n ") +
"\n Configurations:\n " + configurations.mkString("\n ")
val confMap = mapBy(configurations)(_.name)
}
final class Config(val name: String, val extended: Seq[Config])
{
final class Config(val name: String, val extended: Seq[Config]) {
override def toString = name + " (extends: " + extended.map(_.name).mkString(", ") + ")"
}
final class Taskk(val key: AttributeKey[String], val delegates: Seq[Taskk])
{
final class Taskk(val key: AttributeKey[String], val delegates: Seq[Taskk]) {
override def toString = key.label + " (delegates: " + delegates.map(_.key.label).mkString(", ") + ")"
}
def mapBy[K, T](s: Seq[T])(f: T => K): Map[K, T] = s map { t => (f(t), t) } toMap;
implicit lazy val arbKeys: Arbitrary[Keys] = Arbitrary(keysGen)
lazy val keysGen: Gen[Keys] = for(env <- mkEnv; keyCount <- chooseShrinkable(1, KeysPerEnv); keys <- listOfN(keyCount, scope(env)) ) yield new Keys(env, keys)
lazy val keysGen: Gen[Keys] = for (env <- mkEnv; keyCount <- chooseShrinkable(1, KeysPerEnv); keys <- listOfN(keyCount, scope(env))) yield new Keys(env, keys)
def scope(env: Env): Gen[Scope] =
for {
build <- oneOf(env.builds)
project <- oneOf(build.projects)
cAxis <- oneOrGlobal(project.configurations map toConfigKey)
tAxis <- oneOrGlobal( env.tasks map getKey )
pAxis <- orGlobal( frequency( (1, BuildRef(build.uri)), (3, ProjectRef(build.uri, project.id) ) ) )
} yield
Scope( pAxis, cAxis, tAxis, Global)
tAxis <- oneOrGlobal(env.tasks map getKey)
pAxis <- orGlobal(frequency((1, BuildRef(build.uri)), (3, ProjectRef(build.uri, project.id))))
} yield Scope(pAxis, cAxis, tAxis, Global)
def orGlobal[T](gen: Gen[T]): Gen[ScopeAxis[T]] =
frequency( (1, gen map Select.apply), (1, Global) )
frequency((1, gen map Select.apply), (1, Global))
def oneOrGlobal[T](gen: Seq[T]): Gen[ScopeAxis[T]] = orGlobal(oneOf(gen))
def makeParser(structure: Structure): Parser[ScopedKey[_]] =
@ -186,7 +171,7 @@ object TestBuild
{
implicit val display = Def.showRelativeKey(current, env.allProjects.size > 1)
val data = Def.make(settings)(env.delegates, const(Nil), display)
val keys = data.allKeys( (s, key) => ScopedKey(s, key))
val keys = data.allKeys((s, key) => ScopedKey(s, key))
val keyMap = keys.map(k => (k.key.label, k.key)).toMap[String, AttributeKey[_]]
val projectsMap = env.builds.map(b => (b.uri, b.projects.map(_.id).toSet)).toMap
new Structure(env, current, data, KeyIndex(keys, projectsMap), keyMap)
@ -203,67 +188,65 @@ object TestBuild
implicit def maskGen(implicit arbBoolean: Arbitrary[Boolean]): Gen[ScopeMask] =
{
val b = arbBoolean.arbitrary
for(p <- b; c <- b; t <- b; x <- b) yield
ScopeMask(project = p, config = c, task = t, extra = x)
for (p <- b; c <- b; t <- b; x <- b) yield ScopeMask(project = p, config = c, task = t, extra = x)
}
implicit lazy val idGen: Gen[String] = for(size <- chooseShrinkable(1, MaxIDSize); cs <- listOfN(size, alphaChar)) yield cs.mkString
implicit lazy val optIDGen: Gen[Option[String]] = frequency( (1, idGen map some.fn), (1, None) )
implicit lazy val uriGen: Gen[URI] = for(sch <- idGen; ssp <- idGen; frag <- optIDGen) yield new URI(sch, ssp, frag.orNull)
implicit lazy val idGen: Gen[String] = for (size <- chooseShrinkable(1, MaxIDSize); cs <- listOfN(size, alphaChar)) yield cs.mkString
implicit lazy val optIDGen: Gen[Option[String]] = frequency((1, idGen map some.fn), (1, None))
implicit lazy val uriGen: Gen[URI] = for (sch <- idGen; ssp <- idGen; frag <- optIDGen) yield new URI(sch, ssp, frag.orNull)
implicit def envGen(implicit bGen: Gen[Build], tasks: Gen[Seq[Taskk]]): Gen[Env] =
for(i <- MaxBuildsGen; bs <- listOfN(i, bGen); ts <- tasks) yield new Env(bs, ts)
implicit def buildGen(implicit uGen: Gen[URI], pGen: URI => Gen[Seq[Proj]]): Gen[Build] = for(u <- uGen; ps <- pGen(u)) yield new Build(u, ps)
for (i <- MaxBuildsGen; bs <- listOfN(i, bGen); ts <- tasks) yield new Env(bs, ts)
implicit def buildGen(implicit uGen: Gen[URI], pGen: URI => Gen[Seq[Proj]]): Gen[Build] = for (u <- uGen; ps <- pGen(u)) yield new Build(u, ps)
def nGen[T](igen: Gen[Int])(implicit g: Gen[T]): Gen[List[T]] = igen flatMap { ig => listOfN(ig, g) }
implicit def genProjects(build: URI)(implicit genID: Gen[String], maxDeps: Gen[Int], count: Gen[Int], confs: Gen[Seq[Config]]): Gen[Seq[Proj]] =
genAcyclic(maxDeps, genID, count) { (id: String) =>
for(cs <- confs) yield { (deps: Seq[Proj]) =>
new Proj(id, deps.map{dep => ProjectRef(build, dep.id) }, cs)
for (cs <- confs) yield { (deps: Seq[Proj]) =>
new Proj(id, deps.map { dep => ProjectRef(build, dep.id) }, cs)
}
}
def genConfigs(implicit genName: Gen[String], maxDeps: Gen[Int], count: Gen[Int]): Gen[Seq[Config]] =
genAcyclicDirect[Config,String](maxDeps, genName, count)( (key, deps) => new Config(key, deps) )
genAcyclicDirect[Config, String](maxDeps, genName, count)((key, deps) => new Config(key, deps))
def genTasks(implicit genName: Gen[String], maxDeps: Gen[Int], count: Gen[Int]): Gen[Seq[Taskk]] =
genAcyclicDirect[Taskk,String](maxDeps, genName, count)( (key, deps) => new Taskk(AttributeKey[String](key), deps) )
genAcyclicDirect[Taskk, String](maxDeps, genName, count)((key, deps) => new Taskk(AttributeKey[String](key), deps))
def genAcyclicDirect[A,T](maxDeps: Gen[Int], keyGen: Gen[T], max: Gen[Int])(make: (T, Seq[A]) => A): Gen[Seq[ A ]] =
genAcyclic[A,T](maxDeps, keyGen, max) { t =>
def genAcyclicDirect[A, T](maxDeps: Gen[Int], keyGen: Gen[T], max: Gen[Int])(make: (T, Seq[A]) => A): Gen[Seq[A]] =
genAcyclic[A, T](maxDeps, keyGen, max) { t =>
Gen.value { deps =>
make(t, deps)
}
}
def genAcyclic[A,T](maxDeps: Gen[Int], keyGen: Gen[T], max: Gen[Int])(make: T => Gen[Seq[A] => A]): Gen[Seq[ A ]] =
def genAcyclic[A, T](maxDeps: Gen[Int], keyGen: Gen[T], max: Gen[Int])(make: T => Gen[Seq[A] => A]): Gen[Seq[A]] =
max flatMap { count =>
listOfN(count, keyGen) flatMap { keys =>
genAcyclic(maxDeps, keys.distinct)(make)
}
}
def genAcyclic[A,T](maxDeps: Gen[Int], keys: List[T])(make: T => Gen[Seq[A] => A]): Gen[Seq[ A ]] =
def genAcyclic[A, T](maxDeps: Gen[Int], keys: List[T])(make: T => Gen[Seq[A] => A]): Gen[Seq[A]] =
genAcyclic(maxDeps, keys, Nil) flatMap { pairs =>
sequence( pairs.map { case (key, deps) => mapMake(key, deps, make) } ) flatMap { inputs =>
sequence(pairs.map { case (key, deps) => mapMake(key, deps, make) }) flatMap { inputs =>
val made = new collection.mutable.HashMap[T, A]
for( (key, deps, mk) <- inputs)
for ((key, deps, mk) <- inputs)
made(key) = mk(deps map made)
keys map made
}
}
def mapMake[A,T](key: T, deps: Seq[T], make: T => Gen[Seq[A] => A]): Gen[Inputs[A,T]] =
def mapMake[A, T](key: T, deps: Seq[T], make: T => Gen[Seq[A] => A]): Gen[Inputs[A, T]] =
make(key) map { (mk: Seq[A] => A) => (key, deps, mk) }
def genAcyclic[T](maxDeps: Gen[Int], names: List[T], acc: List[Gen[ (T,Seq[T]) ]]): Gen[Seq[ (T,Seq[T]) ]] =
names match
{
def genAcyclic[T](maxDeps: Gen[Int], names: List[T], acc: List[Gen[(T, Seq[T])]]): Gen[Seq[(T, Seq[T])]] =
names match {
case Nil => sequence(acc)
case x :: xs =>
val next = for(depCount <- maxDeps; d <- pick(depCount min xs.size, xs) ) yield (x, d.toList)
val next = for (depCount <- maxDeps; d <- pick(depCount min xs.size, xs)) yield (x, d.toList)
genAcyclic(maxDeps, xs, next :: acc)
}
def sequence[T](gs: Seq[Gen[T]]): Gen[Seq[T]] = Gen.parameterized { prms =>
wrap( gs map { g => g(prms) getOrElse error("failed generator") } )
wrap(gs map { g => g(prms) getOrElse error("failed generator") })
}
type Inputs[A,T] = (T, Seq[T], Seq[A] => A)
type Inputs[A, T] = (T, Seq[T], Seq[A] => A)
}

View File

@ -152,6 +152,7 @@ object Sbt extends Build {
)
private def doScripted(launcher: File, scriptedSbtClasspath: Seq[Attributed[File]], scriptedSbtInstance: ScalaInstance, sourcePath: File, args: Seq[String]) {
System.err.println(s"About to run tests: ${args.mkString("\n * ", "\n * ", "\n")}")
val noJLine = new classpath.FilteredLoader(scriptedSbtInstance.loader, "jline." :: Nil)
val loader = classpath.ClasspathUtilities.toLoader(scriptedSbtClasspath.files, noJLine)
val m = ModuleUtilities.getObject("sbt.test.ScriptedTests", loader)
@ -174,6 +175,8 @@ object Sbt extends Build {
import sbt.complete._
import DefaultParsers._
// Paging, 1-index based.
case class ScriptedTestPage(page: Int, total: Int)
def scriptedParser(scriptedBase: File): Parser[Seq[String]] =
{
val pairs = (scriptedBase * AllPassFilter * AllPassFilter * "test").get map { (f: File) =>
@ -184,9 +187,36 @@ object Sbt extends Build {
val id = charClass(c => !c.isWhitespace && c != '/').+.string
val groupP = token(id.examples(pairMap.keySet.toSet)) <~ token('/')
def nameP(group: String) = token("*".id | id.examples(pairMap(group)))
val testID = for (group <- groupP; name <- nameP(group)) yield (group, name)
(token(Space) ~> matched(testID)).*
// A parser for page definitions
val pageP: Parser[ScriptedTestPage] = ("*" ~ NatBasic ~ "of" ~ NatBasic) map {
case _ ~ page ~ _ ~ total => ScriptedTestPage(page, total)
}
// Grabs the filenames from a given test group in the current page definition.
def pagedFilenames(group: String, page: ScriptedTestPage): Seq[String] = {
val files = pairMap(group).toSeq.sortBy(_.toLowerCase)
val pageSize = files.size / page.total
// The last page may loose some values, so we explicitly keep them
val dropped = files.drop(pageSize * (page.page - 1))
if (page.page == page.total) dropped
else dropped.take(pageSize)
}
def nameP(group: String) = {
token("*".id | id.examples(pairMap(group)))
}
val PagedIds: Parser[Seq[String]] =
for {
group <- groupP
page <- pageP
files = pagedFilenames(group, page)
// TODO - Fail the parser if we don't have enough files for the given page size
//if !files.isEmpty
} yield files map (f => group + '/' + f)
val testID = (for (group <- groupP; name <- nameP(group)) yield (group, name))
val testIdAsGroup = matched(testID) map (test => Seq(test))
//(token(Space) ~> matched(testID)).*
(token(Space) ~> (PagedIds | testIdAsGroup)).* map (_.flatten)
}
lazy val scripted = InputKey[Unit]("scripted")

View File

@ -1,18 +1,19 @@
package sbt
import org.scalacheck._
import Prop.{Exception => _, _}
import Gen.{alphaNumChar,frequency,listOf1,oneOf}
import Prop.{ Exception => _, _ }
import Gen.{ alphaNumChar, frequency, listOf1, oneOf }
import java.io.File
object ForkTest extends Properties("Fork")
{
/** Heuristic for limiting the length of the classpath string.
object ForkTest extends Properties("Fork") {
/**
* Heuristic for limiting the length of the classpath string.
* Longer than this will hit hard limits in the total space
* allowed for process initialization, which includes environment variables, at least on linux. */
* allowed for process initialization, which includes environment variables, at least on linux.
*/
final val MaximumClasspathLength = 100000
lazy val genOptionName = frequency( ( 9, Some("-cp")), (9, Some("-classpath")), (1, None))
lazy val genOptionName = frequency((9, Some("-cp")), (9, Some("-classpath")), (1, None))
lazy val pathElement = listOf1(alphaNumChar).map(_.mkString)
lazy val path = listOf1(pathElement).map(_.mkString(File.separator))
lazy val genRelClasspath = listOf1(path)
@ -27,26 +28,28 @@ object ForkTest extends Properties("Fork")
Nil
property("Arbitrary length classpath successfully passed.") = forAllNoShrink(genOptionName, genRelClasspath) { (optionName: Option[String], relCP: List[String]) =>
IO.withTemporaryDirectory { dir => TestLogger { log =>
IO.withTemporaryDirectory { dir =>
TestLogger { log =>
val withScala = requiredEntries ::: relCP.map(rel => new File(dir, rel))
val absClasspath = trimClasspath(Path.makeString(withScala))
val args = optionName.map(_ :: absClasspath :: Nil).toList.flatten ++ mainAndArgs
val config = ForkOptions(outputStrategy = Some(LoggedOutput(log)))
val exitCode = try Fork.java(config, args) catch { case e: Exception => e.printStackTrace; 1 }
val expectedCode = if(optionName.isEmpty) 1 else 0
val expectedCode = if (optionName.isEmpty) 1 else 0
s"temporary directory: ${dir.getAbsolutePath}" |:
s"required classpath: ${requiredEntries.mkString("\n\t", "\n\t", "")}" |:
s"main and args: ${mainAndArgs.mkString(" ")}" |:
s"args length: ${args.mkString(" ").length}" |:
s"exitCode: $exitCode, expected: $expectedCode" |:
(exitCode == expectedCode)
}}
}
}
}
private[this] def trimClasspath(cp: String): String =
if(cp.length > MaximumClasspathLength) {
if (cp.length > MaximumClasspathLength) {
val lastEntryI = cp.lastIndexOf(File.pathSeparatorChar, MaximumClasspathLength)
if(lastEntryI > 0)
if (lastEntryI > 0)
cp.substring(0, lastEntryI)
else
cp

View File

@ -8,8 +8,7 @@ import Prop._
import TaskGen._
import Task._
object ExecuteSpec extends Properties("Execute")
{
object ExecuteSpec extends Properties("Execute") {
val iGen = Arbitrary.arbInt.arbitrary
property("evaluates simple task") = forAll(iGen, MaxWorkersGen) { (i: Int, workers: Int) =>
("Workers: " + workers) |:
@ -27,24 +26,24 @@ object ExecuteSpec extends Properties("Execute")
property("evaluates simple mapped task") = forAll(iGen, MaxTasksGen, MaxWorkersGen) { (i: Int, times: Int, workers: Int) =>
("Workers: " + workers) |: ("Value: " + i) |: ("Times: " + times) |:
{
def result = tryRun(task(i).map(_*times), false, workers)
checkResult(result, i*times)
def result = tryRun(task(i).map(_ * times), false, workers)
checkResult(result, i * times)
}
}
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])
def t = ( initial /: (0 until times) )( (t,ignore) => t.map(_ + i))
checkResult(tryRun(t, false, workers), i*times)
val initial = task(0) map (identity[Int])
def t = (initial /: (0 until times))((t, ignore) => t.map(_ + i))
checkResult(tryRun(t, 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 = tryRun(task(i).flatMap(x => task(x*times)), false, workers)
checkResult(result, i*times)
def result = tryRun(task(i).flatMap(x => task(x * times)), false, workers)
checkResult(result, i * times)
}
}
}

View File

@ -6,8 +6,7 @@ package sbt
import org.scalacheck._
import Gen.choose
object TaskGen extends std.TaskExtra
{
object TaskGen extends std.TaskExtra {
// upper bounds to make the tests finish in reasonable time
val MaxTasks = 100
val MaxWorkers = 29

View File

@ -5,8 +5,7 @@ import Prop._
import TaskGen._
import Task._
object TaskRunnerCircularTest extends Properties("TaskRunner Circular")
{
object TaskRunnerCircularTest extends Properties("TaskRunner Circular") {
property("Catches circular references") = forAll(MaxTasksGen, MaxWorkersGen) { checkCircularReferences _ }
property("Allows references to completed tasks") = forAllNoShrink(MaxTasksGen, MaxWorkersGen) { allowedReference _ }
final def allowedReference(intermediate: Int, workers: Int) =
@ -14,10 +13,10 @@ object TaskRunnerCircularTest extends Properties("TaskRunner Circular")
val top = task(intermediate).named("top")
def iterate(tk: Task[Int]): Task[Int] =
tk flatMap { t =>
if(t <= 0)
if (t <= 0)
top
else
iterate(task(t-1).named((t-1).toString) )
iterate(task(t - 1).named((t - 1).toString))
}
try { checkResult(tryRun(iterate(top), true, workers), intermediate) }
catch { case i: Incomplete if cyclic(i) => ("Unexpected cyclic exception: " + i) |: false }
@ -27,10 +26,10 @@ object TaskRunnerCircularTest extends Properties("TaskRunner Circular")
lazy val top = iterate(task(intermediate).named("bottom"), intermediate)
def iterate(tk: Task[Int], i: Int): Task[Int] =
tk flatMap { t =>
if(t <= 0)
if (t <= 0)
top
else
iterate(task(t-1).named((t-1).toString), i-1)
iterate(task(t - 1).named((t - 1).toString), i - 1)
}
try { tryRun(top, true, workers); false }
catch { case i: Incomplete => cyclic(i) }

View File

@ -6,32 +6,30 @@ import Task._
import TaskGen._
import math.abs
object TaskRunnerForkTest extends Properties("TaskRunner Fork")
{
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(tryRun(values.fork(f => () ).join.map(_.toList),false, 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} reduced{_ + _}
checkResult(tryRun(task, false, workers), 5*(m+1)*m)
val task = (0 to m) fork { _ * 10 } reduced { _ + _ }
checkResult(tryRun(task, false, workers), 5 * (m + 1) * m)
}
}
property("Double join") = forAll(MaxJoinGen, MaxJoinGen, MaxWorkersGen) { (a: Int, b: Int, workers: Int) =>
runDoubleJoin(abs(a),abs(b),workers)
runDoubleJoin(abs(a), abs(b), workers)
true
}
def runDoubleJoin(a: Int, b: Int, workers: Int)
{
def runDoubleJoin(a: Int, b: Int, workers: Int) {
def inner(i: Int) = List.range(0, b).map(j => task(j).named(j.toString)).join
tryRun( List.range(0,a).map(inner).join, false, workers)
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(tryRun( m.tasks.reduced(_ + _), false, workers), expected)
val expected = m.reduceLeft(_ + _)
checkResult(tryRun(m.tasks.reduced(_ + _), false, workers), expected)
}
}
}

View File

@ -1,31 +1,30 @@
package sbt
package std
import Types._
import TaskExtra._
import TaskTest.tryRun
import TaskGen.{MaxWorkers,MaxWorkersGen}
import Types._
import TaskExtra._
import TaskTest.tryRun
import TaskGen.{ MaxWorkers, MaxWorkersGen }
import org.scalacheck._
import Prop.forAll
import Transform.taskToNode
import ConcurrentRestrictions.{All, completionService, limitTotal, tagged => tagged0, TagMap, unrestricted}
import org.scalacheck._
import Prop.forAll
import Transform.taskToNode
import ConcurrentRestrictions.{ All, completionService, limitTotal, tagged => tagged0, TagMap, unrestricted }
import java.util.concurrent.{CountDownLatch, TimeUnit}
import java.util.concurrent.{ CountDownLatch, TimeUnit }
object TaskSerial extends Properties("task serial")
{
object TaskSerial extends Properties("task serial") {
val checkCycles = true
val Timeout = 100 // in milliseconds
def eval[T](t: Task[T]): T = tryRun(t, checkCycles, limitTotal(MaxWorkers))
property("Evaluates basic") = forAll { (i: Int) =>
checkResult( eval( task(i) ), i )
checkResult(eval(task(i)), i)
}
property("Evaluates Function0") = forAll { (i: Int) =>
checkResult( eval( () => i ), i )
checkResult(eval(() => i), i)
}
// verifies that all tasks get scheduled simultaneously (1-3) or do not (4)
@ -33,10 +32,10 @@ object TaskSerial extends Properties("task serial")
val size = math.max(1, sze)
val halfSize = size / 2 + 1
val all =
checkArbitrary(size, tagged(_ => true), true ) &&
checkArbitrary(size, unrestricted[Task[_]], true ) &&
checkArbitrary(size, limitTotal[Task[_]](size), true ) &&
checkArbitrary(size, limitTotal[Task[_]](halfSize), size <= halfSize )
checkArbitrary(size, tagged(_ => true), true) &&
checkArbitrary(size, unrestricted[Task[_]], true) &&
checkArbitrary(size, limitTotal[Task[_]](size), true) &&
checkArbitrary(size, limitTotal[Task[_]](halfSize), size <= halfSize)
all :| ("Size: " + size) :| ("Half size: " + halfSize)
}
@ -49,9 +48,9 @@ object TaskSerial extends Properties("task serial")
}
val tasks = (0 until size).map(_ => mktask).toList.join.map { results =>
val success = results.forall(idFun[Boolean])
assert( success == shouldSucceed, if(shouldSucceed) unschedulableMsg else scheduledMsg)
assert(success == shouldSucceed, if (shouldSucceed) unschedulableMsg else scheduledMsg)
}
checkResult( evalRestricted( tasks )( restrictions ), () )
checkResult(evalRestricted(tasks)(restrictions), ())
}
def unschedulableMsg = "Some tasks were unschedulable: verify this is an actual failure by extending the timeout to several seconds."
def scheduledMsg = "All tasks were unexpectedly scheduled."
@ -61,11 +60,10 @@ object TaskSerial extends Properties("task serial")
tryRun[T](t, checkCycles, restrictions)
}
object TaskTest
{
object TaskTest {
def run[T](root: Task[T], checkCycles: Boolean, restrictions: ConcurrentRestrictions[Task[_]]): Result[T] =
{
val (service, shutdown) = completionService[Task[_],Completed](restrictions, (x: String) => System.err.println(x))
val (service, shutdown) = completionService[Task[_], Completed](restrictions, (x: String) => System.err.println(x))
val x = new Execute[Task](Execute.config(checkCycles), Execute.noTriggers, ExecuteProgress.empty[Task])(taskToNode(idK[Task]))
try { x.run(root)(service) } finally { shutdown() }

View File

@ -7,18 +7,17 @@ import Types._
import Task._
import Execute._
object Test extends std.TaskExtra
{
def t2[A, B](a: Task[A], b: Task[B]) = multInputTask[({type l[L[x]] = (L[A], L[B])})#l]((a, b))(AList.tuple2)
def t3[A, B, C](a: Task[A], b: Task[B], c: Task[C]) = multInputTask[({type l[L[x]] = (L[A], L[B], L[C])})#l]((a, b, c))(AList.tuple3)
object Test extends std.TaskExtra {
def t2[A, B](a: Task[A], b: Task[B]) = multInputTask[({ type l[L[x]] = (L[A], L[B]) })#l]((a, b))(AList.tuple2)
def t3[A, B, C](a: Task[A], b: Task[B], c: Task[C]) = multInputTask[({ type l[L[x]] = (L[A], L[B], L[C]) })#l]((a, b, c))(AList.tuple3)
val a = task(3)
val b = task[Boolean](error("test"))
val b2 = task(true)
val c = task("asdf")
val h1 = t3(a,b,c).map { case (aa,bb,cc) => aa + " " + bb + " " + cc }
val h2 = t3(a,b2,c).map { case (aa,bb,cc) => aa + " " + bb + " " + cc }
val h1 = t3(a, b, c).map { case (aa, bb, cc) => aa + " " + bb + " " + cc }
val h2 = t3(a, b2, c).map { case (aa, bb, cc) => aa + " " + bb + " " + cc }
type Values = (Result[Int], Result[Boolean], Result[String])
@ -28,22 +27,21 @@ object Test extends std.TaskExtra
val cs = x.productIterator.toList.collect { case Inc(x) => x } // workaround for double definition bug
throw Incomplete(None, causes = cs)
}
val d2 = t3(a,b2,c) mapR f
val d2 = t3(a, b2, c) mapR f
val f2: Values => Task[Any] = {
case (Value(aa), Value(bb), Value(cc)) => task(aa + " " + bb + " " + cc)
case x => d3
}
lazy val d = t3(a,b,c) flatMapR f2
lazy val d = t3(a, b, c) flatMapR f2
val f3: Values => Task[Any] = {
case (Value(aa), Value(bb), Value(cc)) => task(aa + " " + bb + " " + cc)
case x => d2
}
lazy val d3= t3(a,b,c) flatMapR f3
lazy val d3 = t3(a, b, c) flatMapR f3
def d4(i: Int): Task[Int] = nop flatMap { _ => val x = math.random; if(x < 0.01) task(i); else d4(i+1) }
def d4(i: Int): Task[Int] = nop flatMap { _ => val x = math.random; if (x < 0.01) task(i); else d4(i + 1) }
def go()
{
def go() {
def run[T](root: Task[T]) =
println("Result : " + TaskGen.run(root, true, 2))
@ -53,7 +51,7 @@ object Test extends std.TaskExtra
run(c)
run(d)
run(d2)
run( d4(0) )
run(d4(0))
run(h1)
run(h2)
}

View File

@ -5,14 +5,13 @@ import Prop._
import TaskGen._
import Task._
object TaskRunnerCallTest extends Properties("TaskRunner Call")
{
object TaskRunnerCallTest extends Properties("TaskRunner Call") {
property("calculates fibonacci") = forAll(MaxTasksGen, MaxWorkersGen) { (i: Int, workers: Int) =>
(i > 0) ==> {
val f = fibDirect(i)
("Workers: " + workers) |: ("i: " + i) |: ("fib(i): " + f) |:
{
def result = tryRun( fibTask(i), false, workers)
def result = tryRun(fibTask(i), false, workers)
checkResult(result, f)
}
}
@ -20,25 +19,25 @@ object TaskRunnerCallTest extends Properties("TaskRunner Call")
final def fibTask(i: Int) =
{
require(i > 0)
lazy val next: (Int,Int,Int) => Task[Int] =
lazy val next: (Int, Int, Int) => Task[Int] =
(index, x1, x2) =>
{
if(index == i)
if (index == i)
task(x2)
else
iterate( (index+1, x2, x1+x2) )
iterate((index + 1, x2, x1 + x2))
}
def iterate(iteration: (Int,Int,Int)) = task( iteration ) flatMap next.tupled
iterate( (1, 0, 1) )
def iterate(iteration: (Int, Int, Int)) = task(iteration) flatMap next.tupled
iterate((1, 0, 1))
}
final def fibDirect(i: Int): Int =
{
require(i > 0)
def build(index: Int, x1: Int, x2: Int): Int =
if(index == i)
if (index == i)
x2
else
build(index+1, x2, x1+x2)
build(index + 1, x2, x1 + x2)
build(1, 0, 1)
}
}

View File

@ -9,38 +9,35 @@ import TaskGen._
import Task._
import Types._
object TaskRunnerSortTest extends Properties("TaskRunnerSort")
{
object TaskRunnerSortTest extends Properties("TaskRunnerSort") {
property("sort") = forAll(TaskListGen, MaxWorkersGen) { (list: List[Int], workers: Int) =>
val a = list.toArray
val sorted = a.toArray
java.util.Arrays.sort(sorted)
("Workers: " + workers) |: ("Array: " + a.toList) |:
{
def result = tryRun( sort(a.toSeq), false, 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: Seq[Int]): Seq[Int] =
{
if(a.length < 2)
if (a.length < 2)
a
else
{
else {
val pivot = a(0)
val (lt,gte) = a.view.drop(1).partition(_ < pivot)
val (lt, gte) = a.view.drop(1).partition(_ < pivot)
sortDirect(lt) ++ List(pivot) ++ sortDirect(gte)
}
}
final def sort(a: Seq[Int]): Task[Seq[Int]] =
{
if(a.length < 200)
if (a.length < 200)
task(sortDirect(a))
else
{
else {
task(a) flatMap { a =>
val pivot = a(0)
val (lt,gte) = a.view.drop(1).partition(_ < pivot)
val (lt, gte) = a.view.drop(1).partition(_ < pivot)
Test.t2(sort(lt), sort(gte)) map {
case (l, g) => l ++ List(pivot) ++ g
}

View File

@ -5,18 +5,14 @@ package sbt
import org.scalacheck.Prop._
object checkResult
{
object checkResult {
def apply[T](run: => T, expected: T) =
{
("Expected: " + expected) |:
(try
{
(try {
val actual = run
("Actual: " + actual) |: (actual == expected)
}
catch
{
} catch {
case i: Incomplete =>
println(i)
"One or more tasks failed" |: false

View File

@ -5,10 +5,9 @@ import org.scalacheck._
import Prop._
import java.io.File
object ConcurrentCache extends Properties("ClassLoaderCache concurrent access")
{
implicit lazy val concurrentArb: Arbitrary[Int] = Arbitrary( Gen.choose(1, 1000) )
implicit lazy val filenameArb: Arbitrary[String] = Arbitrary( Gen.alphaStr )
object ConcurrentCache extends Properties("ClassLoaderCache concurrent access") {
implicit lazy val concurrentArb: Arbitrary[Int] = Arbitrary(Gen.choose(1, 1000))
implicit lazy val filenameArb: Arbitrary[String] = Arbitrary(Gen.alphaStr)
property("Same class loader for same classpaths concurrently processed") = forAll { (names: List[String], concurrent: Int) =>
withcp(names.distinct) { files =>
@ -19,7 +18,7 @@ object ConcurrentCache extends Properties("ClassLoaderCache concurrent access")
}
private[this] def withcp[T](names: List[String])(f: List[File] => T): T = IO.withTemporaryDirectory { tmp =>
val files = names.map{ name =>
val files = names.map { name =>
val file = new File(tmp, name)
IO.touch(file)
file
@ -27,5 +26,5 @@ object ConcurrentCache extends Properties("ClassLoaderCache concurrent access")
f(files)
}
private[this] def sameClassLoader(loaders: Seq[ClassLoader]): Boolean = loaders.size < 2 ||
loaders.sliding(2).forall { case Seq(x,y) => x == y }
loaders.sliding(2).forall { case Seq(x, y) => x == y }
}

View File

@ -8,11 +8,10 @@ import Prop._
import scala.collection.mutable.HashSet
object DagSpecification extends Properties("Dag")
{
property("No repeated nodes") = forAll{ (dag: TestDag) => isSet(dag.topologicalSort) }
property("Sort contains node") = forAll{ (dag: TestDag) => dag.topologicalSort.contains(dag) }
property("Dependencies precede node") = forAll{ (dag: TestDag) => dependenciesPrecedeNodes(dag.topologicalSort) }
object DagSpecification extends Properties("Dag") {
property("No repeated nodes") = forAll { (dag: TestDag) => isSet(dag.topologicalSort) }
property("Sort contains node") = forAll { (dag: TestDag) => dag.topologicalSort.contains(dag) }
property("Dependencies precede node") = forAll { (dag: TestDag) => dependenciesPrecedeNodes(dag.topologicalSort) }
implicit lazy val arbTestDag: Arbitrary[TestDag] = Arbitrary(Gen.sized(dagGen))
private def dagGen(nodeCount: Int): Gen[TestDag] =
@ -20,10 +19,9 @@ object DagSpecification extends Properties("Dag")
val nodes = new HashSet[TestDag]
def nonterminalGen(p: Gen.Parameters): Gen[TestDag] =
{
for(i <- 0 until nodeCount; nextDeps <- Gen.someOf(nodes).apply(p))
for (i <- 0 until nodeCount; nextDeps <- Gen.someOf(nodes).apply(p))
nodes += new TestDag(i, nextDeps)
for(nextDeps <- Gen.someOf(nodes)) yield
new TestDag(nodeCount, nextDeps)
for (nextDeps <- Gen.someOf(nodes)) yield new TestDag(nodeCount, nextDeps)
}
Gen.parameterized(nonterminalGen)
}
@ -34,23 +32,19 @@ object DagSpecification extends Properties("Dag")
val seen = new HashSet[TestDag]
def iterate(remaining: List[TestDag]): Boolean =
{
remaining match
{
remaining match {
case Nil => true
case node :: tail =>
if(node.dependencies.forall(seen.contains) && !seen.contains(node))
{
if (node.dependencies.forall(seen.contains) && !seen.contains(node)) {
seen += node
iterate(tail)
}
else
} else
false
}
}
iterate(sort)
}
}
class TestDag(id: Int, val dependencies: Iterable[TestDag]) extends Dag[TestDag]
{
class TestDag(id: Int, val dependencies: Iterable[TestDag]) extends Dag[TestDag] {
override def toString = id + "->" + dependencies.mkString("[", ",", "]")
}

View File

@ -1,10 +1,9 @@
package sbt
import org.scalacheck._
import Prop._
import org.scalacheck._
import Prop._
object KeyTest extends Properties("AttributeKey")
{
object KeyTest extends Properties("AttributeKey") {
property("equality") = {
compare(AttributeKey[Int]("test"), AttributeKey[Int]("test"), true) &&
compare(AttributeKey[Int]("test"), AttributeKey[Int]("test", "description"), true) &&
@ -25,11 +24,9 @@ object KeyTest extends Properties("AttributeKey")
compare0(a, b, same)
def compare0(a: AttributeKey[_], b: AttributeKey[_], same: Boolean) =
if(same)
{
if (same) {
("equality" |: (a == b)) &&
("hash" |: (a.hashCode == b.hashCode))
}
else
} else
("equality" |: (a != b))
}

View File

@ -7,11 +7,11 @@ import Types._
// compilation test
object LiteralTest {
def x[A[_],B[_]](f: A ~> B) = f
def x[A[_], B[_]](f: A ~> B) = f
import Param._
val f = x { (p: Param[Option,List]) => p.ret( p.in.toList ) }
val f = x { (p: Param[Option, List]) => p.ret(p.in.toList) }
val a: List[Int] = f( Some(3) )
val b: List[String] = f( Some("aa") )
val a: List[Int] = f(Some(3))
val b: List[String] = f(Some("aa"))
}

View File

@ -6,8 +6,7 @@ package sbt
import Types._
// compilation test
object PMapTest
{
object PMapTest {
val mp = new DelegatingPMap[Some, Id](new collection.mutable.HashMap)
mp(Some("asdf")) = "a"
mp(Some(3)) = 9

View File

@ -10,16 +10,16 @@ final case class Scope(nestIndex: Int, idAtIndex: Int = 0)
// Lots of type constructors would become binary, which as you may know requires lots of type lambdas
// when you want a type function with only one parameter.
// That would be a general pain.)
object SettingsExample extends Init[Scope]
{
object SettingsExample extends Init[Scope] {
// Provides a way of showing a Scope+AttributeKey[_]
val showFullKey: Show[ScopedKey[_]] = new Show[ScopedKey[_]] {
def apply(key: ScopedKey[_]) = s"${key.scope.nestIndex}(${key.scope.idAtIndex})/${key.key.label}"
}
// A sample delegation function that delegates to a Scope with a lower index.
val delegates: Scope => Seq[Scope] = { case s @ Scope(index, proj) =>
s +: (if(index <= 0) Nil else { (if (proj > 0) List(Scope(index)) else Nil) ++: delegates(Scope(index-1)) })
val delegates: Scope => Seq[Scope] = {
case s @ Scope(index, proj) =>
s +: (if (index <= 0) Nil else { (if (proj > 0) List(Scope(index)) else Nil) ++: delegates(Scope(index - 1)) })
}
// Not using this feature in this example.
@ -30,8 +30,7 @@ object SettingsExample extends Init[Scope]
/** Usage Example **/
object SettingsUsage
{
object SettingsUsage {
import SettingsExample._
import Types._
@ -48,8 +47,8 @@ object SettingsUsage
// Define some settings
val mySettings: Seq[Setting[_]] = Seq(
setting( a3, value( 3 ) ),
setting( b4, map(a4)(_ * 3)),
setting(a3, value(3)),
setting(b4, map(a4)(_ * 3)),
update(a5)(_ + 1)
)
@ -59,29 +58,30 @@ object SettingsUsage
val applied: Settings[Scope] = make(mySettings)(delegates, scopeLocal, showFullKey)
// Show results.
/* for(i <- 0 to 5; k <- Seq(a, b)) {
/* for(i <- 0 to 5; k <- Seq(a, b)) {
println( k.label + i + " = " + applied.get( Scope(i), k) )
}*/
/** Output:
* For the None results, we never defined the value and there was no value to delegate to.
* For a3, we explicitly defined it to be 3.
* a4 wasn't defined, so it delegates to a3 according to our delegates function.
* b4 gets the value for a4 (which delegates to a3, so it is 3) and multiplies by 3
* a5 is defined as the previous value of a5 + 1 and
* since no previous value of a5 was defined, it delegates to a4, resulting in 3+1=4.
* b5 isn't defined explicitly, so it delegates to b4 and is therefore equal to 9 as well
a0 = None
b0 = None
a1 = None
b1 = None
a2 = None
b2 = None
a3 = Some(3)
b3 = None
a4 = Some(3)
b4 = Some(9)
a5 = Some(4)
b5 = Some(9)
**/
/**
* Output:
* For the None results, we never defined the value and there was no value to delegate to.
* For a3, we explicitly defined it to be 3.
* a4 wasn't defined, so it delegates to a3 according to our delegates function.
* b4 gets the value for a4 (which delegates to a3, so it is 3) and multiplies by 3
* a5 is defined as the previous value of a5 + 1 and
* since no previous value of a5 was defined, it delegates to a4, resulting in 3+1=4.
* b5 isn't defined explicitly, so it delegates to b4 and is therefore equal to 9 as well
* a0 = None
* b0 = None
* a1 = None
* b1 = None
* a2 = None
* b2 = None
* a3 = Some(3)
* b3 = None
* a4 = Some(3)
* b4 = Some(9)
* a5 = Some(4)
* b5 = Some(9)
*/
}

View File

@ -5,23 +5,22 @@ import Prop._
import SettingsUsage._
import SettingsExample._
object SettingsTest extends Properties("settings")
{
object SettingsTest extends Properties("settings") {
import scala.reflect.Manifest
final val ChainMax = 5000
lazy val chainLengthGen = Gen.choose(1, ChainMax)
property("Basic settings test") = secure( all( tests: _*) )
property("Basic settings test") = secure(all(tests: _*))
property("Basic chain") = forAll(chainLengthGen) { (i: Int) =>
val abs = math.abs(i)
singleIntTest( chain( abs, value(0)), abs )
singleIntTest(chain(abs, value(0)), abs)
}
property("Basic bind chain") = forAll(chainLengthGen) { (i: Int) =>
val abs = math.abs(i)
singleIntTest( chainBind(value(abs)), 0 )
singleIntTest(chainBind(value(abs)), 0)
}
property("Allows references to completed settings") = forAllNoShrink(30) { allowedReference }
@ -30,12 +29,12 @@ object SettingsTest extends Properties("settings")
val top = value(intermediate)
def iterate(init: Initialize[Int]): Initialize[Int] =
bind(init) { t =>
if(t <= 0)
if (t <= 0)
top
else
iterate(value(t-1) )
iterate(value(t - 1))
}
evaluate( setting(chk, iterate(top)) :: Nil); true
evaluate(setting(chk, iterate(top)) :: Nil); true
}
property("Derived setting chain depending on (prev derived, normal setting)") = forAllNoShrink(Gen.choose(1, 100)) { derivedSettings }
@ -55,8 +54,8 @@ object SettingsTest extends Properties("settings")
} yield derive(setting(scoped1, nextInit))
).toSeq
{ checkKey(last, Some(nr-1), evaluate(setting(chk, value(0)) +: derivedSettings)) :| "Not derived?" } &&
{ checkKey( last, None, evaluate(derivedSettings)) :| "Should not be derived" }
{ checkKey(last, Some(nr - 1), evaluate(setting(chk, value(0)) +: derivedSettings)) :| "Not derived?" } &&
{ checkKey(last, None, evaluate(derivedSettings)) :| "Should not be derived" }
}
}
@ -101,7 +100,8 @@ object SettingsTest extends Properties("settings")
property("DerivedSetting in ThisBuild scopes derived settings under projects thus allowing safe +=") = forAllNoShrink(Gen.choose(1, 100)) { derivedSettingsScope }
final def derivedSettingsScope(nrProjects: Int): Prop =
{
forAll(mkAttrKeys[Int](2)) { case List(key, derivedKey) =>
forAll(mkAttrKeys[Int](2)) {
case List(key, derivedKey) =>
val projectKeys = for { proj <- 1 to nrProjects } yield ScopedKey(Scope(1, proj), key)
val projectDerivedKeys = for { proj <- 1 to nrProjects } yield ScopedKey(Scope(1, proj), derivedKey)
val globalKey = ScopedKey(Scope(0), key)
@ -117,44 +117,44 @@ object SettingsTest extends Properties("settings")
}
}
// Circular (dynamic) references currently loop infinitely.
// This is the expected behavior (detecting dynamic cycles is expensive),
// but it may be necessary to provide an option to detect them (with a performance hit)
// This would test that cycle detection.
// property("Catches circular references") = forAll(chainLengthGen) { checkCircularReferences _ }
// Circular (dynamic) references currently loop infinitely.
// This is the expected behavior (detecting dynamic cycles is expensive),
// but it may be necessary to provide an option to detect them (with a performance hit)
// This would test that cycle detection.
// property("Catches circular references") = forAll(chainLengthGen) { checkCircularReferences _ }
final def checkCircularReferences(intermediate: Int): Prop =
{
val ccr = new CCR(intermediate)
try { evaluate( setting(chk, ccr.top) :: Nil); false }
try { evaluate(setting(chk, ccr.top) :: Nil); false }
catch { case e: java.lang.Exception => true }
}
def tests =
for(i <- 0 to 5; k <- Seq(a, b)) yield {
val expected = expectedValues(2*i + (if(k == a) 0 else 1))
checkKey[Int]( ScopedKey( Scope(i), k ), expected, applied)
for (i <- 0 to 5; k <- Seq(a, b)) yield {
val expected = expectedValues(2 * i + (if (k == a) 0 else 1))
checkKey[Int](ScopedKey(Scope(i), k), expected, applied)
}
lazy val expectedValues = None :: None :: None :: None :: None :: None :: Some(3) :: None :: Some(3) :: Some(9) :: Some(4) :: Some(9) :: Nil
lazy val ch = AttributeKey[Int]("ch")
lazy val chk = ScopedKey( Scope(0), ch)
lazy val chk = ScopedKey(Scope(0), ch)
def chain(i: Int, prev: Initialize[Int]): Initialize[Int] =
if(i <= 0) prev else chain(i - 1, prev(_ + 1))
if (i <= 0) prev else chain(i - 1, prev(_ + 1))
def chainBind(prev: Initialize[Int]): Initialize[Int] =
bind(prev) { v =>
if(v <= 0) prev else chainBind(value(v - 1) )
if (v <= 0) prev else chainBind(value(v - 1))
}
def singleIntTest(i: Initialize[Int], expected: Int) =
{
val eval = evaluate( setting( chk, i ) :: Nil )
checkKey( chk, Some(expected), eval )
val eval = evaluate(setting(chk, i) :: Nil)
checkKey(chk, Some(expected), eval)
}
def checkKey[T](key: ScopedKey[T], expected: Option[T], settings: Settings[Scope]) =
{
val value = settings.get( key.scope, key.key)
val value = settings.get(key.scope, key.key)
("Key: " + key) |:
("Value: " + value) |:
("Expected: " + expected) |:
@ -166,14 +166,13 @@ object SettingsTest extends Properties("settings")
catch { case e: Throwable => e.printStackTrace; throw e }
}
// This setup is a workaround for module synchronization issues
final class CCR(intermediate: Int)
{
final class CCR(intermediate: Int) {
lazy val top = iterate(value(intermediate), intermediate)
def iterate(init: Initialize[Int], i: Int): Initialize[Int] =
bind(init) { t =>
if(t <= 0)
if (t <= 0)
top
else
iterate(value(t - 1), t-1)
iterate(value(t - 1), t - 1)
}
}

View File

@ -1,7 +1,6 @@
package sbt.complete
object JLineTest
{
object JLineTest {
import DefaultParsers._
val one = "blue" | "green" | "black"
@ -11,13 +10,12 @@ object JLineTest
val num = token(NatBasic)
val five = (num ~ token("+" | "-") ~ num) <~ token('=') flatMap {
case a ~ "+" ~ b => token((a+b).toString)
case a ~ "-" ~ b => token((a-b).toString)
case a ~ "+" ~ b => token((a + b).toString)
case a ~ "-" ~ b => token((a - b).toString)
}
val parsers = Map("1" -> one, "2" -> two, "3" -> three, "4" -> four, "5" -> five)
def main(args: Array[String])
{
def main(args: Array[String]) {
import jline.TerminalFactory
import jline.console.ConsoleReader
val reader = new ConsoleReader()
@ -27,7 +25,7 @@ object JLineTest
JLineCompletion.installCustomCompletor(reader, parser)
def loop() {
val line = reader.readLine("> ")
if(line ne null) {
if (line ne null) {
println("Result: " + apply(parser)(line).resultEmpty)
loop()
}
@ -36,11 +34,10 @@ object JLineTest
}
}
import Parser._
import org.scalacheck._
import Parser._
import org.scalacheck._
object ParserTest extends Properties("Completing Parser")
{
object ParserTest extends Properties("Completing Parser") {
import Parsers._
import DefaultParsers.matches
@ -52,8 +49,8 @@ object ParserTest extends Properties("Completing Parser")
def p[T](f: T): T = { println(f); f }
def checkSingle(in: String, expect: Completion)(expectDisplay: Completion = expect) =
( ("token '" + in + "'") |: checkOne(in, nested, expect)) &&
( ("display '" + in + "'") |: checkOne(in, nestedDisplay, expectDisplay) )
(("token '" + in + "'") |: checkOne(in, nested, expect)) &&
(("display '" + in + "'") |: checkOne(in, nestedDisplay, expectDisplay))
def checkOne(in: String, parser: Parser[_], expect: Completion): Prop =
completions(parser, in, 1) == Completions.single(expect)
@ -61,40 +58,40 @@ object ParserTest extends Properties("Completing Parser")
def checkAll(in: String, parser: Parser[_], expect: Completions): Prop =
{
val cs = completions(parser, in, 1)
("completions: " + cs) |: ("Expected: " + expect) |: ( (cs == expect): Prop)
("completions: " + cs) |: ("Expected: " + expect) |: ((cs == expect): Prop)
}
def checkInvalid(in: String) =
( ("token '" + in + "'") |: checkInv(in, nested) ) &&
( ("display '" + in + "'") |: checkInv(in, nestedDisplay) )
(("token '" + in + "'") |: checkInv(in, nested)) &&
(("display '" + in + "'") |: checkInv(in, nestedDisplay))
def checkInv(in: String, parser: Parser[_]): Prop =
{
val cs = completions(parser, in, 1)
("completions: " + cs) |: (( cs == Completions.nil): Prop)
("completions: " + cs) |: ((cs == Completions.nil): Prop)
}
property("nested tokens a") = checkSingle("", Completion.tokenStrict("","a1") )( Completion.displayStrict("<a1>"))
property("nested tokens a1") = checkSingle("a", Completion.tokenStrict("a","1") )( Completion.displayStrict("<a1>"))
property("nested tokens a") = checkSingle("", Completion.tokenStrict("", "a1"))(Completion.displayStrict("<a1>"))
property("nested tokens a1") = checkSingle("a", Completion.tokenStrict("a", "1"))(Completion.displayStrict("<a1>"))
property("nested tokens a inv") = checkInvalid("b")
property("nested tokens b") = checkSingle("a1", Completion.tokenStrict("","b2") )( Completion.displayStrict("<b2>"))
property("nested tokens b2") = checkSingle("a1b", Completion.tokenStrict("b","2") )( Completion.displayStrict("<b2>"))
property("nested tokens b") = checkSingle("a1", Completion.tokenStrict("", "b2"))(Completion.displayStrict("<b2>"))
property("nested tokens b2") = checkSingle("a1b", Completion.tokenStrict("b", "2"))(Completion.displayStrict("<b2>"))
property("nested tokens b inv") = checkInvalid("a1a")
property("nested tokens c") = checkSingle("a1b2", Completion.suggestStrict("c3") )()
property("nested tokens c") = checkSingle("a1b2", Completion.suggestStrict("c3"))()
property("nested tokens c3") = checkSingle("a1b2c", Completion.suggestStrict("3"))()
property("nested tokens c inv") = checkInvalid("a1b2a")
property("suggest space") = checkOne("", spacePort, Completion.tokenStrict("", " "))
property("suggest port") = checkOne(" ", spacePort, Completion.displayStrict("<port>") )
property("suggest port") = checkOne(" ", spacePort, Completion.displayStrict("<port>"))
property("no suggest at end") = checkOne("asdf", "asdf", Completion.suggestStrict(""))
property("no suggest at token end") = checkOne("asdf", token("asdf"), Completion.suggestStrict(""))
property("empty suggest for examples") = checkOne("asdf", any.+.examples("asdf", "qwer"), Completion.suggestStrict(""))
property("empty suggest for examples token") = checkOne("asdf", token(any.+.examples("asdf", "qwer")), Completion.suggestStrict(""))
val colors = Set("blue", "green", "red")
val base = (seen: Seq[String]) => token( ID examples (colors -- seen) )
val sep = token( Space )
val repeat = repeatDep( base, sep)
val base = (seen: Seq[String]) => token(ID examples (colors -- seen))
val sep = token(Space)
val repeat = repeatDep(base, sep)
def completionStrings(ss: Set[String]): Completions = Completions(ss.map { s => Completion.tokenStrict("", s) })
property("repeatDep no suggestions for bad input") = checkInv(".", repeat)
@ -111,21 +108,20 @@ object ParserTest extends Properties("Completing Parser")
property("repeatDep accepts one token") = matches(repeat, colors.toSeq.head)
property("repeatDep accepts two tokens") = matches(repeat, colors.toSeq.take(2).mkString(" "))
}
object ParserExample
{
object ParserExample {
val ws = charClass(_.isWhitespace)+
val notws = charClass(!_.isWhitespace)+
val name = token("test")
val options = (ws ~> token("quick" | "failed" | "new") )*
val options = (ws ~> token("quick" | "failed" | "new"))*
val exampleSet = Set("am", "is", "are", "was", "were")
val include = (ws ~> token(examples(notws.string, new FixedSetExamples(exampleSet), exampleSet.size, false )) )*
val include = (ws ~> token(examples(notws.string, new FixedSetExamples(exampleSet), exampleSet.size, false)))*
val t = name ~ options ~ include
// Get completions for some different inputs
println(completions(t, "te", 1))
println(completions(t, "test ",1))
println(completions(t, "test ", 1))
println(completions(t, "test w", 1))
// Get the parsed result for different inputs
@ -134,21 +130,19 @@ object ParserExample
println(apply(t)("test w").resultEmpty)
println(apply(t)("test was were").resultEmpty)
def run(n: Int)
{
def run(n: Int) {
val a = 'a'.id
val aq = a.?
val aqn = repeat(aq, min = n, max = n)
val an = repeat(a, min = n, max = n)
val ann = aqn ~ an
def r = apply(ann)("a"*(n*2)).resultEmpty
def r = apply(ann)("a" * (n * 2)).resultEmpty
println(r.isValid)
}
def run2(n: Int)
{
def run2(n: Int) {
val ab = "ab".?.*
val r = apply(ab)("a"*n).resultEmpty
val r = apply(ab)("a" * n).resultEmpty
println(r)
}
}

View File

@ -6,8 +6,7 @@ import sbt.IO.withTemporaryDirectory
import java.io.File
import sbt.IO._
class FileExamplesTest extends Specification
{
class FileExamplesTest extends Specification {
"listing all files in an absolute base directory" should {
"produce the entire base directory's contents" in new directoryStructure {
@ -49,8 +48,7 @@ class FileExamplesTest extends Specification
}
}
class directoryStructure(withCompletionPrefix: String = "") extends Scope with DelayedInit
{
class directoryStructure(withCompletionPrefix: String = "") extends Scope with DelayedInit {
var fileExamples: FileExamples = _
var baseDir: File = _
var childFiles: List[File] = _

View File

@ -6,15 +6,14 @@ import org.scalacheck._
import Prop._
import Arbitrary.arbLong
object CopySpec extends Properties("Copy")
{
object CopySpec extends Properties("Copy") {
// set to 0.25 GB by default for success on most systems without running out of space.
// when modifying IO.copyFile, verify against 1 GB or higher, preferably > 4 GB
final val MaxFileSizeBits = 28
final val BufferSize = 1*1024*1024
final val BufferSize = 1 * 1024 * 1024
val randomSize = Gen.choose(0, MaxFileSizeBits).map( 1L << _ )
val pow2Size = (0 to (MaxFileSizeBits - 1)).toList.map( 1L << _ )
val randomSize = Gen.choose(0, MaxFileSizeBits).map(1L << _)
val pow2Size = (0 to (MaxFileSizeBits - 1)).toList.map(1L << _)
val derivedSize = pow2Size.map(_ - 1) ::: pow2Size.map(_ + 1) ::: pow2Size
val fileSizeGen: Gen[Long] =
@ -41,13 +40,13 @@ object CopySpec extends Properties("Copy")
val buffer = new Array[Byte](BufferSize)
def loop(offset: Long) {
val len = math.min(size - offset, BufferSize)
if(len > 0) {
if (len > 0) {
rnd.nextBytes(buffer)
IO.append(file, buffer)
loop(offset + len)
}
}
if(size == 0L) IO.touch(file) else loop(0)
if (size == 0L) IO.touch(file) else loop(0)
}
def checkContentsSame(f1: File, f2: File) {
val len = f1.length
@ -56,7 +55,7 @@ object CopySpec extends Properties("Copy")
Using.fileInputStream(f2) { in2 =>
val buffer1 = new Array[Byte](BufferSize)
val buffer2 = new Array[Byte](BufferSize)
def loop(offset: Long): Unit = if(offset < len) {
def loop(offset: Long): Unit = if (offset < len) {
val read1 = in1.read(buffer1)
val read2 = in2.read(buffer2)
assert(read1 == read2, "Read " + (read1, read2).toString + " bytes from " + (f1, f2).toString)

View File

@ -5,20 +5,19 @@ package sbt
import org.scalacheck._
import Prop._
import Arbitrary.{arbString => _, arbChar => _, _}
import java.io.{File, IOException}
import Arbitrary.{ arbString => _, arbChar => _, _ }
import java.io.{ File, IOException }
object WriteContentSpecification extends Properties("Write content")
{
property("Roundtrip string") = forAll( writeAndCheckString _)
object WriteContentSpecification extends Properties("Write content") {
property("Roundtrip string") = forAll(writeAndCheckString _)
property("Roundtrip bytes") = forAll(writeAndCheckBytes _)
property("Write string overwrites") = forAll(overwriteAndCheckStrings _)
property("Write bytes overwrites") = forAll( overwriteAndCheckBytes _)
property("Append string appends") = forAll( appendAndCheckStrings _)
property("Append bytes appends") = forAll( appendAndCheckBytes _)
property("Write bytes overwrites") = forAll(overwriteAndCheckBytes _)
property("Append string appends") = forAll(appendAndCheckStrings _)
property("Append bytes appends") = forAll(appendAndCheckBytes _)
property("Unzip doesn't stack overflow") = largeUnzip()
implicit lazy val validChar: Arbitrary[Char] = Arbitrary( for(i <- Gen.choose(0, 0xd7ff)) yield i.toChar )
implicit lazy val validChar: Arbitrary[Char] = Arbitrary(for (i <- Gen.choose(0, 0xd7ff)) yield i.toChar)
implicit lazy val validString: Arbitrary[String] = Arbitrary(arbitrary[List[Char]] map (_.mkString))
private def largeUnzip() =
@ -64,13 +63,13 @@ object WriteContentSpecification extends Properties("Write content")
withTemporaryFile { file =>
append(file, a, charset)
append(file, b, charset)
read(file, charset) == (a+b)
read(file, charset) == (a + b)
}
private def appendAndCheckBytes(a: Array[Byte], b: Array[Byte]) =
withTemporaryFile { file =>
append(file, a)
append(file, b)
readBytes(file) sameElements (a++b)
readBytes(file) sameElements (a ++ b)
}
private def withTemporaryFile[T](f: File => T): T =

View File

@ -6,35 +6,40 @@ package sbt
import org.scalacheck._
import Prop._
object NameFilterSpecification extends Properties("NameFilter")
{
property("All pass accepts everything") = forAll{ (s: String) => AllPassFilter.accept(s) }
object NameFilterSpecification extends Properties("NameFilter") {
property("All pass accepts everything") = forAll { (s: String) => AllPassFilter.accept(s) }
property("Exact filter matches provided string") = forAll {
(s1: String, s2: String) => (new ExactFilter(s1)).accept(s2) == (s1 == s2) }
property("Exact filter matches valid string") = forAll{ (s: String) => (new ExactFilter(s)).accept(s) }
(s1: String, s2: String) => (new ExactFilter(s1)).accept(s2) == (s1 == s2)
}
property("Exact filter matches valid string") = forAll { (s: String) => (new ExactFilter(s)).accept(s) }
property("Glob filter matches provided string if no *s") = forAll {
(s1: String, s2: String) =>
{
val stripped = stripAsterisksAndControl(s1)
(GlobFilter(stripped).accept(s2) == (stripped == s2))
} }
}
}
property("Glob filter matches valid string if no *s") = forAll {
(s: String) =>
{
val stripped = stripAsterisksAndControl(s)
GlobFilter(stripped).accept(stripped)
}}
}
}
property("Glob filter matches valid") = forAll {
(list: List[String]) =>
{
val stripped = list.map(stripAsterisksAndControl)
GlobFilter(stripped.mkString("*")).accept(stripped.mkString)
}}
}
}
/** Raw control characters are stripped because they are not allowed in expressions.
* Asterisks are stripped because they are added under the control of the tests.*/
/**
* Raw control characters are stripped because they are not allowed in expressions.
* Asterisks are stripped because they are added under the control of the tests.
*/
private def stripAsterisksAndControl(s: String) = (s filter validChar).toString
private[this] def validChar(c: Char) =
!java.lang.Character.isISOControl(c) &&

View File

@ -12,21 +12,22 @@ import RichURI._
object RichURISpecification extends Properties("Rich URI") {
val strGen = {
val charGen = frequency((1, value(' ')), (9, alphaChar))
val withEmptyGen = for(cs <- listOf(charGen)) yield cs.mkString
val withEmptyGen = for (cs <- listOf(charGen)) yield cs.mkString
withEmptyGen map (_.trim.replace(" ", "%20")) filter (!_.isEmpty)
}
val pathGen =
for(s <- listOf1(strGen)) yield s.mkString("/", "/", "")
for (s <- listOf1(strGen)) yield s.mkString("/", "/", "")
def nullable[T >: Null](g: Gen[T]): Gen[T] = frequency((1, value(null)), (25, g))
implicit val arbitraryURI: Arbitrary[URI] =
Arbitrary(
for (scheme <- identifier;
for (
scheme <- identifier;
path <- pathGen;
fragment <- nullable(strGen))
yield new URI(scheme, "file:" + path, fragment)
fragment <- nullable(strGen)
) yield new URI(scheme, "file:" + path, fragment)
)
property("withoutFragment should drop fragment") = forAll { (uri: URI) =>

View File

@ -10,25 +10,23 @@ import IO._
import java.io.File
import Function.tupled
object CheckStash extends Specification
{
object CheckStash extends Specification {
"stash" should {
"handle empty files" in {
stash(Set()) { }
stash(Set()) {}
true must beTrue
}
"move files during execution" in {
WithFiles(TestFiles : _*) ( checkMove )
WithFiles(TestFiles: _*)(checkMove)
}
"restore files on exceptions but not errors" in {
WithFiles(TestFiles : _*) ( checkRestore )
WithFiles(TestFiles: _*)(checkRestore)
}
}
def checkRestore(seq: Seq[File])
{
def checkRestore(seq: Seq[File]) {
allCorrect(seq)
stash0(seq, throw new TestRuntimeException) must beFalse
@ -40,22 +38,19 @@ object CheckStash extends Specification
stash0(seq, throw new TestError) must beFalse
noneExist(seq)
}
def checkMove(seq: Seq[File])
{
def checkMove(seq: Seq[File]) {
allCorrect(seq)
stash0(seq, ()) must beTrue
noneExist(seq)
}
def stash0(seq: Seq[File], post: => Unit): Boolean =
try
{
try {
stash(Set() ++ seq) {
noneExist(seq)
post
}
true
}
catch {
} catch {
case _: TestError | _: TestException | _: TestRuntimeException => false
}

View File

@ -1,19 +1,19 @@
package sbt
import java.io.File
import IO.{withTemporaryDirectory, write}
import IO.{ withTemporaryDirectory, write }
object WithFiles
{
/** Takes the relative path -> content pairs and writes the content to a file in a temporary directory. The written file
object WithFiles {
/**
* Takes the relative path -> content pairs and writes the content to a file in a temporary directory. The written file
* path is the relative path resolved against the temporary directory path. The provided function is called with the resolved file paths
* in the same order as the inputs. */
* in the same order as the inputs.
*/
def apply[T](sources: (File, String)*)(f: Seq[File] => T): T =
{
withTemporaryDirectory { dir =>
val sourceFiles =
for((file, content) <- sources) yield
{
for ((file, content) <- sources) yield {
assert(!file.isAbsolute)
val to = new File(dir, file.getPath)
write(to, content)

View File

@ -2,12 +2,11 @@ package sbt
import org.scalacheck._
import Prop._
import Gen.{listOf, oneOf}
import Gen.{ listOf, oneOf }
import ConsoleLogger.{ESC, hasEscapeSequence, isEscapeTerminator, removeEscapeSequences}
import ConsoleLogger.{ ESC, hasEscapeSequence, isEscapeTerminator, removeEscapeSequences }
object Escapes extends Properties("Escapes")
{
object Escapes extends Properties("Escapes") {
property("genTerminator only generates terminators") =
forAllNoShrink(genTerminator) { (c: Char) => isEscapeTerminator(c) }
@ -37,7 +36,7 @@ object Escapes extends Properties("Escapes")
}
property("removeEscapeSequences returns string without escape sequences") =
forAllNoShrink( genWithoutEscape, genEscapePairs ) { (start: String, escapes: List[EscapeAndNot]) =>
forAllNoShrink(genWithoutEscape, genEscapePairs) { (start: String, escapes: List[EscapeAndNot]) =>
val withEscapes: String = start + escapes.map { ean => ean.escape.makeString + ean.notEscape }
val removed: String = removeEscapeSequences(withEscapes)
val original = start + escapes.map(_.notEscape)
@ -47,21 +46,19 @@ object Escapes extends Properties("Escapes")
}
final case class EscapeAndNot(escape: EscapeSequence, notEscape: String)
final case class EscapeSequence(content: String, terminator: Char)
{
assert( content.forall(c => !isEscapeTerminator(c) ), "Escape sequence content contains an escape terminator: '" + content + "'" )
assert( isEscapeTerminator(terminator) )
final case class EscapeSequence(content: String, terminator: Char) {
assert(content.forall(c => !isEscapeTerminator(c)), "Escape sequence content contains an escape terminator: '" + content + "'")
assert(isEscapeTerminator(terminator))
def makeString: String = ESC + content + terminator
}
private[this] def noEscape(s: String): String = s.replace(ESC, ' ')
lazy val genEscapeSequence: Gen[EscapeSequence] = oneOf(genKnownSequence, genArbitraryEscapeSequence)
lazy val genEscapePair: Gen[EscapeAndNot] = for(esc <- genEscapeSequence; not <- genWithoutEscape) yield EscapeAndNot(esc, not)
lazy val genEscapePair: Gen[EscapeAndNot] = for (esc <- genEscapeSequence; not <- genWithoutEscape) yield EscapeAndNot(esc, not)
lazy val genEscapePairs: Gen[List[EscapeAndNot]] = listOf(genEscapePair)
lazy val genArbitraryEscapeSequence: Gen[EscapeSequence] =
for(content <- genWithoutTerminator; term <- genTerminator) yield
new EscapeSequence(content, term)
for (content <- genWithoutTerminator; term <- genTerminator) yield new EscapeSequence(content, term)
lazy val genKnownSequence: Gen[EscapeSequence] =
oneOf((misc ++ setGraphicsMode ++ setMode ++ resetMode).map(toEscapeSequence))
@ -71,21 +68,19 @@ object Escapes extends Properties("Escapes")
lazy val misc = Seq("14;23H", "5;3f", "2A", "94B", "19C", "85D", "s", "u", "2J", "K")
lazy val setGraphicsMode: Seq[String] =
for(txt <- 0 to 8; fg <- 30 to 37; bg <- 40 to 47) yield
txt.toString + ";" + fg.toString + ";" + bg.toString + "m"
for (txt <- 0 to 8; fg <- 30 to 37; bg <- 40 to 47) yield txt.toString + ";" + fg.toString + ";" + bg.toString + "m"
lazy val resetMode = setModeLike('I')
lazy val setMode = setModeLike('h')
def setModeLike(term: Char): Seq[String] = (0 to 19).map(i => "=" + i.toString + term)
lazy val genWithoutTerminator = genRawString.map( _.filter { c => !isEscapeTerminator(c) } )
lazy val genWithoutTerminator = genRawString.map(_.filter { c => !isEscapeTerminator(c) })
lazy val genTerminator: Gen[Char] = Gen.choose('@', '~')
lazy val genWithoutEscape: Gen[String] = genRawString.map(noEscape)
def genWithRandomEscapes: Gen[String] =
for(ls <- listOf(genRawString); end <- genRawString) yield
ls.mkString("", ESC.toString, ESC.toString + end)
for (ls <- listOf(genRawString); end <- genRawString) yield ls.mkString("", ESC.toString, ESC.toString + end)
private def genRawString = Arbitrary.arbString.arbitrary
}

View File

@ -4,47 +4,47 @@
package sbt
import org.scalacheck._
import Arbitrary.{arbitrary => arb, _}
import Gen.{listOfN, oneOf}
import Arbitrary.{ arbitrary => arb, _ }
import Gen.{ listOfN, oneOf }
import Prop._
import java.io.Writer
object LogWriterTest extends Properties("Log Writer")
{
object LogWriterTest extends Properties("Log Writer") {
final val MaxLines = 100
final val MaxSegments = 10
/* Tests that content written through a LoggerWriter is properly passed to the underlying Logger.
* Each line, determined by the specified newline separator, must be logged at the correct logging level. */
property("properly logged") = forAll { (output: Output, newLine: NewLine) =>
import output.{lines, level}
import output.{ lines, level }
val log = new RecordingLogger
val writer = new LoggerWriter(log, Some(level), newLine.str)
logLines(writer, lines, newLine.str)
val events = log.getEvents
("Recorded:\n" + events.map(show).mkString("\n")) |:
check( toLines(lines), events, level)
check(toLines(lines), events, level)
}
/** Displays a LogEvent in a useful format for debugging. In particular, we are only interested in `Log` types
* and non-printable characters should be escaped*/
/**
* Displays a LogEvent in a useful format for debugging. In particular, we are only interested in `Log` types
* and non-printable characters should be escaped
*/
def show(event: LogEvent): String =
event match
{
event match {
case l: Log => "Log('" + Escape(l.msg) + "', " + l.level + ")"
case _ => "Not Log"
}
/** Writes the given lines to the Writer. `lines` is taken to be a list of lines, which are
/**
* Writes the given lines to the Writer. `lines` is taken to be a list of lines, which are
* represented as separately written segments (ToLog instances). ToLog.`byCharacter`
* indicates whether to write the segment by character (true) or all at once (false)*/
def logLines(writer: Writer, lines: List[List[ToLog]], newLine: String)
{
for(line <- lines; section <- line)
{
* indicates whether to write the segment by character (true) or all at once (false)
*/
def logLines(writer: Writer, lines: List[List[ToLog]], newLine: String) {
for (line <- lines; section <- line) {
val content = section.content
val normalized = Escape.newline(content, newLine)
if(section.byCharacter)
if (section.byCharacter)
normalized.foreach { c => writer.write(c.toInt) }
else
writer.write(normalized)
@ -58,7 +58,7 @@ object LogWriterTest extends Properties("Log Writer")
/** Checks that the expected `lines` were recorded as `events` at level `Lvl`.*/
def check(lines: List[String], events: List[LogEvent], Lvl: Level.Value): Boolean =
(lines zip events) forall {
case (line, log : Log) => log.level == Lvl && line == log.msg
case (line, log: Log) => log.level == Lvl && line == log.msg
case _ => false
}
@ -72,29 +72,25 @@ object LogWriterTest extends Properties("Log Writer")
implicit lazy val arbLog: Arbitrary[ToLog] = Arbitrary(genLog)
implicit lazy val arbLine: Arbitrary[List[ToLog]] = Arbitrary(genLine)
implicit lazy val arbNewLine: Arbitrary[NewLine] = Arbitrary(genNewLine)
implicit lazy val arbLevel : Arbitrary[Level.Value] = Arbitrary(genLevel)
implicit lazy val arbLevel: Arbitrary[Level.Value] = Arbitrary(genLevel)
implicit def genLine(implicit logG: Gen[ToLog]): Gen[List[ToLog]] =
for(l <- listOf[ToLog](MaxSegments); last <- logG) yield
(addNewline(last) :: l.filter(!_.content.isEmpty)).reverse
for (l <- listOf[ToLog](MaxSegments); last <- logG) yield (addNewline(last) :: l.filter(!_.content.isEmpty)).reverse
implicit def genLog(implicit content: Arbitrary[String], byChar: Arbitrary[Boolean]): Gen[ToLog] =
for(c <- content.arbitrary; by <- byChar.arbitrary) yield
{
for (c <- content.arbitrary; by <- byChar.arbitrary) yield {
assert(c != null)
new ToLog(removeNewlines(c), by)
}
implicit lazy val genNewLine: Gen[NewLine] =
for(str <- oneOf("\n", "\r", "\r\n")) yield
new NewLine(str)
for (str <- oneOf("\n", "\r", "\r\n")) yield new NewLine(str)
implicit lazy val genLevel: Gen[Level.Value] =
oneOf(Level.values.toSeq)
implicit lazy val genOutput: Gen[Output] =
for(ls <- listOf[List[ToLog]](MaxLines); lv <- genLevel) yield
new Output(ls, lv)
for (ls <- listOf[List[ToLog]](MaxLines); lv <- genLevel) yield new Output(ls, lv)
def removeNewlines(s: String) = s.replaceAll("""[\n\r]+""", "")
def addNewline(l: ToLog): ToLog =
@ -106,46 +102,40 @@ object LogWriterTest extends Properties("Log Writer")
/* Helper classes*/
final class Output(val lines: List[List[ToLog]], val level: Level.Value) extends NotNull
{
final class Output(val lines: List[List[ToLog]], val level: Level.Value) extends NotNull {
override def toString =
"Level: " + level + "\n" + lines.map(_.mkString).mkString("\n")
}
final class NewLine(val str: String) extends NotNull
{
final class NewLine(val str: String) extends NotNull {
override def toString = Escape(str)
}
final class ToLog(val content: String, val byCharacter: Boolean) extends NotNull
{
final class ToLog(val content: String, val byCharacter: Boolean) extends NotNull {
def contentOnly = Escape.newline(content, "")
override def toString = if(content.isEmpty) "" else "ToLog('" + Escape(contentOnly) + "', " + byCharacter + ")"
override def toString = if (content.isEmpty) "" else "ToLog('" + Escape(contentOnly) + "', " + byCharacter + ")"
}
/** Defines some utility methods for escaping unprintable characters.*/
object Escape
{
object Escape {
/** Escapes characters with code less than 20 by printing them as unicode escapes.*/
def apply(s: String): String =
{
val builder = new StringBuilder(s.length)
for(c <- s)
{
for (c <- s) {
def escaped = pad(c.toInt.toHexString.toUpperCase, 4, '0')
if(c < 20) builder.append("\\u").append(escaped) else builder.append(c)
if (c < 20) builder.append("\\u").append(escaped) else builder.append(c)
}
builder.toString
}
def pad(s: String, minLength: Int, extra: Char) =
{
val diff = minLength - s.length
if(diff <= 0) s else List.make(diff, extra).mkString("", "", s)
if (diff <= 0) s else List.make(diff, extra).mkString("", "", s)
}
/** Replaces a \n character at the end of a string `s` with `nl`.*/
def newline(s: String, nl: String): String =
if(s.endsWith("\n")) s.substring(0, s.length - 1) + nl else s
if (s.endsWith("\n")) s.substring(0, s.length - 1) + nl else s
}
/** Records logging events for later retrieval.*/
final class RecordingLogger extends BasicLogger
{
final class RecordingLogger extends BasicLogger {
private var events: List[LogEvent] = Nil
def getEvents = events.reverse

View File

@ -1,7 +1,6 @@
package sbt
object TestLogger
{
object TestLogger {
def apply[T](f: Logger => T): T =
{
val log = new BufferedLogger(ConsoleLogger())

View File

@ -1,21 +1,20 @@
package sbt
package logic
import org.scalacheck._
import Prop.secure
import Logic.{LogicException, Matched}
import org.scalacheck._
import Prop.secure
import Logic.{ LogicException, Matched }
object LogicTest extends Properties("Logic")
{
object LogicTest extends Properties("Logic") {
import TestClauses._
property("Handles trivial resolution.") = secure( expect(trivial, Set(A) ) )
property("Handles less trivial resolution.") = secure( expect(lessTrivial, Set(B,A,D)) )
property("Handles cycles without negation") = secure( expect(cycles, Set(F,A,B)) )
property("Handles basic exclusion.") = secure( expect(excludedPos, Set()) )
property("Handles exclusion of head proved by negation.") = secure( expect(excludedNeg, Set()) )
property("Handles trivial resolution.") = secure(expect(trivial, Set(A)))
property("Handles less trivial resolution.") = secure(expect(lessTrivial, Set(B, A, D)))
property("Handles cycles without negation") = secure(expect(cycles, Set(F, A, B)))
property("Handles basic exclusion.") = secure(expect(excludedPos, Set()))
property("Handles exclusion of head proved by negation.") = secure(expect(excludedNeg, Set()))
// TODO: actually check ordering, probably as part of a check that dependencies are satisifed
property("Properly orders results.") = secure( expect(ordering, Set(B,A,C,E,F)))
property("Properly orders results.") = secure(expect(ordering, Set(B, A, C, E, F)))
property("Detects cyclic negation") = secure(
Logic.reduceAll(badClauses, Set()) match {
case Right(res) => false
@ -32,8 +31,7 @@ object LogicTest extends Properties("Logic")
}
}
object TestClauses
{
object TestClauses {
val A = Atom("A")
val B = Atom("B")
@ -103,7 +101,7 @@ object TestClauses
(C && !D).proves(E) ::
(A && B).proves(C) ::
Nil
Logic.reduceAll(cs, Set(A,B))
Logic.reduceAll(cs, Set(A, B))
}
def all {

View File

@ -1,30 +1,29 @@
package sbt
import java.io.File
import org.scalacheck.{Arbitrary, Gen, Prop, Properties}
import org.scalacheck.{ Arbitrary, Gen, Prop, Properties }
import Prop._
import Process._
object ProcessSpecification extends Properties("Process I/O")
{
object ProcessSpecification extends Properties("Process I/O") {
implicit val exitCodeArb: Arbitrary[Array[Byte]] = Arbitrary(
for(size <- Gen.choose(0, 10);
l <- Gen.listOfN[Byte](size, Arbitrary.arbByte.arbitrary))
yield
l.toArray
for (
size <- Gen.choose(0, 10);
l <- Gen.listOfN[Byte](size, Arbitrary.arbByte.arbitrary)
) yield l.toArray
)
/*property("Correct exit code") = forAll( (exitCode: Byte) => checkExit(exitCode))
property("#&& correct") = forAll( (exitCodes: Array[Byte]) => checkBinary(exitCodes)(_ #&& _)(_ && _))
property("#|| correct") = forAll( (exitCodes: Array[Byte]) => checkBinary(exitCodes)(_ #|| _)(_ || _))
property("### correct") = forAll( (exitCodes: Array[Byte]) => checkBinary(exitCodes)(_ ### _)( (x,latest) => latest))*/
property("Pipe to output file") = forAll( (data: Array[Byte]) => checkFileOut(data))
property("Pipe from input file") = forAll( (data: Array[Byte]) => checkFileIn(data))
property("Pipe to process") = forAll( (data: Array[Byte]) => checkPipe(data))
property("Pipe to process ignores input exit code") = forAll( (data: Array[Byte], code: Byte) => checkPipeExit(data, code))
property("Pipe from input file to bad process preserves correct exit code.") = forAll( (data: Array[Byte], code: Byte) => checkFileInExit(data, code))
property("Pipe to output file from bad process preserves correct exit code.") = forAll( (data: Array[Byte], code: Byte) => checkFileOutExit(data, code))
property("Pipe to output file") = forAll((data: Array[Byte]) => checkFileOut(data))
property("Pipe from input file") = forAll((data: Array[Byte]) => checkFileIn(data))
property("Pipe to process") = forAll((data: Array[Byte]) => checkPipe(data))
property("Pipe to process ignores input exit code") = forAll((data: Array[Byte], code: Byte) => checkPipeExit(data, code))
property("Pipe from input file to bad process preserves correct exit code.") = forAll((data: Array[Byte], code: Byte) => checkFileInExit(data, code))
property("Pipe to output file from bad process preserves correct exit code.") = forAll((data: Array[Byte], code: Byte) => checkFileOutExit(data, code))
private def checkBinary(codes: Array[Byte])(reduceProcesses: (ProcessBuilder, ProcessBuilder) => ProcessBuilder)(reduceExit: (Boolean, Boolean) => Boolean) =
{
@ -64,7 +63,7 @@ object ProcessSpecification extends Properties("Process I/O")
}
}
private def checkPipeExit(data: Array[Byte], code: Byte) =
withTempFiles { (a,b) =>
withTempFiles { (a, b) =>
IO.write(a, data)
val catCommand = process("sbt.cat")
val exitCommand = process(s"sbt.exit $code")
@ -76,7 +75,7 @@ object ProcessSpecification extends Properties("Process I/O")
}
private def checkFileOutExit(data: Array[Byte], exitCode: Byte) =
withTempFiles { (a,b) =>
withTempFiles { (a, b) =>
IO.write(a, data)
val code = unsigned(exitCode)
val command = process(s"sbt.exit $code")
@ -88,7 +87,7 @@ object ProcessSpecification extends Properties("Process I/O")
}
private def checkFileInExit(data: Array[Byte], exitCode: Byte) =
withTempFiles { (a,b) =>
withTempFiles { (a, b) =>
IO.write(a, data)
val code = unsigned(exitCode)
val command = process(s"sbt.exit $code")
@ -102,7 +101,7 @@ object ProcessSpecification extends Properties("Process I/O")
withTempFiles { (a, b) =>
IO.write(a, data)
val process = f(a, b)
( process ! ) == 0 && sameFiles(a, b)
(process !) == 0 && sameFiles(a, b)
}
private def sameFiles(a: File, b: File) =
IO.readBytes(a) sameElements IO.readBytes(b)
@ -112,13 +111,12 @@ object ProcessSpecification extends Properties("Process I/O")
val temporaryFile1 = temp()
val temporaryFile2 = temp()
try f(temporaryFile1, temporaryFile2)
finally
{
finally {
temporaryFile1.delete()
temporaryFile2.delete()
}
}
private def unsigned(b: Int): Int = ((b: Int) +256) % 256
private def unsigned(b: Int): Int = ((b: Int) + 256) % 256
private def unsigned(b: Byte): Int = unsigned(b: Int)
private def process(command: String) =
{
@ -127,7 +125,7 @@ object ProcessSpecification extends Properties("Process I/O")
val thisClasspath = List(getSource[Product], getSource[IO.type], getSource[SourceTag]).mkString(File.pathSeparator)
"java -cp " + thisClasspath + " " + command
}
private def getSource[T : Manifest]: String =
private def getSource[T: Manifest]: String =
IO.classLocationFile[T].getAbsolutePath
}
private trait SourceTag

View File

@ -1,20 +1,16 @@
package sbt
import java.io.{File, FileNotFoundException, IOException}
import java.io.{ File, FileNotFoundException, IOException }
object exit
{
def main(args: Array[String])
{
object exit {
def main(args: Array[String]) {
System.exit(java.lang.Integer.parseInt(args(0)))
}
}
object cat
{
def main(args: Array[String])
{
object cat {
def main(args: Array[String]) {
try {
if(args.length == 0)
if (args.length == 0)
IO.transfer(System.in, System.out)
else
catFiles(args.toList)
@ -28,29 +24,24 @@ object cat
}
private def catFiles(filenames: List[String]): Option[String] =
{
filenames match
{
filenames match {
case head :: tail =>
val file = new File(head)
if(file.isDirectory)
if (file.isDirectory)
throw new IOException("Is directory: " + file)
else if(file.exists)
{
else if (file.exists) {
Using.fileInputStream(file) { stream =>
IO.transfer(stream, System.out)
}
catFiles(tail)
}
else
} else
throw new FileNotFoundException("No such file or directory: " + file)
case Nil => None
}
}
}
object echo
{
def main(args: Array[String])
{
object echo {
def main(args: Array[String]) {
System.out.println(args.mkString(" "))
}
}

View File

@ -6,8 +6,7 @@ package sbt
import org.scalacheck._
import Prop._
object RelationTest extends Properties("Relation")
{
object RelationTest extends Properties("Relation") {
property("Added entry check") = forAll { (pairs: List[(Int, Double)]) =>
val r = Relation.empty[Int, Double] ++ pairs
check(r, pairs)
@ -19,7 +18,8 @@ object RelationTest extends Properties("Relation")
r._1s == _1s && r.forwardMap.keySet == _1s &&
r._2s == _2s && r.reverseMap.keySet == _2s &&
pairs.forall { case (a, b) =>
pairs.forall {
case (a, b) =>
(r.forward(a) contains b) &&
(r.reverse(b) contains a) &&
(r.forwardMap(a) contains b) &&
@ -28,26 +28,27 @@ object RelationTest extends Properties("Relation")
}
property("Does not contain removed entries") = forAll { (pairs: List[(Int, Double, Boolean)]) =>
val add = pairs.map { case (a,b,c) => (a,b) }
val add = pairs.map { case (a, b, c) => (a, b) }
val added = Relation.empty[Int, Double] ++ add
val removeFine = pairs.collect { case (a,b,true) => (a,b) }
val removeFine = pairs.collect { case (a, b, true) => (a, b) }
val removeCoarse = removeFine.map(_._1)
val r = added -- removeCoarse
def notIn[X,Y](map: Map[X, Set[Y]], a: X, b: Y) = map.get(a).forall(set => ! (set contains b) )
def notIn[X, Y](map: Map[X, Set[Y]], a: X, b: Y) = map.get(a).forall(set => !(set contains b))
all(removeCoarse) { rem =>
("_1s does not contain removed" |: (!r._1s.contains(rem)) ) &&
("Forward does not contain removed" |: r.forward(rem).isEmpty ) &&
("Forward map does not contain removed" |: !r.forwardMap.contains(rem) ) &&
("Removed is not a value in reverse map" |: !r.reverseMap.values.toSet.contains(rem) )
("_1s does not contain removed" |: (!r._1s.contains(rem))) &&
("Forward does not contain removed" |: r.forward(rem).isEmpty) &&
("Forward map does not contain removed" |: !r.forwardMap.contains(rem)) &&
("Removed is not a value in reverse map" |: !r.reverseMap.values.toSet.contains(rem))
} &&
all(removeFine) { case (a, b) =>
("Forward does not contain removed" |: ( !r.forward(a).contains(b) ) ) &&
("Reverse does not contain removed" |: ( !r.reverse(b).contains(a) ) ) &&
("Forward map does not contain removed" |: ( notIn(r.forwardMap, a, b) ) ) &&
("Reverse map does not contain removed" |: ( notIn(r.reverseMap, b, a) ) )
all(removeFine) {
case (a, b) =>
("Forward does not contain removed" |: (!r.forward(a).contains(b))) &&
("Reverse does not contain removed" |: (!r.reverse(b).contains(a))) &&
("Forward map does not contain removed" |: (notIn(r.forwardMap, a, b))) &&
("Reverse map does not contain removed" |: (notIn(r.reverseMap, b, a)))
}
}
@ -68,11 +69,10 @@ object RelationTest extends Properties("Relation")
}
def all[T](s: Seq[T])(p: T => Prop): Prop =
if(s.isEmpty) true else s.map(p).reduceLeft(_ && _)
if (s.isEmpty) true else s.map(p).reduceLeft(_ && _)
}
object EmptyRelationTest extends Properties("Empty relation")
{
object EmptyRelationTest extends Properties("Empty relation") {
lazy val e = Relation.empty[Int, Double]
property("Forward empty") = forAll { (i: Int) => e.forward(i).isEmpty }