mirror of https://github.com/sbt/sbt.git
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:
commit
329278b531
|
|
@ -3,30 +3,29 @@ package sbt
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import Types.:+:
|
import Types.:+:
|
||||||
|
|
||||||
object CacheTest// extends Properties("Cache test")
|
object CacheTest // extends Properties("Cache test")
|
||||||
{
|
{
|
||||||
val lengthCache = new File("/tmp/length-cache")
|
val lengthCache = new File("/tmp/length-cache")
|
||||||
val cCache = new File("/tmp/c-cache")
|
val cCache = new File("/tmp/c-cache")
|
||||||
|
|
||||||
import Cache._
|
import Cache._
|
||||||
import FileInfo.hash._
|
import FileInfo.hash._
|
||||||
import Ordering._
|
import Ordering._
|
||||||
import sbinary.DefaultProtocol.FileFormat
|
import sbinary.DefaultProtocol.FileFormat
|
||||||
def test
|
def test {
|
||||||
{
|
lazy val create = new File("test")
|
||||||
lazy val create = new File("test")
|
|
||||||
|
|
||||||
val length = cached(lengthCache) {
|
val length = cached(lengthCache) {
|
||||||
(f: File) => { println("File length: " + f.length); f.length }
|
(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 c = cached(cCache) { (in: (File :+: Long :+: HNil)) =>
|
||||||
val file :+: len :+: HNil = in
|
val file :+: len :+: HNil = in
|
||||||
println("File: " + file + " (" + file.exists + "), length: " + len)
|
println("File: " + file + " (" + file.exists + "), length: " + len)
|
||||||
(len+1) :+: file :+: HNil
|
(len + 1) :+: file :+: HNil
|
||||||
}
|
}
|
||||||
c(create :+: fileLength :+: HNil)
|
c(create :+: fileLength :+: HNil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8,49 +8,43 @@ import Prop._
|
||||||
|
|
||||||
import scala.collection.mutable.HashSet
|
import scala.collection.mutable.HashSet
|
||||||
|
|
||||||
object DagSpecification extends Properties("Dag")
|
object DagSpecification extends Properties("Dag") {
|
||||||
{
|
property("No repeated nodes") = forAll { (dag: TestDag) => isSet(dag.topologicalSort) }
|
||||||
property("No repeated nodes") = forAll{ (dag: TestDag) => isSet(dag.topologicalSort) }
|
property("Sort contains node") = forAll { (dag: TestDag) => dag.topologicalSort.contains(dag) }
|
||||||
property("Sort contains node") = forAll{ (dag: TestDag) => dag.topologicalSort.contains(dag) }
|
property("Dependencies precede node") = forAll { (dag: TestDag) => dependenciesPrecedeNodes(dag.topologicalSort) }
|
||||||
property("Dependencies precede node") = forAll{ (dag: TestDag) => dependenciesPrecedeNodes(dag.topologicalSort) }
|
|
||||||
|
|
||||||
implicit lazy val arbTestDag: Arbitrary[TestDag] = Arbitrary(Gen.sized(dagGen))
|
implicit lazy val arbTestDag: Arbitrary[TestDag] = Arbitrary(Gen.sized(dagGen))
|
||||||
private def dagGen(nodeCount: Int): Gen[TestDag] =
|
private def dagGen(nodeCount: Int): Gen[TestDag] =
|
||||||
{
|
{
|
||||||
val nodes = new HashSet[TestDag]
|
val nodes = new HashSet[TestDag]
|
||||||
def nonterminalGen(p: Gen.Parameters): Gen[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)
|
nodes += new TestDag(i, nextDeps)
|
||||||
for(nextDeps <- Gen.someOf(nodes)) yield
|
for (nextDeps <- Gen.someOf(nodes)) yield new TestDag(nodeCount, nextDeps)
|
||||||
new TestDag(nodeCount, nextDeps)
|
}
|
||||||
}
|
Gen.parameterized(nonterminalGen)
|
||||||
Gen.parameterized(nonterminalGen)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private def isSet[T](c: Seq[T]) = Set(c: _*).size == c.size
|
private def isSet[T](c: Seq[T]) = Set(c: _*).size == c.size
|
||||||
private def dependenciesPrecedeNodes(sort: List[TestDag]) =
|
private def dependenciesPrecedeNodes(sort: List[TestDag]) =
|
||||||
{
|
{
|
||||||
val seen = new HashSet[TestDag]
|
val seen = new HashSet[TestDag]
|
||||||
def iterate(remaining: List[TestDag]): Boolean =
|
def iterate(remaining: List[TestDag]): Boolean =
|
||||||
{
|
{
|
||||||
remaining match
|
remaining match {
|
||||||
{
|
case Nil => true
|
||||||
case Nil => true
|
case node :: tail =>
|
||||||
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)
|
||||||
seen += node
|
} else
|
||||||
iterate(tail)
|
false
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
false
|
iterate(sort)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
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("[", ",", "]")
|
||||||
override def toString = id + "->" + dependencies.mkString("[", ",", "]")
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,35 +1,32 @@
|
||||||
package sbt
|
package sbt
|
||||||
|
|
||||||
import org.scalacheck._
|
import org.scalacheck._
|
||||||
import Prop._
|
import Prop._
|
||||||
|
|
||||||
object KeyTest extends Properties("AttributeKey")
|
object KeyTest extends Properties("AttributeKey") {
|
||||||
{
|
property("equality") = {
|
||||||
property("equality") = {
|
compare(AttributeKey[Int]("test"), AttributeKey[Int]("test"), true) &&
|
||||||
compare(AttributeKey[Int]("test"), AttributeKey[Int]("test"), true) &&
|
compare(AttributeKey[Int]("test"), AttributeKey[Int]("test", "description"), true) &&
|
||||||
compare(AttributeKey[Int]("test"), AttributeKey[Int]("test", "description"), true) &&
|
compare(AttributeKey[Int]("test", "a"), AttributeKey[Int]("test", "b"), true) &&
|
||||||
compare(AttributeKey[Int]("test", "a"), AttributeKey[Int]("test", "b"), true) &&
|
compare(AttributeKey[Int]("test"), AttributeKey[Int]("tests"), false) &&
|
||||||
compare(AttributeKey[Int]("test"), AttributeKey[Int]("tests"), false) &&
|
compare(AttributeKey[Int]("test"), AttributeKey[Double]("test"), false) &&
|
||||||
compare(AttributeKey[Int]("test"), AttributeKey[Double]("test"), false) &&
|
compare(AttributeKey[java.lang.Integer]("test"), AttributeKey[Int]("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, String]]("test"), true) &&
|
compare(AttributeKey[Map[Int, String]]("test"), AttributeKey[Map[Int, _]]("test"), false)
|
||||||
compare(AttributeKey[Map[Int, String]]("test"), AttributeKey[Map[Int, _]]("test"), false)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
def compare(a: AttributeKey[_], b: AttributeKey[_], same: Boolean) =
|
def compare(a: AttributeKey[_], b: AttributeKey[_], same: Boolean) =
|
||||||
("a.label: " + a.label) |:
|
("a.label: " + a.label) |:
|
||||||
("a.manifest: " + a.manifest) |:
|
("a.manifest: " + a.manifest) |:
|
||||||
("b.label: " + b.label) |:
|
("b.label: " + b.label) |:
|
||||||
("b.manifest: " + b.manifest) |:
|
("b.manifest: " + b.manifest) |:
|
||||||
("expected equal? " + same) |:
|
("expected equal? " + same) |:
|
||||||
compare0(a, b, same)
|
compare0(a, b, same)
|
||||||
|
|
||||||
def compare0(a: AttributeKey[_], b: AttributeKey[_], same: Boolean) =
|
def compare0(a: AttributeKey[_], b: AttributeKey[_], same: Boolean) =
|
||||||
if(same)
|
if (same) {
|
||||||
{
|
("equality" |: (a == b)) &&
|
||||||
("equality" |: (a == b)) &&
|
("hash" |: (a.hashCode == b.hashCode))
|
||||||
("hash" |: (a.hashCode == b.hashCode))
|
} else
|
||||||
}
|
("equality" |: (a != b))
|
||||||
else
|
|
||||||
("equality" |: (a != b))
|
|
||||||
}
|
}
|
||||||
|
|
@ -7,11 +7,11 @@ import Types._
|
||||||
|
|
||||||
// compilation test
|
// compilation test
|
||||||
object LiteralTest {
|
object LiteralTest {
|
||||||
def x[A[_],B[_]](f: A ~> B) = f
|
def x[A[_], B[_]](f: A ~> B) = f
|
||||||
|
|
||||||
import Param._
|
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 a: List[Int] = f(Some(3))
|
||||||
val b: List[String] = f( Some("aa") )
|
val b: List[String] = f(Some("aa"))
|
||||||
}
|
}
|
||||||
|
|
@ -6,14 +6,13 @@ package sbt
|
||||||
import Types._
|
import Types._
|
||||||
|
|
||||||
// compilation test
|
// compilation test
|
||||||
object PMapTest
|
object PMapTest {
|
||||||
{
|
val mp = new DelegatingPMap[Some, Id](new collection.mutable.HashMap)
|
||||||
val mp = new DelegatingPMap[Some, Id](new collection.mutable.HashMap)
|
mp(Some("asdf")) = "a"
|
||||||
mp(Some("asdf")) = "a"
|
mp(Some(3)) = 9
|
||||||
mp(Some(3)) = 9
|
val x = Some(3) :^: Some("asdf") :^: KNil
|
||||||
val x = Some(3) :^: Some("asdf") :^: KNil
|
val y = x.transform[Id](mp)
|
||||||
val y = x.transform[Id](mp)
|
assert(y.head == 9)
|
||||||
assert(y.head == 9)
|
assert(y.tail.head == "a")
|
||||||
assert(y.tail.head == "a")
|
assert(y.tail.tail == KNil)
|
||||||
assert(y.tail.tail == KNil)
|
|
||||||
}
|
}
|
||||||
|
|
@ -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
|
// 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.
|
// when you want a type function with only one parameter.
|
||||||
// That would be a general pain.)
|
// That would be a general pain.)
|
||||||
object SettingsExample extends Init[Scope]
|
object SettingsExample extends Init[Scope] {
|
||||||
{
|
// Provides a way of showing a Scope+AttributeKey[_]
|
||||||
// Provides a way of showing a Scope+AttributeKey[_]
|
val showFullKey: Show[ScopedKey[_]] = new Show[ScopedKey[_]] {
|
||||||
val showFullKey: Show[ScopedKey[_]] = new Show[ScopedKey[_]] {
|
def apply(key: ScopedKey[_]) = s"${key.scope.nestIndex}(${key.scope.idAtIndex})/${key.key.label}"
|
||||||
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.
|
// A sample delegation function that delegates to a Scope with a lower index.
|
||||||
val delegates: Scope => Seq[Scope] = { case s @ Scope(index, proj) =>
|
val delegates: Scope => Seq[Scope] = {
|
||||||
s +: (if(index <= 0) Nil else { (if (proj > 0) List(Scope(index)) else Nil) ++: delegates(Scope(index-1)) })
|
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.
|
// Not using this feature in this example.
|
||||||
val scopeLocal: ScopeLocal = _ => Nil
|
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 **/
|
/** Usage Example **/
|
||||||
|
|
||||||
object SettingsUsage
|
object SettingsUsage {
|
||||||
{
|
import SettingsExample._
|
||||||
import SettingsExample._
|
import Types._
|
||||||
import Types._
|
|
||||||
|
|
||||||
// Define some keys
|
// Define some keys
|
||||||
val a = AttributeKey[Int]("a")
|
val a = AttributeKey[Int]("a")
|
||||||
val b = AttributeKey[Int]("b")
|
val b = AttributeKey[Int]("b")
|
||||||
|
|
||||||
// Scope these keys
|
// Scope these keys
|
||||||
val a3 = ScopedKey(Scope(3), a)
|
val a3 = ScopedKey(Scope(3), a)
|
||||||
val a4 = ScopedKey(Scope(4), a)
|
val a4 = ScopedKey(Scope(4), a)
|
||||||
val a5 = ScopedKey(Scope(5), a)
|
val a5 = ScopedKey(Scope(5), a)
|
||||||
|
|
||||||
val b4 = ScopedKey(Scope(4), b)
|
val b4 = ScopedKey(Scope(4), b)
|
||||||
|
|
||||||
// Define some settings
|
// Define some settings
|
||||||
val mySettings: Seq[Setting[_]] = Seq(
|
val mySettings: Seq[Setting[_]] = Seq(
|
||||||
setting( a3, value( 3 ) ),
|
setting(a3, value(3)),
|
||||||
setting( b4, map(a4)(_ * 3)),
|
setting(b4, map(a4)(_ * 3)),
|
||||||
update(a5)(_ + 1)
|
update(a5)(_ + 1)
|
||||||
)
|
)
|
||||||
|
|
||||||
// "compiles" and applies the settings.
|
// "compiles" and applies the settings.
|
||||||
// This can be split into multiple steps to access intermediate results if desired.
|
// This can be split into multiple steps to access intermediate results if desired.
|
||||||
// The 'inspect' command operates on the output of 'compile', for example.
|
// The 'inspect' command operates on the output of 'compile', for example.
|
||||||
val applied: Settings[Scope] = make(mySettings)(delegates, scopeLocal, showFullKey)
|
val applied: Settings[Scope] = make(mySettings)(delegates, scopeLocal, showFullKey)
|
||||||
|
|
||||||
// Show results.
|
// 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) )
|
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.
|
* Output:
|
||||||
* For a3, we explicitly defined it to be 3.
|
* For the None results, we never defined the value and there was no value to delegate to.
|
||||||
* a4 wasn't defined, so it delegates to a3 according to our delegates function.
|
* For a3, we explicitly defined it to be 3.
|
||||||
* b4 gets the value for a4 (which delegates to a3, so it is 3) and multiplies by 3
|
* a4 wasn't defined, so it delegates to a3 according to our delegates function.
|
||||||
* a5 is defined as the previous value of a5 + 1 and
|
* b4 gets the value for a4 (which delegates to a3, so it is 3) and multiplies by 3
|
||||||
* since no previous value of a5 was defined, it delegates to a4, resulting in 3+1=4.
|
* a5 is defined as the previous value of a5 + 1 and
|
||||||
* b5 isn't defined explicitly, so it delegates to b4 and is therefore equal to 9 as well
|
* since no previous value of a5 was defined, it delegates to a4, resulting in 3+1=4.
|
||||||
a0 = None
|
* b5 isn't defined explicitly, so it delegates to b4 and is therefore equal to 9 as well
|
||||||
b0 = None
|
* a0 = None
|
||||||
a1 = None
|
* b0 = None
|
||||||
b1 = None
|
* a1 = None
|
||||||
a2 = None
|
* b1 = None
|
||||||
b2 = None
|
* a2 = None
|
||||||
a3 = Some(3)
|
* b2 = None
|
||||||
b3 = None
|
* a3 = Some(3)
|
||||||
a4 = Some(3)
|
* b3 = None
|
||||||
b4 = Some(9)
|
* a4 = Some(3)
|
||||||
a5 = Some(4)
|
* b4 = Some(9)
|
||||||
b5 = Some(9)
|
* a5 = Some(4)
|
||||||
**/
|
* b5 = Some(9)
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,175 +5,174 @@ import Prop._
|
||||||
import SettingsUsage._
|
import SettingsUsage._
|
||||||
import SettingsExample._
|
import SettingsExample._
|
||||||
|
|
||||||
object SettingsTest extends Properties("settings")
|
object SettingsTest extends Properties("settings") {
|
||||||
{
|
|
||||||
|
|
||||||
import scala.reflect.Manifest
|
import scala.reflect.Manifest
|
||||||
|
|
||||||
final val ChainMax = 5000
|
final val ChainMax = 5000
|
||||||
lazy val chainLengthGen = Gen.choose(1, ChainMax)
|
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) =>
|
property("Basic chain") = forAll(chainLengthGen) { (i: Int) =>
|
||||||
val abs = math.abs(i)
|
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) =>
|
property("Basic bind chain") = forAll(chainLengthGen) { (i: Int) =>
|
||||||
val abs = math.abs(i)
|
val abs = math.abs(i)
|
||||||
singleIntTest( chainBind(value(abs)), 0 )
|
singleIntTest(chainBind(value(abs)), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
property("Allows references to completed settings") = forAllNoShrink(30) { allowedReference }
|
property("Allows references to completed settings") = forAllNoShrink(30) { allowedReference }
|
||||||
final def allowedReference(intermediate: Int): Prop =
|
final def allowedReference(intermediate: Int): Prop =
|
||||||
{
|
{
|
||||||
val top = value(intermediate)
|
val top = value(intermediate)
|
||||||
def iterate(init: Initialize[Int]): Initialize[Int] =
|
def iterate(init: Initialize[Int]): Initialize[Int] =
|
||||||
bind(init) { t =>
|
bind(init) { t =>
|
||||||
if(t <= 0)
|
if (t <= 0)
|
||||||
top
|
top
|
||||||
else
|
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 }
|
property("Derived setting chain depending on (prev derived, normal setting)") = forAllNoShrink(Gen.choose(1, 100)) { derivedSettings }
|
||||||
final def derivedSettings(nr: Int): Prop =
|
final def derivedSettings(nr: Int): Prop =
|
||||||
{
|
{
|
||||||
val genScopedKeys = {
|
val genScopedKeys = {
|
||||||
val attrKeys = mkAttrKeys[Int](nr)
|
val attrKeys = mkAttrKeys[Int](nr)
|
||||||
attrKeys map (_ map (ak => ScopedKey(Scope(0), ak)))
|
attrKeys map (_ map (ak => ScopedKey(Scope(0), ak)))
|
||||||
}
|
}
|
||||||
forAll(genScopedKeys) { scopedKeys =>
|
forAll(genScopedKeys) { scopedKeys =>
|
||||||
val last = scopedKeys.last
|
val last = scopedKeys.last
|
||||||
val derivedSettings: Seq[Setting[Int]] = (
|
val derivedSettings: Seq[Setting[Int]] = (
|
||||||
for {
|
for {
|
||||||
List(scoped0, scoped1) <- chk :: scopedKeys sliding 2
|
List(scoped0, scoped1) <- chk :: scopedKeys sliding 2
|
||||||
nextInit = if (scoped0 == chk) chk
|
nextInit = if (scoped0 == chk) chk
|
||||||
else (scoped0 zipWith chk) { (p, _) => p + 1 }
|
else (scoped0 zipWith chk) { (p, _) => p + 1 }
|
||||||
} yield derive(setting(scoped1, nextInit))
|
} yield derive(setting(scoped1, nextInit))
|
||||||
).toSeq
|
).toSeq
|
||||||
|
|
||||||
{ checkKey(last, Some(nr-1), evaluate(setting(chk, value(0)) +: derivedSettings)) :| "Not derived?" } &&
|
{ checkKey(last, Some(nr - 1), evaluate(setting(chk, value(0)) +: derivedSettings)) :| "Not derived?" } &&
|
||||||
{ checkKey( last, None, evaluate(derivedSettings)) :| "Should not be derived" }
|
{ checkKey(last, None, evaluate(derivedSettings)) :| "Should not be derived" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def mkAttrKeys[T](nr: Int)(implicit mf: Manifest[T]): Gen[List[AttributeKey[T]]] =
|
private def mkAttrKeys[T](nr: Int)(implicit mf: Manifest[T]): Gen[List[AttributeKey[T]]] =
|
||||||
{
|
{
|
||||||
val alphaStr = Gen.alphaStr
|
val alphaStr = Gen.alphaStr
|
||||||
for {
|
for {
|
||||||
list <- Gen.listOfN(nr, alphaStr) suchThat (l => l.size == l.distinct.size)
|
list <- Gen.listOfN(nr, alphaStr) suchThat (l => l.size == l.distinct.size)
|
||||||
item <- list
|
item <- list
|
||||||
} yield AttributeKey[T](item)
|
} yield AttributeKey[T](item)
|
||||||
}
|
}
|
||||||
|
|
||||||
property("Derived setting(s) replace DerivedSetting in the Seq[Setting[_]]") = derivedKeepsPosition
|
property("Derived setting(s) replace DerivedSetting in the Seq[Setting[_]]") = derivedKeepsPosition
|
||||||
final def derivedKeepsPosition: Prop =
|
final def derivedKeepsPosition: Prop =
|
||||||
{
|
{
|
||||||
val a: ScopedKey[Int] = ScopedKey(Scope(0), AttributeKey[Int]("a"))
|
val a: ScopedKey[Int] = ScopedKey(Scope(0), AttributeKey[Int]("a"))
|
||||||
val b: ScopedKey[Int] = ScopedKey(Scope(0), AttributeKey[Int]("b"))
|
val b: ScopedKey[Int] = ScopedKey(Scope(0), AttributeKey[Int]("b"))
|
||||||
val prop1 = {
|
val prop1 = {
|
||||||
val settings: Seq[Setting[_]] = Seq(
|
val settings: Seq[Setting[_]] = Seq(
|
||||||
setting(a, value(3)),
|
setting(a, value(3)),
|
||||||
setting(b, value(6)),
|
setting(b, value(6)),
|
||||||
derive(setting(b, a)),
|
derive(setting(b, a)),
|
||||||
setting(a, value(5)),
|
setting(a, value(5)),
|
||||||
setting(b, value(8))
|
setting(b, value(8))
|
||||||
)
|
)
|
||||||
val ev = evaluate(settings)
|
val ev = evaluate(settings)
|
||||||
checkKey(a, Some(5), ev) && checkKey(b, Some(8), ev)
|
checkKey(a, Some(5), ev) && checkKey(b, Some(8), ev)
|
||||||
}
|
}
|
||||||
val prop2 = {
|
val prop2 = {
|
||||||
val settings: Seq[Setting[Int]] = Seq(
|
val settings: Seq[Setting[Int]] = Seq(
|
||||||
setting(a, value(3)),
|
setting(a, value(3)),
|
||||||
setting(b, value(6)),
|
setting(b, value(6)),
|
||||||
derive(setting(b, a)),
|
derive(setting(b, a)),
|
||||||
setting(a, value(5))
|
setting(a, value(5))
|
||||||
)
|
)
|
||||||
val ev = evaluate(settings)
|
val ev = evaluate(settings)
|
||||||
checkKey(a, Some(5), ev) && checkKey(b, Some(5), ev)
|
checkKey(a, Some(5), ev) && checkKey(b, Some(5), ev)
|
||||||
}
|
}
|
||||||
prop1 && prop2
|
prop1 && prop2
|
||||||
}
|
}
|
||||||
|
|
||||||
property("DerivedSetting in ThisBuild scopes derived settings under projects thus allowing safe +=") = forAllNoShrink(Gen.choose(1, 100)) { derivedSettingsScope }
|
property("DerivedSetting in ThisBuild scopes derived settings under projects thus allowing safe +=") = forAllNoShrink(Gen.choose(1, 100)) { derivedSettingsScope }
|
||||||
final def derivedSettingsScope(nrProjects: Int): Prop =
|
final def derivedSettingsScope(nrProjects: Int): Prop =
|
||||||
{
|
{
|
||||||
forAll(mkAttrKeys[Int](2)) { case List(key, derivedKey) =>
|
forAll(mkAttrKeys[Int](2)) {
|
||||||
val projectKeys = for { proj <- 1 to nrProjects } yield ScopedKey(Scope(1, proj), key)
|
case List(key, derivedKey) =>
|
||||||
val projectDerivedKeys = for { proj <- 1 to nrProjects } yield ScopedKey(Scope(1, proj), derivedKey)
|
val projectKeys = for { proj <- 1 to nrProjects } yield ScopedKey(Scope(1, proj), key)
|
||||||
val globalKey = ScopedKey(Scope(0), key)
|
val projectDerivedKeys = for { proj <- 1 to nrProjects } yield ScopedKey(Scope(1, proj), derivedKey)
|
||||||
val globalDerivedKey = ScopedKey(Scope(0), derivedKey)
|
val globalKey = ScopedKey(Scope(0), key)
|
||||||
// Each project defines an initial value, but the update is defined in globalKey.
|
val globalDerivedKey = ScopedKey(Scope(0), derivedKey)
|
||||||
// However, the derived Settings that come from this should be scoped in each project.
|
// Each project defines an initial value, but the update is defined in globalKey.
|
||||||
val settings: Seq[Setting[_]] =
|
// However, the derived Settings that come from this should be scoped in each project.
|
||||||
derive(setting(globalDerivedKey, SettingsExample.map(globalKey)(_ + 1))) +: projectKeys.map(pk => setting(pk, value(0)))
|
val settings: Seq[Setting[_]] =
|
||||||
val ev = evaluate(settings)
|
derive(setting(globalDerivedKey, SettingsExample.map(globalKey)(_ + 1))) +: projectKeys.map(pk => setting(pk, value(0)))
|
||||||
// Also check that the key has no value at the "global" scope
|
val ev = evaluate(settings)
|
||||||
val props = for { pk <- projectDerivedKeys } yield checkKey(pk, Some(1), ev)
|
// Also check that the key has no value at the "global" scope
|
||||||
checkKey(globalDerivedKey, None, ev) && Prop.all(props: _*)
|
val props = for { pk <- projectDerivedKeys } yield checkKey(pk, Some(1), ev)
|
||||||
}
|
checkKey(globalDerivedKey, None, ev) && Prop.all(props: _*)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Circular (dynamic) references currently loop infinitely.
|
// Circular (dynamic) references currently loop infinitely.
|
||||||
// This is the expected behavior (detecting dynamic cycles is expensive),
|
// 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)
|
// but it may be necessary to provide an option to detect them (with a performance hit)
|
||||||
// This would test that cycle detection.
|
// This would test that cycle detection.
|
||||||
// property("Catches circular references") = forAll(chainLengthGen) { checkCircularReferences _ }
|
// property("Catches circular references") = forAll(chainLengthGen) { checkCircularReferences _ }
|
||||||
final def checkCircularReferences(intermediate: Int): Prop =
|
final def checkCircularReferences(intermediate: Int): Prop =
|
||||||
{
|
{
|
||||||
val ccr = new CCR(intermediate)
|
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 }
|
catch { case e: java.lang.Exception => true }
|
||||||
}
|
}
|
||||||
|
|
||||||
def tests =
|
def tests =
|
||||||
for(i <- 0 to 5; k <- Seq(a, b)) yield {
|
for (i <- 0 to 5; k <- Seq(a, b)) yield {
|
||||||
val expected = expectedValues(2*i + (if(k == a) 0 else 1))
|
val expected = expectedValues(2 * i + (if (k == a) 0 else 1))
|
||||||
checkKey[Int]( ScopedKey( Scope(i), k ), expected, applied)
|
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 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] =
|
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] =
|
def chainBind(prev: Initialize[Int]): Initialize[Int] =
|
||||||
bind(prev) { v =>
|
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) =
|
def singleIntTest(i: Initialize[Int], expected: Int) =
|
||||||
{
|
{
|
||||||
val eval = evaluate( setting( chk, i ) :: Nil )
|
val eval = evaluate(setting(chk, i) :: Nil)
|
||||||
checkKey( chk, Some(expected), eval )
|
checkKey(chk, Some(expected), eval)
|
||||||
}
|
}
|
||||||
|
|
||||||
def checkKey[T](key: ScopedKey[T], expected: Option[T], settings: Settings[Scope]) =
|
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) |:
|
("Key: " + key) |:
|
||||||
("Value: " + value) |:
|
("Value: " + value) |:
|
||||||
("Expected: " + expected) |:
|
("Expected: " + expected) |:
|
||||||
(value == expected)
|
(value == expected)
|
||||||
}
|
}
|
||||||
|
|
||||||
def evaluate(settings: Seq[Setting[_]]): Settings[Scope] =
|
def evaluate(settings: Seq[Setting[_]]): Settings[Scope] =
|
||||||
try { make(settings)(delegates, scopeLocal, showFullKey) }
|
try { make(settings)(delegates, scopeLocal, showFullKey) }
|
||||||
catch { case e: Throwable => e.printStackTrace; throw e }
|
catch { case e: Throwable => e.printStackTrace; throw e }
|
||||||
}
|
}
|
||||||
// This setup is a workaround for module synchronization issues
|
// 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)
|
||||||
lazy val top = iterate(value(intermediate), intermediate)
|
def iterate(init: Initialize[Int], i: Int): Initialize[Int] =
|
||||||
def iterate(init: Initialize[Int], i: Int): Initialize[Int] =
|
bind(init) { t =>
|
||||||
bind(init) { t =>
|
if (t <= 0)
|
||||||
if(t <= 0)
|
top
|
||||||
top
|
else
|
||||||
else
|
iterate(value(t - 1), t - 1)
|
||||||
iterate(value(t - 1), t-1)
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,154 +1,148 @@
|
||||||
package sbt.complete
|
package sbt.complete
|
||||||
|
|
||||||
object JLineTest
|
object JLineTest {
|
||||||
{
|
import DefaultParsers._
|
||||||
import DefaultParsers._
|
|
||||||
|
|
||||||
val one = "blue" | "green" | "black"
|
val one = "blue" | "green" | "black"
|
||||||
val two = token("color" ~> Space) ~> token(one)
|
val two = token("color" ~> Space) ~> token(one)
|
||||||
val three = token("color" ~> Space) ~> token(ID.examples("blue", "green", "black"))
|
val three = token("color" ~> Space) ~> token(ID.examples("blue", "green", "black"))
|
||||||
val four = token("color" ~> Space) ~> token(ID, "<color name>")
|
val four = token("color" ~> Space) ~> token(ID, "<color name>")
|
||||||
|
|
||||||
val num = token(NatBasic)
|
val num = token(NatBasic)
|
||||||
val five = (num ~ token("+" | "-") ~ num) <~ token('=') flatMap {
|
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)
|
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.TerminalFactory
|
import jline.console.ConsoleReader
|
||||||
import jline.console.ConsoleReader
|
val reader = new ConsoleReader()
|
||||||
val reader = new ConsoleReader()
|
TerminalFactory.get.init
|
||||||
TerminalFactory.get.init
|
|
||||||
|
|
||||||
val parser = parsers(args(0))
|
val parser = parsers(args(0))
|
||||||
JLineCompletion.installCustomCompletor(reader, parser)
|
JLineCompletion.installCustomCompletor(reader, parser)
|
||||||
def loop() {
|
def loop() {
|
||||||
val line = reader.readLine("> ")
|
val line = reader.readLine("> ")
|
||||||
if(line ne null) {
|
if (line ne null) {
|
||||||
println("Result: " + apply(parser)(line).resultEmpty)
|
println("Result: " + apply(parser)(line).resultEmpty)
|
||||||
loop()
|
loop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
loop()
|
loop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
import Parser._
|
import Parser._
|
||||||
import org.scalacheck._
|
import org.scalacheck._
|
||||||
|
|
||||||
object ParserTest extends Properties("Completing Parser")
|
object ParserTest extends Properties("Completing Parser") {
|
||||||
{
|
import Parsers._
|
||||||
import Parsers._
|
import DefaultParsers.matches
|
||||||
import DefaultParsers.matches
|
|
||||||
|
|
||||||
val nested = (token("a1") ~ token("b2")) ~ "c3"
|
val nested = (token("a1") ~ token("b2")) ~ "c3"
|
||||||
val nestedDisplay = (token("a1", "<a1>") ~ token("b2", "<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) =
|
def checkSingle(in: String, expect: Completion)(expectDisplay: Completion = expect) =
|
||||||
( ("token '" + in + "'") |: checkOne(in, nested, expect)) &&
|
(("token '" + in + "'") |: checkOne(in, nested, expect)) &&
|
||||||
( ("display '" + in + "'") |: checkOne(in, nestedDisplay, expectDisplay) )
|
(("display '" + in + "'") |: checkOne(in, nestedDisplay, expectDisplay))
|
||||||
|
|
||||||
def checkOne(in: String, parser: Parser[_], expect: Completion): Prop =
|
def checkOne(in: String, parser: Parser[_], expect: Completion): Prop =
|
||||||
completions(parser, in, 1) == Completions.single(expect)
|
completions(parser, in, 1) == Completions.single(expect)
|
||||||
|
|
||||||
def checkAll(in: String, parser: Parser[_], expect: Completions): Prop =
|
def checkAll(in: String, parser: Parser[_], expect: Completions): Prop =
|
||||||
{
|
{
|
||||||
val cs = completions(parser, in, 1)
|
val cs = completions(parser, in, 1)
|
||||||
("completions: " + cs) |: ("Expected: " + expect) |: ( (cs == expect): Prop)
|
("completions: " + cs) |: ("Expected: " + expect) |: ((cs == expect): Prop)
|
||||||
}
|
}
|
||||||
|
|
||||||
def checkInvalid(in: String) =
|
def checkInvalid(in: String) =
|
||||||
( ("token '" + in + "'") |: checkInv(in, nested) ) &&
|
(("token '" + in + "'") |: checkInv(in, nested)) &&
|
||||||
( ("display '" + in + "'") |: checkInv(in, nestedDisplay) )
|
(("display '" + in + "'") |: checkInv(in, nestedDisplay))
|
||||||
|
|
||||||
def checkInv(in: String, parser: Parser[_]): Prop =
|
def checkInv(in: String, parser: Parser[_]): Prop =
|
||||||
{
|
{
|
||||||
val cs = completions(parser, in, 1)
|
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 a") = checkSingle("", Completion.tokenStrict("", "a1"))(Completion.displayStrict("<a1>"))
|
||||||
property("nested tokens a1") = checkSingle("a", Completion.tokenStrict("a","1") )( 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 a inv") = checkInvalid("b")
|
||||||
property("nested tokens b") = checkSingle("a1", Completion.tokenStrict("","b2") )( 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 b2") = checkSingle("a1b", Completion.tokenStrict("b", "2"))(Completion.displayStrict("<b2>"))
|
||||||
property("nested tokens b inv") = checkInvalid("a1a")
|
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 c3") = checkSingle("a1b2c", Completion.suggestStrict("3"))()
|
||||||
property("nested tokens c inv") = checkInvalid("a1b2a")
|
property("nested tokens c inv") = checkInvalid("a1b2a")
|
||||||
|
|
||||||
property("suggest space") = checkOne("", spacePort, Completion.tokenStrict("", " "))
|
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 end") = checkOne("asdf", "asdf", Completion.suggestStrict(""))
|
||||||
property("no suggest at token end") = checkOne("asdf", token("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") = checkOne("asdf", any.+.examples("asdf", "qwer"), Completion.suggestStrict(""))
|
||||||
property("empty suggest for examples token") = checkOne("asdf", token(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 colors = Set("blue", "green", "red")
|
||||||
val base = (seen: Seq[String]) => token( ID examples (colors -- seen) )
|
val base = (seen: Seq[String]) => token(ID examples (colors -- seen))
|
||||||
val sep = token( Space )
|
val sep = token(Space)
|
||||||
val repeat = repeatDep( base, sep)
|
val repeat = repeatDep(base, sep)
|
||||||
def completionStrings(ss: Set[String]): Completions = Completions(ss.map { s => Completion.tokenStrict("", s) })
|
def completionStrings(ss: Set[String]): Completions = Completions(ss.map { s => Completion.tokenStrict("", s) })
|
||||||
|
|
||||||
property("repeatDep no suggestions for bad input") = checkInv(".", repeat)
|
property("repeatDep no suggestions for bad input") = checkInv(".", repeat)
|
||||||
property("repeatDep suggest all") = checkAll("", repeat, completionStrings(colors))
|
property("repeatDep suggest all") = checkAll("", repeat, completionStrings(colors))
|
||||||
property("repeatDep suggest remaining two") = {
|
property("repeatDep suggest remaining two") = {
|
||||||
val first = colors.toSeq.head
|
val first = colors.toSeq.head
|
||||||
checkAll(first + " ", repeat, completionStrings(colors - first))
|
checkAll(first + " ", repeat, completionStrings(colors - first))
|
||||||
}
|
}
|
||||||
property("repeatDep suggest remaining one") = {
|
property("repeatDep suggest remaining one") = {
|
||||||
val take = colors.toSeq.take(2)
|
val take = colors.toSeq.take(2)
|
||||||
checkAll(take.mkString("", " ", " "), repeat, completionStrings(colors -- take))
|
checkAll(take.mkString("", " ", " "), repeat, completionStrings(colors -- take))
|
||||||
}
|
}
|
||||||
property("repeatDep requires at least one token") = !matches(repeat, "")
|
property("repeatDep requires at least one token") = !matches(repeat, "")
|
||||||
property("repeatDep accepts one token") = matches(repeat, colors.toSeq.head)
|
property("repeatDep accepts one token") = matches(repeat, colors.toSeq.head)
|
||||||
property("repeatDep accepts two tokens") = matches(repeat, colors.toSeq.take(2).mkString(" "))
|
property("repeatDep accepts two tokens") = matches(repeat, colors.toSeq.take(2).mkString(" "))
|
||||||
}
|
}
|
||||||
object ParserExample
|
object ParserExample {
|
||||||
{
|
val ws = charClass(_.isWhitespace)+
|
||||||
val ws = charClass(_.isWhitespace)+
|
val notws = charClass(!_.isWhitespace)+
|
||||||
val notws = charClass(!_.isWhitespace)+
|
|
||||||
|
|
||||||
val name = token("test")
|
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 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
|
val t = name ~ options ~ include
|
||||||
|
|
||||||
// Get completions for some different inputs
|
// Get completions for some different inputs
|
||||||
println(completions(t, "te", 1))
|
println(completions(t, "te", 1))
|
||||||
println(completions(t, "test ",1))
|
println(completions(t, "test ", 1))
|
||||||
println(completions(t, "test w", 1))
|
println(completions(t, "test w", 1))
|
||||||
|
|
||||||
// Get the parsed result for different inputs
|
// Get the parsed result for different inputs
|
||||||
println(apply(t)("te").resultEmpty)
|
println(apply(t)("te").resultEmpty)
|
||||||
println(apply(t)("test").resultEmpty)
|
println(apply(t)("test").resultEmpty)
|
||||||
println(apply(t)("test w").resultEmpty)
|
println(apply(t)("test w").resultEmpty)
|
||||||
println(apply(t)("test was were").resultEmpty)
|
println(apply(t)("test was were").resultEmpty)
|
||||||
|
|
||||||
def run(n: Int)
|
def run(n: Int) {
|
||||||
{
|
val a = 'a'.id
|
||||||
val a = 'a'.id
|
val aq = a.?
|
||||||
val aq = a.?
|
val aqn = repeat(aq, min = n, max = n)
|
||||||
val aqn = repeat(aq, min = n, max = n)
|
val an = repeat(a, min = n, max = n)
|
||||||
val an = repeat(a, min = n, max = n)
|
val ann = aqn ~ an
|
||||||
val ann = aqn ~ an
|
|
||||||
|
|
||||||
def r = apply(ann)("a"*(n*2)).resultEmpty
|
def r = apply(ann)("a" * (n * 2)).resultEmpty
|
||||||
println(r.isValid)
|
println(r.isValid)
|
||||||
}
|
}
|
||||||
def run2(n: Int)
|
def run2(n: Int) {
|
||||||
{
|
val ab = "ab".?.*
|
||||||
val ab = "ab".?.*
|
val r = apply(ab)("a" * n).resultEmpty
|
||||||
val r = apply(ab)("a"*n).resultEmpty
|
println(r)
|
||||||
println(r)
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -6,87 +6,85 @@ import sbt.IO.withTemporaryDirectory
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import sbt.IO._
|
import sbt.IO._
|
||||||
|
|
||||||
class FileExamplesTest extends Specification
|
class FileExamplesTest extends Specification {
|
||||||
{
|
|
||||||
|
|
||||||
"listing all files in an absolute base directory" should {
|
"listing all files in an absolute base directory" should {
|
||||||
"produce the entire base directory's contents" in new directoryStructure {
|
"produce the entire base directory's contents" in new directoryStructure {
|
||||||
fileExamples().toList should containTheSameElementsAs(allRelativizedPaths)
|
fileExamples().toList should containTheSameElementsAs(allRelativizedPaths)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"listing files with a prefix that matches none" should {
|
"listing files with a prefix that matches none" should {
|
||||||
"produce an empty list" in new directoryStructure(withCompletionPrefix = "z") {
|
"produce an empty list" in new directoryStructure(withCompletionPrefix = "z") {
|
||||||
fileExamples().toList should beEmpty
|
fileExamples().toList should beEmpty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"listing single-character prefixed files" should {
|
"listing single-character prefixed files" should {
|
||||||
"produce matching paths only" in new directoryStructure(withCompletionPrefix = "f") {
|
"produce matching paths only" in new directoryStructure(withCompletionPrefix = "f") {
|
||||||
fileExamples().toList should containTheSameElementsAs(prefixedPathsOnly)
|
fileExamples().toList should containTheSameElementsAs(prefixedPathsOnly)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"listing directory-prefixed files" should {
|
"listing directory-prefixed files" should {
|
||||||
"produce matching paths only" in new directoryStructure(withCompletionPrefix = "far") {
|
"produce matching paths only" in new directoryStructure(withCompletionPrefix = "far") {
|
||||||
fileExamples().toList should containTheSameElementsAs(prefixedPathsOnly)
|
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) {
|
"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)
|
fileExamples().toList should containTheSameElementsAs(prefixedPathsOnly)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"listing files with a sub-path prefix" should {
|
"listing files with a sub-path prefix" should {
|
||||||
"produce matching paths only" in new directoryStructure(withCompletionPrefix = "far" + File.separator + "ba") {
|
"produce matching paths only" in new directoryStructure(withCompletionPrefix = "far" + File.separator + "ba") {
|
||||||
fileExamples().toList should containTheSameElementsAs(prefixedPathsOnly)
|
fileExamples().toList should containTheSameElementsAs(prefixedPathsOnly)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"completing a full path" should {
|
"completing a full path" should {
|
||||||
"produce a list with an empty string" in new directoryStructure(withCompletionPrefix = "bazaar") {
|
"produce a list with an empty string" in new directoryStructure(withCompletionPrefix = "bazaar") {
|
||||||
fileExamples().toList shouldEqual List("")
|
fileExamples().toList shouldEqual List("")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class directoryStructure(withCompletionPrefix: String = "") extends Scope with DelayedInit
|
class directoryStructure(withCompletionPrefix: String = "") extends Scope with DelayedInit {
|
||||||
{
|
var fileExamples: FileExamples = _
|
||||||
var fileExamples: FileExamples = _
|
var baseDir: File = _
|
||||||
var baseDir: File = _
|
var childFiles: List[File] = _
|
||||||
var childFiles: List[File] = _
|
var childDirectories: List[File] = _
|
||||||
var childDirectories: List[File] = _
|
var nestedFiles: List[File] = _
|
||||||
var nestedFiles: List[File] = _
|
var nestedDirectories: List[File] = _
|
||||||
var nestedDirectories: List[File] = _
|
|
||||||
|
|
||||||
def allRelativizedPaths: List[String] =
|
def allRelativizedPaths: List[String] =
|
||||||
(childFiles ++ childDirectories ++ nestedFiles ++ nestedDirectories).map(relativize(baseDir, _).get)
|
(childFiles ++ childDirectories ++ nestedFiles ++ nestedDirectories).map(relativize(baseDir, _).get)
|
||||||
|
|
||||||
def prefixedPathsOnly: List[String] =
|
def prefixedPathsOnly: List[String] =
|
||||||
allRelativizedPaths.filter(_ startsWith withCompletionPrefix).map(_ substring withCompletionPrefix.length)
|
allRelativizedPaths.filter(_ startsWith withCompletionPrefix).map(_ substring withCompletionPrefix.length)
|
||||||
|
|
||||||
override def delayedInit(testBody: => Unit): Unit = {
|
override def delayedInit(testBody: => Unit): Unit = {
|
||||||
withTemporaryDirectory {
|
withTemporaryDirectory {
|
||||||
tempDir =>
|
tempDir =>
|
||||||
createSampleDirStructure(tempDir)
|
createSampleDirStructure(tempDir)
|
||||||
fileExamples = new FileExamples(baseDir, withCompletionPrefix)
|
fileExamples = new FileExamples(baseDir, withCompletionPrefix)
|
||||||
testBody
|
testBody
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private def createSampleDirStructure(tempDir: File): Unit = {
|
private def createSampleDirStructure(tempDir: File): Unit = {
|
||||||
childFiles = toChildFiles(tempDir, List("foo", "bar", "bazaar"))
|
childFiles = toChildFiles(tempDir, List("foo", "bar", "bazaar"))
|
||||||
childDirectories = toChildFiles(tempDir, List("moo", "far"))
|
childDirectories = toChildFiles(tempDir, List("moo", "far"))
|
||||||
nestedFiles = toChildFiles(childDirectories(1), List("farfile1", "barfile2"))
|
nestedFiles = toChildFiles(childDirectories(1), List("farfile1", "barfile2"))
|
||||||
nestedDirectories = toChildFiles(childDirectories(1), List("fardir1", "bardir2"))
|
nestedDirectories = toChildFiles(childDirectories(1), List("fardir1", "bardir2"))
|
||||||
|
|
||||||
(childDirectories ++ nestedDirectories).map(_.mkdirs())
|
(childDirectories ++ nestedDirectories).map(_.mkdirs())
|
||||||
(childFiles ++ nestedFiles).map(_.createNewFile())
|
(childFiles ++ nestedFiles).map(_.createNewFile())
|
||||||
|
|
||||||
// NOTE: Creating a new file here because `tempDir.listFiles()` returned an empty list.
|
// NOTE: Creating a new file here because `tempDir.listFiles()` returned an empty list.
|
||||||
baseDir = new File(tempDir.getCanonicalPath)
|
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, _))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,22 +5,22 @@ import org.specs2.specification.Scope
|
||||||
|
|
||||||
class FixedSetExamplesTest extends Specification {
|
class FixedSetExamplesTest extends Specification {
|
||||||
|
|
||||||
"adding a prefix" should {
|
"adding a prefix" should {
|
||||||
"produce a smaller set of examples with the prefix removed" in new examples {
|
"produce a smaller set of examples with the prefix removed" in new examples {
|
||||||
fixedSetExamples.withAddedPrefix("f")() must containTheSameElementsAs(List("oo", "ool", "u"))
|
fixedSetExamples.withAddedPrefix("f")() must containTheSameElementsAs(List("oo", "ool", "u"))
|
||||||
fixedSetExamples.withAddedPrefix("fo")() must containTheSameElementsAs(List("o", "ol"))
|
fixedSetExamples.withAddedPrefix("fo")() must containTheSameElementsAs(List("o", "ol"))
|
||||||
fixedSetExamples.withAddedPrefix("b")() must containTheSameElementsAs(List("ar"))
|
fixedSetExamples.withAddedPrefix("b")() must containTheSameElementsAs(List("ar"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"without a prefix" should {
|
"without a prefix" should {
|
||||||
"produce the original set" in new examples {
|
"produce the original set" in new examples {
|
||||||
fixedSetExamples() mustEqual exampleSet
|
fixedSetExamples() mustEqual exampleSet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait examples extends Scope {
|
trait examples extends Scope {
|
||||||
val exampleSet = List("foo", "bar", "fool", "fu")
|
val exampleSet = List("foo", "bar", "fool", "fu")
|
||||||
val fixedSetExamples = FixedSetExamples(exampleSet)
|
val fixedSetExamples = FixedSetExamples(exampleSet)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,88 +6,88 @@ import Completion._
|
||||||
|
|
||||||
class ParserWithExamplesTest extends Specification {
|
class ParserWithExamplesTest extends Specification {
|
||||||
|
|
||||||
"listing a limited number of completions" should {
|
"listing a limited number of completions" should {
|
||||||
"grab only the needed number of elements from the iterable source of examples" in new parserWithLazyExamples {
|
"grab only the needed number of elements from the iterable source of examples" in new parserWithLazyExamples {
|
||||||
parserWithExamples.completions(0)
|
parserWithExamples.completions(0)
|
||||||
examples.size shouldEqual maxNumberOfExamples
|
examples.size shouldEqual maxNumberOfExamples
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"listing only valid completions" should {
|
"listing only valid completions" should {
|
||||||
"use the delegate parser to remove invalid examples" in new parserWithValidExamples {
|
"use the delegate parser to remove invalid examples" in new parserWithValidExamples {
|
||||||
val validCompletions = Completions(Set(
|
val validCompletions = Completions(Set(
|
||||||
suggestion("blue"),
|
suggestion("blue"),
|
||||||
suggestion("red")
|
suggestion("red")
|
||||||
))
|
))
|
||||||
parserWithExamples.completions(0) shouldEqual validCompletions
|
parserWithExamples.completions(0) shouldEqual validCompletions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"listing valid completions in a derived parser" should {
|
"listing valid completions in a derived parser" should {
|
||||||
"produce only valid examples that start with the character of the derivation" in new parserWithValidExamples {
|
"produce only valid examples that start with the character of the derivation" in new parserWithValidExamples {
|
||||||
val derivedCompletions = Completions(Set(
|
val derivedCompletions = Completions(Set(
|
||||||
suggestion("lue")
|
suggestion("lue")
|
||||||
))
|
))
|
||||||
parserWithExamples.derive('b').completions(0) shouldEqual derivedCompletions
|
parserWithExamples.derive('b').completions(0) shouldEqual derivedCompletions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"listing valid and invalid completions" should {
|
"listing valid and invalid completions" should {
|
||||||
"produce the entire source of examples" in new parserWithAllExamples {
|
"produce the entire source of examples" in new parserWithAllExamples {
|
||||||
val completions = Completions(examples.map(suggestion(_)).toSet)
|
val completions = Completions(examples.map(suggestion(_)).toSet)
|
||||||
parserWithExamples.completions(0) shouldEqual completions
|
parserWithExamples.completions(0) shouldEqual completions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"listing valid and invalid completions in a derived parser" should {
|
"listing valid and invalid completions in a derived parser" should {
|
||||||
"produce only examples that start with the character of the derivation" in new parserWithAllExamples {
|
"produce only examples that start with the character of the derivation" in new parserWithAllExamples {
|
||||||
val derivedCompletions = Completions(Set(
|
val derivedCompletions = Completions(Set(
|
||||||
suggestion("lue"),
|
suggestion("lue"),
|
||||||
suggestion("lock")
|
suggestion("lock")
|
||||||
))
|
))
|
||||||
parserWithExamples.derive('b').completions(0) shouldEqual derivedCompletions
|
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"),
|
case class parser(examples: Iterable[String] = Set("blue", "yellow", "greeen", "block", "red"),
|
||||||
maxNumberOfExamples: Int = 25,
|
maxNumberOfExamples: Int = 25,
|
||||||
removeInvalidExamples: Boolean) extends Scope {
|
removeInvalidExamples: Boolean) extends Scope {
|
||||||
|
|
||||||
import DefaultParsers._
|
import DefaultParsers._
|
||||||
|
|
||||||
val colorParser = "blue" | "green" | "black" | "red"
|
val colorParser = "blue" | "green" | "black" | "red"
|
||||||
val parserWithExamples: Parser[String] = new ParserWithExamples[String](
|
val parserWithExamples: Parser[String] = new ParserWithExamples[String](
|
||||||
colorParser,
|
colorParser,
|
||||||
FixedSetExamples(examples),
|
FixedSetExamples(examples),
|
||||||
maxNumberOfExamples,
|
maxNumberOfExamples,
|
||||||
removeInvalidExamples
|
removeInvalidExamples
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
case class GrowableSourceOfExamples() extends Iterable[String] {
|
case class GrowableSourceOfExamples() extends Iterable[String] {
|
||||||
private var numberOfIteratedElements: Int = 0
|
private var numberOfIteratedElements: Int = 0
|
||||||
|
|
||||||
override def iterator: Iterator[String] = {
|
override def iterator: Iterator[String] = {
|
||||||
new Iterator[String] {
|
new Iterator[String] {
|
||||||
var currentElement = 0
|
var currentElement = 0
|
||||||
|
|
||||||
override def next(): String = {
|
override def next(): String = {
|
||||||
currentElement += 1
|
currentElement += 1
|
||||||
numberOfIteratedElements = Math.max(currentElement, numberOfIteratedElements)
|
numberOfIteratedElements = Math.max(currentElement, numberOfIteratedElements)
|
||||||
numberOfIteratedElements.toString
|
numberOfIteratedElements.toString
|
||||||
}
|
}
|
||||||
|
|
||||||
override def hasNext: Boolean = true
|
override def hasNext: Boolean = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override def size: Int = numberOfIteratedElements
|
override def size: Int = numberOfIteratedElements
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,90 +2,85 @@ package sbt
|
||||||
|
|
||||||
import org.scalacheck._
|
import org.scalacheck._
|
||||||
import Prop._
|
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") =
|
||||||
property("genTerminator only generates terminators") =
|
forAllNoShrink(genTerminator) { (c: Char) => isEscapeTerminator(c) }
|
||||||
forAllNoShrink(genTerminator) { (c: Char) => isEscapeTerminator(c) }
|
|
||||||
|
|
||||||
property("genWithoutTerminator only generates terminators") =
|
property("genWithoutTerminator only generates terminators") =
|
||||||
forAllNoShrink(genWithoutTerminator) { (s: String) =>
|
forAllNoShrink(genWithoutTerminator) { (s: String) =>
|
||||||
s.forall { c => !isEscapeTerminator(c) }
|
s.forall { c => !isEscapeTerminator(c) }
|
||||||
}
|
}
|
||||||
|
|
||||||
property("hasEscapeSequence is false when no escape character is present") = forAllNoShrink(genWithoutEscape) { (s: String) =>
|
property("hasEscapeSequence is false when no escape character is present") = forAllNoShrink(genWithoutEscape) { (s: String) =>
|
||||||
!hasEscapeSequence(s)
|
!hasEscapeSequence(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
property("hasEscapeSequence is true when escape character is present") = forAllNoShrink(genWithRandomEscapes) { (s: String) =>
|
property("hasEscapeSequence is true when escape character is present") = forAllNoShrink(genWithRandomEscapes) { (s: String) =>
|
||||||
hasEscapeSequence(s)
|
hasEscapeSequence(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
property("removeEscapeSequences is the identity when no escape character is present") = forAllNoShrink(genWithoutEscape) { (s: String) =>
|
property("removeEscapeSequences is the identity when no escape character is present") = forAllNoShrink(genWithoutEscape) { (s: String) =>
|
||||||
val removed: String = removeEscapeSequences(s)
|
val removed: String = removeEscapeSequences(s)
|
||||||
("Escape sequence removed: '" + removed + "'") |:
|
("Escape sequence removed: '" + removed + "'") |:
|
||||||
(removed == s)
|
(removed == s)
|
||||||
}
|
}
|
||||||
|
|
||||||
property("No escape characters remain after removeEscapeSequences") = forAll { (s: String) =>
|
property("No escape characters remain after removeEscapeSequences") = forAll { (s: String) =>
|
||||||
val removed: String = removeEscapeSequences(s)
|
val removed: String = removeEscapeSequences(s)
|
||||||
("Escape sequence removed: '" + removed + "'") |:
|
("Escape sequence removed: '" + removed + "'") |:
|
||||||
!hasEscapeSequence(removed)
|
!hasEscapeSequence(removed)
|
||||||
}
|
}
|
||||||
|
|
||||||
property("removeEscapeSequences returns string without escape sequences") =
|
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 withEscapes: String = start + escapes.map { ean => ean.escape.makeString + ean.notEscape }
|
||||||
val removed: String = removeEscapeSequences(withEscapes)
|
val removed: String = removeEscapeSequences(withEscapes)
|
||||||
val original = start + escapes.map(_.notEscape)
|
val original = start + escapes.map(_.notEscape)
|
||||||
("Input string with escapes: '" + withEscapes + "'") |:
|
("Input string with escapes: '" + withEscapes + "'") |:
|
||||||
("Escapes removed '" + removed + "'") |:
|
("Escapes removed '" + removed + "'") |:
|
||||||
(original == removed)
|
(original == removed)
|
||||||
}
|
}
|
||||||
|
|
||||||
final case class EscapeAndNot(escape: EscapeSequence, notEscape: String)
|
final case class EscapeAndNot(escape: EscapeSequence, notEscape: String)
|
||||||
final case class EscapeSequence(content: String, terminator: Char)
|
final case class EscapeSequence(content: String, terminator: Char) {
|
||||||
{
|
assert(content.forall(c => !isEscapeTerminator(c)), "Escape sequence content contains an escape terminator: '" + content + "'")
|
||||||
assert( content.forall(c => !isEscapeTerminator(c) ), "Escape sequence content contains an escape terminator: '" + content + "'" )
|
assert(isEscapeTerminator(terminator))
|
||||||
assert( isEscapeTerminator(terminator) )
|
def makeString: String = ESC + content + terminator
|
||||||
def makeString: String = ESC + content + terminator
|
}
|
||||||
}
|
private[this] def noEscape(s: String): String = s.replace(ESC, ' ')
|
||||||
private[this] def noEscape(s: String): String = s.replace(ESC, ' ')
|
|
||||||
|
|
||||||
lazy val genEscapeSequence: Gen[EscapeSequence] = oneOf(genKnownSequence, genArbitraryEscapeSequence)
|
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 genEscapePairs: Gen[List[EscapeAndNot]] = listOf(genEscapePair)
|
||||||
|
|
||||||
lazy val genArbitraryEscapeSequence: Gen[EscapeSequence] =
|
lazy val genArbitraryEscapeSequence: Gen[EscapeSequence] =
|
||||||
for(content <- genWithoutTerminator; term <- genTerminator) yield
|
for (content <- genWithoutTerminator; term <- genTerminator) yield new EscapeSequence(content, term)
|
||||||
new EscapeSequence(content, term)
|
|
||||||
|
|
||||||
lazy val genKnownSequence: Gen[EscapeSequence] =
|
lazy val genKnownSequence: Gen[EscapeSequence] =
|
||||||
oneOf((misc ++ setGraphicsMode ++ setMode ++ resetMode).map(toEscapeSequence))
|
oneOf((misc ++ setGraphicsMode ++ setMode ++ resetMode).map(toEscapeSequence))
|
||||||
|
|
||||||
def toEscapeSequence(s: String): EscapeSequence = EscapeSequence(s.init, s.last)
|
def toEscapeSequence(s: String): EscapeSequence = EscapeSequence(s.init, s.last)
|
||||||
|
|
||||||
lazy val misc = Seq("14;23H", "5;3f", "2A", "94B", "19C", "85D", "s", "u", "2J", "K")
|
lazy val misc = Seq("14;23H", "5;3f", "2A", "94B", "19C", "85D", "s", "u", "2J", "K")
|
||||||
|
|
||||||
lazy val setGraphicsMode: Seq[String] =
|
lazy val setGraphicsMode: Seq[String] =
|
||||||
for(txt <- 0 to 8; fg <- 30 to 37; bg <- 40 to 47) yield
|
for (txt <- 0 to 8; fg <- 30 to 37; bg <- 40 to 47) yield txt.toString + ";" + fg.toString + ";" + bg.toString + "m"
|
||||||
txt.toString + ";" + fg.toString + ";" + bg.toString + "m"
|
|
||||||
|
|
||||||
lazy val resetMode = setModeLike('I')
|
lazy val resetMode = setModeLike('I')
|
||||||
lazy val setMode = setModeLike('h')
|
lazy val setMode = setModeLike('h')
|
||||||
def setModeLike(term: Char): Seq[String] = (0 to 19).map(i => "=" + i.toString + term)
|
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 genTerminator: Gen[Char] = Gen.choose('@', '~')
|
||||||
lazy val genWithoutEscape: Gen[String] = genRawString.map(noEscape)
|
lazy val genWithoutEscape: Gen[String] = genRawString.map(noEscape)
|
||||||
|
|
||||||
def genWithRandomEscapes: Gen[String] =
|
def genWithRandomEscapes: Gen[String] =
|
||||||
for(ls <- listOf(genRawString); end <- genRawString) yield
|
for (ls <- listOf(genRawString); end <- genRawString) yield ls.mkString("", ESC.toString, ESC.toString + end)
|
||||||
ls.mkString("", ESC.toString, ESC.toString + end)
|
|
||||||
|
|
||||||
private def genRawString = Arbitrary.arbString.arbitrary
|
private def genRawString = Arbitrary.arbString.arbitrary
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,157 +4,147 @@
|
||||||
package sbt
|
package sbt
|
||||||
|
|
||||||
import org.scalacheck._
|
import org.scalacheck._
|
||||||
import Arbitrary.{arbitrary => arb, _}
|
import Arbitrary.{ arbitrary => arb, _ }
|
||||||
import Gen.{listOfN, oneOf}
|
import Gen.{ listOfN, oneOf }
|
||||||
import Prop._
|
import Prop._
|
||||||
|
|
||||||
import java.io.Writer
|
import java.io.Writer
|
||||||
|
|
||||||
object LogWriterTest extends Properties("Log Writer")
|
object LogWriterTest extends Properties("Log Writer") {
|
||||||
{
|
final val MaxLines = 100
|
||||||
final val MaxLines = 100
|
final val MaxSegments = 10
|
||||||
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. */
|
* Each line, determined by the specified newline separator, must be logged at the correct logging level. */
|
||||||
property("properly logged") = forAll { (output: Output, newLine: NewLine) =>
|
property("properly logged") = forAll { (output: Output, newLine: NewLine) =>
|
||||||
import output.{lines, level}
|
import output.{ lines, level }
|
||||||
val log = new RecordingLogger
|
val log = new RecordingLogger
|
||||||
val writer = new LoggerWriter(log, Some(level), newLine.str)
|
val writer = new LoggerWriter(log, Some(level), newLine.str)
|
||||||
logLines(writer, lines, newLine.str)
|
logLines(writer, lines, newLine.str)
|
||||||
val events = log.getEvents
|
val events = log.getEvents
|
||||||
("Recorded:\n" + events.map(show).mkString("\n")) |:
|
("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
|
||||||
def show(event: LogEvent): String =
|
* and non-printable characters should be escaped
|
||||||
event match
|
*/
|
||||||
{
|
def show(event: LogEvent): String =
|
||||||
case l: Log => "Log('" + Escape(l.msg) + "', " + l.level + ")"
|
event match {
|
||||||
case _ => "Not Log"
|
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)*/
|
* Writes the given lines to the Writer. `lines` is taken to be a list of lines, which are
|
||||||
def logLines(writer: Writer, lines: List[List[ToLog]], newLine: String)
|
* represented as separately written segments (ToLog instances). ToLog.`byCharacter`
|
||||||
{
|
* indicates whether to write the segment by character (true) or all at once (false)
|
||||||
for(line <- lines; section <- line)
|
*/
|
||||||
{
|
def logLines(writer: Writer, lines: List[List[ToLog]], newLine: String) {
|
||||||
val content = section.content
|
for (line <- lines; section <- line) {
|
||||||
val normalized = Escape.newline(content, newLine)
|
val content = section.content
|
||||||
if(section.byCharacter)
|
val normalized = Escape.newline(content, newLine)
|
||||||
normalized.foreach { c => writer.write(c.toInt) }
|
if (section.byCharacter)
|
||||||
else
|
normalized.foreach { c => writer.write(c.toInt) }
|
||||||
writer.write(normalized)
|
else
|
||||||
}
|
writer.write(normalized)
|
||||||
writer.flush()
|
}
|
||||||
}
|
writer.flush()
|
||||||
|
}
|
||||||
|
|
||||||
/** Converts the given lines in segments to lines as Strings for checking the results of the test.*/
|
/** 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] =
|
def toLines(lines: List[List[ToLog]]): List[String] =
|
||||||
lines.map(_.map(_.contentOnly).mkString)
|
lines.map(_.map(_.contentOnly).mkString)
|
||||||
/** Checks that the expected `lines` were recorded as `events` at level `Lvl`.*/
|
/** Checks that the expected `lines` were recorded as `events` at level `Lvl`.*/
|
||||||
def check(lines: List[String], events: List[LogEvent], Lvl: Level.Value): Boolean =
|
def check(lines: List[String], events: List[LogEvent], Lvl: Level.Value): Boolean =
|
||||||
(lines zip events) forall {
|
(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
|
case _ => false
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The following are implicit generators to build up a write sequence.
|
/* The following are implicit generators to build up a write sequence.
|
||||||
* ToLog represents a written segment. NewLine represents one of the possible
|
* ToLog represents a written segment. NewLine represents one of the possible
|
||||||
* newline separators. A List[ToLog] represents a full line and always includes a
|
* 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
|
* final ToLog with a trailing '\n'. Newline characters are otherwise not present in
|
||||||
* the `content` of a ToLog instance.*/
|
* the `content` of a ToLog instance.*/
|
||||||
|
|
||||||
implicit lazy val arbOut: Arbitrary[Output] = Arbitrary(genOutput)
|
implicit lazy val arbOut: Arbitrary[Output] = Arbitrary(genOutput)
|
||||||
implicit lazy val arbLog: Arbitrary[ToLog] = Arbitrary(genLog)
|
implicit lazy val arbLog: Arbitrary[ToLog] = Arbitrary(genLog)
|
||||||
implicit lazy val arbLine: Arbitrary[List[ToLog]] = Arbitrary(genLine)
|
implicit lazy val arbLine: Arbitrary[List[ToLog]] = Arbitrary(genLine)
|
||||||
implicit lazy val arbNewLine: Arbitrary[NewLine] = Arbitrary(genNewLine)
|
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]] =
|
implicit def genLine(implicit logG: Gen[ToLog]): Gen[List[ToLog]] =
|
||||||
for(l <- listOf[ToLog](MaxSegments); last <- logG) yield
|
for (l <- listOf[ToLog](MaxSegments); last <- logG) yield (addNewline(last) :: l.filter(!_.content.isEmpty)).reverse
|
||||||
(addNewline(last) :: l.filter(!_.content.isEmpty)).reverse
|
|
||||||
|
|
||||||
implicit def genLog(implicit content: Arbitrary[String], byChar: Arbitrary[Boolean]): Gen[ToLog] =
|
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)
|
||||||
assert(c != null)
|
new ToLog(removeNewlines(c), by)
|
||||||
new ToLog(removeNewlines(c), by)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
implicit lazy val genNewLine: Gen[NewLine] =
|
implicit lazy val genNewLine: Gen[NewLine] =
|
||||||
for(str <- oneOf("\n", "\r", "\r\n")) yield
|
for (str <- oneOf("\n", "\r", "\r\n")) yield new NewLine(str)
|
||||||
new NewLine(str)
|
|
||||||
|
|
||||||
implicit lazy val genLevel: Gen[Level.Value] =
|
implicit lazy val genLevel: Gen[Level.Value] =
|
||||||
oneOf(Level.values.toSeq)
|
oneOf(Level.values.toSeq)
|
||||||
|
|
||||||
implicit lazy val genOutput: Gen[Output] =
|
implicit lazy val genOutput: Gen[Output] =
|
||||||
for(ls <- listOf[List[ToLog]](MaxLines); lv <- genLevel) yield
|
for (ls <- listOf[List[ToLog]](MaxLines); lv <- genLevel) yield new Output(ls, lv)
|
||||||
new Output(ls, lv)
|
|
||||||
|
|
||||||
def removeNewlines(s: String) = s.replaceAll("""[\n\r]+""", "")
|
def removeNewlines(s: String) = s.replaceAll("""[\n\r]+""", "")
|
||||||
def addNewline(l: ToLog): ToLog =
|
def addNewline(l: ToLog): ToLog =
|
||||||
new ToLog(l.content + "\n", l.byCharacter) // \n will be replaced by a random line terminator for all lines
|
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]] =
|
def listOf[T](max: Int)(implicit content: Arbitrary[T]): Gen[List[T]] =
|
||||||
Gen.choose(0, max) flatMap { sz => listOfN(sz, content.arbitrary) }
|
Gen.choose(0, max) flatMap { sz => listOfN(sz, content.arbitrary) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Helper classes*/
|
/* 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 =
|
||||||
override def toString =
|
"Level: " + level + "\n" + lines.map(_.mkString).mkString("\n")
|
||||||
"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)
|
||||||
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, "")
|
||||||
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.*/
|
/** 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.*/
|
||||||
/** Escapes characters with code less than 20 by printing them as unicode escapes.*/
|
def apply(s: String): String =
|
||||||
def apply(s: String): String =
|
{
|
||||||
{
|
val builder = new StringBuilder(s.length)
|
||||||
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)
|
||||||
def escaped = pad(c.toInt.toHexString.toUpperCase, 4, '0')
|
}
|
||||||
if(c < 20) builder.append("\\u").append(escaped) else builder.append(c)
|
builder.toString
|
||||||
}
|
}
|
||||||
builder.toString
|
def pad(s: String, minLength: Int, extra: Char) =
|
||||||
}
|
{
|
||||||
def pad(s: String, minLength: Int, extra: Char) =
|
val diff = minLength - s.length
|
||||||
{
|
if (diff <= 0) s else List.make(diff, extra).mkString("", "", s)
|
||||||
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 =
|
||||||
/** Replaces a \n character at the end of a string `s` with `nl`.*/
|
if (s.endsWith("\n")) s.substring(0, s.length - 1) + nl else s
|
||||||
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.*/
|
/** Records logging events for later retrieval.*/
|
||||||
final class RecordingLogger extends BasicLogger
|
final class RecordingLogger extends BasicLogger {
|
||||||
{
|
private var events: List[LogEvent] = Nil
|
||||||
private var events: List[LogEvent] = Nil
|
|
||||||
|
|
||||||
def getEvents = events.reverse
|
def getEvents = events.reverse
|
||||||
|
|
||||||
override def ansiCodesSupported = true
|
override def ansiCodesSupported = true
|
||||||
def trace(t: => Throwable) { events ::= new Trace(t) }
|
def trace(t: => Throwable) { events ::= new Trace(t) }
|
||||||
def log(level: Level.Value, message: => String) { events ::= new Log(level, message) }
|
def log(level: Level.Value, message: => String) { events ::= new Log(level, message) }
|
||||||
def success(message: => String) { events ::= new Success(message) }
|
def success(message: => String) { events ::= new Success(message) }
|
||||||
def logAll(es: Seq[LogEvent]) { events :::= es.toList }
|
def logAll(es: Seq[LogEvent]) { events :::= es.toList }
|
||||||
def control(event: ControlEvent.Value, message: => String) { events ::= new ControlEvent(event, message) }
|
def control(event: ControlEvent.Value, message: => String) { events ::= new ControlEvent(event, message) }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
package sbt
|
package sbt
|
||||||
|
|
||||||
object TestLogger
|
object TestLogger {
|
||||||
{
|
def apply[T](f: Logger => T): T =
|
||||||
def apply[T](f: Logger => T): T =
|
{
|
||||||
{
|
val log = new BufferedLogger(ConsoleLogger())
|
||||||
val log = new BufferedLogger(ConsoleLogger())
|
log.setLevel(Level.Debug)
|
||||||
log.setLevel(Level.Debug)
|
log.bufferQuietly(f(log))
|
||||||
log.bufferQuietly(f(log))
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,117 +1,115 @@
|
||||||
package sbt
|
package sbt
|
||||||
package logic
|
package logic
|
||||||
|
|
||||||
import org.scalacheck._
|
import org.scalacheck._
|
||||||
import Prop.secure
|
import Prop.secure
|
||||||
import Logic.{LogicException, Matched}
|
import Logic.{ LogicException, Matched }
|
||||||
|
|
||||||
object LogicTest extends Properties("Logic")
|
object LogicTest extends Properties("Logic") {
|
||||||
{
|
import TestClauses._
|
||||||
import TestClauses._
|
|
||||||
|
|
||||||
property("Handles trivial resolution.") = secure( expect(trivial, Set(A) ) )
|
property("Handles trivial resolution.") = secure(expect(trivial, Set(A)))
|
||||||
property("Handles less trivial resolution.") = secure( expect(lessTrivial, Set(B,A,D)) )
|
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 cycles without negation") = secure(expect(cycles, Set(F, A, B)))
|
||||||
property("Handles basic exclusion.") = secure( expect(excludedPos, Set()) )
|
property("Handles basic exclusion.") = secure(expect(excludedPos, Set()))
|
||||||
property("Handles exclusion of head proved by negation.") = secure( expect(excludedNeg, 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
|
// 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(
|
property("Detects cyclic negation") = secure(
|
||||||
Logic.reduceAll(badClauses, Set()) match {
|
Logic.reduceAll(badClauses, Set()) match {
|
||||||
case Right(res) => false
|
case Right(res) => false
|
||||||
case Left(err: Logic.CyclicNegation) => true
|
case Left(err: Logic.CyclicNegation) => true
|
||||||
case Left(err) => error(s"Expected cyclic error, got: $err")
|
case Left(err) => error(s"Expected cyclic error, got: $err")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
def expect(result: Either[LogicException, Matched], expected: Set[Atom]) = result match {
|
def expect(result: Either[LogicException, Matched], expected: Set[Atom]) = result match {
|
||||||
case Left(err) => false
|
case Left(err) => false
|
||||||
case Right(res) =>
|
case Right(res) =>
|
||||||
val actual = res.provenSet
|
val actual = res.provenSet
|
||||||
(actual == expected) || error(s"Expected to prove $expected, but actually proved $actual")
|
(actual == expected) || error(s"Expected to prove $expected, but actually proved $actual")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object TestClauses
|
object TestClauses {
|
||||||
{
|
|
||||||
|
|
||||||
val A = Atom("A")
|
val A = Atom("A")
|
||||||
val B = Atom("B")
|
val B = Atom("B")
|
||||||
val C = Atom("C")
|
val C = Atom("C")
|
||||||
val D = Atom("D")
|
val D = Atom("D")
|
||||||
val E = Atom("E")
|
val E = Atom("E")
|
||||||
val F = Atom("F")
|
val F = Atom("F")
|
||||||
val G = Atom("G")
|
val G = Atom("G")
|
||||||
|
|
||||||
val clauses =
|
val clauses =
|
||||||
A.proves(B) ::
|
A.proves(B) ::
|
||||||
A.proves(F) ::
|
A.proves(F) ::
|
||||||
B.proves(F) ::
|
B.proves(F) ::
|
||||||
F.proves(A) ::
|
F.proves(A) ::
|
||||||
(!C).proves(F) ::
|
(!C).proves(F) ::
|
||||||
D.proves(C) ::
|
D.proves(C) ::
|
||||||
C.proves(D) ::
|
C.proves(D) ::
|
||||||
Nil
|
Nil
|
||||||
|
|
||||||
val cycles = Logic.reduceAll(clauses, Set())
|
val cycles = Logic.reduceAll(clauses, Set())
|
||||||
|
|
||||||
val badClauses =
|
val badClauses =
|
||||||
A.proves(D) ::
|
A.proves(D) ::
|
||||||
clauses
|
clauses
|
||||||
|
|
||||||
val excludedNeg = {
|
val excludedNeg = {
|
||||||
val cs =
|
val cs =
|
||||||
(!A).proves(B) ::
|
(!A).proves(B) ::
|
||||||
Nil
|
Nil
|
||||||
val init =
|
val init =
|
||||||
(!A) ::
|
(!A) ::
|
||||||
(!B) ::
|
(!B) ::
|
||||||
Nil
|
Nil
|
||||||
Logic.reduceAll(cs, init.toSet)
|
Logic.reduceAll(cs, init.toSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
val excludedPos = {
|
val excludedPos = {
|
||||||
val cs =
|
val cs =
|
||||||
A.proves(B) ::
|
A.proves(B) ::
|
||||||
Nil
|
Nil
|
||||||
val init =
|
val init =
|
||||||
A ::
|
A ::
|
||||||
(!B) ::
|
(!B) ::
|
||||||
Nil
|
Nil
|
||||||
Logic.reduceAll(cs, init.toSet)
|
Logic.reduceAll(cs, init.toSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
val trivial = {
|
val trivial = {
|
||||||
val cs =
|
val cs =
|
||||||
Formula.True.proves(A) ::
|
Formula.True.proves(A) ::
|
||||||
Nil
|
Nil
|
||||||
Logic.reduceAll(cs, Set.empty)
|
Logic.reduceAll(cs, Set.empty)
|
||||||
}
|
}
|
||||||
|
|
||||||
val lessTrivial = {
|
val lessTrivial = {
|
||||||
val cs =
|
val cs =
|
||||||
Formula.True.proves(A) ::
|
Formula.True.proves(A) ::
|
||||||
Formula.True.proves(B) ::
|
Formula.True.proves(B) ::
|
||||||
(A && B && (!C)).proves(D) ::
|
(A && B && (!C)).proves(D) ::
|
||||||
Nil
|
Nil
|
||||||
Logic.reduceAll(cs, Set())
|
Logic.reduceAll(cs, Set())
|
||||||
}
|
}
|
||||||
|
|
||||||
val ordering = {
|
val ordering = {
|
||||||
val cs =
|
val cs =
|
||||||
E.proves(F) ::
|
E.proves(F) ::
|
||||||
(C && !D).proves(E) ::
|
(C && !D).proves(E) ::
|
||||||
(A && B).proves(C) ::
|
(A && B).proves(C) ::
|
||||||
Nil
|
Nil
|
||||||
Logic.reduceAll(cs, Set(A,B))
|
Logic.reduceAll(cs, Set(A, B))
|
||||||
}
|
}
|
||||||
|
|
||||||
def all {
|
def all {
|
||||||
println(s"Cycles: $cycles")
|
println(s"Cycles: $cycles")
|
||||||
println(s"xNeg: $excludedNeg")
|
println(s"xNeg: $excludedNeg")
|
||||||
println(s"xPos: $excludedPos")
|
println(s"xPos: $excludedPos")
|
||||||
println(s"trivial: $trivial")
|
println(s"trivial: $trivial")
|
||||||
println(s"lessTrivial: $lessTrivial")
|
println(s"lessTrivial: $lessTrivial")
|
||||||
println(s"ordering: $ordering")
|
println(s"ordering: $ordering")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,133 +1,131 @@
|
||||||
package sbt
|
package sbt
|
||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import org.scalacheck.{Arbitrary, Gen, Prop, Properties}
|
import org.scalacheck.{ Arbitrary, Gen, Prop, Properties }
|
||||||
import Prop._
|
import Prop._
|
||||||
|
|
||||||
import Process._
|
import Process._
|
||||||
|
|
||||||
object ProcessSpecification extends Properties("Process I/O")
|
object ProcessSpecification extends Properties("Process I/O") {
|
||||||
{
|
implicit val exitCodeArb: Arbitrary[Array[Byte]] = Arbitrary(
|
||||||
implicit val exitCodeArb: Arbitrary[Array[Byte]] = Arbitrary(
|
for (
|
||||||
for(size <- Gen.choose(0, 10);
|
size <- Gen.choose(0, 10);
|
||||||
l <- Gen.listOfN[Byte](size, Arbitrary.arbByte.arbitrary))
|
l <- Gen.listOfN[Byte](size, Arbitrary.arbByte.arbitrary)
|
||||||
yield
|
) yield l.toArray
|
||||||
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)(_ #|| _)(_ || _))
|
property("#|| correct") = forAll( (exitCodes: Array[Byte]) => checkBinary(exitCodes)(_ #|| _)(_ || _))
|
||||||
property("### correct") = forAll( (exitCodes: Array[Byte]) => checkBinary(exitCodes)(_ ### _)( (x,latest) => latest))*/
|
property("### correct") = forAll( (exitCodes: Array[Byte]) => checkBinary(exitCodes)(_ ### _)( (x,latest) => latest))*/
|
||||||
property("Pipe to output file") = forAll( (data: Array[Byte]) => checkFileOut(data))
|
property("Pipe to output file") = forAll((data: Array[Byte]) => checkFileOut(data))
|
||||||
property("Pipe from input file") = forAll( (data: Array[Byte]) => checkFileIn(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") = 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 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 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 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) =
|
private def checkBinary(codes: Array[Byte])(reduceProcesses: (ProcessBuilder, ProcessBuilder) => ProcessBuilder)(reduceExit: (Boolean, Boolean) => Boolean) =
|
||||||
{
|
{
|
||||||
(codes.length > 1) ==>
|
(codes.length > 1) ==>
|
||||||
{
|
{
|
||||||
val unsignedCodes = codes.map(unsigned)
|
val unsignedCodes = codes.map(unsigned)
|
||||||
val exitCode = unsignedCodes.map(code => Process(process("sbt.exit " + code))).reduceLeft(reduceProcesses) !
|
val exitCode = unsignedCodes.map(code => Process(process("sbt.exit " + code))).reduceLeft(reduceProcesses) !
|
||||||
val expectedExitCode = unsignedCodes.map(toBoolean).reduceLeft(reduceExit)
|
val expectedExitCode = unsignedCodes.map(toBoolean).reduceLeft(reduceExit)
|
||||||
toBoolean(exitCode) == expectedExitCode
|
toBoolean(exitCode) == expectedExitCode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private def toBoolean(exitCode: Int) = exitCode == 0
|
private def toBoolean(exitCode: Int) = exitCode == 0
|
||||||
private def checkExit(code: Byte) =
|
private def checkExit(code: Byte) =
|
||||||
{
|
{
|
||||||
val exitCode = unsigned(code)
|
val exitCode = unsigned(code)
|
||||||
(process("sbt.exit " + exitCode) !) == exitCode
|
(process("sbt.exit " + exitCode) !) == exitCode
|
||||||
}
|
}
|
||||||
private def checkFileOut(data: Array[Byte]) =
|
private def checkFileOut(data: Array[Byte]) =
|
||||||
{
|
{
|
||||||
withData(data) { (temporaryFile, temporaryFile2) =>
|
withData(data) { (temporaryFile, temporaryFile2) =>
|
||||||
val catCommand = process("sbt.cat " + temporaryFile.getAbsolutePath)
|
val catCommand = process("sbt.cat " + temporaryFile.getAbsolutePath)
|
||||||
catCommand #> temporaryFile2
|
catCommand #> temporaryFile2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private def checkFileIn(data: Array[Byte]) =
|
private def checkFileIn(data: Array[Byte]) =
|
||||||
{
|
{
|
||||||
withData(data) { (temporaryFile, temporaryFile2) =>
|
withData(data) { (temporaryFile, temporaryFile2) =>
|
||||||
val catCommand = process("sbt.cat")
|
val catCommand = process("sbt.cat")
|
||||||
temporaryFile #> catCommand #> temporaryFile2
|
temporaryFile #> catCommand #> temporaryFile2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private def checkPipe(data: Array[Byte]) =
|
private def checkPipe(data: Array[Byte]) =
|
||||||
{
|
{
|
||||||
withData(data) { (temporaryFile, temporaryFile2) =>
|
withData(data) { (temporaryFile, temporaryFile2) =>
|
||||||
val catCommand = process("sbt.cat")
|
val catCommand = process("sbt.cat")
|
||||||
temporaryFile #> catCommand #| catCommand #> temporaryFile2
|
temporaryFile #> catCommand #| catCommand #> temporaryFile2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private def checkPipeExit(data: Array[Byte], code: Byte) =
|
private def checkPipeExit(data: Array[Byte], code: Byte) =
|
||||||
withTempFiles { (a,b) =>
|
withTempFiles { (a, b) =>
|
||||||
IO.write(a, data)
|
IO.write(a, data)
|
||||||
val catCommand = process("sbt.cat")
|
val catCommand = process("sbt.cat")
|
||||||
val exitCommand = process(s"sbt.exit $code")
|
val exitCommand = process(s"sbt.exit $code")
|
||||||
val exit = (a #> exitCommand #| catCommand #> b).!
|
val exit = (a #> exitCommand #| catCommand #> b).!
|
||||||
(s"Exit code: $exit") |:
|
(s"Exit code: $exit") |:
|
||||||
(s"Output file length: ${b.length}") |:
|
(s"Output file length: ${b.length}") |:
|
||||||
(exit == 0) &&
|
(exit == 0) &&
|
||||||
(b.length == 0)
|
(b.length == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def checkFileOutExit(data: Array[Byte], exitCode: Byte) =
|
private def checkFileOutExit(data: Array[Byte], exitCode: Byte) =
|
||||||
withTempFiles { (a,b) =>
|
withTempFiles { (a, b) =>
|
||||||
IO.write(a, data)
|
IO.write(a, data)
|
||||||
val code = unsigned(exitCode)
|
val code = unsigned(exitCode)
|
||||||
val command = process(s"sbt.exit $code")
|
val command = process(s"sbt.exit $code")
|
||||||
val exit = (a #> command #> b).!
|
val exit = (a #> command #> b).!
|
||||||
(s"Exit code: $exit, expected: $code") |:
|
(s"Exit code: $exit, expected: $code") |:
|
||||||
(s"Output file length: ${b.length}") |:
|
(s"Output file length: ${b.length}") |:
|
||||||
(exit == code) &&
|
(exit == code) &&
|
||||||
(b.length == 0)
|
(b.length == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def checkFileInExit(data: Array[Byte], exitCode: Byte) =
|
private def checkFileInExit(data: Array[Byte], exitCode: Byte) =
|
||||||
withTempFiles { (a,b) =>
|
withTempFiles { (a, b) =>
|
||||||
IO.write(a, data)
|
IO.write(a, data)
|
||||||
val code = unsigned(exitCode)
|
val code = unsigned(exitCode)
|
||||||
val command = process(s"sbt.exit $code")
|
val command = process(s"sbt.exit $code")
|
||||||
val exit = (a #> command).!
|
val exit = (a #> command).!
|
||||||
(s"Exit code: $exit, expected: $code") |:
|
(s"Exit code: $exit, expected: $code") |:
|
||||||
(exit == code)
|
(exit == code)
|
||||||
}
|
}
|
||||||
|
|
||||||
private def temp() = File.createTempFile("sbt", "")
|
private def temp() = File.createTempFile("sbt", "")
|
||||||
private def withData(data: Array[Byte])(f: (File, File) => ProcessBuilder) =
|
private def withData(data: Array[Byte])(f: (File, File) => ProcessBuilder) =
|
||||||
withTempFiles { (a, b) =>
|
withTempFiles { (a, b) =>
|
||||||
IO.write(a, data)
|
IO.write(a, data)
|
||||||
val process = f(a, b)
|
val process = f(a, b)
|
||||||
( process ! ) == 0 && sameFiles(a, b)
|
(process !) == 0 && sameFiles(a, b)
|
||||||
}
|
}
|
||||||
private def sameFiles(a: File, b: File) =
|
private def sameFiles(a: File, b: File) =
|
||||||
IO.readBytes(a) sameElements IO.readBytes(b)
|
IO.readBytes(a) sameElements IO.readBytes(b)
|
||||||
|
|
||||||
private def withTempFiles[T](f: (File, File) => T): T =
|
private def withTempFiles[T](f: (File, File) => T): T =
|
||||||
{
|
{
|
||||||
val temporaryFile1 = temp()
|
val temporaryFile1 = temp()
|
||||||
val temporaryFile2 = temp()
|
val temporaryFile2 = temp()
|
||||||
try f(temporaryFile1, temporaryFile2)
|
try f(temporaryFile1, temporaryFile2)
|
||||||
finally
|
finally {
|
||||||
{
|
temporaryFile1.delete()
|
||||||
temporaryFile1.delete()
|
temporaryFile2.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 unsigned(b: Byte): Int = unsigned(b: Int)
|
private def process(command: String) =
|
||||||
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 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)
|
val thisClasspath = List(getSource[Product], getSource[IO.type], getSource[SourceTag]).mkString(File.pathSeparator)
|
||||||
"java -cp " + thisClasspath + " " + command
|
"java -cp " + thisClasspath + " " + command
|
||||||
}
|
}
|
||||||
private def getSource[T : Manifest]: String =
|
private def getSource[T: Manifest]: String =
|
||||||
IO.classLocationFile[T].getAbsolutePath
|
IO.classLocationFile[T].getAbsolutePath
|
||||||
}
|
}
|
||||||
private trait SourceTag
|
private trait SourceTag
|
||||||
|
|
|
||||||
|
|
@ -1,56 +1,47 @@
|
||||||
package sbt
|
package sbt
|
||||||
|
|
||||||
import java.io.{File, FileNotFoundException, IOException}
|
import java.io.{ File, FileNotFoundException, IOException }
|
||||||
|
|
||||||
object exit
|
object exit {
|
||||||
{
|
def main(args: Array[String]) {
|
||||||
def main(args: Array[String])
|
System.exit(java.lang.Integer.parseInt(args(0)))
|
||||||
{
|
}
|
||||||
System.exit(java.lang.Integer.parseInt(args(0)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
object cat
|
object cat {
|
||||||
{
|
def main(args: Array[String]) {
|
||||||
def main(args: Array[String])
|
try {
|
||||||
{
|
if (args.length == 0)
|
||||||
try {
|
IO.transfer(System.in, System.out)
|
||||||
if(args.length == 0)
|
else
|
||||||
IO.transfer(System.in, System.out)
|
catFiles(args.toList)
|
||||||
else
|
System.exit(0)
|
||||||
catFiles(args.toList)
|
} catch {
|
||||||
System.exit(0)
|
case e =>
|
||||||
} catch {
|
e.printStackTrace()
|
||||||
case e =>
|
System.err.println("Error: " + e.toString)
|
||||||
e.printStackTrace()
|
System.exit(1)
|
||||||
System.err.println("Error: " + e.toString)
|
}
|
||||||
System.exit(1)
|
}
|
||||||
}
|
private def catFiles(filenames: List[String]): Option[String] =
|
||||||
}
|
{
|
||||||
private def catFiles(filenames: List[String]): Option[String] =
|
filenames match {
|
||||||
{
|
case head :: tail =>
|
||||||
filenames match
|
val file = new File(head)
|
||||||
{
|
if (file.isDirectory)
|
||||||
case head :: tail =>
|
throw new IOException("Is directory: " + file)
|
||||||
val file = new File(head)
|
else if (file.exists) {
|
||||||
if(file.isDirectory)
|
Using.fileInputStream(file) { stream =>
|
||||||
throw new IOException("Is directory: " + file)
|
IO.transfer(stream, System.out)
|
||||||
else if(file.exists)
|
}
|
||||||
{
|
catFiles(tail)
|
||||||
Using.fileInputStream(file) { stream =>
|
} else
|
||||||
IO.transfer(stream, System.out)
|
throw new FileNotFoundException("No such file or directory: " + file)
|
||||||
}
|
case Nil => None
|
||||||
catFiles(tail)
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
throw new FileNotFoundException("No such file or directory: " + file)
|
|
||||||
case Nil => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
object echo
|
object echo {
|
||||||
{
|
def main(args: Array[String]) {
|
||||||
def main(args: Array[String])
|
System.out.println(args.mkString(" "))
|
||||||
{
|
}
|
||||||
System.out.println(args.mkString(" "))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -6,79 +6,79 @@ package sbt
|
||||||
import org.scalacheck._
|
import org.scalacheck._
|
||||||
import Prop._
|
import Prop._
|
||||||
|
|
||||||
object RelationTest extends Properties("Relation")
|
object RelationTest extends Properties("Relation") {
|
||||||
{
|
property("Added entry check") = forAll { (pairs: List[(Int, Double)]) =>
|
||||||
property("Added entry check") = forAll { (pairs: List[(Int, Double)]) =>
|
val r = Relation.empty[Int, Double] ++ pairs
|
||||||
val r = Relation.empty[Int, Double] ++ pairs
|
check(r, pairs)
|
||||||
check(r, pairs)
|
}
|
||||||
}
|
def check(r: Relation[Int, Double], pairs: Seq[(Int, Double)]) =
|
||||||
def check(r: Relation[Int, Double], pairs: Seq[(Int, Double)]) =
|
{
|
||||||
{
|
val _1s = pairs.map(_._1).toSet
|
||||||
val _1s = pairs.map(_._1).toSet
|
val _2s = pairs.map(_._2).toSet
|
||||||
val _2s = pairs.map(_._2).toSet
|
|
||||||
|
|
||||||
r._1s == _1s && r.forwardMap.keySet == _1s &&
|
r._1s == _1s && r.forwardMap.keySet == _1s &&
|
||||||
r._2s == _2s && r.reverseMap.keySet == _2s &&
|
r._2s == _2s && r.reverseMap.keySet == _2s &&
|
||||||
pairs.forall { case (a, b) =>
|
pairs.forall {
|
||||||
(r.forward(a) contains b) &&
|
case (a, b) =>
|
||||||
(r.reverse(b) contains a) &&
|
(r.forward(a) contains b) &&
|
||||||
(r.forwardMap(a) contains b) &&
|
(r.reverse(b) contains a) &&
|
||||||
(r.reverseMap(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)]) =>
|
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 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 removeCoarse = removeFine.map(_._1)
|
||||||
val r = added -- removeCoarse
|
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 =>
|
all(removeCoarse) { rem =>
|
||||||
("_1s does not contain removed" |: (!r._1s.contains(rem)) ) &&
|
("_1s does not contain removed" |: (!r._1s.contains(rem))) &&
|
||||||
("Forward does not contain removed" |: r.forward(rem).isEmpty ) &&
|
("Forward does not contain removed" |: r.forward(rem).isEmpty) &&
|
||||||
("Forward map does not contain removed" |: !r.forwardMap.contains(rem) ) &&
|
("Forward map does not contain removed" |: !r.forwardMap.contains(rem)) &&
|
||||||
("Removed is not a value in reverse map" |: !r.reverseMap.values.toSet.contains(rem) )
|
("Removed is not a value in reverse map" |: !r.reverseMap.values.toSet.contains(rem))
|
||||||
} &&
|
} &&
|
||||||
all(removeFine) { case (a, b) =>
|
all(removeFine) {
|
||||||
("Forward does not contain removed" |: ( !r.forward(a).contains(b) ) ) &&
|
case (a, b) =>
|
||||||
("Reverse does not contain removed" |: ( !r.reverse(b).contains(a) ) ) &&
|
("Forward does not contain removed" |: (!r.forward(a).contains(b))) &&
|
||||||
("Forward map does not contain removed" |: ( notIn(r.forwardMap, a, b) ) ) &&
|
("Reverse does not contain removed" |: (!r.reverse(b).contains(a))) &&
|
||||||
("Reverse map does not contain removed" |: ( notIn(r.reverseMap, b, 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) =>
|
property("Groups correctly") = forAll { (entries: List[(Int, Double)], randomInt: Int) =>
|
||||||
val splitInto = math.abs(randomInt) % 10 + 1 // Split into 1-10 groups.
|
val splitInto = math.abs(randomInt) % 10 + 1 // Split into 1-10 groups.
|
||||||
val rel = Relation.empty[Int, Double] ++ entries
|
val rel = Relation.empty[Int, Double] ++ entries
|
||||||
val grouped = rel groupBy (_._1 % splitInto)
|
val grouped = rel groupBy (_._1 % splitInto)
|
||||||
all(grouped.toSeq) {
|
all(grouped.toSeq) {
|
||||||
case (k, rel_k) => rel_k._1s forall { _ % splitInto == k }
|
case (k, rel_k) => rel_k._1s forall { _ % splitInto == k }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property("Computes size correctly") = forAll { (entries: List[(Int, Double)]) =>
|
property("Computes size correctly") = forAll { (entries: List[(Int, Double)]) =>
|
||||||
val rel = Relation.empty[Int, Double] ++ entries
|
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
|
val computed = rel.size
|
||||||
"Expected size: %d. Computed size: %d.".format(expected, computed) |: expected == computed
|
"Expected size: %d. Computed size: %d.".format(expected, computed) |: expected == computed
|
||||||
}
|
}
|
||||||
|
|
||||||
def all[T](s: Seq[T])(p: T => Prop): Prop =
|
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]
|
||||||
lazy val e = Relation.empty[Int, Double]
|
|
||||||
|
|
||||||
property("Forward empty") = forAll { (i: Int) => e.forward(i).isEmpty }
|
property("Forward empty") = forAll { (i: Int) => e.forward(i).isEmpty }
|
||||||
property("Reverse empty") = forAll { (i: Double) => e.reverse(i).isEmpty }
|
property("Reverse empty") = forAll { (i: Double) => e.reverse(i).isEmpty }
|
||||||
property("Forward map empty") = e.forwardMap.isEmpty
|
property("Forward map empty") = e.forwardMap.isEmpty
|
||||||
property("Reverse map empty") = e.reverseMap.isEmpty
|
property("Reverse map empty") = e.reverseMap.isEmpty
|
||||||
property("_1 empty") = e._1s.isEmpty
|
property("_1 empty") = e._1s.isEmpty
|
||||||
property("_2 empty") = e._2s.isEmpty
|
property("_2 empty") = e._2s.isEmpty
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue