local Parser = require "argparse" getmetatable(Parser()).error = function(_, msg) error(msg) end describe("tests related to help message generation", function() it("creates correct help message for empty parser", function() local parser = Parser "foo" assert.equal([[ Usage: foo [-h] Options: -h, --help Show this help message and exit.]], parser:get_help()) end) it("does not create extra help options when :prepare is called several times", function() local parser = Parser "foo" assert.equal([[ Usage: foo [-h] Options: -h, --help Show this help message and exit.]], parser:get_help()) end) it("uses custom help option ", function() local parser = Parser "foo" :add_help "/?" assert.equal([[ Usage: foo [/?] Options: /? Show this help message and exit.]], parser:get_help()) end) it("uses description and epilog", function() local parser = Parser("foo", "A description.", "An epilog.") assert.equal([[ Usage: foo [-h] A description. Options: -h, --help Show this help message and exit. An epilog.]], parser:get_help()) end) it("creates correct help message for arguments", function() local parser = Parser "foo" parser:argument "first" parser:argument "second-and-third" :args "2" parser:argument "maybe-fourth" :args "?" parser:argument("others", "Optional.") :args "*" assert.equal([[ Usage: foo [-h] [] [] ... Arguments: first second-and-third maybe-fourth others Optional. Options: -h, --help Show this help message and exit.]], parser:get_help()) end) it("creates correct help message for options", function() local parser = Parser "foo" parser:flag "-q" "--quiet" parser:option "--from" :count "1" :target "server" parser:option "--config" assert.equal([[ Usage: foo [-q] --from [--config ] [-h] Options: -q, --quiet --from --config -h, --help Show this help message and exit.]], parser:get_help()) end) it("adds margin for multiline descriptions", function() local parser = Parser "foo" parser:flag "-v" :count "0-2" :target "verbosity" :description [[ Sets verbosity level. -v: Report all warnings. -vv: Report all debugging information.]] assert.equal([[ Usage: foo [-v] [-h] Options: -v Sets verbosity level. -v: Report all warnings. -vv: Report all debugging information. -h, --help Show this help message and exit.]], parser:get_help()) end) it("puts different aliases on different lines if there are arguments", function() local parser = Parser "foo" parser:option "-o --output" assert.equal([[ Usage: foo [-o ] [-h] Options: -o , --output -h, --help Show this help message and exit.]], parser:get_help()) end) it("handles description with more lines than usage", function() local parser = Parser "foo" parser:option "-o --output" :description [[ Sets output file. If missing, 'a.out' is used by default. If '-' is passed, output to stdount. ]] assert.equal([[ Usage: foo [-o ] [-h] Options: -o , Sets output file. --output If missing, 'a.out' is used by default. If '-' is passed, output to stdount. -h, --help Show this help message and exit.]], parser:get_help()) end) it("handles description with less lines than usage", function() local parser = Parser "foo" parser:option "-o --output" :description "Sets output file." assert.equal([[ Usage: foo [-o ] [-h] Options: -o , Sets output file. --output -h, --help Show this help message and exit.]], parser:get_help()) end) it("handles very long argument lists", function() local parser = Parser "foo" parser:option "-t --at-least-three" :args("3+") :argname {"", "", ""} :description "Sometimes argument lists are really long." assert.equal([[ Usage: foo [-h] [-t ...] Options: -t ..., --at-least-three ... Sometimes argument lists are really long. -h, --help Show this help message and exit.]], parser:get_help()) end) it("shows default values", function() local parser = Parser "foo" parser:option "-o" :default "a.out" parser:option "-p" :default "8080" :description "Port." assert.equal([[ Usage: foo [-o ] [-p

] [-h] Options: -o default: a.out -p

Port. (default: 8080) -h, --help Show this help message and exit.]], parser:get_help()) end) it("does not show default value when show_default == false", function() local parser = Parser "foo" parser:option "-o" :default "a.out" :show_default(false) parser:option "-p" :default "8080" :show_default(false) :description "Port." assert.equal([[ Usage: foo [-o ] [-p

] [-h] Options: -o -p

Port. -h, --help Show this help message and exit.]], parser:get_help()) end) it("creates correct help message for commands", function() local parser = Parser "foo" parser:flag "-q --quiet" local run = parser:command "run" :description "Run! " run:option "--where" assert.equal([[ Usage: foo [-q] [-h] ... Options: -q, --quiet -h, --help Show this help message and exit. Commands: run Run! ]], parser:get_help()) end) it("creates correct help message for subcommands", function() local parser = Parser "foo" parser:flag "-q" "--quiet" local run = parser:command "run" run:option "--where" assert.equal([[ Usage: foo run [--where ] [-h] Options: --where -h, --help Show this help message and exit.]], run:get_help()) end) it("uses message provided by user", function() local parser = Parser "foo" :help "I don't like your format of help messages" parser:flag "-q" "--quiet" assert.equal([[ I don't like your format of help messages]], parser:get_help()) end) it("does not mention hidden arguments, options, and commands", function() local parser = Parser "foo" parser:argument "normal" parser:argument "deprecated" :args "?" :hidden(true) parser:flag "--feature" parser:flag "--misfeature" :hidden(true) parser:command "good" parser:command "okay" parser:command "never-use-this-one" :hidden(true) assert.equal([[ Usage: foo [--feature] [-h] ... Arguments: normal Options: --feature -h, --help Show this help message and exit. Commands: good okay]], parser:get_help()) end) it("omits categories if all elements are hidden", function() local parser = Parser "foo" :add_help(false) parser:argument "deprecated" :args "?" :hidden(true) parser:flag "--misfeature" :hidden(true) assert.equal([[ Usage: foo]], parser:get_help()) end) it("supports grouping options", function() local parser = Parser "foo" :add_help(false) parser:argument "thing" parser:group("Options for setting position", parser:option "--coords" :args(2) :argname {"", ""} :description "Set coordinates.", parser:option "--polar" :args(2) :argname {"", ""} :description "Set polar coordinates." ) parser:group("Options for setting style", parser:flag "--dotted" :description "More dots.", parser:option "--width" :argname "" :description "Set width." ) assert.equal([[ Usage: foo [--coords ] [--polar ] [--dotted] [--width ] Arguments: thing Options for setting position: --coords Set coordinates. --polar Set polar coordinates. Options for setting style: --dotted More dots. --width Set width.]], parser:get_help()) end) it("adds default group with 'other' prefix if not all elements of a type are grouped", function() local parser = Parser "foo" parser:group("Main arguments", parser:argument "foo", parser:argument "bar", parser:flag "--use-default-args" ) parser:argument "optional" :args "?" parser:group("Main options", parser:flag "--something", parser:option "--test" ) parser:flag "--version" parser:group("Some commands", parser:command "foo", parser:command "bar" ) parser:command "another-command" assert.equal([[ Usage: foo [--use-default-args] [--something] [--test ] [--version] [-h] [] ... Main arguments: foo bar --use-default-args Other arguments: optional Main options: --something --test Other options: --version -h, --help Show this help message and exit. Some commands: foo bar Other commands: another-command]], parser:get_help()) end) it("allows spacing out element help blocks more with help_vertical_space", function() local parser = Parser "foo" :help_vertical_space(1) parser:argument "arg1" :description "Argument number one." parser:argument "arg2" :description "Argument number two." parser:flag "-p" :description "This is a thing." parser:option "-f --foo" :description [[ And this things uses many lines. Because it has lots of complex behaviour. That needs documenting.]] assert.equal([[ Usage: foo [-p] [-f ] [-h] Arguments: arg1 Argument number one. arg2 Argument number two. Options: -p This is a thing. -f , And this things uses many lines. --foo Because it has lots of complex behaviour. That needs documenting. -h, --help Show this help message and exit.]], parser:get_help()) end) it("inherits help_vertical_space in commands", function() local parser = Parser "foo" :help_vertical_space(1) local cmd1 = parser:command "cmd1" :help_vertical_space(2) cmd1:flag("-a", "Do a thing.") cmd1:flag("-b", "Do b thing.") local cmd2 = parser:command "cmd2" cmd2:flag("-c", "Do c thing.") cmd2:flag("-d", "Do d thing.") assert.equal([[ Usage: foo cmd1 [-a] [-b] [-h] Options: -a Do a thing. -b Do b thing. -h, --help Show this help message and exit.]], cmd1:get_help()) assert.equal([[ Usage: foo cmd2 [-c] [-d] [-h] Options: -c Do c thing. -d Do d thing. -h, --help Show this help message and exit.]], cmd2:get_help()) end) it("allows configuring margins using help_usage_margin and help_description_margin", function() local parser = Parser "foo" :help_usage_margin(2) :help_description_margin(15) parser:argument "arg1" :description "Argument number one." parser:argument "arg2" :description "Argument number two." parser:flag "-p" :description "This is a thing." parser:option "-f --foo" :description [[ And this things uses many lines. Because it has lots of complex behaviour. That needs documenting.]] assert.equal([[ Usage: foo [-p] [-f ] [-h] Arguments: arg1 Argument number one. arg2 Argument number two. Options: -p This is a thing. -f , And this things uses many lines. --foo Because it has lots of complex behaviour. That needs documenting. -h, --help Show this help message and exit.]], parser:get_help()) end) describe("autowrap", function() it("automatically wraps descriptions to match given max width", function() local parser = Parser "foo" :help_max_width(80) parser:option "-f --foo" :description("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor " .. "incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation " .. "ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit " .. "in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat " .. "non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.") parser:option "-b --bar" :description "See above." assert.equal([[ Usage: foo [-f ] [-b ] [-h] Options: -f , Lorem ipsum dolor sit amet, consectetur adipiscing --foo elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. -b , See above. --bar -h, --help Show this help message and exit.]], parser:get_help()) end) it("preserves existing line breaks", function() local parser = Parser "foo" :help_max_width(80) parser:option "-f --foo" :description("This is a long line, it should be broken down into several lines. " .. [[ It just keeps going and going. This should always be a new line. Another one. ]]) parser:option "-b --bar" assert.equal([[ Usage: foo [-f ] [-b ] [-h] Options: -f , This is a long line, it should be broken down into --foo several lines. It just keeps going and going. This should always be a new line. Another one. -b , --bar -h, --help Show this help message and exit.]], parser:get_help()) end) it("preserves indentation", function() local parser = Parser "foo" :help_max_width(80) parser:option "-f --foo" :description("This is a long line, it should be broken down into several lines.\n" .. " This paragraph is indented with three spaces, so when it gets broken down into several lines, " .. "they will be, too.\n\n" .. " That was an empty line there, preserve it.") assert.equal([[ Usage: foo [-f ] [-h] Options: -f , This is a long line, it should be broken down into --foo several lines. This paragraph is indented with three spaces, so when it gets broken down into several lines, they will be, too. That was an empty line there, preserve it. -h, --help Show this help message and exit.]], parser:get_help()) end) it("preserves indentation of list items", function() local parser = Parser "foo" :help_max_width(80) parser:option "-f --foo" :description("Let's start a list:\n\n" .. "* Here is a list item.\n" .. "* Here is another one, this one is very long so it needs several lines. More words. Word. Word.\n" .. " + Here is a nested list item. Word. Word. Word. Word. Word. Bird. Word. Bird. Bird. Bird.\n" .. "* Back to normal list, this one uses several spaces after the list item mark. Bird. Bird. Bird.") assert.equal([[ Usage: foo [-f ] [-h] Options: -f , Let's start a list: --foo * Here is a list item. * Here is another one, this one is very long so it needs several lines. More words. Word. Word. + Here is a nested list item. Word. Word. Word. Word. Word. Bird. Word. Bird. Bird. Bird. * Back to normal list, this one uses several spaces after the list item mark. Bird. Bird. Bird. -h, --help Show this help message and exit.]], parser:get_help()) end) it("preserves multiple spaces between words", function() local parser = Parser "foo" :help_max_width(80) parser:option "-f --foo" :description("This is a long line with two spaces between words, it should be broken down.") assert.equal([[ Usage: foo [-f ] [-h] Options: -f , This is a long line with two spaces between --foo words, it should be broken down. -h, --help Show this help message and exit.]], parser:get_help()) end) it("autowraps description and epilog", function() local parser = Parser "foo" :help_max_width(80) :description("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor " .. "incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation " .. "ullamco laboris nisi ut aliquip ex ea commodo consequat.") :epilog("Duis aute irure dolor in reprehenderit " .. "in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat " .. "non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.") assert.equal([[ Usage: foo [-h] Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Options: -h, --help Show this help message and exit. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]], parser:get_help()) end) end) end)