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 329278b531
18 changed files with 1080 additions and 1129 deletions

View File

@ -3,30 +3,29 @@ 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")
val lengthCache = new File("/tmp/length-cache")
val cCache = new File("/tmp/c-cache")
import Cache._
import FileInfo.hash._
import Ordering._
import sbinary.DefaultProtocol.FileFormat
def test
{
lazy val create = new File("test")
import Cache._
import FileInfo.hash._
import Ordering._
import sbinary.DefaultProtocol.FileFormat
def test {
lazy val create = new File("test")
val length = cached(lengthCache) {
(f: File) => { println("File length: " + f.length); f.length }
}
val length = cached(lengthCache) {
(f: File) => { println("File length: " + f.length); f.length }
}
lazy val fileLength = length(create)
lazy val fileLength = length(create)
val c = cached(cCache) { (in: (File :+: Long :+: HNil)) =>
val file :+: len :+: HNil = in
println("File: " + file + " (" + file.exists + "), length: " + len)
(len+1) :+: file :+: HNil
}
c(create :+: fileLength :+: HNil)
}
val c = cached(cCache) { (in: (File :+: Long :+: HNil)) =>
val file :+: len :+: HNil = in
println("File: " + file + " (" + file.exists + "), length: " + len)
(len + 1) :+: file :+: HNil
}
c(create :+: fileLength :+: HNil)
}
}

View File

@ -8,49 +8,43 @@ 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] =
{
val nodes = new HashSet[TestDag]
def nonterminalGen(p: Gen.Parameters): Gen[TestDag] =
{
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)
}
Gen.parameterized(nonterminalGen)
}
implicit lazy val arbTestDag: Arbitrary[TestDag] = Arbitrary(Gen.sized(dagGen))
private def dagGen(nodeCount: Int): Gen[TestDag] =
{
val nodes = new HashSet[TestDag]
def nonterminalGen(p: Gen.Parameters): Gen[TestDag] =
{
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)
}
Gen.parameterized(nonterminalGen)
}
private def isSet[T](c: Seq[T]) = Set(c: _*).size == c.size
private def dependenciesPrecedeNodes(sort: List[TestDag]) =
{
val seen = new HashSet[TestDag]
def iterate(remaining: List[TestDag]): Boolean =
{
remaining match
{
case Nil => true
case node :: tail =>
if(node.dependencies.forall(seen.contains) && !seen.contains(node))
{
seen += node
iterate(tail)
}
else
false
}
}
iterate(sort)
}
private def isSet[T](c: Seq[T]) = Set(c: _*).size == c.size
private def dependenciesPrecedeNodes(sort: List[TestDag]) =
{
val seen = new HashSet[TestDag]
def iterate(remaining: List[TestDag]): Boolean =
{
remaining match {
case Nil => true
case node :: tail =>
if (node.dependencies.forall(seen.contains) && !seen.contains(node)) {
seen += node
iterate(tail)
} else
false
}
}
iterate(sort)
}
}
class TestDag(id: Int, val dependencies: Iterable[TestDag]) extends Dag[TestDag]
{
override def toString = id + "->" + dependencies.mkString("[", ",", "]")
class TestDag(id: Int, val dependencies: Iterable[TestDag]) extends Dag[TestDag] {
override def toString = id + "->" + dependencies.mkString("[", ",", "]")
}

View File

@ -1,35 +1,32 @@
package sbt
import org.scalacheck._
import Prop._
import org.scalacheck._
import Prop._
object KeyTest extends Properties("AttributeKey")
{
property("equality") = {
compare(AttributeKey[Int]("test"), AttributeKey[Int]("test"), true) &&
compare(AttributeKey[Int]("test"), AttributeKey[Int]("test", "description"), true) &&
compare(AttributeKey[Int]("test", "a"), AttributeKey[Int]("test", "b"), true) &&
compare(AttributeKey[Int]("test"), AttributeKey[Int]("tests"), false) &&
compare(AttributeKey[Int]("test"), AttributeKey[Double]("test"), false) &&
compare(AttributeKey[java.lang.Integer]("test"), AttributeKey[Int]("test"), false) &&
compare(AttributeKey[Map[Int, String]]("test"), AttributeKey[Map[Int, String]]("test"), true) &&
compare(AttributeKey[Map[Int, String]]("test"), AttributeKey[Map[Int, _]]("test"), false)
}
object KeyTest extends Properties("AttributeKey") {
property("equality") = {
compare(AttributeKey[Int]("test"), AttributeKey[Int]("test"), true) &&
compare(AttributeKey[Int]("test"), AttributeKey[Int]("test", "description"), true) &&
compare(AttributeKey[Int]("test", "a"), AttributeKey[Int]("test", "b"), true) &&
compare(AttributeKey[Int]("test"), AttributeKey[Int]("tests"), false) &&
compare(AttributeKey[Int]("test"), AttributeKey[Double]("test"), false) &&
compare(AttributeKey[java.lang.Integer]("test"), AttributeKey[Int]("test"), false) &&
compare(AttributeKey[Map[Int, String]]("test"), AttributeKey[Map[Int, String]]("test"), true) &&
compare(AttributeKey[Map[Int, String]]("test"), AttributeKey[Map[Int, _]]("test"), false)
}
def compare(a: AttributeKey[_], b: AttributeKey[_], same: Boolean) =
("a.label: " + a.label) |:
("a.manifest: " + a.manifest) |:
("b.label: " + b.label) |:
("b.manifest: " + b.manifest) |:
("expected equal? " + same) |:
compare0(a, b, same)
def compare(a: AttributeKey[_], b: AttributeKey[_], same: Boolean) =
("a.label: " + a.label) |:
("a.manifest: " + a.manifest) |:
("b.label: " + b.label) |:
("b.manifest: " + b.manifest) |:
("expected equal? " + same) |:
compare0(a, b, same)
def compare0(a: AttributeKey[_], b: AttributeKey[_], same: Boolean) =
if(same)
{
("equality" |: (a == b)) &&
("hash" |: (a.hashCode == b.hashCode))
}
else
("equality" |: (a != b))
def compare0(a: AttributeKey[_], b: AttributeKey[_], same: Boolean) =
if (same) {
("equality" |: (a == b)) &&
("hash" |: (a.hashCode == b.hashCode))
} 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,14 +6,13 @@ package sbt
import Types._
// compilation test
object PMapTest
{
val mp = new DelegatingPMap[Some, Id](new collection.mutable.HashMap)
mp(Some("asdf")) = "a"
mp(Some(3)) = 9
val x = Some(3) :^: Some("asdf") :^: KNil
val y = x.transform[Id](mp)
assert(y.head == 9)
assert(y.tail.head == "a")
assert(y.tail.tail == KNil)
object PMapTest {
val mp = new DelegatingPMap[Some, Id](new collection.mutable.HashMap)
mp(Some("asdf")) = "a"
mp(Some(3)) = 9
val x = Some(3) :^: Some("asdf") :^: KNil
val y = x.transform[Id](mp)
assert(y.head == 9)
assert(y.tail.head == "a")
assert(y.tail.tail == KNil)
}

View File

@ -10,78 +10,78 @@ 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]
{
// 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}"
}
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)) })
}
// 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)) })
}
// Not using this feature in this example.
val scopeLocal: ScopeLocal = _ => Nil
// Not using this feature in this example.
val scopeLocal: ScopeLocal = _ => Nil
// These three functions + a scope (here, Scope) are sufficient for defining our settings system.
// These three functions + a scope (here, Scope) are sufficient for defining our settings system.
}
/** Usage Example **/
object SettingsUsage
{
import SettingsExample._
import Types._
object SettingsUsage {
import SettingsExample._
import Types._
// Define some keys
val a = AttributeKey[Int]("a")
val b = AttributeKey[Int]("b")
// Define some keys
val a = AttributeKey[Int]("a")
val b = AttributeKey[Int]("b")
// Scope these keys
val a3 = ScopedKey(Scope(3), a)
val a4 = ScopedKey(Scope(4), a)
val a5 = ScopedKey(Scope(5), a)
// Scope these keys
val a3 = ScopedKey(Scope(3), a)
val a4 = ScopedKey(Scope(4), a)
val a5 = ScopedKey(Scope(5), a)
val b4 = ScopedKey(Scope(4), b)
val b4 = ScopedKey(Scope(4), b)
// Define some settings
val mySettings: Seq[Setting[_]] = Seq(
setting( a3, value( 3 ) ),
setting( b4, map(a4)(_ * 3)),
update(a5)(_ + 1)
)
// Define some settings
val mySettings: Seq[Setting[_]] = Seq(
setting(a3, value(3)),
setting(b4, map(a4)(_ * 3)),
update(a5)(_ + 1)
)
// "compiles" and applies the settings.
// This can be split into multiple steps to access intermediate results if desired.
// The 'inspect' command operates on the output of 'compile', for example.
val applied: Settings[Scope] = make(mySettings)(delegates, scopeLocal, showFullKey)
// "compiles" and applies the settings.
// This can be split into multiple steps to access intermediate results if desired.
// The 'inspect' command operates on the output of 'compile', for example.
val applied: Settings[Scope] = make(mySettings)(delegates, scopeLocal, showFullKey)
// Show results.
/* for(i <- 0 to 5; k <- Seq(a, b)) {
// Show results.
/* 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,175 +5,174 @@ import Prop._
import SettingsUsage._
import SettingsExample._
object SettingsTest extends Properties("settings")
{
object SettingsTest extends Properties("settings") {
import scala.reflect.Manifest
import scala.reflect.Manifest
final val ChainMax = 5000
lazy val chainLengthGen = Gen.choose(1, ChainMax)
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 )
}
property("Basic bind chain") = forAll(chainLengthGen) { (i: Int) =>
val abs = math.abs(i)
singleIntTest( chainBind(value(abs)), 0 )
}
property("Basic chain") = forAll(chainLengthGen) { (i: Int) =>
val abs = math.abs(i)
singleIntTest(chain(abs, value(0)), abs)
}
property("Basic bind chain") = forAll(chainLengthGen) { (i: Int) =>
val abs = math.abs(i)
singleIntTest(chainBind(value(abs)), 0)
}
property("Allows references to completed settings") = forAllNoShrink(30) { allowedReference }
final def allowedReference(intermediate: Int): Prop =
{
val top = value(intermediate)
def iterate(init: Initialize[Int]): Initialize[Int] =
bind(init) { t =>
if(t <= 0)
top
else
iterate(value(t-1) )
}
evaluate( setting(chk, iterate(top)) :: Nil); true
}
property("Allows references to completed settings") = forAllNoShrink(30) { allowedReference }
final def allowedReference(intermediate: Int): Prop =
{
val top = value(intermediate)
def iterate(init: Initialize[Int]): Initialize[Int] =
bind(init) { t =>
if (t <= 0)
top
else
iterate(value(t - 1))
}
evaluate(setting(chk, iterate(top)) :: Nil); true
}
property("Derived setting chain depending on (prev derived, normal setting)") = forAllNoShrink(Gen.choose(1, 100)) { derivedSettings }
final def derivedSettings(nr: Int): Prop =
{
val genScopedKeys = {
val attrKeys = mkAttrKeys[Int](nr)
attrKeys map (_ map (ak => ScopedKey(Scope(0), ak)))
}
forAll(genScopedKeys) { scopedKeys =>
val last = scopedKeys.last
val derivedSettings: Seq[Setting[Int]] = (
for {
List(scoped0, scoped1) <- chk :: scopedKeys sliding 2
nextInit = if (scoped0 == chk) chk
else (scoped0 zipWith chk) { (p, _) => p + 1 }
} yield derive(setting(scoped1, nextInit))
).toSeq
property("Derived setting chain depending on (prev derived, normal setting)") = forAllNoShrink(Gen.choose(1, 100)) { derivedSettings }
final def derivedSettings(nr: Int): Prop =
{
val genScopedKeys = {
val attrKeys = mkAttrKeys[Int](nr)
attrKeys map (_ map (ak => ScopedKey(Scope(0), ak)))
}
forAll(genScopedKeys) { scopedKeys =>
val last = scopedKeys.last
val derivedSettings: Seq[Setting[Int]] = (
for {
List(scoped0, scoped1) <- chk :: scopedKeys sliding 2
nextInit = if (scoped0 == chk) chk
else (scoped0 zipWith chk) { (p, _) => p + 1 }
} 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" }
}
}
private def mkAttrKeys[T](nr: Int)(implicit mf: Manifest[T]): Gen[List[AttributeKey[T]]] =
{
val alphaStr = Gen.alphaStr
for {
list <- Gen.listOfN(nr, alphaStr) suchThat (l => l.size == l.distinct.size)
item <- list
} yield AttributeKey[T](item)
}
private def mkAttrKeys[T](nr: Int)(implicit mf: Manifest[T]): Gen[List[AttributeKey[T]]] =
{
val alphaStr = Gen.alphaStr
for {
list <- Gen.listOfN(nr, alphaStr) suchThat (l => l.size == l.distinct.size)
item <- list
} yield AttributeKey[T](item)
}
property("Derived setting(s) replace DerivedSetting in the Seq[Setting[_]]") = derivedKeepsPosition
final def derivedKeepsPosition: Prop =
{
val a: ScopedKey[Int] = ScopedKey(Scope(0), AttributeKey[Int]("a"))
val b: ScopedKey[Int] = ScopedKey(Scope(0), AttributeKey[Int]("b"))
val prop1 = {
val settings: Seq[Setting[_]] = Seq(
setting(a, value(3)),
setting(b, value(6)),
derive(setting(b, a)),
setting(a, value(5)),
setting(b, value(8))
)
val ev = evaluate(settings)
checkKey(a, Some(5), ev) && checkKey(b, Some(8), ev)
}
val prop2 = {
val settings: Seq[Setting[Int]] = Seq(
setting(a, value(3)),
setting(b, value(6)),
derive(setting(b, a)),
setting(a, value(5))
)
val ev = evaluate(settings)
checkKey(a, Some(5), ev) && checkKey(b, Some(5), ev)
}
prop1 && prop2
}
property("Derived setting(s) replace DerivedSetting in the Seq[Setting[_]]") = derivedKeepsPosition
final def derivedKeepsPosition: Prop =
{
val a: ScopedKey[Int] = ScopedKey(Scope(0), AttributeKey[Int]("a"))
val b: ScopedKey[Int] = ScopedKey(Scope(0), AttributeKey[Int]("b"))
val prop1 = {
val settings: Seq[Setting[_]] = Seq(
setting(a, value(3)),
setting(b, value(6)),
derive(setting(b, a)),
setting(a, value(5)),
setting(b, value(8))
)
val ev = evaluate(settings)
checkKey(a, Some(5), ev) && checkKey(b, Some(8), ev)
}
val prop2 = {
val settings: Seq[Setting[Int]] = Seq(
setting(a, value(3)),
setting(b, value(6)),
derive(setting(b, a)),
setting(a, value(5))
)
val ev = evaluate(settings)
checkKey(a, Some(5), ev) && checkKey(b, Some(5), ev)
}
prop1 && prop2
}
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) =>
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)
val globalDerivedKey = ScopedKey(Scope(0), derivedKey)
// Each project defines an initial value, but the update is defined in globalKey.
// However, the derived Settings that come from this should be scoped in each project.
val settings: Seq[Setting[_]] =
derive(setting(globalDerivedKey, SettingsExample.map(globalKey)(_ + 1))) +: projectKeys.map(pk => setting(pk, value(0)))
val ev = evaluate(settings)
// Also check that the key has no value at the "global" scope
val props = for { pk <- projectDerivedKeys } yield checkKey(pk, Some(1), ev)
checkKey(globalDerivedKey, None, ev) && Prop.all(props: _*)
}
}
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) =>
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)
val globalDerivedKey = ScopedKey(Scope(0), derivedKey)
// Each project defines an initial value, but the update is defined in globalKey.
// However, the derived Settings that come from this should be scoped in each project.
val settings: Seq[Setting[_]] =
derive(setting(globalDerivedKey, SettingsExample.map(globalKey)(_ + 1))) +: projectKeys.map(pk => setting(pk, value(0)))
val ev = evaluate(settings)
// Also check that the key has no value at the "global" scope
val props = for { pk <- projectDerivedKeys } yield checkKey(pk, Some(1), ev)
checkKey(globalDerivedKey, None, ev) && Prop.all(props: _*)
}
}
// 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 }
catch { case e: java.lang.Exception => true }
}
// 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 }
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)
}
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)
}
lazy val expectedValues = None :: None :: None :: None :: None :: None :: Some(3) :: None :: Some(3) :: Some(9) :: Some(4) :: Some(9) :: Nil
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)
def chain(i: Int, prev: Initialize[Int]): Initialize[Int] =
if(i <= 0) prev else chain(i - 1, prev(_ + 1))
lazy val ch = AttributeKey[Int]("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))
def chainBind(prev: Initialize[Int]): Initialize[Int] =
bind(prev) { v =>
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 )
}
def chainBind(prev: Initialize[Int]): Initialize[Int] =
bind(prev) { v =>
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)
}
def checkKey[T](key: ScopedKey[T], expected: Option[T], settings: Settings[Scope]) =
{
val value = settings.get( key.scope, key.key)
("Key: " + key) |:
("Value: " + value) |:
("Expected: " + expected) |:
(value == expected)
}
def checkKey[T](key: ScopedKey[T], expected: Option[T], settings: Settings[Scope]) =
{
val value = settings.get(key.scope, key.key)
("Key: " + key) |:
("Value: " + value) |:
("Expected: " + expected) |:
(value == expected)
}
def evaluate(settings: Seq[Setting[_]]): Settings[Scope] =
try { make(settings)(delegates, scopeLocal, showFullKey) }
catch { case e: Throwable => e.printStackTrace; throw e }
def evaluate(settings: Seq[Setting[_]]): Settings[Scope] =
try { make(settings)(delegates, scopeLocal, showFullKey) }
catch { case e: Throwable => e.printStackTrace; throw e }
}
// This setup is a workaround for module synchronization issues
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)
top
else
iterate(value(t - 1), t-1)
}
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)
top
else
iterate(value(t - 1), t - 1)
}
}

View File

@ -1,154 +1,148 @@
package sbt.complete
object JLineTest
{
import DefaultParsers._
object JLineTest {
import DefaultParsers._
val one = "blue" | "green" | "black"
val two = token("color" ~> Space) ~> token(one)
val three = token("color" ~> Space) ~> token(ID.examples("blue", "green", "black"))
val four = token("color" ~> Space) ~> token(ID, "<color name>")
val one = "blue" | "green" | "black"
val two = token("color" ~> Space) ~> token(one)
val three = token("color" ~> Space) ~> token(ID.examples("blue", "green", "black"))
val four = token("color" ~> Space) ~> token(ID, "<color name>")
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)
}
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)
}
val parsers = Map("1" -> one, "2" -> two, "3" -> three, "4" -> four, "5" -> five)
def main(args: Array[String])
{
import jline.TerminalFactory
import jline.console.ConsoleReader
val reader = new ConsoleReader()
TerminalFactory.get.init
val parsers = Map("1" -> one, "2" -> two, "3" -> three, "4" -> four, "5" -> five)
def main(args: Array[String]) {
import jline.TerminalFactory
import jline.console.ConsoleReader
val reader = new ConsoleReader()
TerminalFactory.get.init
val parser = parsers(args(0))
JLineCompletion.installCustomCompletor(reader, parser)
def loop() {
val line = reader.readLine("> ")
if(line ne null) {
println("Result: " + apply(parser)(line).resultEmpty)
loop()
}
}
loop()
}
val parser = parsers(args(0))
JLineCompletion.installCustomCompletor(reader, parser)
def loop() {
val line = reader.readLine("> ")
if (line ne null) {
println("Result: " + apply(parser)(line).resultEmpty)
loop()
}
}
loop()
}
}
import Parser._
import org.scalacheck._
import Parser._
import org.scalacheck._
object ParserTest extends Properties("Completing Parser")
{
import Parsers._
import DefaultParsers.matches
object ParserTest extends Properties("Completing Parser") {
import Parsers._
import DefaultParsers.matches
val nested = (token("a1") ~ token("b2")) ~ "c3"
val nestedDisplay = (token("a1", "<a1>") ~ token("b2", "<b2>")) ~ "c3"
val nested = (token("a1") ~ token("b2")) ~ "c3"
val nestedDisplay = (token("a1", "<a1>") ~ token("b2", "<b2>")) ~ "c3"
val spacePort = (token(Space) ~> Port)
val spacePort = (token(Space) ~> Port)
def p[T](f: T): T = { println(f); f }
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) )
def checkOne(in: String, parser: Parser[_], expect: Completion): Prop =
completions(parser, in, 1) == Completions.single(expect)
def checkSingle(in: String, expect: Completion)(expectDisplay: Completion = expect) =
(("token '" + in + "'") |: checkOne(in, nested, expect)) &&
(("display '" + in + "'") |: checkOne(in, nestedDisplay, expectDisplay))
def checkAll(in: String, parser: Parser[_], expect: Completions): Prop =
{
val cs = completions(parser, in, 1)
("completions: " + cs) |: ("Expected: " + expect) |: ( (cs == expect): Prop)
}
def checkInvalid(in: String) =
( ("token '" + in + "'") |: checkInv(in, nested) ) &&
( ("display '" + in + "'") |: checkInv(in, nestedDisplay) )
def checkOne(in: String, parser: Parser[_], expect: Completion): Prop =
completions(parser, in, 1) == Completions.single(expect)
def checkInv(in: String, parser: Parser[_]): Prop =
{
val cs = completions(parser, in, 1)
("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 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 inv") = checkInvalid("a1a")
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")
def checkAll(in: String, parser: Parser[_], expect: Completions): Prop =
{
val cs = completions(parser, in, 1)
("completions: " + cs) |: ("Expected: " + expect) |: ((cs == expect): Prop)
}
property("suggest space") = checkOne("", spacePort, Completion.tokenStrict("", " "))
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(""))
def checkInvalid(in: String) =
(("token '" + in + "'") |: checkInv(in, nested)) &&
(("display '" + in + "'") |: checkInv(in, nestedDisplay))
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)
def completionStrings(ss: Set[String]): Completions = Completions(ss.map { s => Completion.tokenStrict("", s) })
def checkInv(in: String, parser: Parser[_]): Prop =
{
val cs = completions(parser, in, 1)
("completions: " + cs) |: ((cs == Completions.nil): Prop)
}
property("repeatDep no suggestions for bad input") = checkInv(".", repeat)
property("repeatDep suggest all") = checkAll("", repeat, completionStrings(colors))
property("repeatDep suggest remaining two") = {
val first = colors.toSeq.head
checkAll(first + " ", repeat, completionStrings(colors - first))
}
property("repeatDep suggest remaining one") = {
val take = colors.toSeq.take(2)
checkAll(take.mkString("", " ", " "), repeat, completionStrings(colors -- take))
}
property("repeatDep requires at least one token") = !matches(repeat, "")
property("repeatDep accepts one token") = matches(repeat, colors.toSeq.head)
property("repeatDep accepts two tokens") = matches(repeat, colors.toSeq.take(2).mkString(" "))
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 inv") = checkInvalid("a1a")
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("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)
def completionStrings(ss: Set[String]): Completions = Completions(ss.map { s => Completion.tokenStrict("", s) })
property("repeatDep no suggestions for bad input") = checkInv(".", repeat)
property("repeatDep suggest all") = checkAll("", repeat, completionStrings(colors))
property("repeatDep suggest remaining two") = {
val first = colors.toSeq.head
checkAll(first + " ", repeat, completionStrings(colors - first))
}
property("repeatDep suggest remaining one") = {
val take = colors.toSeq.take(2)
checkAll(take.mkString("", " ", " "), repeat, completionStrings(colors -- take))
}
property("repeatDep requires at least one token") = !matches(repeat, "")
property("repeatDep accepts one token") = matches(repeat, colors.toSeq.head)
property("repeatDep accepts two tokens") = matches(repeat, colors.toSeq.take(2).mkString(" "))
}
object ParserExample
{
val ws = charClass(_.isWhitespace)+
val notws = charClass(!_.isWhitespace)+
object ParserExample {
val ws = charClass(_.isWhitespace)+
val notws = charClass(!_.isWhitespace)+
val name = token("test")
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 name = token("test")
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 t = name ~ options ~ include
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 w", 1))
// Get completions for some different inputs
println(completions(t, "te", 1))
println(completions(t, "test ", 1))
println(completions(t, "test w", 1))
// Get the parsed result for different inputs
println(apply(t)("te").resultEmpty)
println(apply(t)("test").resultEmpty)
println(apply(t)("test w").resultEmpty)
println(apply(t)("test was were").resultEmpty)
// Get the parsed result for different inputs
println(apply(t)("te").resultEmpty)
println(apply(t)("test").resultEmpty)
println(apply(t)("test w").resultEmpty)
println(apply(t)("test was were").resultEmpty)
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 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
println(r.isValid)
}
def run2(n: Int)
{
val ab = "ab".?.*
val r = apply(ab)("a"*n).resultEmpty
println(r)
}
def r = apply(ann)("a" * (n * 2)).resultEmpty
println(r.isValid)
}
def run2(n: Int) {
val ab = "ab".?.*
val r = apply(ab)("a" * n).resultEmpty
println(r)
}
}

View File

@ -6,87 +6,85 @@ 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 {
fileExamples().toList should containTheSameElementsAs(allRelativizedPaths)
}
}
"listing all files in an absolute base directory" should {
"produce the entire base directory's contents" in new directoryStructure {
fileExamples().toList should containTheSameElementsAs(allRelativizedPaths)
}
}
"listing files with a prefix that matches none" should {
"produce an empty list" in new directoryStructure(withCompletionPrefix = "z") {
fileExamples().toList should beEmpty
}
}
"listing files with a prefix that matches none" should {
"produce an empty list" in new directoryStructure(withCompletionPrefix = "z") {
fileExamples().toList should beEmpty
}
}
"listing single-character prefixed files" should {
"produce matching paths only" in new directoryStructure(withCompletionPrefix = "f") {
fileExamples().toList should containTheSameElementsAs(prefixedPathsOnly)
}
}
"listing single-character prefixed files" should {
"produce matching paths only" in new directoryStructure(withCompletionPrefix = "f") {
fileExamples().toList should containTheSameElementsAs(prefixedPathsOnly)
}
}
"listing directory-prefixed files" should {
"produce matching paths only" in new directoryStructure(withCompletionPrefix = "far") {
fileExamples().toList should containTheSameElementsAs(prefixedPathsOnly)
}
"listing directory-prefixed files" should {
"produce matching paths only" in new directoryStructure(withCompletionPrefix = "far") {
fileExamples().toList should containTheSameElementsAs(prefixedPathsOnly)
}
"produce sub-dir contents only when appending a file separator to the directory" in new directoryStructure(withCompletionPrefix = "far" + File.separator) {
fileExamples().toList should containTheSameElementsAs(prefixedPathsOnly)
}
}
"produce sub-dir contents only when appending a file separator to the directory" in new directoryStructure(withCompletionPrefix = "far" + File.separator) {
fileExamples().toList should containTheSameElementsAs(prefixedPathsOnly)
}
}
"listing files with a sub-path prefix" should {
"produce matching paths only" in new directoryStructure(withCompletionPrefix = "far" + File.separator + "ba") {
fileExamples().toList should containTheSameElementsAs(prefixedPathsOnly)
}
}
"listing files with a sub-path prefix" should {
"produce matching paths only" in new directoryStructure(withCompletionPrefix = "far" + File.separator + "ba") {
fileExamples().toList should containTheSameElementsAs(prefixedPathsOnly)
}
}
"completing a full path" should {
"produce a list with an empty string" in new directoryStructure(withCompletionPrefix = "bazaar") {
fileExamples().toList shouldEqual List("")
}
}
"completing a full path" should {
"produce a list with an empty string" in new directoryStructure(withCompletionPrefix = "bazaar") {
fileExamples().toList shouldEqual List("")
}
}
class directoryStructure(withCompletionPrefix: String = "") extends Scope with DelayedInit
{
var fileExamples: FileExamples = _
var baseDir: File = _
var childFiles: List[File] = _
var childDirectories: List[File] = _
var nestedFiles: List[File] = _
var nestedDirectories: List[File] = _
class directoryStructure(withCompletionPrefix: String = "") extends Scope with DelayedInit {
var fileExamples: FileExamples = _
var baseDir: File = _
var childFiles: List[File] = _
var childDirectories: List[File] = _
var nestedFiles: List[File] = _
var nestedDirectories: List[File] = _
def allRelativizedPaths: List[String] =
(childFiles ++ childDirectories ++ nestedFiles ++ nestedDirectories).map(relativize(baseDir, _).get)
def allRelativizedPaths: List[String] =
(childFiles ++ childDirectories ++ nestedFiles ++ nestedDirectories).map(relativize(baseDir, _).get)
def prefixedPathsOnly: List[String] =
allRelativizedPaths.filter(_ startsWith withCompletionPrefix).map(_ substring withCompletionPrefix.length)
def prefixedPathsOnly: List[String] =
allRelativizedPaths.filter(_ startsWith withCompletionPrefix).map(_ substring withCompletionPrefix.length)
override def delayedInit(testBody: => Unit): Unit = {
withTemporaryDirectory {
tempDir =>
createSampleDirStructure(tempDir)
fileExamples = new FileExamples(baseDir, withCompletionPrefix)
testBody
}
}
override def delayedInit(testBody: => Unit): Unit = {
withTemporaryDirectory {
tempDir =>
createSampleDirStructure(tempDir)
fileExamples = new FileExamples(baseDir, withCompletionPrefix)
testBody
}
}
private def createSampleDirStructure(tempDir: File): Unit = {
childFiles = toChildFiles(tempDir, List("foo", "bar", "bazaar"))
childDirectories = toChildFiles(tempDir, List("moo", "far"))
nestedFiles = toChildFiles(childDirectories(1), List("farfile1", "barfile2"))
nestedDirectories = toChildFiles(childDirectories(1), List("fardir1", "bardir2"))
private def createSampleDirStructure(tempDir: File): Unit = {
childFiles = toChildFiles(tempDir, List("foo", "bar", "bazaar"))
childDirectories = toChildFiles(tempDir, List("moo", "far"))
nestedFiles = toChildFiles(childDirectories(1), List("farfile1", "barfile2"))
nestedDirectories = toChildFiles(childDirectories(1), List("fardir1", "bardir2"))
(childDirectories ++ nestedDirectories).map(_.mkdirs())
(childFiles ++ nestedFiles).map(_.createNewFile())
(childDirectories ++ nestedDirectories).map(_.mkdirs())
(childFiles ++ nestedFiles).map(_.createNewFile())
// NOTE: Creating a new file here because `tempDir.listFiles()` returned an empty list.
baseDir = new File(tempDir.getCanonicalPath)
}
// NOTE: Creating a new file here because `tempDir.listFiles()` returned an empty list.
baseDir = new File(tempDir.getCanonicalPath)
}
private def toChildFiles(baseDir: File, files: List[String]): List[File] = files.map(new File(baseDir, _))
}
private def toChildFiles(baseDir: File, files: List[String]): List[File] = files.map(new File(baseDir, _))
}
}

View File

@ -5,22 +5,22 @@ import org.specs2.specification.Scope
class FixedSetExamplesTest extends Specification {
"adding a prefix" should {
"produce a smaller set of examples with the prefix removed" in new examples {
fixedSetExamples.withAddedPrefix("f")() must containTheSameElementsAs(List("oo", "ool", "u"))
fixedSetExamples.withAddedPrefix("fo")() must containTheSameElementsAs(List("o", "ol"))
fixedSetExamples.withAddedPrefix("b")() must containTheSameElementsAs(List("ar"))
}
}
"adding a prefix" should {
"produce a smaller set of examples with the prefix removed" in new examples {
fixedSetExamples.withAddedPrefix("f")() must containTheSameElementsAs(List("oo", "ool", "u"))
fixedSetExamples.withAddedPrefix("fo")() must containTheSameElementsAs(List("o", "ol"))
fixedSetExamples.withAddedPrefix("b")() must containTheSameElementsAs(List("ar"))
}
}
"without a prefix" should {
"produce the original set" in new examples {
fixedSetExamples() mustEqual exampleSet
}
}
"without a prefix" should {
"produce the original set" in new examples {
fixedSetExamples() mustEqual exampleSet
}
}
trait examples extends Scope {
val exampleSet = List("foo", "bar", "fool", "fu")
val fixedSetExamples = FixedSetExamples(exampleSet)
}
trait examples extends Scope {
val exampleSet = List("foo", "bar", "fool", "fu")
val fixedSetExamples = FixedSetExamples(exampleSet)
}
}

View File

@ -6,88 +6,88 @@ import Completion._
class ParserWithExamplesTest extends Specification {
"listing a limited number of completions" should {
"grab only the needed number of elements from the iterable source of examples" in new parserWithLazyExamples {
parserWithExamples.completions(0)
examples.size shouldEqual maxNumberOfExamples
}
}
"listing a limited number of completions" should {
"grab only the needed number of elements from the iterable source of examples" in new parserWithLazyExamples {
parserWithExamples.completions(0)
examples.size shouldEqual maxNumberOfExamples
}
}
"listing only valid completions" should {
"use the delegate parser to remove invalid examples" in new parserWithValidExamples {
val validCompletions = Completions(Set(
suggestion("blue"),
suggestion("red")
))
parserWithExamples.completions(0) shouldEqual validCompletions
}
}
"listing only valid completions" should {
"use the delegate parser to remove invalid examples" in new parserWithValidExamples {
val validCompletions = Completions(Set(
suggestion("blue"),
suggestion("red")
))
parserWithExamples.completions(0) shouldEqual validCompletions
}
}
"listing valid completions in a derived parser" should {
"produce only valid examples that start with the character of the derivation" in new parserWithValidExamples {
val derivedCompletions = Completions(Set(
suggestion("lue")
))
parserWithExamples.derive('b').completions(0) shouldEqual derivedCompletions
}
}
"listing valid completions in a derived parser" should {
"produce only valid examples that start with the character of the derivation" in new parserWithValidExamples {
val derivedCompletions = Completions(Set(
suggestion("lue")
))
parserWithExamples.derive('b').completions(0) shouldEqual derivedCompletions
}
}
"listing valid and invalid completions" should {
"produce the entire source of examples" in new parserWithAllExamples {
val completions = Completions(examples.map(suggestion(_)).toSet)
parserWithExamples.completions(0) shouldEqual completions
}
}
"listing valid and invalid completions" should {
"produce the entire source of examples" in new parserWithAllExamples {
val completions = Completions(examples.map(suggestion(_)).toSet)
parserWithExamples.completions(0) shouldEqual completions
}
}
"listing valid and invalid completions in a derived parser" should {
"produce only examples that start with the character of the derivation" in new parserWithAllExamples {
val derivedCompletions = Completions(Set(
suggestion("lue"),
suggestion("lock")
))
parserWithExamples.derive('b').completions(0) shouldEqual derivedCompletions
}
}
"listing valid and invalid completions in a derived parser" should {
"produce only examples that start with the character of the derivation" in new parserWithAllExamples {
val derivedCompletions = Completions(Set(
suggestion("lue"),
suggestion("lock")
))
parserWithExamples.derive('b').completions(0) shouldEqual derivedCompletions
}
}
class parserWithLazyExamples extends parser(GrowableSourceOfExamples(), maxNumberOfExamples = 5, removeInvalidExamples = false)
class parserWithLazyExamples extends parser(GrowableSourceOfExamples(), maxNumberOfExamples = 5, removeInvalidExamples = false)
class parserWithValidExamples extends parser(removeInvalidExamples = true)
class parserWithValidExamples extends parser(removeInvalidExamples = true)
class parserWithAllExamples extends parser(removeInvalidExamples = false)
class parserWithAllExamples extends parser(removeInvalidExamples = false)
case class parser(examples: Iterable[String] = Set("blue", "yellow", "greeen", "block", "red"),
maxNumberOfExamples: Int = 25,
removeInvalidExamples: Boolean) extends Scope {
case class parser(examples: Iterable[String] = Set("blue", "yellow", "greeen", "block", "red"),
maxNumberOfExamples: Int = 25,
removeInvalidExamples: Boolean) extends Scope {
import DefaultParsers._
import DefaultParsers._
val colorParser = "blue" | "green" | "black" | "red"
val parserWithExamples: Parser[String] = new ParserWithExamples[String](
colorParser,
FixedSetExamples(examples),
maxNumberOfExamples,
removeInvalidExamples
)
}
val colorParser = "blue" | "green" | "black" | "red"
val parserWithExamples: Parser[String] = new ParserWithExamples[String](
colorParser,
FixedSetExamples(examples),
maxNumberOfExamples,
removeInvalidExamples
)
}
case class GrowableSourceOfExamples() extends Iterable[String] {
private var numberOfIteratedElements: Int = 0
case class GrowableSourceOfExamples() extends Iterable[String] {
private var numberOfIteratedElements: Int = 0
override def iterator: Iterator[String] = {
new Iterator[String] {
var currentElement = 0
override def iterator: Iterator[String] = {
new Iterator[String] {
var currentElement = 0
override def next(): String = {
currentElement += 1
numberOfIteratedElements = Math.max(currentElement, numberOfIteratedElements)
numberOfIteratedElements.toString
}
override def next(): String = {
currentElement += 1
numberOfIteratedElements = Math.max(currentElement, numberOfIteratedElements)
numberOfIteratedElements.toString
}
override def hasNext: Boolean = true
}
}
override def hasNext: Boolean = true
}
}
override def size: Int = numberOfIteratedElements
}
override def size: Int = numberOfIteratedElements
}
}

View File

@ -2,90 +2,85 @@ 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")
{
property("genTerminator only generates terminators") =
forAllNoShrink(genTerminator) { (c: Char) => isEscapeTerminator(c) }
object Escapes extends Properties("Escapes") {
property("genTerminator only generates terminators") =
forAllNoShrink(genTerminator) { (c: Char) => isEscapeTerminator(c) }
property("genWithoutTerminator only generates terminators") =
forAllNoShrink(genWithoutTerminator) { (s: String) =>
s.forall { c => !isEscapeTerminator(c) }
}
property("genWithoutTerminator only generates terminators") =
forAllNoShrink(genWithoutTerminator) { (s: String) =>
s.forall { c => !isEscapeTerminator(c) }
}
property("hasEscapeSequence is false when no escape character is present") = forAllNoShrink(genWithoutEscape) { (s: String) =>
!hasEscapeSequence(s)
}
property("hasEscapeSequence is false when no escape character is present") = forAllNoShrink(genWithoutEscape) { (s: String) =>
!hasEscapeSequence(s)
}
property("hasEscapeSequence is true when escape character is present") = forAllNoShrink(genWithRandomEscapes) { (s: String) =>
hasEscapeSequence(s)
}
property("hasEscapeSequence is true when escape character is present") = forAllNoShrink(genWithRandomEscapes) { (s: String) =>
hasEscapeSequence(s)
}
property("removeEscapeSequences is the identity when no escape character is present") = forAllNoShrink(genWithoutEscape) { (s: String) =>
val removed: String = removeEscapeSequences(s)
("Escape sequence removed: '" + removed + "'") |:
(removed == s)
}
property("removeEscapeSequences is the identity when no escape character is present") = forAllNoShrink(genWithoutEscape) { (s: String) =>
val removed: String = removeEscapeSequences(s)
("Escape sequence removed: '" + removed + "'") |:
(removed == s)
}
property("No escape characters remain after removeEscapeSequences") = forAll { (s: String) =>
val removed: String = removeEscapeSequences(s)
("Escape sequence removed: '" + removed + "'") |:
!hasEscapeSequence(removed)
}
property("No escape characters remain after removeEscapeSequences") = forAll { (s: String) =>
val removed: String = removeEscapeSequences(s)
("Escape sequence removed: '" + removed + "'") |:
!hasEscapeSequence(removed)
}
property("removeEscapeSequences returns string without escape sequences") =
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)
("Input string with escapes: '" + withEscapes + "'") |:
("Escapes removed '" + removed + "'") |:
(original == removed)
}
property("removeEscapeSequences returns string without escape sequences") =
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)
("Input string with escapes: '" + withEscapes + "'") |:
("Escapes removed '" + removed + "'") |:
(original == removed)
}
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) )
def makeString: String = ESC + content + terminator
}
private[this] def noEscape(s: String): String = s.replace(ESC, ' ')
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))
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 genEscapePairs: Gen[List[EscapeAndNot]] = listOf(genEscapePair)
lazy val genEscapeSequence: Gen[EscapeSequence] = oneOf(genKnownSequence, genArbitraryEscapeSequence)
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)
lazy val genKnownSequence: Gen[EscapeSequence] =
oneOf((misc ++ setGraphicsMode ++ setMode ++ resetMode).map(toEscapeSequence))
def toEscapeSequence(s: String): EscapeSequence = EscapeSequence(s.init, s.last)
lazy val genArbitraryEscapeSequence: Gen[EscapeSequence] =
for (content <- genWithoutTerminator; term <- genTerminator) yield new EscapeSequence(content, term)
lazy val misc = Seq("14;23H", "5;3f", "2A", "94B", "19C", "85D", "s", "u", "2J", "K")
lazy val genKnownSequence: Gen[EscapeSequence] =
oneOf((misc ++ setGraphicsMode ++ setMode ++ resetMode).map(toEscapeSequence))
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"
def toEscapeSequence(s: String): EscapeSequence = EscapeSequence(s.init, s.last)
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 misc = Seq("14;23H", "5;3f", "2A", "94B", "19C", "85D", "s", "u", "2J", "K")
lazy val genTerminator: Gen[Char] = Gen.choose('@', '~')
lazy val genWithoutEscape: Gen[String] = genRawString.map(noEscape)
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"
def genWithRandomEscapes: Gen[String] =
for(ls <- listOf(genRawString); end <- genRawString) yield
ls.mkString("", ESC.toString, ESC.toString + end)
lazy val resetMode = setModeLike('I')
lazy val setMode = setModeLike('h')
def setModeLike(term: Char): Seq[String] = (0 to 19).map(i => "=" + i.toString + term)
private def genRawString = Arbitrary.arbString.arbitrary
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)
private def genRawString = Arbitrary.arbString.arbitrary
}

View File

@ -4,157 +4,147 @@
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")
{
final val MaxLines = 100
final val MaxSegments = 10
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.
/* 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}
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)
}
/** 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
{
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
* 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)
{
val content = section.content
val normalized = Escape.newline(content, newLine)
if(section.byCharacter)
normalized.foreach { c => writer.write(c.toInt) }
else
writer.write(normalized)
}
writer.flush()
}
/** Converts the given lines in segments to lines as Strings for checking the results of the test.*/
def toLines(lines: List[List[ToLog]]): List[String] =
lines.map(_.map(_.contentOnly).mkString)
/** 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 _ => false
}
/* The following are implicit generators to build up a write sequence.
property("properly logged") = forAll { (output: Output, newLine: NewLine) =>
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)
}
/**
* 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 {
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
* 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) {
val content = section.content
val normalized = Escape.newline(content, newLine)
if (section.byCharacter)
normalized.foreach { c => writer.write(c.toInt) }
else
writer.write(normalized)
}
writer.flush()
}
/** Converts the given lines in segments to lines as Strings for checking the results of the test.*/
def toLines(lines: List[List[ToLog]]): List[String] =
lines.map(_.map(_.contentOnly).mkString)
/** 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 _ => false
}
/* The following are implicit generators to build up a write sequence.
* ToLog represents a written segment. NewLine represents one of the possible
* newline separators. A List[ToLog] represents a full line and always includes a
* final ToLog with a trailing '\n'. Newline characters are otherwise not present in
* the `content` of a ToLog instance.*/
implicit lazy val arbOut: Arbitrary[Output] = Arbitrary(genOutput)
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 def genLine(implicit logG: Gen[ToLog]): Gen[List[ToLog]] =
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
{
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)
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)
def removeNewlines(s: String) = s.replaceAll("""[\n\r]+""", "")
def addNewline(l: ToLog): ToLog =
new ToLog(l.content + "\n", l.byCharacter) // \n will be replaced by a random line terminator for all lines
implicit lazy val arbOut: Arbitrary[Output] = Arbitrary(genOutput)
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)
def listOf[T](max: Int)(implicit content: Arbitrary[T]): Gen[List[T]] =
Gen.choose(0, max) flatMap { sz => listOfN(sz, content.arbitrary) }
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
implicit def genLog(implicit content: Arbitrary[String], byChar: Arbitrary[Boolean]): Gen[ToLog] =
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)
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)
def removeNewlines(s: String) = s.replaceAll("""[\n\r]+""", "")
def addNewline(l: ToLog): ToLog =
new ToLog(l.content + "\n", l.byCharacter) // \n will be replaced by a random line terminator for all lines
def listOf[T](max: Int)(implicit content: Arbitrary[T]): Gen[List[T]] =
Gen.choose(0, max) flatMap { sz => listOfN(sz, content.arbitrary) }
}
/* Helper classes*/
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 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
{
override def toString = Escape(str)
final class NewLine(val str: String) extends NotNull {
override def toString = Escape(str)
}
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 + ")"
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 + ")"
}
/** Defines some utility methods for escaping unprintable characters.*/
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)
{
def escaped = pad(c.toInt.toHexString.toUpperCase, 4, '0')
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)
}
/** 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
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) {
def escaped = pad(c.toInt.toHexString.toUpperCase, 4, '0')
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)
}
/** 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
}
/** Records logging events for later retrieval.*/
final class RecordingLogger extends BasicLogger
{
private var events: List[LogEvent] = Nil
def getEvents = events.reverse
override def ansiCodesSupported = true
def trace(t: => Throwable) { events ::= new Trace(t) }
def log(level: Level.Value, message: => String) { events ::= new Log(level, message) }
def success(message: => String) { events ::= new Success(message) }
def logAll(es: Seq[LogEvent]) { events :::= es.toList }
def control(event: ControlEvent.Value, message: => String) { events ::= new ControlEvent(event, message) }
final class RecordingLogger extends BasicLogger {
private var events: List[LogEvent] = Nil
def getEvents = events.reverse
override def ansiCodesSupported = true
def trace(t: => Throwable) { events ::= new Trace(t) }
def log(level: Level.Value, message: => String) { events ::= new Log(level, message) }
def success(message: => String) { events ::= new Success(message) }
def logAll(es: Seq[LogEvent]) { events :::= es.toList }
def control(event: ControlEvent.Value, message: => String) { events ::= new ControlEvent(event, message) }
}

View File

@ -1,11 +1,10 @@
package sbt
object TestLogger
{
def apply[T](f: Logger => T): T =
{
val log = new BufferedLogger(ConsoleLogger())
log.setLevel(Level.Debug)
log.bufferQuietly(f(log))
}
object TestLogger {
def apply[T](f: Logger => T): T =
{
val log = new BufferedLogger(ConsoleLogger())
log.setLevel(Level.Debug)
log.bufferQuietly(f(log))
}
}

View File

@ -1,117 +1,115 @@
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")
{
import TestClauses._
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()) )
// 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("Detects cyclic negation") = secure(
Logic.reduceAll(badClauses, Set()) match {
case Right(res) => false
case Left(err: Logic.CyclicNegation) => true
case Left(err) => error(s"Expected cyclic error, got: $err")
}
)
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("Detects cyclic negation") = secure(
Logic.reduceAll(badClauses, Set()) match {
case Right(res) => false
case Left(err: Logic.CyclicNegation) => true
case Left(err) => error(s"Expected cyclic error, got: $err")
}
)
def expect(result: Either[LogicException, Matched], expected: Set[Atom]) = result match {
case Left(err) => false
case Right(res) =>
val actual = res.provenSet
(actual == expected) || error(s"Expected to prove $expected, but actually proved $actual")
}
def expect(result: Either[LogicException, Matched], expected: Set[Atom]) = result match {
case Left(err) => false
case Right(res) =>
val actual = res.provenSet
(actual == expected) || error(s"Expected to prove $expected, but actually proved $actual")
}
}
object TestClauses
{
object TestClauses {
val A = Atom("A")
val B = Atom("B")
val C = Atom("C")
val D = Atom("D")
val E = Atom("E")
val F = Atom("F")
val G = Atom("G")
val A = Atom("A")
val B = Atom("B")
val C = Atom("C")
val D = Atom("D")
val E = Atom("E")
val F = Atom("F")
val G = Atom("G")
val clauses =
A.proves(B) ::
A.proves(F) ::
B.proves(F) ::
F.proves(A) ::
(!C).proves(F) ::
D.proves(C) ::
C.proves(D) ::
Nil
val clauses =
A.proves(B) ::
A.proves(F) ::
B.proves(F) ::
F.proves(A) ::
(!C).proves(F) ::
D.proves(C) ::
C.proves(D) ::
Nil
val cycles = Logic.reduceAll(clauses, Set())
val cycles = Logic.reduceAll(clauses, Set())
val badClauses =
A.proves(D) ::
clauses
val badClauses =
A.proves(D) ::
clauses
val excludedNeg = {
val cs =
(!A).proves(B) ::
Nil
val init =
(!A) ::
(!B) ::
Nil
Logic.reduceAll(cs, init.toSet)
}
val excludedNeg = {
val cs =
(!A).proves(B) ::
Nil
val init =
(!A) ::
(!B) ::
Nil
Logic.reduceAll(cs, init.toSet)
}
val excludedPos = {
val cs =
A.proves(B) ::
Nil
val init =
A ::
(!B) ::
Nil
Logic.reduceAll(cs, init.toSet)
}
val excludedPos = {
val cs =
A.proves(B) ::
Nil
val init =
A ::
(!B) ::
Nil
Logic.reduceAll(cs, init.toSet)
}
val trivial = {
val cs =
Formula.True.proves(A) ::
Nil
Logic.reduceAll(cs, Set.empty)
}
val trivial = {
val cs =
Formula.True.proves(A) ::
Nil
Logic.reduceAll(cs, Set.empty)
}
val lessTrivial = {
val cs =
Formula.True.proves(A) ::
Formula.True.proves(B) ::
(A && B && (!C)).proves(D) ::
Nil
Logic.reduceAll(cs, Set())
}
val lessTrivial = {
val cs =
Formula.True.proves(A) ::
Formula.True.proves(B) ::
(A && B && (!C)).proves(D) ::
Nil
Logic.reduceAll(cs, Set())
}
val ordering = {
val cs =
E.proves(F) ::
(C && !D).proves(E) ::
(A && B).proves(C) ::
Nil
Logic.reduceAll(cs, Set(A,B))
}
val ordering = {
val cs =
E.proves(F) ::
(C && !D).proves(E) ::
(A && B).proves(C) ::
Nil
Logic.reduceAll(cs, Set(A, B))
}
def all {
println(s"Cycles: $cycles")
println(s"xNeg: $excludedNeg")
println(s"xPos: $excludedPos")
println(s"trivial: $trivial")
println(s"lessTrivial: $lessTrivial")
println(s"ordering: $ordering")
}
def all {
println(s"Cycles: $cycles")
println(s"xNeg: $excludedNeg")
println(s"xPos: $excludedPos")
println(s"trivial: $trivial")
println(s"lessTrivial: $lessTrivial")
println(s"ordering: $ordering")
}
}

View File

@ -1,133 +1,131 @@
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")
{
implicit val exitCodeArb: Arbitrary[Array[Byte]] = Arbitrary(
for(size <- Gen.choose(0, 10);
l <- Gen.listOfN[Byte](size, Arbitrary.arbByte.arbitrary))
yield
l.toArray
)
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
)
/*property("Correct exit code") = forAll( (exitCode: Byte) => checkExit(exitCode))
/*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) =
{
(codes.length > 1) ==>
{
val unsignedCodes = codes.map(unsigned)
val exitCode = unsignedCodes.map(code => Process(process("sbt.exit " + code))).reduceLeft(reduceProcesses) !
val expectedExitCode = unsignedCodes.map(toBoolean).reduceLeft(reduceExit)
toBoolean(exitCode) == expectedExitCode
}
}
private def toBoolean(exitCode: Int) = exitCode == 0
private def checkExit(code: Byte) =
{
val exitCode = unsigned(code)
(process("sbt.exit " + exitCode) !) == exitCode
}
private def checkFileOut(data: Array[Byte]) =
{
withData(data) { (temporaryFile, temporaryFile2) =>
val catCommand = process("sbt.cat " + temporaryFile.getAbsolutePath)
catCommand #> temporaryFile2
}
}
private def checkFileIn(data: Array[Byte]) =
{
withData(data) { (temporaryFile, temporaryFile2) =>
val catCommand = process("sbt.cat")
temporaryFile #> catCommand #> temporaryFile2
}
}
private def checkPipe(data: Array[Byte]) =
{
withData(data) { (temporaryFile, temporaryFile2) =>
val catCommand = process("sbt.cat")
temporaryFile #> catCommand #| catCommand #> temporaryFile2
}
}
private def checkPipeExit(data: Array[Byte], code: Byte) =
withTempFiles { (a,b) =>
IO.write(a, data)
val catCommand = process("sbt.cat")
val exitCommand = process(s"sbt.exit $code")
val exit = (a #> exitCommand #| catCommand #> b).!
(s"Exit code: $exit") |:
(s"Output file length: ${b.length}") |:
(exit == 0) &&
(b.length == 0)
}
private def checkBinary(codes: Array[Byte])(reduceProcesses: (ProcessBuilder, ProcessBuilder) => ProcessBuilder)(reduceExit: (Boolean, Boolean) => Boolean) =
{
(codes.length > 1) ==>
{
val unsignedCodes = codes.map(unsigned)
val exitCode = unsignedCodes.map(code => Process(process("sbt.exit " + code))).reduceLeft(reduceProcesses) !
val expectedExitCode = unsignedCodes.map(toBoolean).reduceLeft(reduceExit)
toBoolean(exitCode) == expectedExitCode
}
}
private def toBoolean(exitCode: Int) = exitCode == 0
private def checkExit(code: Byte) =
{
val exitCode = unsigned(code)
(process("sbt.exit " + exitCode) !) == exitCode
}
private def checkFileOut(data: Array[Byte]) =
{
withData(data) { (temporaryFile, temporaryFile2) =>
val catCommand = process("sbt.cat " + temporaryFile.getAbsolutePath)
catCommand #> temporaryFile2
}
}
private def checkFileIn(data: Array[Byte]) =
{
withData(data) { (temporaryFile, temporaryFile2) =>
val catCommand = process("sbt.cat")
temporaryFile #> catCommand #> temporaryFile2
}
}
private def checkPipe(data: Array[Byte]) =
{
withData(data) { (temporaryFile, temporaryFile2) =>
val catCommand = process("sbt.cat")
temporaryFile #> catCommand #| catCommand #> temporaryFile2
}
}
private def checkPipeExit(data: Array[Byte], code: Byte) =
withTempFiles { (a, b) =>
IO.write(a, data)
val catCommand = process("sbt.cat")
val exitCommand = process(s"sbt.exit $code")
val exit = (a #> exitCommand #| catCommand #> b).!
(s"Exit code: $exit") |:
(s"Output file length: ${b.length}") |:
(exit == 0) &&
(b.length == 0)
}
private def checkFileOutExit(data: Array[Byte], exitCode: Byte) =
withTempFiles { (a,b) =>
IO.write(a, data)
val code = unsigned(exitCode)
val command = process(s"sbt.exit $code")
val exit = (a #> command #> b).!
(s"Exit code: $exit, expected: $code") |:
(s"Output file length: ${b.length}") |:
(exit == code) &&
(b.length == 0)
}
private def checkFileOutExit(data: Array[Byte], exitCode: Byte) =
withTempFiles { (a, b) =>
IO.write(a, data)
val code = unsigned(exitCode)
val command = process(s"sbt.exit $code")
val exit = (a #> command #> b).!
(s"Exit code: $exit, expected: $code") |:
(s"Output file length: ${b.length}") |:
(exit == code) &&
(b.length == 0)
}
private def checkFileInExit(data: Array[Byte], exitCode: Byte) =
withTempFiles { (a,b) =>
IO.write(a, data)
val code = unsigned(exitCode)
val command = process(s"sbt.exit $code")
val exit = (a #> command).!
(s"Exit code: $exit, expected: $code") |:
(exit == code)
}
private def checkFileInExit(data: Array[Byte], exitCode: Byte) =
withTempFiles { (a, b) =>
IO.write(a, data)
val code = unsigned(exitCode)
val command = process(s"sbt.exit $code")
val exit = (a #> command).!
(s"Exit code: $exit, expected: $code") |:
(exit == code)
}
private def temp() = File.createTempFile("sbt", "")
private def withData(data: Array[Byte])(f: (File, File) => ProcessBuilder) =
withTempFiles { (a, b) =>
IO.write(a, data)
val process = f(a, b)
( process ! ) == 0 && sameFiles(a, b)
}
private def sameFiles(a: File, b: File) =
IO.readBytes(a) sameElements IO.readBytes(b)
private def temp() = File.createTempFile("sbt", "")
private def withData(data: Array[Byte])(f: (File, File) => ProcessBuilder) =
withTempFiles { (a, b) =>
IO.write(a, data)
val process = f(a, b)
(process !) == 0 && sameFiles(a, b)
}
private def sameFiles(a: File, b: File) =
IO.readBytes(a) sameElements IO.readBytes(b)
private def withTempFiles[T](f: (File, File) => T): T =
{
val temporaryFile1 = temp()
val temporaryFile2 = temp()
try f(temporaryFile1, temporaryFile2)
finally
{
temporaryFile1.delete()
temporaryFile2.delete()
}
}
private def unsigned(b: Int): Int = ((b: Int) +256) % 256
private def unsigned(b: Byte): Int = unsigned(b: Int)
private def process(command: String) =
{
val ignore = echo // just for the compile dependency so that this test is rerun when TestedProcess.scala changes, not used otherwise
private def withTempFiles[T](f: (File, File) => T): T =
{
val temporaryFile1 = temp()
val temporaryFile2 = temp()
try f(temporaryFile1, temporaryFile2)
finally {
temporaryFile1.delete()
temporaryFile2.delete()
}
}
private def unsigned(b: Int): Int = ((b: Int) + 256) % 256
private def unsigned(b: Byte): Int = unsigned(b: Int)
private def process(command: String) =
{
val ignore = echo // just for the compile dependency so that this test is rerun when TestedProcess.scala changes, not used otherwise
val thisClasspath = List(getSource[Product], getSource[IO.type], getSource[SourceTag]).mkString(File.pathSeparator)
"java -cp " + thisClasspath + " " + command
}
private def getSource[T : Manifest]: String =
IO.classLocationFile[T].getAbsolutePath
val thisClasspath = List(getSource[Product], getSource[IO.type], getSource[SourceTag]).mkString(File.pathSeparator)
"java -cp " + thisClasspath + " " + command
}
private def getSource[T: Manifest]: String =
IO.classLocationFile[T].getAbsolutePath
}
private trait SourceTag

View File

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

View File

@ -6,79 +6,79 @@ package sbt
import org.scalacheck._
import Prop._
object RelationTest extends Properties("Relation")
{
property("Added entry check") = forAll { (pairs: List[(Int, Double)]) =>
val r = Relation.empty[Int, Double] ++ pairs
check(r, pairs)
}
def check(r: Relation[Int, Double], pairs: Seq[(Int, Double)]) =
{
val _1s = pairs.map(_._1).toSet
val _2s = pairs.map(_._2).toSet
r._1s == _1s && r.forwardMap.keySet == _1s &&
r._2s == _2s && r.reverseMap.keySet == _2s &&
pairs.forall { case (a, b) =>
(r.forward(a) contains b) &&
(r.reverse(b) contains a) &&
(r.forwardMap(a) contains b) &&
(r.reverseMap(b) contains a)
}
}
property("Does not contain removed entries") = forAll { (pairs: List[(Int, Double, Boolean)]) =>
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 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) )
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) )
} &&
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) ) )
}
}
object RelationTest extends Properties("Relation") {
property("Added entry check") = forAll { (pairs: List[(Int, Double)]) =>
val r = Relation.empty[Int, Double] ++ pairs
check(r, pairs)
}
def check(r: Relation[Int, Double], pairs: Seq[(Int, Double)]) =
{
val _1s = pairs.map(_._1).toSet
val _2s = pairs.map(_._2).toSet
property("Groups correctly") = forAll { (entries: List[(Int, Double)], randomInt: Int) =>
val splitInto = math.abs(randomInt) % 10 + 1 // Split into 1-10 groups.
val rel = Relation.empty[Int, Double] ++ entries
val grouped = rel groupBy (_._1 % splitInto)
all(grouped.toSeq) {
case (k, rel_k) => rel_k._1s forall { _ % splitInto == k }
}
}
r._1s == _1s && r.forwardMap.keySet == _1s &&
r._2s == _2s && r.reverseMap.keySet == _2s &&
pairs.forall {
case (a, b) =>
(r.forward(a) contains b) &&
(r.reverse(b) contains a) &&
(r.forwardMap(a) contains b) &&
(r.reverseMap(b) contains a)
}
}
property("Does not contain removed entries") = forAll { (pairs: List[(Int, Double, Boolean)]) =>
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 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))
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))
} &&
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)))
}
}
property("Groups correctly") = forAll { (entries: List[(Int, Double)], randomInt: Int) =>
val splitInto = math.abs(randomInt) % 10 + 1 // Split into 1-10 groups.
val rel = Relation.empty[Int, Double] ++ entries
val grouped = rel groupBy (_._1 % splitInto)
all(grouped.toSeq) {
case (k, rel_k) => rel_k._1s forall { _ % splitInto == k }
}
}
property("Computes size correctly") = forAll { (entries: List[(Int, Double)]) =>
val rel = Relation.empty[Int, Double] ++ entries
val expected = rel.all.size // Note: not entries.length, as entries may have duplicates.
val expected = rel.all.size // Note: not entries.length, as entries may have duplicates.
val computed = rel.size
"Expected size: %d. Computed size: %d.".format(expected, computed) |: expected == computed
}
def all[T](s: Seq[T])(p: T => Prop): Prop =
if(s.isEmpty) true else s.map(p).reduceLeft(_ && _)
def all[T](s: Seq[T])(p: T => Prop): Prop =
if (s.isEmpty) true else s.map(p).reduceLeft(_ && _)
}
object EmptyRelationTest extends Properties("Empty relation")
{
lazy val e = Relation.empty[Int, Double]
object EmptyRelationTest extends Properties("Empty relation") {
lazy val e = Relation.empty[Int, Double]
property("Forward empty") = forAll { (i: Int) => e.forward(i).isEmpty }
property("Reverse empty") = forAll { (i: Double) => e.reverse(i).isEmpty }
property("Forward map empty") = e.forwardMap.isEmpty
property("Reverse map empty") = e.reverseMap.isEmpty
property("_1 empty") = e._1s.isEmpty
property("_2 empty") = e._2s.isEmpty
property("Forward empty") = forAll { (i: Int) => e.forward(i).isEmpty }
property("Reverse empty") = forAll { (i: Double) => e.reverse(i).isEmpty }
property("Forward map empty") = e.forwardMap.isEmpty
property("Reverse map empty") = e.reverseMap.isEmpty
property("_1 empty") = e._1s.isEmpty
property("_2 empty") = e._2s.isEmpty
}