123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140open!Importtypespeed_level=[`Quick|`Slow]moduleTest_name:sigtypetvalv:name:string->index:int->tvalname:t->Safe_string.tvalindex:t->intvalpp:tFmt.t(** Pretty-print the unescaped test-case name *)valfile:t->string(** An escaped form of the test name with [.output] suffix. *)vallength:t->int(** The approximate number of terminal columns consumed by [pp_name]. *)valcompare:t->t->int(** Order lexicographically by name, then by index. *)end=structtypet={name:Safe_string.t;file:string;index:int}letindex{index;_}=indexletv~name~index=letname=Safe_string.vnameinletfile=letname=matchSafe_string.to_stringnamewith""->""|n->n^"."inFmt.str"%s%03d.output"nameindexin{name;file;index}letpp=Fmt.using(fun{name;_}->name)Safe_string.ppletname{name;_}=nameletfile{file;_}=fileletlength=name>>Safe_string.lengthletcomparett'=matchSafe_string.comparet.namet'.namewith|0->(compare:int->int->int)t.indext'.index|n->nendmoduleRun_result=structtypet=[`Ok|`ExnofTest_name.t*string*unitFmt.t|`ErrorofTest_name.t*unitFmt.t|`Skip|`Todoofstring](** [is_failure] holds for test results that are error states. *)letis_failure:t->bool=function|`Ok|`Skip->false|`Error_|`Exn_|`Todo_->trueendmoduleSuite(M:Monad.S):sigtype'attype'atest_fn=[`Skip|`Runof'a->Run_result.tM.t]type'atest_case={name:Test_name.t;speed_level:speed_level;fn:'atest_fn;}valv:name:string->(_t,[>`Empty_name])result(** Construct a new suite, given a non-empty [name]. Test cases must be added
with {!add}. *)valname:_t->string(** An escaped form of the suite name. *)valpp_name:_tFmt.t(** Pretty-print the unescaped suite name. *)valadd:'at->Test_name.t*string*speed_level*'atest_fn->('at,[`Duplicate_test_pathofstring])resultvaltests:'at->'atest_caselistvaldoc_of_test_name:'at->Test_name.t->stringend=structmoduleString_set=Set.Make(String)type'atest_fn=[`Skip|`Runof'a->Run_result.tM.t]type'atest_case={name:Test_name.t;speed_level:speed_level;fn:'atest_fn;}type'at={name:Safe_string.t;tests:'atest_caselist;(* caches computed from the library values. *)filepaths:String_set.t;doc:(Test_name.t,string)Hashtbl.t;}letv~name=matchString.lengthnamewith|0->Error`Empty_name|_->letname=Safe_string.vnameinlettests=[]inletfilepaths=String_set.emptyinletdoc=Hashtbl.create0inOk{name;tests;filepaths;doc}letname{name;_}=Safe_string.to_stringnameletpp_nameppf{name;_}=Safe_string.ppppfnameletcheck_path_is_uniquettname=matchString_set.mem(Test_name.filetname)t.filepathswith|false->Ok()|true->Error(`Duplicate_test_path(Fmt.to_to_stringTest_name.pptname))letaddt(tname,doc,speed_level,fn)=matchcheck_path_is_uniquettnamewith|Error_ase->e|Ok()->lettests={name=tname;speed_level;fn}::t.testsinletfilepaths=String_set.add(Test_name.filetname)t.filepathsinHashtbl.addt.doctnamedoc;Ok{twithtests;filepaths}lettestst=List.revt.testsletdoc_of_test_nametpath=tryHashtbl.findt.docpathwithNot_found->""end