Merge pull request #4002 from eed3si9n/wip/opt-delegation-test

add tests around scope delegation
This commit is contained in:
Dale Wijnand 2018-04-03 16:43:09 +01:00 committed by GitHub
commit d444b6b8ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 81 additions and 29 deletions

View File

@ -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) =>

View File

@ -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)
}