Skip to content

Commit

Permalink
parse params
Browse files Browse the repository at this point in the history
  • Loading branch information
xuwei-k committed Feb 4, 2017
1 parent df49545 commit c50e827
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 11 deletions.
84 changes: 76 additions & 8 deletions src/main/scala/scalaprops/ScalapropsPlugin.scala
Original file line number Diff line number Diff line change
@@ -1,17 +1,55 @@
package scalaprops

import sbt._, Keys._
import sbt.complete.Parser
import sbt.complete.{DefaultParsers, Parser}
import sbt.complete.DefaultParsers._
import sbinary.DefaultProtocol._
import scala.reflect.NameTransformer

object ScalapropsPlugin extends AutoPlugin {

private[this] val defaultParser: Parser[ScalapropsTest] = (
Space ~> token(StringBasic, _ => true) ~
(Space ~> token(StringBasic, _ => true)).*
).map(ScalapropsTest.tupled)
private[this] val LongBasic = mapOrFail('-'.? ~ Digit.+){
case (neg, digits) =>
(neg.toSeq ++ digits).mkString.toLong
}

private[this] def param[A](p: Parser[A], typeName: String): (String, (ScalapropsTest.Param, A) => ScalapropsTest.Param) => Parser[ScalapropsTest.Param] = {
(key, f) =>
Space ~> token(("--" + key + "=") ~> token(p, s"<${key}: ${typeName}>")).map { x =>
f(ScalapropsTest.Param.Default, x)
}
}
private[this] val long = param(LongBasic, "Long")
private[this] val uint = param(DefaultParsers.NatBasic, "Unsigned Int")

private[this] val Seed =
long("seed", (p, x) => p.copy(seed = Some(x)))
private[this] val MinSuccessful =
uint("minSuccessful", (p, x) => p.copy(minSuccessful = Some(x)))
private[this] val MaxDiscarded =
uint("maxDiscarded", (p, x) => p.copy(maxDiscarded = Some(x)))
private[this] val MinSize =
uint("minSize", (p, x) => p.copy(minSize = Some(x)))
private[this] val MaxSize =
uint("maxSize", (p, x) => p.copy(maxSize = Some(x)))
private[this] val Timeout =
uint("timeout", (p, x) => p.copy(timeout = Some(x)))

private[this] val ParamsParser: Parser[ScalapropsTest.Param] =
Parser.oneOf(Seq(Seed, MinSuccessful, MaxDiscarded, MinSize, MaxSize, Timeout)).*.map(
params => params.foldLeft(ScalapropsTest.Param.Default)(_ merge _)
)

private[this] val defaultParser: Parser[ScalapropsTest] = {
(
Space ~> token(StringBasic, _ => true) ~
(Space ~> token(StringBasic, _ => true)).* ~
ParamsParser
).map{
case classNames Tuple2 methodNames Tuple2 param =>
ScalapropsTest(classNames, methodNames, param)
}
}

object autoImport {
val scalapropsTestNames = TaskKey[Map[String, Set[String]]]("scalapropsTestNames")
Expand Down Expand Up @@ -64,14 +102,44 @@ object ScalapropsPlugin extends AutoPlugin {
)
}

final case class ScalapropsTest(className: String, methodNames: Seq[String])
final case class ScalapropsTest(
className: String,
methodNames: Seq[String],
param: ScalapropsTest.Param
)

object ScalapropsTest {
final case class Param(
seed: Option[Long],
minSuccessful: Option[Int],
maxDiscarded: Option[Int],
minSize: Option[Int],
maxSize: Option[Int],
timeout: Option[Int]
) {
def merge(other: Param): Param = Param(
seed = seed orElse other.seed,
minSuccessful = minSuccessful orElse other.minSuccessful,
maxDiscarded = maxDiscarded orElse other.maxDiscarded,
minSize = minSize orElse other.minSize,
maxSize = maxSize orElse other.maxSize,
timeout = timeout orElse other.timeout
)
}
object Param {
val Default = Param(None, None, None, None, None, None)
}
}

private[this] def createParser(tests: Map[String, Set[String]]): Parser[ScalapropsTest] = {
tests.filter(_._2.nonEmpty).map { case (k, v) =>
val (noChange, changed) = v.partition(n => NameTransformer.decode(n) == n)
val all = noChange ++ changed.map(n => "\"" + NameTransformer.decode(n) + "\"")
val parser = token(k) ~ distinctParser(all)
parser.map(ScalapropsTest.tupled)
val parser = token(k) ~ distinctParser(all) ~ ParamsParser
parser.map{
case className Tuple2 methodName Tuple2 param =>
ScalapropsTest(className, methodName, param)
}
}.reduceOption(_ | _).map(Space ~> _).getOrElse(defaultParser)
}

Expand Down
16 changes: 13 additions & 3 deletions src/test/scala/scalaprops/ScalapropsPluginTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,34 @@ object ScalapropsPluginTest extends Scalaprops {
)
val p = invokeParser(classes)

def show(s: Set[String]) = s.map("\"" + _ + "\"").toList.sorted

def test(input: String, completions: Set[String]) = {
val actual = input.foldLeft(p){_ derive _}.completions(0).get.map(_.display)
assert(actual == completions, s"$actual $completions")
assert(actual == completions, s"\n${show(actual)}\n is not equals \n${show(completions)}")
}

val aaaMethods = classes(aaa)
val keys = Set("minSize", "maxDiscarded", "maxSize", "timeout", "minSuccessful", "seed").map("--" + _ + "=")

test("", Set(" "))
test(" ", classes.keySet)
test(" com", classes.keySet)
test(" com.example.", classes.keySet)
test(" com.example.A", Set("com.example.AAA"))
test(" com.example.AAA", Set(" ", ""))
test(" com.example.AAA ", aaaMethods)
test(" com.example.AAA ", keys ++ aaaMethods)
test(" com.example.AAA -", keys)
test(" com.example.AAA a", aaaMethods)
test(" com.example.AAA aa_x", Set("aa_xx_1", "aa_xx_2"))
test(" com.example.AAA aa_xx_1", Set(" ", ""))
test(" com.example.AAA aa_xx_1 ", Set("aa_xx_2", "aa_yy"))
test(" com.example.AAA aa_xx_1 ", Set("aa_xx_2", "aa_yy") ++ keys)
test(" com.example.AAA --max", Set("--maxDiscarded=", "--maxSize="))
test(" com.example.AAA --maxSize=", Set("<maxSize: Unsigned Int>"))
test(" com.example.AAA --seed", Set("--seed="))
test(" com.example.AAA --seed=", Set("<seed: Long>"))
test(" com.example.AAA --seed=12345", Set("<seed: Long>"))
test(" com.example.AAA --seed=12345 ", keys ++ aaaMethods)
true
}
}

0 comments on commit c50e827

Please sign in to comment.