diff --git a/zio-cli/shared/src/main/scala/zio/cli/CliApp.scala b/zio-cli/shared/src/main/scala/zio/cli/CliApp.scala index 38ecdc1a..f07f5df7 100644 --- a/zio-cli/shared/src/main/scala/zio/cli/CliApp.scala +++ b/zio-cli/shared/src/main/scala/zio/cli/CliApp.scala @@ -116,12 +116,12 @@ object CliApp { self.command .parse(prefix(self.command) ++ args, self.config) .foldZIO( - e => printDocs(e.error), + e => printDocs(e.error) *> ZIO.fail(e), { case CommandDirective.UserDefined(_, value) => self.execute(value) case CommandDirective.BuiltIn(x) => executeBuiltIn(x).catchSome { case e: ValidationError => - printDocs(e.error) + printDocs(e.error) *> ZIO.fail(e) } } ) diff --git a/zio-cli/shared/src/test/scala/zio/cli/CliAppSpec.scala b/zio-cli/shared/src/test/scala/zio/cli/CliAppSpec.scala new file mode 100644 index 00000000..87036f04 --- /dev/null +++ b/zio-cli/shared/src/test/scala/zio/cli/CliAppSpec.scala @@ -0,0 +1,53 @@ +package zio.cli + +import zio._ +import zio.test.Assertion._ +import zio.test._ + +object CliAppSpec extends ZIOSpecDefault { + + private val exitCodeSpec = { + sealed trait Subcommand extends Product with Serializable + object Subcommand { + final case class Make(int: BigInt) extends Subcommand + } + + val makeCmd: Command[Subcommand] = + Command( + name = "make", + args = Args.integer + ).map(file => Subcommand.Make(file)) + + val exampleCmd: Command[Subcommand] = Command("example").subcommands(makeCmd) + + def app(behavior: Task[Unit] = ZIO.unit) = CliApp.make( + name = "Grumpy", + version = "0.0.1", + summary = HelpDoc.Span.text("this is some doc"), + command = exampleCmd + ) { case Subcommand.Make(_) => behavior } + + suite("exit code of the CLI")( + test("should exit with 0 when the command is successful") { + val result = app().run(List("make", "1")) + + assertZIO(result.exitCode)(equalTo(ExitCode.success)) + }, + test("should exit with a code <> 0 when the parsing of the command fails") { + val result = app().run(List("make", "this is not an integer")) + + assertZIO(result.exitCode)(equalTo(ExitCode.failure)) + }, + test("should exit with a code <> 0 when the command fails") { + val result = app(behavior = ZIO.fail(new RuntimeException("Boom"))).run(List("make", "1")) + + assertZIO(result.exitCode)(equalTo(ExitCode.failure)) + } + ) + } + + override def spec: Spec[TestEnvironment & Scope, Any] = + suite("CliApp")( + exitCodeSpec + ) +}