Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file config.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368includeConfig_intfincludeConfig_intf.Typesopen!ImportopenCmdliner_syntax(* Keys are configuration properties, which have defaults and may be
customisable via a CLI. *)moduleKey=structmoduletypeS=sigtypetvaldefault:tendmoduletypeCli=sigincludeSvalterm:toptionCmdliner.Term.tendmoduleFlag(X:sigvalterm:boolCmdliner.Term.tend):Cliwithtypet=bool=structtypet=boolletdefault=false(* If a Cmdliner flag is _not_ set, we interpret it as 'use the program
default' rather than an explicit 'disable'. This changes the type of
{!Cmdliner.Arg.flag} to reflect that fact. *)letterm=X.term>>|functiontrue->Sometrue|false->Noneend(** {1 Definitions of supported keys} *)moduleArg=Cmdliner.ArgmoduleCmd=Cmdliner.CmdmoduleAnd_exit=structtypet=boolletdefault=trueendmoduleRecord_backtrace=structtypet=boolletdefault=trueendmoduleCI=structtypet=ciletdefault=letci=matchSys.getenv"CI"with|"true"->true|_|(exceptionNot_found)->falseandgithub_actions=matchSys.getenv"GITHUB_ACTIONS"with|"true"->true|_|(exceptionNot_found)->falseandocamlci=matchSys.getenv"OCAMLCI"with|"true"->true|_|(exceptionNot_found)->falseinmatch(ci,github_actions,ocamlci)with|true,true,false->`Github_actions|true,false,true->`OCamlci|true,false,false->`Unknown|_->`DisabledendmoduleVerbose=Flag(structletterm=letenv=Cmd.Env.info"ALCOTEST_VERBOSE"inletdoc="Display the test outputs. $(b,WARNING:) when using this option the \
output logs will not be available for further inspection."inArg.(value&flag&info~env["v";"verbose"]~docv:""~doc)end)moduleCompact=Flag(structletterm=letenv=Cmd.Env.info"ALCOTEST_COMPACT"inletdoc="Compact the output of the tests."inArg.(value&flag&info~env["c";"compact"]~docv:""~doc)end)moduleBail=Flag(structletterm=letenv=Cmd.Env.info"ALCOTEST_BAIL"inletdoc="Stop running tests after the first failure."inArg.(value&flag&info~env["bail"]~docv:""~doc)end)moduleJson=Flag(structletterm=letdoc="Display JSON for the results, to be used by a script."inArg.(value&flag&info["json"]~docv:""~doc)end)moduleShow_errors=Flag(structletterm=letenv=Cmd.Env.info"ALCOTEST_SHOW_ERRORS"inletdoc="Display the test errors."inArg.(value&flag&info~env["e";"show-errors"]~docv:""~doc)end)moduleQuick_only=Flag(structletterm=letenv=Cmd.Env.info"ALCOTEST_QUICK_TESTS"inletdoc="Run only the quick tests."inArg.(value&flag&info~env["q";"quick-tests"]~docv:""~doc)end)moduleTail_errors=structtypet=boundletdefault=`Unlimitedletlimit_parsers=matchswith|"unlimited"->Ok`Unlimited|s->(tryletn=int_of_stringsinifn<0thenError(`Msg"numeric limit must be nonnegative or 'unlimited'")elseOk(`Limitn)withFailure_->Error(`Msg"invalid numeric limit"))letlimit_printerppflimit=matchlimitwith|`Unlimited->Fmt.pfppf"unlimited"|`Limitn->Fmt.pfppf"%i"n(* Parse/print a nonnegative number of lines or "unlimited". *)letlimit=Arg.conv(limit_parser,limit_printer)letterm=letenv=Cmd.Env.info"ALCOTEST_TAIL_ERRORS"inletdoc="Show only the last $(docv) lines of output in case of an error."inArg.(value&opt(somelimit)None&info~env["tail-errors"]~docv:"N"~doc)endmoduleLog_dir=structtypet=stringoptionletterm=letdoc="Where to store the log files of the tests."inArg.(value&opt(somedir)None&info["o"]~docv:"DIR"~doc)endmoduleFilter=structtypet=filterletregex:Re.reArg.conv=letparses=tryOkRe.(compile@@Pcre.res)with|Re.Perl.Parse_error->Error(`Msg"Perl-compatible regexp parse error")|Re.Perl.Not_supported->Error(`Msg"unsupported regexp feature")inletprint=Re.pp_reinArg.conv(parse,print)letint_range_list:intlistArg.conv=letexceptionInvalid_formatinletparses=letrecrangelowerupperacc=iflower>upperthenaccelserange(succlower)upper(lower::acc)inletprocess_rangeaccs=String.cuts~sep:".."s|>List.concat_map(String.cuts~sep:"-")|>List.mapString.to_int|>function|[Somei]->i::acc|[Somelower;Someupper]whenlower<=upper->rangelowerupperacc|_->raiseInvalid_formatinletranges=String.cuts~sep:","sinmatchList.fold_leftprocess_range[]rangeswith|list->Oklist|exceptionInvalid_format->Error(`Msg"must be a comma-separated list of integers / integer ranges")inletprintppfset=Fmt.(braces@@list~sep:commaint)ppfsetinArg.conv(parse,print)letterm=let+name_regex=letdoc="A regular expression matching the names of tests to run"inArg.(value&pos0(someregex)None&info[]~doc~docv:"NAME_REGEX")and+index_cases=letdoc="A comma-separated list of test case numbers (and ranges of numbers) \
to run, e.g: '4,6-10,19'. When specifying ranges, both '-' and '..' \
are accepted as valid separators."inArg.(value&pos1(someint_range_list)None&info[]~doc~docv:"TESTCASES")inmatch(name_regex,index_cases)with|None,None->None|_,_->letname_filter=matchname_regexwith|None->fun_->true|Somer->funn->Re.execprninletindex_filter=matchindex_caseswith|None->fun_->true|Someints->letset=Int.Set.of_listintsinfuni->Int.Set.memisetinSome(fun~name~index->ifname_filtername&&index_filterindexthen`Runelse`Skip)endend(* User configs before defaults have been applied. *)moduleUser=structopenKeytypet={and_exit:And_exit.toption;verbose:Verbose.toption;compact:Compact.toption;tail_errors:Tail_errors.toption;quick_only:Quick_only.toption;show_errors:Show_errors.toption;json:Json.toption;filter:Filter.toption;(* TODO: set Log_dir default internally *)log_dir:Log_dir.t;bail:Bail.toption;record_backtrace:Record_backtrace.toption;ci:CI.toption;}let(||)ab=letmerge_onf=Option.(fa||fb)in{and_exit=merge_on(funt->t.and_exit);verbose=merge_on(funt->t.verbose);compact=merge_on(funt->t.compact);tail_errors=merge_on(funt->t.tail_errors);quick_only=merge_on(funt->t.quick_only);show_errors=merge_on(funt->t.show_errors);json=merge_on(funt->t.json);filter=merge_on(funt->t.filter);log_dir=merge_on(funt->t.log_dir);bail=merge_on(funt->t.bail);record_backtrace=merge_on(funt->t.record_backtrace);ci=merge_on(funt->t.ci);}letterm~and_exit~record_backtrace~ci=let+verbose=Verbose.termand+compact=Compact.termand+tail_errors=Tail_errors.termand+show_errors=Show_errors.termand+quick_only=Quick_only.termand+json=Json.termand+filter=Filter.termand+log_dir=Log_dir.termand+bail=Bail.termin{and_exit=Someand_exit;verbose;compact;tail_errors;show_errors;quick_only;json;filter;log_dir;bail;record_backtrace=Somerecord_backtrace;ci=Someci;}(* Lift a config-sensitive function to one that consumes optional arguments that
override config defaults. *)letkcreate:'a.(t->'a)->'awith_options=funf?and_exit?verbose?compact?tail_errors?quick_only?show_errors?json?filter?log_dir?bail?record_backtrace?ci->f{and_exit;verbose;compact;tail_errors;quick_only;show_errors;json;filter;log_dir;bail;record_backtrace;ci;}letcreate:(unit->t)with_options=kcreate(funt()->t)letand_exitt=Option.value~default:And_exit.defaultt.and_exitletrecord_backtracet=Option.value~default:Record_backtrace.defaultt.record_backtraceletcit=Option.value~default:CI.defaultt.ciendletapply_defaults~default_log_dir:User.t->t=fun{and_exit;verbose;compact;tail_errors;quick_only;show_errors;json;filter;log_dir;bail;record_backtrace;ci;}->letopenKeyinobject(self)methodand_exit=Option.value~default:And_exit.defaultand_exitmethodverbose=Option.value~default:Verbose.defaultverbosemethodcompact=Option.value~default:Compact.defaultcompactmethodtail_errors=Option.value~default:Tail_errors.defaulttail_errorsmethodquick_only=Option.value~default:Quick_only.defaultquick_onlymethodshow_errors=match(show_errors,self#ci)with|Someshow_errors,_->show_errors|None,`Disabled->Show_errors.default|None,_->truemethodjson=Option.value~default:Json.defaultjsonmethodfilter=filtermethodlog_dir=Option.value~default:default_log_dirlog_dirmethodbail=Option.value~default:Bail.defaultbailmethodrecord_backtrace=Option.value~default:Record_backtrace.defaultrecord_backtracemethodci=Option.value~default:CI.defaultciend