aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Odersky <jakob@odersky.com>2018-04-29 19:47:30 -0700
committerJakob Odersky <jakob@odersky.com>2018-04-29 19:47:30 -0700
commita107e2b2e7d63375dc93eaa96134c0c124b0f250 (patch)
tree66b82982f4a0f70735853737c547ce7efabae0e5
parent5c7faea2052344c1186a14b15269017d4b676aab (diff)
downloadcommando-a107e2b2e7d63375dc93eaa96134c0c124b0f250.tar.gz
commando-a107e2b2e7d63375dc93eaa96134c0c124b0f250.tar.bz2
commando-a107e2b2e7d63375dc93eaa96134c0c124b0f250.zip
Reenable tests
-rw-r--r--build.sbt4
-rw-r--r--project/plugins.sbt6
-rw-r--r--src/main/scala/api.scala30
-rw-r--r--src/main/scala/definitions.scala2
-rw-r--r--src/main/scala/package.scala38
-rw-r--r--src/main/scala/parsing.scala8
-rw-r--r--src/test/scala/CmdTest.scala.disabled207
-rw-r--r--src/test/scala/ParserTest.scala140
8 files changed, 188 insertions, 247 deletions
diff --git a/build.sbt b/build.sbt
index fe7afad..b79e71e 100644
--- a/build.sbt
+++ b/build.sbt
@@ -7,8 +7,8 @@ lazy val commando = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.in(file("."))
.settings(
scalacOptions ++= Seq(
- "-deprecation",
- "-feature"
+ "-deprecation",
+ "-feature"
),
libraryDependencies ++= Seq(
"com.lihaoyi" %%% "utest" % "0.6.3" % "test"
diff --git a/project/plugins.sbt b/project/plugins.sbt
index 8725466..e63c0d7 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -1,6 +1,6 @@
addSbtPlugin("com.geirsson" % "sbt-scalafmt" % "1.5.1")
-addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "0.4.0")
+addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "0.4.0")
addSbtPlugin("org.portable-scala" % "sbt-scala-native-crossproject" % "0.4.0")
-addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.22")
-addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.3.7")
+addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.22")
+addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.3.7")
diff --git a/src/main/scala/api.scala b/src/main/scala/api.scala
new file mode 100644
index 0000000..44a26f1
--- /dev/null
+++ b/src/main/scala/api.scala
@@ -0,0 +1,30 @@
+package test
+
+import commando._
+
+object Main {
+
+ val command = cmd("docker")(
+ opt("debug", 'D')
+ ).sub(
+ cmd("run")(
+ opt("interactive", 'i'),
+ opt("tty", 't'),
+ pos("container")
+ ).run { arguments =>
+ // run container with arguments
+ },
+ cmd("ps")(
+ opt("all", 'a')
+ ).run { arguments =>
+ if (arguments.contains("all")) {
+ // ...
+ } else {
+ // ...
+ }
+ }
+ )
+
+ def main(args: Array[String]): Unit = commando.parse(args, command)
+
+}
diff --git a/src/main/scala/definitions.scala b/src/main/scala/definitions.scala
index 15c8e2c..8de9e3a 100644
--- a/src/main/scala/definitions.scala
+++ b/src/main/scala/definitions.scala
@@ -63,4 +63,4 @@ case class Command(
object Command {
type Arguments = Map[String, Seq[String]]
-} \ No newline at end of file
+}
diff --git a/src/main/scala/package.scala b/src/main/scala/package.scala
index f813971..68936cd 100644
--- a/src/main/scala/package.scala
+++ b/src/main/scala/package.scala
@@ -2,10 +2,11 @@ package commando
class CommandBuilder(name: String, params: Seq[Parameter]) {
- private def optionals = params.collect{
- case opt: Optional => opt
- }.toSet
- private def positionals = params.collect{
+ private def optionals =
+ params.collect {
+ case opt: Optional => opt
+ }.toSet
+ private def positionals = params.collect {
case pos: Positional => pos
}
@@ -17,32 +18,33 @@ class CommandBuilder(name: String, params: Seq[Parameter]) {
}
-
-
object `package` {
- val DefaultErrorHandler: (Command, String) => Unit = (command: Command, err: String) => {
- System.err.println(s"${command.name}: $err")
- System.exit(2)
- }
-
-
+ val DefaultErrorHandler: (Command, String) => Unit =
+ (command: Command, err: String) => {
+ System.err.println(s"${command.name}: $err")
+ System.exit(2)
+ }
def parse(arguments: Seq[String],
- command: Command, onError: (Command, String) => Unit = DefaultErrorHandler): Unit =
+ command: Command,
+ onError: (Command, String) => Unit = DefaultErrorHandler): Unit =
Parser.parse(arguments, command, onError)
- def cmd(name: String)(params: Parameter*): CommandBuilder = new CommandBuilder(name, params)
- def opt(name: String, short: Char = '\u0000', param: (String, Boolean) = ("", false)): Optional =
+ def cmd(name: String)(params: Parameter*): CommandBuilder =
+ new CommandBuilder(name, params)
+ def opt(name: String,
+ short: Char = '\u0000',
+ param: (String, Boolean) = ("", false)): Optional =
Optional(
name,
if (short == '\u0000') None else Some(short),
argumentAllowed = (param != ("", false)),
argumentRequired = (param != ("", false)) && param._2,
- parameterName = if(param._1 == "") "param" else param._1
+ parameterName = if (param._1 == "") "param" else param._1
)
- def pos(name: String, required: Boolean = true): Positional = Positional(name, required)
-
+ def pos(name: String, required: Boolean = true): Positional =
+ Positional(name, required)
}
diff --git a/src/main/scala/parsing.scala b/src/main/scala/parsing.scala
index 95edc05..2526d39 100644
--- a/src/main/scala/parsing.scala
+++ b/src/main/scala/parsing.scala
@@ -101,9 +101,9 @@ object Parser {
if (parts.size > 1) Some(parts(1)) else None
val opt = (tok.kind: @unchecked) match {
case LONG =>
- longs.getOrElse(name, fatal(s"option --$name unknown"))
+ longs.getOrElse(name, fatal(s"unknown option '--$name'"))
case SHORT =>
- shorts.getOrElse(name, fatal(s"option -$name unknown"))
+ shorts.getOrElse(name, fatal(s"unknown option '-$name'"))
}
if (opt.argumentRequired) {
@@ -144,7 +144,7 @@ object Parser {
accept().value
)
} else {
- fatal(s"too many parameters: '${token.value}'")
+ fatal(s"too many arguments: '${token.value}'")
}
}
@@ -180,7 +180,7 @@ object Parser {
innerLine()
} else if (token.kind == POSITIONAL) {
if (subcommands.isEmpty) {
- fatal(s"too many parameters: '${token.value}'")
+ fatal(s"too many arguments: '${token.value}'")
} else {
subcommands.get(token.value) match {
case None =>
diff --git a/src/test/scala/CmdTest.scala.disabled b/src/test/scala/CmdTest.scala.disabled
deleted file mode 100644
index d943a79..0000000
--- a/src/test/scala/CmdTest.scala.disabled
+++ /dev/null
@@ -1,207 +0,0 @@
-package commando
-
-import utest._
-
-object CmdTests extends TestSuite {
-
- val cbx = commando.Command(
- "cbx",
- commando.Optional("server", Some('s'), Optional.ArgRequired("name")),
- commando.Command(
- "version",
- commando.Optional("verbose", Some('v'), Optional.ArgAllowed("k=v"))),
- commando.Command("login",
- commando.Positional("server_url"),
- commando.Positional("username", false),
- commando.Positional("password", false)),
- commando.Command("run",
- commando.Optional("file", Some('f'), Optional.ArgRequired("file_name")),
- commando.Optional("force", None),
- commando.Positional("pipeline", false)),
- commando.Command("level1",
- commando.Command("level2-1",
- commando.Positional("p2"),
- commando.Command("level3", commando.Positional("p3"))),
- commando.Command("level2-2"))
- )
-
- def parse(in: String): CommandLine = commando.parse(cbx, in.split(" ").tail) match {
- case Left(ex) => throw ex
- case Right(res) => res
- }
-
- def shouldFail(in: String) =
- assert(commando.parse(cbx, in.split(" ").tail).isLeft)
-
- val tests = Tests {
- "printUsage" - {
- cbx.usage
- }
- "simple" - {
- assert(
- parse("cbx version").subcommand.get == CommandLine("version",
- Map.empty,
- None))
- }
- "emptyAllowedOption" - {
- assert(
- parse("cbx version -v").subcommand.get == CommandLine(
- "version",
- Map("verbose" -> ""),
- None))
- assert(
- parse("cbx version --verbose").subcommand.get == CommandLine(
- "version",
- Map("verbose" -> ""),
- None))
- }
- "setAllowedOption" - {
- assert(
- parse("cbx version -v x").subcommand.get == CommandLine(
- "version",
- Map("verbose" -> "x"),
- None))
- assert(
- parse("cbx version --verbose x").subcommand.get == CommandLine(
- "version",
- Map("verbose" -> "x"),
- None))
- assert(
- parse("cbx version --verbose=x").subcommand.get == CommandLine(
- "version",
- Map("verbose" -> "x"),
- None))
- assert(
- parse("cbx version --verbose=x=y").subcommand.get == CommandLine(
- "version",
- Map("verbose" -> "x=y"),
- None))
- assert(
- parse("cbx version --verbose=x=y,z=w").subcommand.get == CommandLine(
- "version",
- Map("verbose" -> "x=y,z=w"),
- None))
- assert(
- parse("cbx version --verbose x=y,z=w").subcommand.get == CommandLine(
- "version",
- Map("verbose" -> "x=y,z=w"),
- None))
- shouldFail("cbx version --verbose x=y z=w")
- }
- "requiredArgOption" - {
- assert(parse("cbx run").subcommand.get == CommandLine("run", Map(), None)) // make sure it works first
- assert(
- parse("cbx run -f x").subcommand.get == CommandLine("run",
- Map("file" -> "x"),
- None))
- assert(
- parse("cbx run --file x").subcommand.get == CommandLine(
- "run",
- Map("file" -> "x"),
- None))
- assert(
- parse("cbx run --file=x").subcommand.get == CommandLine(
- "run",
- Map("file" -> "x"),
- None))
- assert(
- parse("cbx run --file=x=y,z=w").subcommand.get == CommandLine(
- "run",
- Map("file" -> "x=y,z=w"),
- None))
- shouldFail("cbx run --file")
- shouldFail("cbx run --file --")
- }
- "noArgOption" - {
- shouldFail("cbx run --force=x")
- assert(
- parse("cbx run --force x").subcommand.get == CommandLine(
- "run",
- Map("force" -> "", "pipeline" -> "x"),
- None))
- }
- "globalOption" - {
- assert(parse("cbx --server run run").arguments == Map("server" -> "run"))
- assert(
- parse("cbx --server run run").subcommand.get == CommandLine("run",
- Map.empty,
- None))
- assert(parse("cbx -s run run").arguments == Map("server" -> "run"))
- assert(
- parse("cbx -s run run").subcommand.get == CommandLine("run",
- Map.empty,
- None))
- assert(parse("cbx --server=run run").arguments == Map("server" -> "run"))
- assert(
- parse("cbx --server=run run").subcommand.get == CommandLine("run",
- Map.empty,
- None))
- shouldFail("cbx -x run")
- shouldFail("cbx --x run")
- }
- "parameter" - {
- assert(
- parse("cbx login x").subcommand.get == CommandLine(
- "login",
- Map("server_url" -> "x"),
- None))
- assert(
- parse("cbx login x y").subcommand.get == CommandLine(
- "login",
- Map("server_url" -> "x", "username" -> "y"),
- None))
- assert(
- parse("cbx login x y z").subcommand.get == CommandLine(
- "login",
- Map("server_url" -> "x", "username" -> "y", "password" -> "z"),
- None))
- shouldFail("cbx login - y z w")
- assert(
- parse("cbx login - y").subcommand.get == CommandLine(
- "login",
- Map("server_url" -> "-", "username" -> "y"),
- None))
- }
- "outOfOrderOptions" - {
- assert(
- parse("cbx run --force pipelinename -f x").subcommand.get == CommandLine(
- "run",
- Map("force" -> "", "pipeline" -> "pipelinename", "file" -> "x"),
- None))
- assert(
- parse("cbx run --force -- -f").subcommand.get == CommandLine(
- "run",
- Map("force" -> "", "pipeline" -> "-f"),
- None))
- assert(
- parse("cbx run --force -- --file").subcommand.get == CommandLine(
- "run",
- Map("force" -> "", "pipeline" -> "--file"),
- None))
- assert(
- parse("cbx run --force -- --").subcommand.get == CommandLine(
- "run",
- Map("force" -> "", "pipeline" -> "--"),
- None))
- shouldFail("cbx run --force -- -f x") // too many parameters
- }
- "nested1" - {
- val line = parse("cbx level1 level2-1 x=y level3 z").subcommand.get
- val expected = CommandLine(
- "level1",
- Map.empty,
- Some(
- CommandLine("level2-1",
- Map("p2" -> "x=y"),
- Some(CommandLine("level3", Map("p3" -> "z"), None)))))
- assert(line == expected)
- }
- "nested2" - {
- val line = parse("cbx level1 level2-2 --").subcommand.get
- val expected = CommandLine("level1",
- Map.empty,
- Some(CommandLine("level2-2", Map.empty, None)))
- assert(line == expected)
- }
- }
-}
diff --git a/src/test/scala/ParserTest.scala b/src/test/scala/ParserTest.scala
index 11694c4..579ba95 100644
--- a/src/test/scala/ParserTest.scala
+++ b/src/test/scala/ParserTest.scala
@@ -6,22 +6,138 @@ object ParserTest extends TestSuite {
implicit class EliteCommando(line: String) {
def parse(command: Command): Unit = {
- val args = line.split(" ")
- commando.parse(args, command)(err => throw new ParseException(err))
+ val args = line.split(" ").tail
+ commando.parse(args, command, (c, err) => throw new ParseException(err))
+ }
+ def fail(command: Command, message: String): Unit = {
+ val args = line.split(" ").tail
+ try {
+ commando.parse(args, command, (c, err) => throw new ParseException(err))
+ sys.error("parsing succeeded but was expected to fail")
+ } catch {
+ case err: ParseException if err.getMessage.contains(message) =>
+ case err: ParseException =>
+ sys.error(s"parsing failed for the wrong reason: ${err.getMessage}")
+ }
}
}
- val tests = Tests {
- "foo" - {
- val command = cmd("cbx")(
- opt("server", 'S', param = "url" -> false),
- pos("number")
- ).run(
- ctx => println("yoyo, my context was: " + ctx)
+ def cbx(asserts: Command.Arguments => Unit) =
+ cmd("cbx")(
+ opt("server", 's', "name" -> true)
+ ).sub(
+ cmd("version")(
+ opt("verbose", 'v', "k=v" -> false)
+ ).run(asserts),
+ cmd("login")(
+ pos("server_url"),
+ pos("username", false),
+ pos("password", false)
+ ).run(asserts),
+ cmd("run")(
+ opt("file", 'f', "file_name" -> true),
+ opt("force"),
+ pos("pipeline", false)
+ ).run(asserts),
+ cmd("level1")().sub(
+ cmd("level2-1")(
+ pos("p2")
+ ).sub(
+ cmd("level3")(pos("p3")).run(asserts)
+ ),
+ cmd("level2-2")().run(asserts)
)
- "--server x 3 -S 5 --server=2 --server 2".parse(command)
- println(command.usage)
+ )
+
+ val tests = Tests {
+ "print usage" - {
+ cbx(_ => ()).usage
+ }
+ "simple" - {
+ "cbx version" parse cbx { args =>
+ args ==> Map.empty
+ }
+ }
+ "empty allowed optional" - {
+ "cbx version -v" parse cbx { args =>
+ args ==> Map("verbose" -> Seq(""))
+ }
+ "cbx version --verbose" parse cbx { args =>
+ args ==> Map("verbose" -> Seq(""))
+ }
+ }
+ "set allowed optional" - {
+ "cbx version -v x" parse cbx { args =>
+ args ==> Map("verbose" -> Seq("x"))
+ }
+ "cbx version --verbose x" parse cbx { args =>
+ args ==> Map("verbose" -> Seq("x"))
+ }
+ "cbx version --verbose=x" parse cbx { args =>
+ args ==> Map("verbose" -> Seq("x"))
+ }
+ "cbx version --verbose=x=y" parse cbx { args =>
+ args ==> Map("verbose" -> Seq("x=y"))
+ }
+ "cbx version --verbose=x=y,z=w" parse cbx { args =>
+ args ==> Map("verbose" -> Seq("x=y,z=w"))
+ }
+ "cbx version --verbose x=y" parse cbx { args =>
+ args ==> Map("verbose" -> Seq("x=y"))
+ }
+ "cbx version --verbose x=y z=w".fail(cbx(_ => ()), "too many arguments")
+ }
+ "required argument optional" - {
+ "cbx run" parse cbx { _ ==> Map.empty } // make sure it works first
+ "cbx run -f x" parse cbx { _ ==> Map("file" -> Seq("x")) }
+ "cbx run --file x" parse cbx { _ ==> Map("file" -> Seq("x")) }
+ "cbx run --file=x" parse cbx { _ ==> Map("file" -> Seq("x")) }
+ "cbx run --file=x=y,z=w" parse cbx { _ ==> Map("file" -> Seq("x=y,z=w")) }
+ "cbx run --file".fail(cbx(_ => ()), "requires")
+ "cbx run --file --".fail(cbx(_ => ()), "requires")
+ }
+ "no argument optional" - {
+ "cbx run --force=x".fail(cbx(_ => ()), "no argument allowed")
+ "cbx run --force x" parse cbx { _ ==> Map("force" -> Seq(""), "pipeline" -> Seq("x")) }
+ }
+ "global optional" - {
+ "cbx --server run run" parse cbx {_ ==> Map("server" -> Seq("run"))}
+ "cbx -s run run" parse cbx {_ ==> Map("server" -> Seq("run"))}
+ "cbx --server=run run" parse cbx {_ ==> Map("server" -> Seq("run"))}
+ "cbx -x run".fail(cbx(_ => ()), "unknown option")
+ "cbx --x run".fail(cbx(_ => ()), "unknown option")
+ }
+ "positional" - {
+ "cbx login x" parse cbx { _ ==> Map("server_url" -> Seq("x"))}
+ "cbx login x y" parse cbx { _ ==> Map("server_url" -> Seq("x"), "username" -> Seq("y"))}
+ "cbx login x y z" parse cbx { _ ==> Map("server_url" -> Seq("x"), "username" -> Seq("y"), "password" -> Seq("z"))}
+ "cbx login - x y z".fail(cbx(_ => ()), "too many")
+ "cbx login - y" parse cbx { _ ==> Map("server_url" -> Seq("-"), "username" -> Seq("y"))}
+ }
+ "out of order options" - {
+ "cbx run --force pipelinename -f x" parse cbx {
+ _ ==> Map("force" -> Seq(""), "pipeline" -> Seq("pipelinename"), "file" -> Seq("x"))
+ }
+ "cbx run --force -- -f" parse cbx {
+ _ ==> Map("force" -> Seq(""), "pipeline" -> Seq("-f"))
+ }
+ "cbx run --force -- --file" parse cbx {
+ _ ==> Map("force" -> Seq(""), "pipeline" -> Seq("--file"))
+ }
+ "cbx run --force -- --" parse cbx {
+ _ ==> Map("force" -> Seq(""), "pipeline" -> Seq("--"))
+ }
+ "cbx run --force -- -f x".fail(cbx(_ => ()), "too many")
+ }
+ "nested1" - {
+ "cbx level1 level2-1 x=y level3 z" parse cbx {
+ _ ==> Map("p2" -> Seq("x=y"), "p3" -> Seq("z"))
+ }
+ }
+ "nested2" - {
+ "cbx level1 level2-2 --" parse cbx {
+ _ ==> Map.empty
+ }
}
}
-
}