Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file matcher.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467openBaseopenStdioopenExpect_test_commonletfprintf=Out_channel.fprintfmoduleSaved_output=structtypet=|Oneofstring|Many_distinctofstringlistletof_nonempty_list_exnoutputs=let_,rev_deduped_preserving_order=List.foldoutputs~init:(Set.empty(moduleString),[])~f:(fun(as_set,as_list)output->ifSet.memas_setoutputthenas_set,as_listelseSet.addas_setoutput,output::as_list)inmatchList.revrev_deduped_preserving_orderwith|[]->failwith"Saved_output.of_nonempty_list_exn got an empty list"|[output]->Oneoutput|outputs->Many_distinctoutputs;;letto_list=function|Ones->[s]|Many_distinctmany->many;;letmerget1t2=of_nonempty_list_exn(to_listt1@to_listt2)endmoduleTest_outcome=structmoduleExpectations=structtypet=Fmt.tCst.tExpectation.tMap.M(File.Location).t[@@deriving_inlinecompare,equal]let_=fun(_:t)->()letcompare=(funa__001_b__002_->Map.compare_m__t(moduleFile.Location)(funa__003_b__004_->Expectation.compare(funa__005_b__006_->Cst.compareFmt.comparea__005_b__006_)a__003_b__004_)a__001_b__002_:t->t->int);;let_=compareletequal=(funa__009_b__010_->Map.equal_m__t(moduleFile.Location)(funa__011_b__012_->Expectation.equal(funa__013_b__014_->Cst.equalFmt.equala__013_b__014_)a__011_b__012_)a__009_b__010_:t->t->bool);;let_=equal[@@@end]endtypet={expectations:Expectations.t;uncaught_exn_expectation:Fmt.tCst.tExpectation.toption;saved_output:Saved_output.tMap.M(File.Location).t;trailing_output:Saved_output.t;uncaught_exn:Saved_output.toption;upon_unreleasable_issue:Expect_test_config_types.Upon_unreleasable_issue.t}letmerge_exnt{expectations;uncaught_exn_expectation;saved_output;trailing_output;uncaught_exn;upon_unreleasable_issue}=ifnot(Expectations.equalt.expectationsexpectations)thenfailwith"merging tests of different expectations";ifnot(Expect_test_config_types.Upon_unreleasable_issue.equalt.upon_unreleasable_issueupon_unreleasable_issue)thenfailwith"merging tests of different [Upon_unreleasable_issue]";ifnot(Option.equal(Expectation.equal(Cst.equalFmt.equal))t.uncaught_exn_expectationuncaught_exn_expectation)thenfailwith"merging tests of different uncaught exception expectations";{expectations;uncaught_exn_expectation;saved_output=Map.merget.saved_outputsaved_output~f:(fun~key:_->function|`Leftx->Somex|`Rightx->Somex|`Both(x,y)->Some(Saved_output.mergexy));uncaught_exn=(matcht.uncaught_exn,uncaught_exnwith|None,None->None|Somex,None|None,Somex->Somex|Somex,Somey->Some(Saved_output.mergexy));trailing_output=Saved_output.merget.trailing_outputtrailing_output;upon_unreleasable_issue};;endmoduleTest_correction=structmoduleNode_correction=structtypet=|Collector_never_triggered|CorrectionofFmt.tCst.tExpectation.Body.tendmoduleUncaught_exn=structtypet=|Match|Without_expectationofFmt.tCst.tExpectation.Body.t|CorrectionofFmt.tCst.tExpectation.t*Fmt.tCst.tExpectation.Body.t|Unused_expectationofFmt.tCst.tExpectation.tendtypet={location:File.Location.t;(* In the order of the file *)corrections:(Fmt.tCst.tExpectation.t*Node_correction.t)list;uncaught_exn:Uncaught_exn.t;trailing_output:Fmt.tCst.tExpectation.Body.tReconcile.Result.t}letmap_correctionst~f={location=t.location;corrections=List.mapt.corrections~f:(fun(e,c)->(e,matchcwith|Collector_never_triggered->c|Correctionbody->Correction(Expectation.Body.map_prettybody~f)));uncaught_exn=(matcht.uncaught_exnwith|(Match|Unused_expectation_)asx->x|Without_expectationbody->Without_expectation(Expectation.Body.map_prettybody~f)|Correction(e,body)->Correction(e,Expectation.Body.map_prettybody~f));trailing_output=Reconcile.Result.mapt.trailing_output~f:(Expectation.Body.map_pretty~f)};;letcompare_locationsab=comparea.location.line_numberb.location.line_numberletmake~location~corrections~uncaught_exn~trailing_output:tReconcile.Result.t=ifList.is_emptycorrections&&(matchtrailing_outputwith|Reconcile.Result.Match->true|_->false)&&matchuncaught_exnwith|Uncaught_exn.Match->true|_->falsethenMatchelseCorrection{location;corrections;uncaught_exn;trailing_output};;endletindentation_atfile_contents(loc:File.Location.t)=letn=refloc.line_startinwhileChar.equalfile_contents.[!n]' 'doInt.incrndone;!n-loc.line_start;;letevaluate_test~file_contents~(location:File.Location.t)~allow_output_patterns(test:Test_outcome.t)=letcr_for_multiple_outputs~cr_bodyoutputs=letprefix=Expect_test_config_types.Upon_unreleasable_issue.comment_prefixtest.upon_unreleasable_issueinletcr=Printf.sprintf"(* %sexpect_test: %s *)"prefixcr_bodyinletsep=String.init(String.lengthcr)~f:(fun_->'=')inList.intersperse(cr::outputs)~sep|>String.concat~sep:"\n"inletcorrections=Map.to_alisttest.expectations|>List.filter_map~f:(fun(location,(expect:Fmt.tCst.tExpectation.t))->letcorrection_foractual=letdefault_indent=indentation_atfile_contentsexpect.body_locationinmatchReconcile.expectation_body~expect:expect.body~actual~default_indent~pad_single_line:(Option.is_someexpect.tag)~allow_output_patternswith|Match->None|Correctionc->Some(expect,Test_correction.Node_correction.Correctionc)inmatchMap.findtest.saved_outputlocationwith|None->(matchexpect.bodywith|Unreachable->None|_->Some(expect,Test_correction.Node_correction.Collector_never_triggered))|Some(Oneactual)->correction_foractual|Some(Many_distinctoutputs)->letmatches_expectationoutput=Option.is_none(correction_foroutput)inifList.for_alloutputs~f:matches_expectationthenNoneelsecr_for_multiple_outputsoutputs~cr_body:"Collector ran multiple times with different outputs"|>correction_for)inlettrailing_output=letindent=location.start_pos-location.line_start+2inletactual=matchtest.trailing_outputwith|Oneactual->actual|Many_distinctoutputs->cr_for_multiple_outputsoutputs~cr_body:"Test ran multiple times with different trailing outputs"inReconcile.expectation_body~expect:(PrettyCst.empty)~actual~default_indent:indent~pad_single_line:true~allow_output_patternsinletuncaught_exn:Test_correction.Uncaught_exn.t=matchtest.uncaught_exnwith|None->(matchtest.uncaught_exn_expectationwith|None->Match|Somee->Unused_expectatione)|Somex->letindent=location.start_pos-location.line_startinletactual=matchxwith|Oneactual->actual|Many_distinctoutputs->cr_for_multiple_outputsoutputs~cr_body:"Test ran multiple times with different uncaught exceptions"inletexpect=matchtest.uncaught_exn_expectationwith|None->Expectation.Body.PrettyCst.empty|Somee->e.bodyin(matchReconcile.expectation_body~expect~actual~default_indent:indent~pad_single_line:true~allow_output_patternswith|Match->Match|Correctionc->(matchtest.uncaught_exn_expectationwith|None->Without_expectationc|Somee->Correction(e,c)))inTest_correction.make~location~corrections~uncaught_exn~trailing_output;;typemode=|Inline_expect_test|Toplevel_expect_testletoutput_sliceoutsab=Out_channel.output_stringout(String.subs~pos:a~len:(b-a));;letis_space=function|'\t'|'\011'|'\012'|'\r'|' '|'\n'->true|_->false;;letrecoutput_semi_colon_if_neededocfile_contentspos=ifpos>=0then(matchfile_contents.[pos]with|cwhenis_spacec->output_semi_colon_if_neededocfile_contents(pos-1)|';'->()|_->Out_channel.output_charoc';');;letsplit_liness=String.splits~on:'\n'letoutput_correctedoc~file_contents~modetest_corrections=letid_and_string_of_body:_Expectation.Body.t->string*string=function|Exactx->"expect_exact",x|Output->"expect.output",""|Prettyx->"expect",Cst.to_stringx|Unreachable->assertfalseinletoutput_bodyoctagbody=matchtagwith|None->fprintfoc"\"%s\""(String.concat~sep:"\n"(split_linesbody|>List.map~f:String.escaped))|Sometag->lettag=Choose_tag.choose~default:tagbodyinfprintfoc"{%s|%s|%s}"tagbodytaginletofs=List.fold_lefttest_corrections~init:0~f:(funofs(test_correction:Test_correction.t)->lettest_correction,to_skip=(* If we need to remove an [%%expect.uncaught_exn] node, start by adjusting the
end position of the test. *)matchtest_correction.uncaught_exnwith|Unused_expectatione->(* Unfortunately, the OCaml parser doesn't give us the location of the whole
extension point, so we have to find the square brackets ourselves :( *)letstart=refe.extid_location.start_posinwhilenot(Char.equalfile_contents.[!start]'[')doifInt.(>=)ofs!startthenraise_s(Sexp.message"Cannot find '[' marking the start of [%expect.uncaught_exn]"["ofs",Int.sexp_of_tofs;"start",Int.sexp_of_te.extid_location.start_pos]);Int.decrstartdone;while!start-1>ofs&&is_spacefile_contents.[!start-1]doInt.decrstartdone;letfile_len=String.lengthfile_contentsinletstop=refe.body_location.end_posinwhile!stop<file_len&¬(Char.equalfile_contents.[!stop]']')doInt.incrstopdone;ifInt.(>=)!stopfile_lenthenraise_s(Sexp.message"Cannot find ']' marking the end of [%expect.uncaught_exn]"["stop",Int.sexp_of_te.body_location.end_pos]);Int.incrstop;lettest_correction={test_correctionwithlocation={test_correction.locationwithend_pos=!start}}intest_correction,Some(!start,!stop)|_->test_correction,Noneinletofs=List.fold_lefttest_correction.corrections~init:ofs~f:(funofs(e,correction)->match(correction:Test_correction.Node_correction.t)with|Collector_never_triggered->output_sliceocfile_contentsofse.Expectation.extid_location.start_pos;fprintfoc"expect.unreachable";e.body_location.end_pos|Correctionc->letid,body=id_and_string_of_bodycinoutput_sliceocfile_contentsofse.extid_location.start_pos;Out_channel.output_stringocid;output_sliceocfile_contentse.extid_location.end_pose.body_location.start_pos;output_bodyoce.tagbody;e.body_location.end_pos)inletofs=matchtest_correction.trailing_outputwith|Match->ofs|Correctionc->letloc=test_correction.locationinoutput_sliceocfile_contentsofsloc.end_pos;ifmatchmodewith|Inline_expect_test->true|_->falsethenoutput_semi_colon_if_neededocfile_contentsloc.end_pos;letid,body=id_and_string_of_bodycin(matchmodewith|Inline_expect_test->letindent=loc.start_pos-loc.line_start+2infprintfoc"\n%*s[%%%s "indent""id|Toplevel_expect_test->ifloc.end_pos=0||Char.(<>)file_contents.[loc.end_pos-1]'\n'thenOut_channel.output_charoc'\n';fprintfoc"[%%%%%s"id);output_bodyoc(Some"")body;fprintfoc"]";loc.end_posinletofs=matchtest_correction.uncaught_exnwith|Match->ofs|Unused_expectation_->(* handled above *)ofs|Without_expectationc->letloc=test_correction.locationinoutput_sliceocfile_contentsofsloc.end_pos;letindent=loc.start_pos-loc.line_startinfprintfoc"\n%*s[@@expect.uncaught_exn "indent"";output_bodyoc(Some"")(snd(id_and_string_of_bodyc));fprintfoc"]";loc.end_pos|Correction(e,c)->output_sliceocfile_contentsofse.body_location.start_pos;output_bodyoce.tag(snd(id_and_string_of_bodyc));e.body_location.end_posinmatchto_skipwith|None->ofs|Some(start,stop)->output_sliceocfile_contentsofsstart;stop)inoutput_sliceocfile_contentsofs(String.lengthfile_contents);;letwrite_corrected~file~file_contents~modetest_corrections=Out_channel.with_filefile~f:(funoc->output_correctedoc~file_contents~mode(List.sorttest_corrections~compare:Test_correction.compare_locations));;