I’ve been interested in having a command line library that makes it easier to test those aspects of an application. I haven’t found a Fortran library that seems to allow this because they do some or all of the following:
- report they’re own errors directly to the user and stop themselves (can’t test error conditions in a unit testing framework)
- interact directly with get_command_line_argument (can’t run multiple tests at once from a single executable)
- Don’t provide a convenient way of defining/describing the desired command line options
The most compelling example of a library I’ve seen that manages to solve these problems is optparse-applicative for Haskell.
Basically, I’d like to have just the following appear in my main program
class(my_custom_args_type), allocatable :: args
args = parse_command_line()
...
where the internals are organized like the following
function parse_command_line() result(args)
class(my_custom_args_type), allocatable :: args
type(varying_string), allocatable :: arg_strings(:)
type(error_t) :: errors
type(varying_string) :: help_text
arg_strings = get_command_line_strings()
args = run_my_parser(my_command_line_parser(), arg_strings, errors, help_text)
if (errors%has_any()) then
call put_line(errors%to_string())
call put_line(help_text)
error stop
end if
end function
pure function run_my_parser(parser, strings, errors, help_text) result(args)
type(cmdff_parser_t), intent(in) :: parser
type(varying_string), intent(in) :: strings(:)
type(error_t), intent(out) :: errors
type(varyign_string), intent(out) :: help_text
class(my_custom_args_type), allocatable :: args
type(cmdff_parsed_args_t) :: parsed_args
parsed_args = run_parser(parser, strings, errors, help_text)
if (.not.errors%has_any()) then
args = to_my_args(parsed_args, errors)
end if
end function
pure function to_my_args(parsed_args, errors) result(args)
type(cmdff_parsed_args_t), intent(in) :: parsed_args
type(error_t), intent(out) :: errors
class(my_custom_args_type), allocatable :: args
! code to extract data from parsed_args and populate args
end function
pure function my_command_line_parser() result(parser)
type(cmdff_parser_t) :: parser
parser = info( &
sample() + helper(), &
full_description() + program_description("Print a greeting for TARGET") + header("hello - a test for cmdff"))
end function
pure function sample()
type(cmdff_parser_info_t) :: sample
sample = &
string_option(long("hello") + metavar("TARGET") + help("Target for greeting")) &
+ switch(long("quiet") + short("q") + help("Whether to be quiet")) &
+ option(INTEGER_PARSER, long("enthusiasm") + help("How enthusiastically to greet") + show_default() + value(1) + metavar("INT"))
end function
so that I can write tests like the following:
arg_strings = [var_str("some"), var_str("command"), var_str("I'd"), var_str("like"), var_str("to"), var_str("test")]
args = run_my_parser(my_command_line_parser(), arg_strings, errors, help_text)
! make some assertions about errors returned, help_text content, or args values
In this way, the rest of my code is completely divorced from any command line aspects, let alone any knowledge of the command line library I’m using. Even my tests are only aware to a very minimal extent of the command line library I’m using.
I’m curious to know:
- Would there be sufficient interest in having such a library available?
- Would anyone like to collaborate on the project with me?