mirror of https://github.com/sbt/sbt.git
Merge pull request #4002 from eed3si9n/wip/opt-delegation-test
add tests around scope delegation
This commit is contained in:
commit
d444b6b8ae
|
|
@ -16,10 +16,10 @@ import Prop._
|
|||
import Gen._
|
||||
|
||||
object Delegates extends Properties("delegates") {
|
||||
property("generate non-empty configs") = forAll { (c: Seq[Configuration]) =>
|
||||
property("generate non-empty configs") = forAll { (c: Vector[Configuration]) =>
|
||||
c.nonEmpty
|
||||
}
|
||||
property("generate non-empty tasks") = forAll { (t: Seq[Taskk]) =>
|
||||
property("generate non-empty tasks") = forAll { (t: Vector[Taskk]) =>
|
||||
t.nonEmpty
|
||||
}
|
||||
|
||||
|
|
@ -46,6 +46,7 @@ object Delegates extends Properties("delegates") {
|
|||
global forall { _ == Zero }
|
||||
}
|
||||
}
|
||||
|
||||
property("Initial scope present with all combinations of Global axes") = allAxes(
|
||||
globalCombinations)
|
||||
|
||||
|
|
@ -54,12 +55,58 @@ object Delegates extends Properties("delegates") {
|
|||
ds.head == scope
|
||||
}
|
||||
}
|
||||
|
||||
property("global scope last") = forAll { (keys: Keys) =>
|
||||
allDelegates(keys) { (_, ds) =>
|
||||
ds.last == Scope.GlobalScope
|
||||
}
|
||||
}
|
||||
|
||||
property("Project axis delegates to BuildRef then Zero") = forAll { (keys: Keys) =>
|
||||
allDelegates(keys) { (key, ds) =>
|
||||
key.project match {
|
||||
case Zero => true // filtering out of testing
|
||||
case Select(ProjectRef(uri, _)) =>
|
||||
val buildScoped = key.copy(project = Select(BuildRef(uri)))
|
||||
val idxKey = ds.indexOf(key)
|
||||
val idxB = ds.indexOf(buildScoped)
|
||||
val z = key.copy(project = Zero)
|
||||
val idxZ = ds.indexOf(z)
|
||||
if (z == Scope.GlobalScope) true
|
||||
else {
|
||||
(s"idxKey = $idxKey; idxB = $idxB; idxZ = $idxZ") |:
|
||||
(idxKey < idxB) && (idxB < idxZ)
|
||||
}
|
||||
case Select(BuildRef(_)) =>
|
||||
ds.indexOf(key) < ds.indexOf(key.copy(project = Zero))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property("Config axis delegates to parent configuration") = forAll { (keys: Keys) =>
|
||||
allDelegates(keys) { (key, ds) =>
|
||||
key.config match {
|
||||
case Zero => true
|
||||
case Select(config) if key.project.isSelect =>
|
||||
val p = key.project.toOption.get
|
||||
val r = keys.env.resolve(p)
|
||||
val proj = keys.env.projectFor(r)
|
||||
val inh: Vector[ConfigKey] = keys.env.inheritConfig(r, config)
|
||||
val conf = proj.confMap(config.name)
|
||||
if (inh.isEmpty) true
|
||||
else {
|
||||
val idxKey = ds.indexOf(key)
|
||||
val parent = inh.head
|
||||
val a = key.copy(config = Select(parent))
|
||||
val idxA = ds.indexOf(a)
|
||||
(s"idxKey = $idxKey; a = $a; idxA = $idxA") |:
|
||||
idxKey < idxA
|
||||
}
|
||||
case _ => true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def allAxes(f: (Scope, Seq[Scope], Scope => ScopeAxis[_]) => Prop): Prop = forAll {
|
||||
(keys: Keys) =>
|
||||
allDelegates(keys) { (s, ds) =>
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ abstract class TestBuild {
|
|||
(taskAxes, zero.toSet, single.toSet, multi.toSet)
|
||||
}
|
||||
}
|
||||
final class Env(val builds: Seq[Build], val tasks: Seq[Taskk]) {
|
||||
final class Env(val builds: Vector[Build], val tasks: Vector[Taskk]) {
|
||||
override def toString =
|
||||
"Env:\n " + " Tasks:\n " + tasks.mkString("\n ") + "\n" + builds.mkString("\n ")
|
||||
val root = builds.head
|
||||
|
|
@ -129,20 +129,21 @@ abstract class TestBuild {
|
|||
def inheritConfig(ref: ResolvedReference, config: ConfigKey) =
|
||||
projectFor(ref).confMap(config.name).extendsConfigs map toConfigKey
|
||||
def inheritTask(task: AttributeKey[_]) = taskMap.get(task) match {
|
||||
case None => Nil; case Some(t) => t.delegates map getKey
|
||||
case None => Vector()
|
||||
case Some(t) => t.delegates.toVector map getKey
|
||||
}
|
||||
def inheritProject(ref: ProjectRef) = project(ref).delegates
|
||||
def inheritProject(ref: ProjectRef) = project(ref).delegates.toVector
|
||||
def resolve(ref: Reference) = Scope.resolveReference(root.uri, rootProject, ref)
|
||||
lazy val delegates: Scope => Seq[Scope] =
|
||||
Scope.delegates(
|
||||
allProjects,
|
||||
(_: Proj).configurations.map(toConfigKey),
|
||||
(_: Proj).configurations.toVector.map(toConfigKey),
|
||||
resolve,
|
||||
uri => buildMap(uri).root.id,
|
||||
inheritProject,
|
||||
inheritConfig,
|
||||
inheritTask,
|
||||
(ref, mp) => Nil
|
||||
(ref, mp) => Vector()
|
||||
)
|
||||
lazy val allFullScopes: Seq[Scope] =
|
||||
for {
|
||||
|
|
@ -262,13 +263,14 @@ abstract class TestBuild {
|
|||
implicit lazy val uriGen: Gen[URI] = for (sch <- idGen; ssp <- idGen; frag <- optIDGen)
|
||||
yield new URI(sch, ssp, frag.orNull)
|
||||
|
||||
implicit def envGen(implicit bGen: Gen[Build], tasks: Gen[Seq[Taskk]]): Gen[Env] =
|
||||
for (i <- MaxBuildsGen; bs <- listOfN(i, bGen); ts <- tasks) yield new Env(bs, ts)
|
||||
implicit def envGen(implicit bGen: Gen[Build], tasks: Gen[Vector[Taskk]]): Gen[Env] =
|
||||
for (i <- MaxBuildsGen; bs <- containerOfN[Vector, Build](i, bGen); ts <- tasks)
|
||||
yield new Env(bs, ts)
|
||||
implicit def buildGen(implicit uGen: Gen[URI], pGen: URI => Gen[Seq[Proj]]): Gen[Build] =
|
||||
for (u <- uGen; ps <- pGen(u)) yield new Build(u, ps)
|
||||
|
||||
def nGen[T](igen: Gen[Int])(implicit g: Gen[T]): Gen[List[T]] = igen flatMap { ig =>
|
||||
listOfN(ig, g)
|
||||
def nGen[T](igen: Gen[Int])(implicit g: Gen[T]): Gen[Vector[T]] = igen flatMap { ig =>
|
||||
containerOfN[Vector, T](ig, g)
|
||||
}
|
||||
|
||||
implicit def genProjects(build: URI)(implicit genID: Gen[String],
|
||||
|
|
@ -285,34 +287,37 @@ abstract class TestBuild {
|
|||
|
||||
def genConfigs(implicit genName: Gen[String],
|
||||
maxDeps: Gen[Int],
|
||||
count: Gen[Int]): Gen[Seq[Configuration]] =
|
||||
count: Gen[Int]): Gen[Vector[Configuration]] =
|
||||
genAcyclicDirect[Configuration, String](maxDeps, genName, count)(
|
||||
(key, deps) =>
|
||||
Configuration
|
||||
.of(key.capitalize, key)
|
||||
.withExtendsConfigs(deps.toVector))
|
||||
|
||||
def genTasks(implicit genName: Gen[String], maxDeps: Gen[Int], count: Gen[Int]): Gen[Seq[Taskk]] =
|
||||
def genTasks(implicit genName: Gen[String],
|
||||
maxDeps: Gen[Int],
|
||||
count: Gen[Int]): Gen[Vector[Taskk]] =
|
||||
genAcyclicDirect[Taskk, String](maxDeps, genName, count)((key, deps) =>
|
||||
new Taskk(AttributeKey[String](key), deps))
|
||||
|
||||
def genAcyclicDirect[A, T](maxDeps: Gen[Int], keyGen: Gen[T], max: Gen[Int])(
|
||||
make: (T, Seq[A]) => A): Gen[Seq[A]] =
|
||||
make: (T, Vector[A]) => A): Gen[Vector[A]] =
|
||||
genAcyclic[A, T](maxDeps, keyGen, max) { t =>
|
||||
Gen.const { deps =>
|
||||
make(t, deps)
|
||||
make(t, deps.toVector)
|
||||
}
|
||||
}
|
||||
|
||||
def genAcyclic[A, T](maxDeps: Gen[Int], keyGen: Gen[T], max: Gen[Int])(
|
||||
make: T => Gen[Seq[A] => A]): Gen[Seq[A]] =
|
||||
make: T => Gen[Vector[A] => A]): Gen[Vector[A]] =
|
||||
max flatMap { count =>
|
||||
listOfN(count, keyGen) flatMap { keys =>
|
||||
containerOfN[Vector, T](count, keyGen) flatMap { keys =>
|
||||
genAcyclic(maxDeps, keys.distinct)(make)
|
||||
}
|
||||
}
|
||||
def genAcyclic[A, T](maxDeps: Gen[Int], keys: List[T])(make: T => Gen[Seq[A] => A]): Gen[Seq[A]] =
|
||||
genAcyclic(maxDeps, keys, Nil) flatMap { pairs =>
|
||||
def genAcyclic[A, T](maxDeps: Gen[Int], keys: Vector[T])(
|
||||
make: T => Gen[Vector[A] => A]): Gen[Vector[A]] =
|
||||
genAcyclic(maxDeps, keys, Vector()) flatMap { pairs =>
|
||||
sequence(pairs.map { case (key, deps) => mapMake(key, deps, make) }) flatMap { inputs =>
|
||||
val made = new collection.mutable.HashMap[T, A]
|
||||
for ((key, deps, mk) <- inputs)
|
||||
|
|
@ -321,25 +326,25 @@ abstract class TestBuild {
|
|||
}
|
||||
}
|
||||
|
||||
def mapMake[A, T](key: T, deps: Seq[T], make: T => Gen[Seq[A] => A]): Gen[Inputs[A, T]] =
|
||||
make(key) map { (mk: Seq[A] => A) =>
|
||||
def mapMake[A, T](key: T, deps: Vector[T], make: T => Gen[Vector[A] => A]): Gen[Inputs[A, T]] =
|
||||
make(key) map { (mk: Vector[A] => A) =>
|
||||
(key, deps, mk)
|
||||
}
|
||||
|
||||
def genAcyclic[T](maxDeps: Gen[Int],
|
||||
names: List[T],
|
||||
acc: List[Gen[(T, Seq[T])]]): Gen[Seq[(T, Seq[T])]] =
|
||||
names: Vector[T],
|
||||
acc: Vector[Gen[(T, Vector[T])]]): Gen[Vector[(T, Vector[T])]] =
|
||||
names match {
|
||||
case Nil => sequence(acc)
|
||||
case x :: xs =>
|
||||
case Vector() => sequence(acc)
|
||||
case Vector(x, xs @ _*) =>
|
||||
val next = for (depCount <- maxDeps; d <- pick(depCount min xs.size, xs))
|
||||
yield (x, d.toList)
|
||||
genAcyclic(maxDeps, xs, next :: acc)
|
||||
yield (x, d.toVector)
|
||||
genAcyclic(maxDeps, xs.toVector, next +: acc)
|
||||
}
|
||||
def sequence[T](gs: Seq[Gen[T]]): Gen[Seq[T]] = Gen.parameterized { prms =>
|
||||
def sequence[T](gs: Vector[Gen[T]]): Gen[Vector[T]] = Gen.parameterized { prms =>
|
||||
delay(gs map { g =>
|
||||
g(prms, seed) getOrElse sys.error("failed generator")
|
||||
})
|
||||
}
|
||||
type Inputs[A, T] = (T, Seq[T], Seq[A] => A)
|
||||
type Inputs[A, T] = (T, Vector[T], Vector[A] => A)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue