Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file mdx_test.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387(*
* Copyright (c) 2018 Thomas Gazagnaire <thomas@gazagnaire.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)openMdxopenCompatopenResultopenAstringopenMdx.Util.Result.Infixletsrc=Logs.Src.create"cram.test"moduleLog=(valLogs.src_logsrc:Logs.LOG)let(/)=Filename.concat(* From jbuilder's stdlib *)letansi_color_stripstr=letlen=String.lengthstrinletbuf=Buffer.createleninletrecloopi=ifi=lenthenBuffer.contentsbufelsematchstr.[i]with|'\027'->skip(i+1)|c->Buffer.add_charbufc;loop(i+1)andskipi=ifi=lenthenBuffer.contentsbufelsematchstr.[i]with'm'->loop(i+1)|_->skip(i+1)inloop0letoutput_from_lines=`Output(String.drop~rev:true~sat:Char.Ascii.is_blanks)letwith_dirrootf=matchrootwith|None->f()|Somed->(letold_d=Sys.getcwd()intrySys.chdird;letr=f()inSys.chdirold_d;rwithe->Sys.chdirold_d;raisee)letget_envunset_variables=letenv=Array.to_list(Unix.environment())inletenv=List.map(String.cuts~sep:"=")envinletfenvvar=letgl=String.compare(List.nthl0)var<>0inList.filtergenvinletenv=List.fold_leftfenvunset_variablesinArray.of_list(List.map(String.concat~sep:"=")env)letrun_test?rootunset_variablestemp_filet=letcmd=Cram.command_linetinletenv=get_envunset_variablesinLog.info(funl->l"exec: %S"cmd);letfd=Unix.openfiletemp_file[O_WRONLY;O_TRUNC]0inletpid=with_dirroot(fun()->Unix.create_process_env"sh"[|"sh";"-c";cmd|]envUnix.stdinfdfd)inUnix.closefd;Util.Process.wait~pidletroot_dir?root?block()=match(block:Block.toption)with|Some{dir=None;_}->root|Some{dir=Somed;loc={loc_start={pos_fname;_};_};_}->(matchrootwith|Somer->Some(r/d)|None->Some(Filename.dirnamepos_fname/d))|None->rootletresolve_rootfiledirroot=matchrootwithNone->dir/file|Somer->r/dir/fileletrun_cram_tests?syntaxt?rootppftemp_filepadtests=Block.pp_header?syntaxppft;letpad=matchsyntaxwithSomeCram->pad+2|_->padinList.iter(funtest->letroot=root_dir?root~block:t()inletunset_variables=Block.unset_variablestinletn=run_test?rootunset_variablestemp_filetestinletlines=Mdx.Util.File.read_linestemp_fileinletoutput=letoutput=List.mapoutput_from_linelinesinifOutput.equaloutputtest.outputthentest.outputelseOutput.mergeoutputtest.outputinCram.pp_command~padppftest;List.iter(function|`Ellipsis->Output.pp~padppf`Ellipsis|`Outputline->letline=ansi_color_striplineinOutput.pp~padppf(`Outputline))output;Cram.pp_exit_code~padppfn)tests;Block.pp_footer?syntaxppftleteval_test?block?rootccmd=Log.debug(funl->l"eval_test %a"Fmt.(Dump.list(Fmt.fmt"%S"))cmd);letroot=root_dir?root?block()inwith_dirroot(fun()->Mdx_top.evalccmd)leterr_eval~cmdlines=Fmt.epr"Got an error while evaluating:\n---\n%a\n---\n%a\n%!"Fmt.(list~sep:(unit"\n")string)cmdFmt.(list~sep:(unit"\n")string)lines;exit1leteval_raw?block?rootccmd=matcheval_test?block?rootccmdwith|Ok_->()|Errore->err_eval~cmdeletsplit_lineslines=letauxaccs=(* XXX(samoht) support windowns *)letlines=String.cuts~sep:"\n"sinList.appendlinesaccinList.fold_leftaux[](List.revlines)leteval_ocaml~block?syntax?rootcppfcmderrors=letupdate~errors=function|{Block.value=OCamlv;_}asb->{bwithvalue=OCaml{vwitherrors}}(* [eval_ocaml] only called on OCaml blocks *)|_->assertfalseinmatcheval_test?root~blockccmdwith|Ok_->Block.pp?syntaxppf(update~errors:[]block)|Errorlines->leterrors=letlines=split_lineslinesinletoutput=List.mapoutput_from_linelinesinifOutput.equaloutputerrorsthenerrorselseList.map(function|`Ellipsis->`Ellipsis|`Outputx->`Output(ansi_color_stripx))(Output.mergeoutputerrors)inBlock.pp?syntaxppf(update~errorsblock)letlines=functionOkx|Errorx->xletrun_toplevel_tests?syntax?rootcppftestst=Block.pp_header?syntaxppft;List.iter(fun(test:Toplevel.t)->letlines=lines(eval_test?root~block:tctest.command)inletlines=split_lineslinesinletoutput=letoutput=List.mapoutput_from_linelinesinifOutput.equaloutputtest.outputthentest.outputelseoutputinletpad=test.hpadinToplevel.pp_commandppftest;List.iter(function|`Ellipsis->Output.pp~padppf`Ellipsis|`Outputline->letline=ansi_color_striplineinOutput.pp~padppf(`Outputline))output)tests;matchsyntaxwithSomeSyntax.Mli->()|_->Block.pp_footer?syntaxppfttypefile={first:Mdx.Part.file;current:Mdx.Part.file}letfiles:(string,file)Hashtbl.t=Hashtbl.create8lethas_changed~force_output{first;current}=letcontents=Mdx.Part.contentscurrentinifcontents=Mdx.Part.contentsfirst&&force_output=falsethenNoneelseSomecontentsletread_partsfile=tryHashtbl.findfilesfilewithNot_found->(matchMdx.Part.readfilewith|exceptionSys_errormsg->failwithmsg|parts->letf={first=parts;current=parts}inHashtbl.addfilesfilef;f)letread_partfilepart=letparts=read_partsfileinmatchMdx.Part.findparts.current~partwith|None->Fmt.failwith"Cannot find part %S in %s"(matchpartwithNone->""|Somep->p)file|Somelines->letcontents=String.concat~sep:"\n"linesinString.dropcontents~rev:true~sat:Char.Ascii.is_white|>String.drop~sat:(function'\n'->true|_->false)letwrite_parts~force_outputfileparts=letoutput_file=file^".corrected"inmatchhas_changed~force_outputpartswith|None->ifSys.file_existsoutput_filethenSys.removeoutput_file|Somec->letoc=open_outoutput_fileinoutput_stringocc;flushoc;close_outocletupdate_block_content?syntaxppftcontent=Block.pp_header?syntaxppft;Output.ppppf(`Outputcontent);Block.pp_footer?syntaxppftletupdate_file_or_block?syntax?rootppfmd_fileml_fileblockpart=letroot=root_dir?root~block()inletdir=Filename.dirnamemd_fileinletml_file=resolve_rootml_filedirrootinupdate_block_content?syntaxppfblock(read_partml_filepart)exceptionTest_block_failureofBlock.t*stringletwith_non_det~command~output~detnon_deterministic=function(* the command is non-deterministic so skip everything *)|SomeLabel.Nd_commandwhennotnon_deterministic->command()(* its output is non-deterministic; run it but keep the old output. *)|SomeLabel.Nd_outputwhennotnon_deterministic->output()|_->det()letpreludes~prelude~prelude_str=letauxto_linesp=letenv,file=Mdx.Prelude.env_and_filepin(env,to_linesfile)inmatch(prelude,prelude_str)with|[],[]->[]|[],fs->List.map(aux(funx->[x]))fs|fs,[]->List.map(auxMdx.Util.File.read_lines)fs|_->Fmt.failwith"only one of --prelude or --prelude-str shoud be used"letrun_exn~non_deterministic~silent_eval~record_backtrace~syntax~silent~verbose_findlib~prelude~prelude_str~file~section~root~force_output~output~directives~packages~predicates=Printexc.record_backtracerecord_backtrace;letsyntax=matchsyntaxwithSomesyntax->Somesyntax|None->Syntax.infer~fileinletc=Mdx_top.init~verbose:(notsilent_eval)~silent~verbose_findlib~directives~packages~predicates()inletpreludes=preludes~prelude~prelude_strinlettest_block~ppf~temp_filet=letprint_block()=Block.pp?syntaxppftinifBlock.is_active?sectiontthenmatchBlock.valuetwith|Raw_->print_block()|Include{file_included;file_kind=Fk_ocaml{part_included}}->assert(syntax<>SomeCram);update_file_or_block?syntax?rootppffilefile_includedtpart_included|Include{file_included;file_kind=Fk_other_}->letnew_content=read_partfile_includedNoneinupdate_block_content?syntaxppftnew_content|OCaml{non_det;env;errors}->letdet()=assert(syntax<>SomeCram);Mdx_top.in_envenv(fun()->eval_ocaml~block:t?syntax?rootcppft.contentserrors)inwith_non_detnon_deterministicnon_det~command:print_block~output:det~det|Cram{language=_;non_det}->letpad,tests=Cram.of_linest.contentsinwith_non_detnon_deterministicnon_det~command:print_block~output:(fun()->print_block();letunset_variables=Block.unset_variablestinList.iter(funt->ignore(run_test?rootunset_variablestemp_filet))tests)~det:(fun()->run_cram_tests?syntaxt?rootppftemp_filepadtests)|Toplevel{non_det;env}->lettests=letsyntax=Util.Option.valuesyntax~default:NormalinToplevel.of_lines~syntax~loc:t.loct.contentsinwith_non_detnon_deterministicnon_det~command:print_block~output:(fun()->assert(syntax<>SomeCram);print_block();List.iter(fun(test:Toplevel.t)->matchMdx_top.in_envenv(fun()->eval_test~block:t?rootctest.command)with|Ok_->()|Errore->letoutput=List.map(funl->`Outputl)einifOutput.equaltest.outputoutputthen()elseerr_eval~cmd:test.commande)tests)~det:(fun()->assert(syntax<>SomeCram);Mdx_top.in_envenv(fun()->run_toplevel_tests?syntax?rootcppftestst))elseprint_block()inletgen_correctedfile_contentsitems=lettemp_file=Filename.temp_file"ocaml-mdx"".output"inat_exit(fun()->Sys.removetemp_file);letbuf=Buffer.create(String.lengthfile_contents+1024)inletppf=Format.formatter_of_bufferbufinletenvs=Document.envsitemsinletevallines()=eval_raw?rootclinesinleteval_in_envlinesenv=Mdx_top.in_envenv(evallines)inList.iter(function|`All,lines->Ocaml_env.Set.iter(eval_in_envlines)envs|`Oneenv,lines->eval_in_envlinesenv)preludes;List.iter(function|(Mdx.Document.Section_|Text_)ast->Mdx.pp_line?syntaxppft|Blockt->(List.iter(fun(k,v)->Unix.putenvkv)(Block.set_variablest);trytest_block~ppf~temp_filetwithFailuremsg->raise(Test_block_failure(t,msg))))items;Format.pp_print_flushppf();Buffer.contentsbufin(matchoutputwith|Some`Stdout->Mdx.run_to_stdout?syntax~f:gen_correctedfile|Some(`Fileoutfile)->Mdx.run_to_file?syntax~outfile~f:gen_correctedfile|None->Mdx.run?syntax~force_output~f:gen_correctedfile)>>!fun()->Hashtbl.iter(write_parts~force_output)files;0modulePackage=structletunix="unix"letfindlib_top="findlib.top"letfindlib_internal="findlib.internal"letcompilerlibs_toplevel="compiler-libs.toplevel"endmodulePredicate=structletbyte="byte"lettoploop="toploop"end