610 lines
21 KiB
OCaml
610 lines
21 KiB
OCaml
open Inshellah.Parser
|
|
open Inshellah.Manpage
|
|
open Inshellah.Nushell
|
|
|
|
let failures = ref 0
|
|
let passes = ref 0
|
|
|
|
let check name condition =
|
|
if condition then begin
|
|
incr passes;
|
|
Printf.printf " PASS: %s\n" name
|
|
end else begin
|
|
incr failures;
|
|
Printf.printf " FAIL: %s\n" name
|
|
end
|
|
|
|
let parse txt =
|
|
match parse_help txt with
|
|
| Ok r -> r
|
|
| Error msg -> failwith (Printf.sprintf "parse_help failed: %s" msg)
|
|
|
|
(* --- Help parser tests --- *)
|
|
|
|
let test_gnu_basic () =
|
|
Printf.printf "\n== GNU basic flags ==\n";
|
|
let r = parse " -a, --all do not ignore entries starting with .\n" in
|
|
check "one entry" (List.length r.entries = 1);
|
|
let e = List.hd r.entries in
|
|
check "both switch" (e.switch = Both ('a', "all"));
|
|
check "no param" (e.param = None);
|
|
check "desc" (String.length e.desc > 0)
|
|
|
|
let test_gnu_eq_param () =
|
|
Printf.printf "\n== GNU = param ==\n";
|
|
let r = parse " --block-size=SIZE scale sizes by SIZE\n" in
|
|
check "one entry" (List.length r.entries = 1);
|
|
let e = List.hd r.entries in
|
|
check "long switch" (e.switch = Long "block-size");
|
|
check "mandatory param" (e.param = Some (Mandatory "SIZE"))
|
|
|
|
let test_gnu_opt_param () =
|
|
Printf.printf "\n== GNU optional param ==\n";
|
|
let r = parse " --color[=WHEN] color the output WHEN\n" in
|
|
check "one entry" (List.length r.entries = 1);
|
|
let e = List.hd r.entries in
|
|
check "long switch" (e.switch = Long "color");
|
|
check "optional param" (e.param = Some (Optional "WHEN"))
|
|
|
|
let test_underscore_param () =
|
|
Printf.printf "\n== Underscore in param (TIME_STYLE) ==\n";
|
|
let r = parse " --time-style=TIME_STYLE time/date format\n" in
|
|
check "one entry" (List.length r.entries = 1);
|
|
let e = List.hd r.entries in
|
|
check "param with underscore" (e.param = Some (Mandatory "TIME_STYLE"))
|
|
|
|
let test_short_only () =
|
|
Printf.printf "\n== Short-only flag ==\n";
|
|
let r = parse " -v verbose output\n" in
|
|
check "one entry" (List.length r.entries = 1);
|
|
check "short switch" ((List.hd r.entries).switch = Short 'v')
|
|
|
|
let test_long_only () =
|
|
Printf.printf "\n== Long-only flag ==\n";
|
|
let r = parse " --help display help\n" in
|
|
check "one entry" (List.length r.entries = 1);
|
|
check "long switch" ((List.hd r.entries).switch = Long "help")
|
|
|
|
let test_multiline_desc () =
|
|
Printf.printf "\n== Multi-line description ==\n";
|
|
let r = parse {| --block-size=SIZE with -l, scale sizes by SIZE when printing them;
|
|
e.g., '--block-size=M'; see SIZE format below
|
|
|} in
|
|
check "one entry" (List.length r.entries = 1);
|
|
let e = List.hd r.entries in
|
|
check "desc includes continuation" (String.length e.desc > 50)
|
|
|
|
let test_multiple_entries () =
|
|
Printf.printf "\n== Multiple entries ==\n";
|
|
let r = parse {| -a, --all do not ignore entries starting with .
|
|
-A, --almost-all do not list implied . and ..
|
|
--author with -l, print the author of each file
|
|
|} in
|
|
check "three entries" (List.length r.entries = 3)
|
|
|
|
let test_clap_short_sections () =
|
|
Printf.printf "\n== Clap short with section headers ==\n";
|
|
let r = parse {|INPUT OPTIONS:
|
|
-e, --regexp=PATTERN A pattern to search for.
|
|
-f, --file=PATTERNFILE Search for patterns from the given file.
|
|
SEARCH OPTIONS:
|
|
-s, --case-sensitive Search case sensitively.
|
|
|} in
|
|
check "three entries" (List.length r.entries = 3);
|
|
let e = List.hd r.entries in
|
|
check "first is regexp" (e.switch = Both ('e', "regexp"));
|
|
check "first has param" (e.param = Some (Mandatory "PATTERN"))
|
|
|
|
let test_clap_long_style () =
|
|
Printf.printf "\n== Clap long style (desc below flag) ==\n";
|
|
let r = parse {| -H, --hidden
|
|
Include hidden directories and files.
|
|
|
|
--no-ignore
|
|
Do not respect ignore files.
|
|
|} in
|
|
check "two entries" (List.length r.entries = 2);
|
|
let e = List.hd r.entries in
|
|
check "hidden switch" (e.switch = Both ('H', "hidden"));
|
|
check "desc below" (String.length e.desc > 0)
|
|
|
|
let test_clap_long_angle_param () =
|
|
Printf.printf "\n== Clap long angle bracket param ==\n";
|
|
let r = parse {| --nonprintable-notation <notation>
|
|
Set notation for non-printable characters.
|
|
|} in
|
|
check "one entry" (List.length r.entries = 1);
|
|
let e = List.hd r.entries in
|
|
check "long switch" (e.switch = Long "nonprintable-notation");
|
|
check "angle param" (e.param = Some (Mandatory "notation"))
|
|
|
|
let test_space_upper_param () =
|
|
Printf.printf "\n== Space-separated ALL_CAPS param ==\n";
|
|
let r = parse " -f, --foo FOO foo help\n" in
|
|
check "one entry" (List.length r.entries = 1);
|
|
let e = List.hd r.entries in
|
|
check "switch" (e.switch = Both ('f', "foo"));
|
|
check "space param" (e.param = Some (Mandatory "FOO"))
|
|
|
|
let test_go_cobra_flags () =
|
|
Printf.printf "\n== Go/Cobra flags ==\n";
|
|
let r = parse {|Flags:
|
|
-D, --debug Enable debug mode
|
|
-H, --host string Daemon socket to connect to
|
|
-v, --version Print version information
|
|
|} in
|
|
check "three flag entries" (List.length r.entries = 3);
|
|
(* Check the host flag has a type param *)
|
|
let host = List.nth r.entries 1 in
|
|
check "host switch" (host.switch = Both ('H', "host"));
|
|
check "host type param" (host.param = Some (Mandatory "string"))
|
|
|
|
let test_go_cobra_subcommands () =
|
|
Printf.printf "\n== Go/Cobra subcommands ==\n";
|
|
let r = parse {|Common Commands:
|
|
run Create and run a new container from an image
|
|
exec Execute a command in a running container
|
|
build Build an image from a Dockerfile
|
|
|} in
|
|
check "has subcommands" (List.length r.subcommands > 0)
|
|
|
|
let test_busybox_tab () =
|
|
Printf.printf "\n== Busybox tab-indented ==\n";
|
|
let r = parse "\t-1\tOne column output\n\t-a\tInclude names starting with .\n" in
|
|
check "two entries" (List.length r.entries = 2);
|
|
check "first is -1" ((List.hd r.entries).switch = Short '1')
|
|
|
|
let test_no_debug_prints () =
|
|
Printf.printf "\n== No debug side effects ==\n";
|
|
(* The old parser had print_endline at module load time.
|
|
If we got here without "opt param is running" on stdout, we're good. *)
|
|
check "no debug prints" true
|
|
|
|
(* --- Manpage parser tests --- *)
|
|
|
|
let test_manpage_tp_style () =
|
|
Printf.printf "\n== Manpage .TP style ==\n";
|
|
let groff = {|.SH OPTIONS
|
|
.TP
|
|
\fB\-a\fR, \fB\-\-all\fR
|
|
do not ignore entries starting with .
|
|
.TP
|
|
\fB\-A\fR, \fB\-\-almost\-all\fR
|
|
do not list implied . and ..
|
|
.TP
|
|
\fB\-\-block\-size\fR=\fISIZE\fR
|
|
with \fB\-l\fR, scale sizes by SIZE
|
|
.SH AUTHOR
|
|
Written by someone.
|
|
|} in
|
|
let result = parse_manpage_string groff in
|
|
check "three entries" (List.length result.entries = 3);
|
|
if List.length result.entries >= 1 then begin
|
|
let e = List.hd result.entries in
|
|
check "first is -a/--all" (e.switch = Both ('a', "all"));
|
|
check "first desc" (String.length e.desc > 0)
|
|
end;
|
|
if List.length result.entries >= 3 then begin
|
|
let e = List.nth result.entries 2 in
|
|
check "block-size switch" (e.switch = Long "block-size");
|
|
check "block-size param" (e.param = Some (Mandatory "SIZE"))
|
|
end
|
|
|
|
let test_manpage_ip_style () =
|
|
Printf.printf "\n== Manpage .IP style ==\n";
|
|
let groff = {|.SH OPTIONS
|
|
.IP "\fB\-k\fR, \fB\-\-insecure\fR"
|
|
Allow insecure connections.
|
|
.IP "\fB\-o\fR, \fB\-\-output\fR \fIfile\fR"
|
|
Write output to file.
|
|
.SH SEE ALSO
|
|
|} in
|
|
let result = parse_manpage_string groff in
|
|
check "two entries" (List.length result.entries = 2);
|
|
if List.length result.entries >= 1 then begin
|
|
let e = List.hd result.entries in
|
|
check "first is -k/--insecure" (e.switch = Both ('k', "insecure"))
|
|
end
|
|
|
|
let test_manpage_groff_stripping () =
|
|
Printf.printf "\n== Groff escape stripping ==\n";
|
|
let s = strip_groff_escapes {|\fB\-\-color\fR[=\fIWHEN\fR]|} in
|
|
check "font escapes removed" (not (String.contains s 'f' && String.contains s 'B'));
|
|
check "dashes converted" (String.contains s '-');
|
|
let s2 = strip_groff_escapes {|\(aqhello\(aq|} in
|
|
check "aq -> quote" (String.contains s2 '\'')
|
|
|
|
let test_manpage_empty_options () =
|
|
Printf.printf "\n== Manpage with no OPTIONS section ==\n";
|
|
let groff = {|.SH NAME
|
|
foo \- does stuff
|
|
.SH DESCRIPTION
|
|
Does stuff.
|
|
|} in
|
|
let result = parse_manpage_string groff in
|
|
check "no entries" (List.length result.entries = 0)
|
|
|
|
let test_slash_switch_separator () =
|
|
Printf.printf "\n== Slash switch separator (--long / -s) ==\n";
|
|
let r = parse " --verbose / -v Increase verbosity\n" in
|
|
check "one entry" (List.length r.entries = 1);
|
|
let e = List.hd r.entries in
|
|
check "both switch" (e.switch = Both ('v', "verbose"));
|
|
check "no param" (e.param = None);
|
|
check "desc" (e.desc = "Increase verbosity")
|
|
|
|
let test_manpage_nix3_style () =
|
|
Printf.printf "\n== Manpage nix3 style ==\n";
|
|
let groff = {|.SH Options
|
|
.SS Logging-related options
|
|
.IP "\(bu" 3
|
|
.UR #opt-verbose
|
|
\f(CR--verbose\fR
|
|
.UE
|
|
/ \f(CR-v\fR
|
|
.IP
|
|
Increase the logging verbosity level.
|
|
.IP "\(bu" 3
|
|
.UR #opt-quiet
|
|
\f(CR--quiet\fR
|
|
.UE
|
|
.IP
|
|
Decrease the logging verbosity level.
|
|
.SH SEE ALSO
|
|
|} in
|
|
let result = parse_manpage_string groff in
|
|
check "two entries" (List.length result.entries = 2);
|
|
if List.length result.entries >= 1 then begin
|
|
let e = List.hd result.entries in
|
|
check "verbose is Both" (e.switch = Both ('v', "verbose"));
|
|
check "verbose desc" (String.length e.desc > 0)
|
|
end;
|
|
if List.length result.entries >= 2 then begin
|
|
let e = List.nth result.entries 1 in
|
|
check "quiet is Long" (e.switch = Long "quiet");
|
|
check "quiet desc" (String.length e.desc > 0)
|
|
end
|
|
|
|
let test_manpage_nix3_with_params () =
|
|
Printf.printf "\n== Manpage nix3 with params ==\n";
|
|
let groff = {|.SH Options
|
|
.IP "\(bu" 3
|
|
.UR #opt-arg
|
|
\f(CR--arg\fR
|
|
.UE
|
|
\fIname\fR \fIexpr\fR
|
|
.IP
|
|
Pass the value as the argument name to Nix functions.
|
|
.IP "\(bu" 3
|
|
.UR #opt-include
|
|
\f(CR--include\fR
|
|
.UE
|
|
/ \f(CR-I\fR \fIpath\fR
|
|
.IP
|
|
Add path to search path entries.
|
|
.IP
|
|
This option may be given multiple times.
|
|
.SH SEE ALSO
|
|
|} in
|
|
let result = parse_manpage_string groff in
|
|
check "two entries" (List.length result.entries = 2);
|
|
if List.length result.entries >= 1 then begin
|
|
let e = List.hd result.entries in
|
|
check "arg is Long" (e.switch = Long "arg");
|
|
check "arg has param" (e.param <> None)
|
|
end;
|
|
if List.length result.entries >= 2 then begin
|
|
let e = List.nth result.entries 1 in
|
|
check "include is Both" (e.switch = Both ('I', "include"));
|
|
check "include has path param" (e.param = Some (Mandatory "path"))
|
|
end
|
|
|
|
let test_synopsis_subcommand () =
|
|
Printf.printf "\n== SYNOPSIS subcommand detection ==\n";
|
|
let groff = {|.SH "SYNOPSIS"
|
|
.sp
|
|
.nf
|
|
\fBgit\fR \fBcommit\fR [\fB\-a\fR | \fB\-\-interactive\fR]
|
|
.fi
|
|
.SH "DESCRIPTION"
|
|
|} in
|
|
let cmd = extract_synopsis_command groff in
|
|
check "detected git commit" (cmd = Some "git commit")
|
|
|
|
let test_synopsis_standalone () =
|
|
Printf.printf "\n== SYNOPSIS standalone command ==\n";
|
|
let groff = {|.SH Synopsis
|
|
.LP
|
|
\f(CRnix-build\fR [\fIpaths\fR]
|
|
.SH Description
|
|
|} in
|
|
let cmd = extract_synopsis_command groff in
|
|
check "detected nix-build" (cmd = Some "nix-build")
|
|
|
|
let test_synopsis_nix3 () =
|
|
Printf.printf "\n== SYNOPSIS nix3 subcommand ==\n";
|
|
let groff = {|.SH Synopsis
|
|
.LP
|
|
\f(CRnix run\fR [\fIoption\fR] \fIinstallable\fR
|
|
.SH Description
|
|
|} in
|
|
let cmd = extract_synopsis_command groff in
|
|
check "detected nix run" (cmd = Some "nix run")
|
|
|
|
(* --- Nushell generation tests --- *)
|
|
|
|
let contains s sub =
|
|
try
|
|
let _ = Str.search_forward (Str.regexp_string sub) s 0 in true
|
|
with Not_found -> false
|
|
|
|
let test_nushell_basic () =
|
|
Printf.printf "\n== Nushell basic extern ==\n";
|
|
let r = parse " -a, --all do not ignore entries starting with .\n" in
|
|
let nu = generate_extern "ls" r in
|
|
check "has extern" (contains nu "export extern \"ls\"");
|
|
check "has --all(-a)" (contains nu "--all(-a)");
|
|
check "has comment" (contains nu "# do not ignore")
|
|
|
|
let test_nushell_param_types () =
|
|
Printf.printf "\n== Nushell param type mapping ==\n";
|
|
let r = parse {| -w, --width=COLS set output width
|
|
--block-size=SIZE scale sizes
|
|
-o, --output FILE output file
|
|
|} in
|
|
let nu = generate_extern "ls" r in
|
|
check "COLS -> int" (contains nu "--width(-w): int");
|
|
check "SIZE -> string" (contains nu "--block-size: string");
|
|
check "FILE -> path" (contains nu "--output(-o): path")
|
|
|
|
let test_nushell_subcommands () =
|
|
Printf.printf "\n== Nushell subcommands ==\n";
|
|
let r = parse {|Common Commands:
|
|
run Create and run a new container
|
|
exec Execute a command
|
|
|
|
Flags:
|
|
-D, --debug Enable debug mode
|
|
|} in
|
|
let nu = generate_extern "docker" r in
|
|
check "has main extern" (contains nu "export extern \"docker\"");
|
|
check "has --debug" (contains nu "--debug(-D)");
|
|
check "has run subcommand" (contains nu "export extern \"docker run\"");
|
|
check "has exec subcommand" (contains nu "export extern \"docker exec\"")
|
|
|
|
let test_nushell_from_manpage () =
|
|
Printf.printf "\n== Nushell from manpage ==\n";
|
|
let groff = {|.SH OPTIONS
|
|
.TP
|
|
\fB\-a\fR, \fB\-\-all\fR
|
|
do not ignore entries starting with .
|
|
.TP
|
|
\fB\-\-block\-size\fR=\fISIZE\fR
|
|
scale sizes by SIZE
|
|
.SH AUTHOR
|
|
|} in
|
|
let result = parse_manpage_string groff in
|
|
let nu = generate_extern "ls" result in
|
|
check "has extern" (contains nu "export extern \"ls\"");
|
|
check "has --all(-a)" (contains nu "--all(-a)");
|
|
check "has --block-size" (contains nu "--block-size: string")
|
|
|
|
let test_nushell_module () =
|
|
Printf.printf "\n== Nushell module wrapper ==\n";
|
|
let r = parse " -v, --verbose verbose output\n" in
|
|
let nu = generate_module "myapp" r in
|
|
check "has module" (contains nu "module myapp-completions");
|
|
check "has extern inside" (contains nu "export extern \"myapp\"");
|
|
check "has flag" (contains nu "--verbose(-v)")
|
|
|
|
let test_dedup_entries () =
|
|
Printf.printf "\n== Deduplication ==\n";
|
|
let r = parse {| -v, --verbose verbose output
|
|
--verbose verbose mode
|
|
-v be verbose
|
|
|} in
|
|
let nu = generate_extern "test" r in
|
|
(* Count occurrences of --verbose *)
|
|
let count =
|
|
let re = Str.regexp_string "--verbose" in
|
|
let n = ref 0 in
|
|
let i = ref 0 in
|
|
(try while true do
|
|
let _ = Str.search_forward re nu !i in
|
|
incr n; i := Str.match_end ()
|
|
done with Not_found -> ());
|
|
!n
|
|
in
|
|
check "verbose appears once" (count = 1);
|
|
check "best version kept (Both)" (contains nu "--verbose(-v)")
|
|
|
|
let test_dedup_manpage () =
|
|
Printf.printf "\n== Dedup from manpage ==\n";
|
|
let groff = {|.SH OPTIONS
|
|
.TP
|
|
\fB\-v\fR, \fB\-\-verbose\fR
|
|
Be verbose.
|
|
.SH DESCRIPTION
|
|
Use \fB\-v\fR for verbose output.
|
|
Use \fB\-\-verbose\fR to see more.
|
|
|} in
|
|
let result = parse_manpage_string groff in
|
|
let nu = generate_extern "test" result in
|
|
check "has --verbose(-v)" (contains nu "--verbose(-v)");
|
|
(* Should not have standalone -v or duplicate --verbose *)
|
|
let lines = String.split_on_char '\n' nu in
|
|
let verbose_lines = List.filter (fun l -> contains l "verbose") lines in
|
|
check "only one verbose line" (List.length verbose_lines = 1)
|
|
|
|
let test_commands_section_subcommands () =
|
|
Printf.printf "\n== COMMANDS section subcommand extraction ==\n";
|
|
(* manpages like systemctl have a COMMANDS section with bold command names
|
|
* inside .PP + .RS/.RE blocks. these should be extracted as subcommands
|
|
* and treated as leaf nodes (no entries of their own). *)
|
|
let groff = {|.SH OPTIONS
|
|
.TP
|
|
\fB\-\-user\fR
|
|
Talk to the service manager of the calling user.
|
|
.TP
|
|
\fB\-\-system\fR
|
|
Talk to the service manager of the system.
|
|
.SH COMMANDS
|
|
.PP
|
|
\fBstart\fR \fIUNIT\fR\&...
|
|
.RS 4
|
|
Start (activate) one or more units.
|
|
.RE
|
|
.PP
|
|
\fBstop\fR \fIUNIT\fR\&...
|
|
.RS 4
|
|
Stop (deactivate) one or more units.
|
|
.RE
|
|
.PP
|
|
\fBreload\fR \fIUNIT\fR\&...
|
|
.RS 4
|
|
Asks all units to reload their configuration.
|
|
.RE
|
|
.SH SEE ALSO
|
|
|} in
|
|
let result = parse_manpage_string groff in
|
|
check "has options entries" (List.length result.entries = 2);
|
|
check "has subcommands" (List.length result.subcommands = 3);
|
|
let sc_names = List.map (fun (sc : subcommand) -> sc.name) result.subcommands in
|
|
check "has start" (List.mem "start" sc_names);
|
|
check "has stop" (List.mem "stop" sc_names);
|
|
check "has reload" (List.mem "reload" sc_names);
|
|
(* verify subcommand descriptions are extracted *)
|
|
let start_sc = List.find (fun (sc : subcommand) -> sc.name = "start") result.subcommands in
|
|
check "start has desc" (String.length start_sc.desc > 0)
|
|
|
|
let test_self_listing_detection () =
|
|
Printf.printf "\n== Self-listing subcommand detection ==\n";
|
|
(* when a subcommand's --help shows the parent's help text,
|
|
* the subcommand name appears in its own subcommand list.
|
|
* the parser should detect this — tested via parse_help. *)
|
|
let help_text = {|systemctl [OPTIONS...] COMMAND ...
|
|
|
|
Unit Commands:
|
|
start UNIT... Start (activate) one or more units
|
|
stop UNIT... Stop (deactivate) one or more units
|
|
status [PATTERN...] Show runtime status
|
|
|
|
Options:
|
|
--user Talk to the user service manager
|
|
--system Talk to the system service manager
|
|
|} in
|
|
let r = parse help_text in
|
|
let has_start = List.exists (fun (sc : subcommand) -> sc.name = "start") r.subcommands in
|
|
check "detected start as subcommand" has_start;
|
|
(* the self-listing logic (in main.ml) would check: is "start" in r.subcommands?
|
|
* here we just verify the parser extracts it correctly. *)
|
|
check "has entries too" (List.length r.entries >= 2)
|
|
|
|
let test_nu_file_parsing () =
|
|
Printf.printf "\n== .nu file parsing ==\n";
|
|
let nu_source = {|module completions {
|
|
|
|
# Unofficial CLI tool
|
|
export extern mytool [
|
|
--help(-h) # Print help
|
|
--version(-V) # Print version
|
|
]
|
|
|
|
# List all items
|
|
export extern "mytool list" [
|
|
--raw # Output as JSON
|
|
--format(-f): string # Output format
|
|
--help(-h) # Print help
|
|
name?: string # Filter by name
|
|
]
|
|
|
|
}
|
|
|
|
use completions *
|
|
|} in
|
|
let r = Inshellah.Store.parse_nu_completions "mytool" nu_source in
|
|
check "has entries" (List.length r.entries = 2);
|
|
check "has subcommands" (List.length r.subcommands >= 1);
|
|
let list_sc = List.find_opt (fun (sc : subcommand) -> sc.name = "list") r.subcommands in
|
|
check "has list subcommand" (list_sc <> None);
|
|
check "description" (r.description = "Unofficial CLI tool");
|
|
(* test subcommand lookup *)
|
|
let r2 = Inshellah.Store.parse_nu_completions "mytool list" nu_source in
|
|
check "list has entries" (List.length r2.entries = 3);
|
|
let has_format = List.exists (fun (e : entry) ->
|
|
e.switch = Both ('f', "format")) r2.entries in
|
|
check "list has --format(-f)" has_format;
|
|
check "list has positional" (List.length r2.positionals >= 1)
|
|
|
|
let test_italic_synopsis () =
|
|
Printf.printf "\n== Italic in SYNOPSIS ==\n";
|
|
let groff = {|.SH Synopsis
|
|
.LP
|
|
\f(CRnix-env\fR \fIoperation\fR [\fIoptions\fR] [\fIarguments…\fR]
|
|
.SH Description
|
|
|} in
|
|
let cmd = extract_synopsis_command groff in
|
|
check "no phantom operation" (cmd = Some "nix-env")
|
|
|
|
let test_font_boundary_spacing () =
|
|
Printf.printf "\n== Font boundary spacing ==\n";
|
|
(* \fB--max-results\fR\fIcount\fR should become "--max-results count" *)
|
|
let s = strip_groff_escapes {|\fB\-\-max\-results\fR\fIcount\fR|} in
|
|
check "has space before param" (contains s "--max-results count");
|
|
(* \fB--color\fR[=\fIWHEN\fR] should NOT insert space before = *)
|
|
let s2 = strip_groff_escapes {|\fB\-\-color\fR[=\fIWHEN\fR]|} in
|
|
check "no space before =" (contains s2 "--color[=WHEN]")
|
|
|
|
let () =
|
|
Printf.printf "Running help parser tests...\n";
|
|
test_gnu_basic ();
|
|
test_gnu_eq_param ();
|
|
test_gnu_opt_param ();
|
|
test_underscore_param ();
|
|
test_short_only ();
|
|
test_long_only ();
|
|
test_multiline_desc ();
|
|
test_multiple_entries ();
|
|
test_clap_short_sections ();
|
|
test_clap_long_style ();
|
|
test_clap_long_angle_param ();
|
|
test_space_upper_param ();
|
|
test_go_cobra_flags ();
|
|
test_go_cobra_subcommands ();
|
|
test_busybox_tab ();
|
|
test_no_debug_prints ();
|
|
|
|
Printf.printf "\nRunning manpage parser tests...\n";
|
|
test_manpage_tp_style ();
|
|
test_manpage_ip_style ();
|
|
test_manpage_groff_stripping ();
|
|
test_manpage_empty_options ();
|
|
test_slash_switch_separator ();
|
|
test_manpage_nix3_style ();
|
|
test_manpage_nix3_with_params ();
|
|
test_synopsis_subcommand ();
|
|
test_synopsis_standalone ();
|
|
test_synopsis_nix3 ();
|
|
|
|
Printf.printf "\nRunning nushell generation tests...\n";
|
|
test_nushell_basic ();
|
|
test_nushell_param_types ();
|
|
test_nushell_subcommands ();
|
|
test_nushell_from_manpage ();
|
|
test_nushell_module ();
|
|
|
|
Printf.printf "\nRunning dedup and font tests...\n";
|
|
test_dedup_entries ();
|
|
test_dedup_manpage ();
|
|
test_font_boundary_spacing ();
|
|
|
|
Printf.printf "\nRunning COMMANDS section tests...\n";
|
|
test_commands_section_subcommands ();
|
|
test_self_listing_detection ();
|
|
|
|
Printf.printf "\nRunning .nu and synopsis tests...\n";
|
|
test_nu_file_parsing ();
|
|
test_italic_synopsis ();
|
|
|
|
Printf.printf "\n=== Results: %d passed, %d failed ===\n" !passes !failures;
|
|
if !failures > 0 then exit 1
|