(*--------------------------------------------------------------------------- Copyright (c) 2025 The cmdliner programmers. All rights reserved. SPDX-License-Identifier: ISC ---------------------------------------------------------------------------*) open B0_std open B0_testing open Cmdliner open Cmdliner.Term.Syntax (* The tests have the following structure: let test = let cmd = … (* A command definition *) in (* A few snapshots of valid cli parses *) parse … (* A few snapshots of invalid cli parses *) error … (* A snapshot of a plain text version of the manual *) Testing_cmdliner.snap_man … *) let test_with_used_args = Test.test "Term.with_used_args" @@ fun () -> let cmd = Cmd.make (Cmd.info "test_with_used_args" ~doc:"Test cli arg capture") @@ let args = let+ a = Arg.(value & flag & info ["a"; "aaa"]) and+ b = Arg.(value & opt (some string) None & info ["b"; "bbb"]) and+ c = Arg.(value & pos_all string [] & info []) in (a, b, c) in let+ parse, args = Term.with_used_args args in args, parse in let t = Test.T.(t2 (list string) (t3 bool (option string) (list string))) in let parse = Testing_cmdliner.snap_parse t cmd in let error err = Testing_cmdliner.snap_eval_error err cmd in parse [] @@ __POS_OF__ ([], (false, None, [])); (* Note some of these are bugs, see issue #204 *) parse ["--"] @@ __POS_OF__ ([], (false, None, [])); parse ["hoho"; "-a"; "-bmsg"] @@ __POS_OF__ (["-a"; "-b"; "msg"; "hoho"], (true, Some "msg", ["hoho"])); parse ["hoho"; "-a"; "-bmsg"; "hihi"] @@ __POS_OF__ (["-a"; "-b"; "msg"; "hoho"; "hihi"], (true, Some "msg", ["hoho"; "hihi"])); parse ["--"; "hoho"; "-a"; "-bbla"; "hihi"] @@ __POS_OF__ (["hoho"; "-a"; "-bbla"; "hihi"], (false, None, ["hoho"; "-a"; "-bbla"; "hihi"])); parse ["hoho"; "-a"; "--bbb=msg"; "hihi"] @@ __POS_OF__ (["-a"; "--bbb"; "msg"; "hoho"; "hihi"], (true, Some "msg", ["hoho"; "hihi"])); (**) error `Term ["--opt"] @@ __POS_OF__ "Usage: \u{001B}[01mtest_with_used_args\u{001B}[m [\u{001B}[01m--help\u{001B}[m] [\u{001B}[01m--aaa\u{001B}[m] [\u{001B}[01m--bbb\u{001B}[m=\u{001B}[04mVAL\u{001B}[m] [\u{001B}[04mOPTION\u{001B}[m]… [\u{001B}[04mARG\u{001B}[m]…\n\ test_with_used_args: \u{001B}[31munknown\u{001B}[m option \u{001B}[01m--opt\u{001B}[m\n"; (**) Testing_cmdliner.snap_man cmd @@ __POS_OF__ {|NAME test_with_used_args - Test cli arg capture SYNOPSIS test_with_used_args [--aaa] [--bbb=VAL] [OPTION]… [ARG]… OPTIONS -a, --aaa -b VAL, --bbb=VAL COMMON OPTIONS --help[=FMT] (default=auto) Show this help in format FMT. The value FMT must be one of auto, pager, groff or plain. With auto, the format is pager or plain whenever the TERM env var is dumb or undefined. EXIT STATUS test_with_used_args exits with: 0 on success. 123 on indiscriminate errors reported on standard error. 124 on command line parsing errors. |}; () let term_duplication = Test.test "Term.app duplicates" @@ fun () -> let cmd = Cmd.make (Cmd.info "test_term_dups" ~doc:"Test multiple term usage") @@ let+ p = let doc = "First pos argument should show up only once in the docs" in Arg.(value & pos 0 string "popopo" & info [] ~doc ~docv:"POS") and+ o = let doc = "This should show up only once in the docs" in Arg.(value & flag & info ["f"; "flag"] ~doc) in (p, p, o, o) in let t = Test.T.(t4 string string bool bool) in let parse = Testing_cmdliner.snap_parse t cmd in let error err = Testing_cmdliner.snap_eval_error err cmd in parse [] @@ __POS_OF__ ("popopo", "popopo", false, false); parse ["0"] @@ __POS_OF__ ("0", "0", false, false); parse ["0"; "-f"] @@ __POS_OF__ ("0", "0", true, true); (**) error `Term ["0"; "1"] @@ __POS_OF__ "Usage: \u{001B}[01mtest_term_dups\u{001B}[m [\u{001B}[01m--help\u{001B}[m] [\u{001B}[01m--flag\u{001B}[m] [\u{001B}[04mOPTION\u{001B}[m]… [\u{001B}[04mPOS\u{001B}[m]\n\ test_term_dups: \u{001B}[31mtoo many arguments\u{001B}[m, don't know what to do with \u{001B}[01m1\u{001B}[m\n"; (**) Testing_cmdliner.snap_man cmd @@ __POS_OF__ {|NAME test_term_dups - Test multiple term usage SYNOPSIS test_term_dups [--flag] [OPTION]… [POS] ARGUMENTS POS (absent=popopo) First pos argument should show up only once in the docs OPTIONS -f, --flag This should show up only once in the docs COMMON OPTIONS --help[=FMT] (default=auto) Show this help in format FMT. The value FMT must be one of auto, pager, groff or plain. With auto, the format is pager or plain whenever the TERM env var is dumb or undefined. EXIT STATUS test_term_dups exits with: 0 on success. 123 on indiscriminate errors reported on standard error. 124 on command line parsing errors. |}; () let test_env = Test.test "Term.env" @@ fun () -> let env = function "HEYHO" -> Some "Let's go" | _ -> None in let cmd = Cmd.make (Cmd.info "test_env" ~doc:"Test Term.env") @@ let+ env = Term.env in Test.(option T.string) (env "HEYHO") (Some "Let's go") in Testing_cmdliner.test_eval_result ~env Test.T.unit cmd [] (Ok (`Ok ())); () let main () = let doc = "Test term specifications" in Test.main ~doc @@ fun () -> Test.autorun () let () = if !Sys.interactive then () else exit (main ())