Skip to content

Commit ba1c79f

Browse files
committed
refactor: extract testable CLI action and package name resolution
1 parent 12a7e5e commit ba1c79f

2 files changed

Lines changed: 144 additions & 54 deletions

File tree

src/unitest.gleam

Lines changed: 97 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ pub type ResolvedExecutionMode {
5151
ResolvedParallel(workers: Int)
5252
}
5353

54+
@internal
55+
pub type CliAction {
56+
RunWithCliOptions(cli.CliOptions)
57+
ShowCliMessage(message: String, exit_code: Int)
58+
}
59+
5460
/// Configuration options for the test runner.
5561
///
5662
/// ## Fields
@@ -239,12 +245,35 @@ pub fn resolve_execution_mode(
239245
fn default_workers() -> Int
240246

241247
fn run_with_args(args: List(String), options: Options) -> Nil {
248+
case resolve_cli_action(args) {
249+
RunWithCliOptions(cli_opts) -> run_with_cli_opts(cli_opts, options)
250+
ShowCliMessage(message, exit_code) -> {
251+
io.println_error(message)
252+
253+
case exit_code {
254+
0 -> Nil
255+
_ -> halt(exit_code)
256+
}
257+
}
258+
}
259+
}
260+
261+
@internal
262+
pub fn resolve_cli_action(args: List(String)) -> CliAction {
242263
case cli.parse(args) {
243-
Error(help) -> io.println(help)
244-
Ok(cli_opts) -> run_with_cli_opts(cli_opts, options)
264+
Ok(cli_opts) -> RunWithCliOptions(cli_opts)
265+
Error(message) ->
266+
case wants_help(args) {
267+
True -> ShowCliMessage(message, 0)
268+
False -> ShowCliMessage(message, 1)
269+
}
245270
}
246271
}
247272

273+
fn wants_help(args: List(String)) -> Bool {
274+
list.contains(args, "--help") || list.contains(args, "-h")
275+
}
276+
248277
fn run_with_cli_opts(cli_opts: cli.CliOptions, options: Options) -> Nil {
249278
let use_color = should_use_color(cli_opts.no_color)
250279
let tests = discover.discover_from_fs(options.test_directory)
@@ -338,46 +367,61 @@ fn execute_and_finish(
338367
sort_reversed: Bool,
339368
check_results: Bool,
340369
) -> Nil {
341-
let package_name = get_package_name()
342-
let platform =
343-
runner.Platform(
344-
now_ms: now_ms,
345-
run_test: fn(t, k) { run_test_async(t, package_name, check_results, k) },
346-
start_module_pool: fn(module_groups, pool_workers) {
347-
start_module_pool(
348-
module_groups,
349-
package_name,
350-
check_results,
351-
pool_workers,
370+
case get_package_name() {
371+
Error(error) -> {
372+
io.println_error(error)
373+
halt(1)
374+
}
375+
Ok(package_name) -> {
376+
let platform =
377+
runner.Platform(
378+
now_ms: now_ms,
379+
run_test: fn(t, k) {
380+
run_test_async(t, package_name, check_results, k)
381+
},
382+
start_module_pool: fn(module_groups, pool_workers) {
383+
start_module_pool(
384+
module_groups,
385+
package_name,
386+
check_results,
387+
pool_workers,
388+
)
389+
},
390+
receive_pool_result: receive_pool_result,
391+
print: io.print,
352392
)
353-
},
354-
receive_pool_result: receive_pool_result,
355-
print: io.print,
356-
)
357393

358-
let #(on_result, cleanup) =
359-
build_on_result_callback(reporter, use_color, sort_order, sort_reversed)
394+
let #(on_result, cleanup) =
395+
build_on_result_callback(reporter, use_color, sort_order, sort_reversed)
360396

361-
let on_complete = fn(exec_result: runner.ExecuteResult) {
362-
cleanup(exec_result)
363-
io.println(runner.render_summary(exec_result.report, use_color))
364-
halt(exit_code(exec_result.report))
365-
}
397+
let on_complete = fn(exec_result: runner.ExecuteResult) {
398+
cleanup(exec_result)
399+
io.println(runner.render_summary(exec_result.report, use_color))
400+
halt(exit_code(exec_result.report))
401+
}
366402

367-
case mode {
368-
ResolvedSequential ->
369-
runner.execute_sequential(plan, seed, platform, on_result, on_complete)
370-
ResolvedAsync ->
371-
runner.execute_pooled(plan, seed, 1, platform, on_result, on_complete)
372-
ResolvedParallel(workers) ->
373-
runner.execute_pooled(
374-
plan,
375-
seed,
376-
workers,
377-
platform,
378-
on_result,
379-
on_complete,
380-
)
403+
case mode {
404+
ResolvedSequential ->
405+
runner.execute_sequential(
406+
plan,
407+
seed,
408+
platform,
409+
on_result,
410+
on_complete,
411+
)
412+
ResolvedAsync ->
413+
runner.execute_pooled(plan, seed, 1, platform, on_result, on_complete)
414+
ResolvedParallel(workers) ->
415+
runner.execute_pooled(
416+
plan,
417+
seed,
418+
workers,
419+
platform,
420+
on_result,
421+
on_complete,
422+
)
423+
}
424+
}
381425
}
382426
}
383427

@@ -488,22 +532,9 @@ fn yield_then(next: fn() -> Nil) -> Nil
488532
@external(javascript, "./unitest_ffi.mjs", "halt")
489533
fn halt(code: Int) -> Nil
490534

491-
fn get_package_name() -> String {
492-
let name_result = case simplifile.read("gleam.toml") {
493-
Ok(content) ->
494-
parse_package_name(content)
495-
|> result.replace_error("Error: Could not find 'name' in gleam.toml")
496-
Error(_) -> Error("Error: Could not read gleam.toml")
497-
}
498-
499-
case name_result {
500-
Ok(name) -> name
501-
Error(error) -> {
502-
io.println_error(error)
503-
halt(1)
504-
""
505-
}
506-
}
535+
fn get_package_name() -> Result(String, String) {
536+
simplifile.read("gleam.toml")
537+
|> resolve_package_name
507538
}
508539

509540
@internal
@@ -522,3 +553,15 @@ pub fn parse_package_name(content: String) -> Result(String, Nil) {
522553
}
523554
})
524555
}
556+
557+
@internal
558+
pub fn resolve_package_name(
559+
toml_result: Result(String, a),
560+
) -> Result(String, String) {
561+
case toml_result {
562+
Ok(content) ->
563+
parse_package_name(content)
564+
|> result.replace_error("Error: Could not find 'name' in gleam.toml")
565+
Error(_) -> Error("Error: Could not read gleam.toml")
566+
}
567+
}

test/unitest_test.gleam

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,18 @@ pub fn main() -> Nil {
88
unitest.main()
99
}
1010

11+
fn default_cli_opts() -> cli.CliOptions {
12+
cli.CliOptions(
13+
seed: option.None,
14+
filter: cli.Filter(location: cli.AllLocations, tag: option.None),
15+
no_color: False,
16+
reporter: cli.DotReporter,
17+
sort_order: option.None,
18+
sort_reversed: False,
19+
workers: option.None,
20+
)
21+
}
22+
1123
pub fn exit_code_zero_when_no_failures_test() {
1224
let report =
1325
runner.Report(
@@ -63,6 +75,41 @@ pub fn parse_package_name_empty_content_returns_error_test() {
6375
assert unitest.parse_package_name("") == Error(Nil)
6476
}
6577

78+
pub fn resolve_package_name_returns_name_for_valid_content_test() {
79+
assert unitest.resolve_package_name(Ok(
80+
"name = \"unitest\"\nversion = \"1.0.0\"",
81+
))
82+
== Ok("unitest")
83+
}
84+
85+
pub fn resolve_package_name_returns_read_error_test() {
86+
assert unitest.resolve_package_name(Error(Nil))
87+
== Error("Error: Could not read gleam.toml")
88+
}
89+
90+
pub fn resolve_package_name_returns_parse_error_test() {
91+
assert unitest.resolve_package_name(Ok("version = \"1.0.0\""))
92+
== Error("Error: Could not find 'name' in gleam.toml")
93+
}
94+
95+
pub fn resolve_cli_action_runs_valid_args_test() {
96+
assert unitest.resolve_cli_action(["--workers", "4"])
97+
== unitest.RunWithCliOptions(
98+
cli.CliOptions(..default_cli_opts(), workers: option.Some(4)),
99+
)
100+
}
101+
102+
pub fn resolve_cli_action_marks_validation_errors_fatal_test() {
103+
assert unitest.resolve_cli_action(["--workers", "0"])
104+
== unitest.ShowCliMessage(message: "Workers must be positive", exit_code: 1)
105+
}
106+
107+
pub fn resolve_cli_action_keeps_help_non_fatal_test() {
108+
let assert Error(help_text) = cli.parse(["--help"])
109+
assert unitest.resolve_cli_action(["--help"])
110+
== unitest.ShowCliMessage(message: help_text, exit_code: 0)
111+
}
112+
66113
pub fn default_options_returns_expected_defaults_test() {
67114
let opts = unitest.default_options()
68115
assert opts.seed == option.None

0 commit comments

Comments
 (0)