sbt/main/src/test/scala/ParseKey.scala

129 lines
4.9 KiB
Scala

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