mirror of https://github.com/sbt/sbt.git
Cleanup test/ParseKey
This commit is contained in:
parent
ca874d5d5f
commit
25988d2256
|
|
@ -8,166 +8,114 @@
|
|||
package sbt
|
||||
|
||||
import Def.{ displayFull, displayMasked, ScopedKey }
|
||||
import sbt.internal.{ TestBuild, Resolve }
|
||||
import TestBuild._
|
||||
import sbt.internal.util.complete._
|
||||
import sbt.internal.{ TestBuild, Resolve }, TestBuild._
|
||||
import sbt.internal.util.complete.Parser
|
||||
|
||||
import org.scalacheck._
|
||||
import Gen._
|
||||
import Prop._
|
||||
import Arbitrary.arbBool
|
||||
import org.scalacheck._, Arbitrary.arbitrary, Gen._, Prop._
|
||||
|
||||
/**
|
||||
* 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 => mask0 }
|
||||
|
||||
val hasZeroConfig = key.scope.config == Zero
|
||||
val mask = if (hasZeroConfig) mask0.copy(project = true) else mask0
|
||||
val expected = resolve(structure, key, mask)
|
||||
// Note that this explicitly displays the configuration axis set to Zero.
|
||||
// This is to disambiguate `proj/Zero/name`, which could render potentially
|
||||
// as `Zero/name`, but could be interpretted as `Zero/Zero/name`.
|
||||
val s = displayMasked(key, mask, hasZeroConfig)
|
||||
("Key: " + displayPedantic(key)) |:
|
||||
parseExpected(structure, s, 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)
|
||||
// skip when config axis is set to Zero
|
||||
val hasZeroConfig = key.scope.config == Zero
|
||||
|
||||
("Key: " + displayPedantic(key)) |:
|
||||
("Mask: " + mask) |:
|
||||
("Current: " + structure.current) |:
|
||||
parse(structure, string) {
|
||||
case Left(_) => false
|
||||
case Right(_) if hasZeroConfig => true
|
||||
case Right(sk) => sk.scope.project == Select(structure.current)
|
||||
}
|
||||
}
|
||||
|
||||
property("An unspecified task axis resolves to Zero") = forAllNoShrink(structureDefinedKey) {
|
||||
property("An explicitly specified axis is always parsed to that explicit value") = forAll {
|
||||
(skm: StructureKeyMask) =>
|
||||
import skm.{ structure, key }
|
||||
val mask = skm.mask.copy(task = false)
|
||||
val string = displayMasked(key, mask)
|
||||
val hasZeroConfig = key.scope.config == Zero
|
||||
val mask = if (hasZeroConfig) skm.mask.copy(project = true) else skm.mask
|
||||
// Note that this explicitly displays the configuration axis set to Zero.
|
||||
// This is to disambiguate `proj/Zero/name`, which could render potentially
|
||||
// as `Zero/name`, but could be interpreted as `Zero/Zero/name`.
|
||||
val expected = ScopedKey(
|
||||
Resolve(structure.extra, Select(structure.current), key.key, mask)(key.scope),
|
||||
key.key
|
||||
)
|
||||
parseCheck(structure, key, mask, hasZeroConfig)(
|
||||
sk =>
|
||||
Project.equal(sk, expected, mask)
|
||||
:| s"$sk.key == $expected.key: ${sk.key == expected.key}"
|
||||
:| s"${sk.scope} == ${expected.scope}: ${Scope.equal(sk.scope, expected.scope, mask)}"
|
||||
) :| s"Expected: ${displayFull(expected)}"
|
||||
}
|
||||
|
||||
("Key: " + displayPedantic(key)) |:
|
||||
("Mask: " + mask) |:
|
||||
parse(structure, string) {
|
||||
case Left(_) => false
|
||||
case Right(sk) => sk.scope.task == Zero
|
||||
}
|
||||
property("An unspecified project axis resolves to the current project") = forAll {
|
||||
(skm: StructureKeyMask) =>
|
||||
import skm.{ structure, key }
|
||||
val mask = skm.mask.copy(project = false)
|
||||
// skip when config axis is set to Zero
|
||||
val hasZeroConfig = key.scope.config == Zero
|
||||
parseCheck(structure, key, mask)(
|
||||
sk =>
|
||||
(hasZeroConfig || sk.scope.project == Select(structure.current))
|
||||
:| s"Current: ${structure.current}"
|
||||
)
|
||||
}
|
||||
|
||||
property("An unspecified task axis resolves to Zero") = forAll { (skm: StructureKeyMask) =>
|
||||
import skm.{ structure, key }
|
||||
val mask = skm.mask.copy(task = false)
|
||||
parseCheck(structure, key, mask)(_.scope.task == Zero)
|
||||
}
|
||||
|
||||
property(
|
||||
"An unspecified configuration axis resolves to the first configuration directly defining the key or else Zero") =
|
||||
forAllNoShrink(structureDefinedKey) { (skm: StructureKeyMask) =>
|
||||
forAll { (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: " + displayPedantic(key)) |:
|
||||
("Mask: " + mask) |:
|
||||
("Expected configuration: " + resolvedConfig.map(_.name)) |:
|
||||
parse(structure, string) {
|
||||
case Right(sk) => (sk.scope.config == resolvedConfig) || (sk.scope == Scope.GlobalScope)
|
||||
case Left(_) => false
|
||||
}
|
||||
parseCheck(structure, key, mask)(
|
||||
sk => (sk.scope.config == resolvedConfig) || (sk.scope == Scope.GlobalScope)
|
||||
) :| s"Expected configuration: ${resolvedConfig map (_.name)}"
|
||||
}
|
||||
|
||||
def displayPedantic(scoped: ScopedKey[_]): String =
|
||||
Scope.displayPedantic(scoped.scope, scoped.key.label)
|
||||
|
||||
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(_) => false
|
||||
case Right(sk) =>
|
||||
(s"${sk}.key == ${expected}.key: ${sk.key == expected.key}") |:
|
||||
(s"${sk.scope} == ${expected.scope}: ${Scope.equal(sk.scope, expected.scope, mask)}") |:
|
||||
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)
|
||||
}
|
||||
|
||||
// Here we're shadowing the in-scope implicit called `mkEnv` for this method
|
||||
// so that it will use the passed-in `Gen` rather than the one imported
|
||||
// from TestBuild.
|
||||
def genStructure(implicit mkEnv: 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)
|
||||
}
|
||||
|
||||
// Here we're shadowing the in-scope implicit called `mkEnv` for this method
|
||||
// so that it will use the passed-in `Gen` rather than the one imported
|
||||
// from TestBuild.
|
||||
def structureGenF(f: (Seq[Scope], Env, ProjectRef) => Structure)(
|
||||
implicit mkEnv: Gen[Env]): Gen[Structure] =
|
||||
structureGen((s, e, p) => Gen.const(f(s, e, p)))
|
||||
// Here we're shadowing the in-scope implicit called `mkEnv` for this method
|
||||
// so that it will use the passed-in `Gen` rather than the one imported
|
||||
// from TestBuild.
|
||||
def structureGen(f: (Seq[Scope], Env, ProjectRef) => Gen[Structure])(
|
||||
implicit mkEnv: Gen[Env]): Gen[Structure] =
|
||||
implicit val arbStructure: Arbitrary[Structure] = Arbitrary {
|
||||
for {
|
||||
env <- mkEnv
|
||||
loadFactor <- choose(0.0, 1.0)
|
||||
scopes <- pickN(loadFactor, env.allFullScopes)
|
||||
current <- oneOf(env.allProjects.unzip._1)
|
||||
structure <- f(scopes, env, current)
|
||||
structure <- {
|
||||
val settings = for (scope <- scopes; t <- env.tasks)
|
||||
yield Def.setting(ScopedKey(scope, t.key), Def.value(""))
|
||||
TestBuild.structure(env, settings, current)
|
||||
}
|
||||
} yield structure
|
||||
}
|
||||
|
||||
// pickN is a function that randomly picks load % items from the from sequence.
|
||||
final class StructureKeyMask(val structure: Structure, val key: ScopedKey[_], val mask: ScopeMask)
|
||||
|
||||
implicit val arbStructureKeyMask: Arbitrary[StructureKeyMask] = Arbitrary {
|
||||
for {
|
||||
mask <- maskGen
|
||||
structure <- arbitrary[Structure]
|
||||
key <- for {
|
||||
scope <- TestBuild.scope(structure.env)
|
||||
key <- oneOf(structure.allAttributeKeys.toSeq)
|
||||
} yield ScopedKey(scope, key)
|
||||
} yield new StructureKeyMask(structure, key, mask)
|
||||
}
|
||||
|
||||
def parseCheck(
|
||||
structure: Structure,
|
||||
key: ScopedKey[_],
|
||||
mask: ScopeMask,
|
||||
showZeroConfig: Boolean = false,
|
||||
)(f: ScopedKey[_] => Prop): Prop = {
|
||||
val s = displayMasked(key, mask, showZeroConfig)
|
||||
val parser = makeParser(structure)
|
||||
val parsed = Parser.result(parser, s).left.map(_().toString)
|
||||
(
|
||||
parsed.fold(_ => falsified, f)
|
||||
:| s"Key: ${Scope.displayPedantic(key.scope, key.key.label)}"
|
||||
:| s"Mask: $mask"
|
||||
:| s"Key string: '$s'"
|
||||
:| s"Parsed: ${parsed.right.map(displayFull)}"
|
||||
:| s"Structure: $structure"
|
||||
)
|
||||
}
|
||||
|
||||
// pickN is a function that randomly picks load % items from the "from" sequence.
|
||||
// The rest of the tests expect at least one item, so I changed it to return 1 in case of 0.
|
||||
def pickN[T](load: Double, from: Seq[T]): Gen[Seq[T]] =
|
||||
pick(Math.max((load * from.size).toInt, 1), from)
|
||||
pick((load * from.size).toInt max 1, from)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue