///|
priv struct ParsedTest {
help : Bool
json : Bool
package_path : String?
target : String
project_root : String
}
///|
fn test_usage() -> String {
(
#|Usage: moui test [package] [options]
#|
#|Run a project's MoonBit tests. Defaults to the `app` package when it
#|exists, otherwise runs every package in the project.
#|
#|Options:
#| --package PATH Package path (same as the positional argument).
#| --target TARGET MoonBit target (native or wasm-gc). Defaults to native.
#| --project-root PATH Project root. Defaults to the current directory.
#| --json Emit a machine-readable result envelope.
#| -h, --help Show this help.
)
}
///|
fn parse_test_args(
args : Array[String],
cwd : String,
) -> Result[ParsedTest, String] {
let help = Ref(false)
let json = Ref(false)
let package_name : Ref[String?] = Ref(None)
let target = Ref("native")
let project_root = Ref(cwd)
let positional : Array[String] = []
let mut index = 0
while index < args.length() {
let argument = args[index]
let (name, inline) = option_parts(argument)
match name {
"-h" | "--help" =>
match flag_without_value(inline, name) {
Ok(_) => help.val = true
Err(message) => return Err(message)
}
"--json" =>
match flag_without_value(inline, name) {
Ok(_) => json.val = true
Err(message) => return Err(message)
}
"--package" | "--target" | "--project-root" =>
match option_value(args, index, inline, name) {
Ok((value, next)) => {
match name {
"--package" => package_name.val = Some(value)
"--target" => target.val = value
"--project-root" => project_root.val = make_absolute(value, cwd)
_ => ()
}
index = next
continue
}
Err(message) => return Err(message)
}
_ if argument.has_prefix("-") =>
return Err("unknown option for moui test: " + name)
_ => positional.push(argument)
}
index += 1
}
if positional.length() > 1 ||
(positional.length() == 1 && package_name.val is Some(_)) {
return Err("moui test accepts at most one package path")
}
if package_name.val is None && positional.length() == 1 {
package_name.val = Some(positional[0])
}
Ok({
help: help.val,
json: json.val,
package_path: package_name.val,
target: target.val,
project_root: project_root.val,
})
}
///|
fn test_default_package(project_root : String) -> String? {
if path_is_file(join_path(project_root, "app/moon.pkg")) {
Some("app")
} else {
None
}
}
///|
fn run_test(args : Array[String], cwd : String) -> CliOutcome {
let parsed = match parse_test_args(args, cwd) {
Ok(value) => value
Err(message) => return failed_outcome(message, false, test_usage())
}
if parsed.help {
return stdout_outcome(test_usage())
}
let package_name = match parsed.package_path {
Some(value) => Some(value)
None => test_default_package(parsed.project_root)
}
let argv = ["moon", "test"]
match package_name {
Some(value) => argv.push(value)
None => ()
}
argv.push("--target")
argv.push(parsed.target)
let result = match
process_exec_argv(argv, cwd=parsed.project_root, capture=parsed.json) {
Ok(value) => value
Err(message) => return failed_outcome(message, parsed.json, test_usage())
}
if parsed.json {
let fields : Map[String, Json] = Map([])
fields["schemaVersion"] = Json::number(1.0)
fields["command"] = Json::string("test")
fields["ok"] = Json::boolean(result.exit_code == 0)
fields["exitCode"] = Json::number(result.exit_code.to_double())
fields["package"] = match package_name {
Some(value) => Json::string(value)
None => Json::null()
}
fields["target"] = Json::string(parsed.target)
fields["stdout"] = Json::string(result.stdout)
fields["stderr"] = Json::string(result.stderr)
let output = Json::object(fields).stringify(indent=2) + "\n"
{ exit_code: result.exit_code, stdout: output, stderr: "", }
} else {
{ exit_code: result.exit_code, stdout: "", stderr: "", }
}
}