123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325(**************************************************************************)(* The OUnit library *)(* *)(* Copyright (C) 2002-2008 Maas-Maarten Zeeman. *)(* Copyright (C) 2010 OCamlCore SARL *)(* Copyright (C) 2013 Sylvain Le Gall *)(* *)(* The package OUnit is copyright by Maas-Maarten Zeeman, OCamlCore SARL *)(* and Sylvain Le Gall. *)(* *)(* Permission is hereby granted, free of charge, to any person obtaining *)(* a copy of this document and the OUnit software ("the Software"), to *)(* deal in the Software without restriction, including without limitation *)(* the rights to use, copy, modify, merge, publish, distribute, *)(* sublicense, and/or sell copies of the Software, and to permit persons *)(* to whom the Software is furnished to do so, subject to the following *)(* conditions: *)(* *)(* The above copyright notice and this permission notice shall be *)(* included in all copies or substantial portions of the Software. *)(* *)(* The Software is provided ``as is'', without warranty of any kind, *)(* express or implied, including but not limited to the warranties of *)(* merchantability, fitness for a particular purpose and noninfringement. *)(* In no event shall Maas-Maarten Zeeman be liable for any claim, damages *)(* or other liability, whether in an action of contract, tort or *)(* otherwise, arising from, out of or in connection with the Software or *)(* the use or other dealings in the software. *)(* *)(* See LICENSE.txt for details. *)(**************************************************************************)openOUnitLoggeropenOUnitTestopenOUnitResultSummaryletocaml_positionpos=Printf.sprintf"File \"%s\", line %d, characters 1-1:"pos.filenamepos.lineletmultilinefstr=ifString.lengthstr>0thenletbuf=Buffer.create80inletflush()=f(Buffer.contentsbuf);Buffer.clearbufinString.iter(function'\n'->flush()|c->Buffer.add_charbufc)str;flush()letcountresultsf=List.fold_left(funcount(_,test_result,_)->ifftest_resultthencount+1elsecount)0results(* TODO: deprecate in 2.1.0. *)letresults_style_1_X=OUnitConf.make_bool"results_style_1_X"false"Use OUnit 1.X results printer (will be deprecated in 2.1.0+)."letformat_display_eventconflog_event=matchlog_event.eventwith|GlobalEvente->beginmatchewith|GConf(_,_)|GLog_|GStart|GEnd->""|GResults(running_time,results,test_case_count)->letseparator1=String.make(Format.get_margin())'='inletseparator2=String.make(Format.get_margin())'-'inletbuf=Buffer.create1024inletbprintffmt=Printf.bprintfbuffmtinletprint_results=List.iter(fun(path,test_result,pos_opt)->bprintf"%s\n"separator1;ifresults_style_1_Xconfthenbeginbprintf"%s: %s\n\n"(result_flavourtest_result)(string_of_pathpath);endelsebeginbprintf"Error: %s.\n\n"(string_of_pathpath);beginmatchpos_optwith|Somepos->bprintf"%s\nError: %s (in the log).\n\n"(ocaml_positionpos)(string_of_pathpath)|None->()end;beginmatchtest_resultwith|RError(_,Somebacktrace)->bprintf"%s\n"backtrace|RFailure(_,Somepos,_)->bprintf"%s\nError: %s (in the code).\n\n"(ocaml_positionpos)(string_of_pathpath)|RFailure(_,_,Somebacktrace)->bprintf"%s\n"backtrace|_->()end;end;bprintf"%s\n"(result_msgtest_result);bprintf"%s\n"separator2)inletfilterf=letlst=List.filter(fun(_,test_result,_)->ftest_result)resultsinlst,List.lengthlstinleterrors,nerrors=filteris_errorinletfailures,nfailures=filteris_failureinletskips,nskips=filteris_skipinlet_,ntodos=filteris_todoinlettimeouts,ntimeouts=filteris_timeoutinbprintf"\n";print_resultserrors;print_resultsfailures;print_resultstimeouts;bprintf"Ran: %d tests in: %.2f seconds.\n"(List.lengthresults)running_time;(* Print final verdict *)ifwas_successfulresultsthenbeginifskips=[]thenbprintf"OK"elsebprintf"OK: Cases: %d Skip: %d"test_case_countnskipsendelsebeginbprintf"FAILED: Cases: %d Tried: %d Errors: %d \
Failures: %d Skip: %d Todo: %d \
Timeouts: %d."test_case_count(List.lengthresults)nerrorsnfailuresnskipsntodosntimeouts;end;bprintf"\n";Buffer.contentsbufend|TestEvent(_,e)->beginmatchewith|EStart|EEnd|ELog_|ELogRaw_->""|EResultRSuccess->"."|EResult(RFailure_)->"F"|EResult(RError_)->"E"|EResult(RSkip_)->"S"|EResult(RTodo_)->"T"|EResult(RTimeout_)->"~"endletformat_log_eventev=letrlst=ref[]inlettimestamp_str=OUnitUtils.date_iso8601ev.timestampinletspfprefmt=Printf.ksprintf(multiline(funl->rlst:=(timestamp_str^" "^ev.shard^" "^pre^": "^l)::!rlst))fmtinletispffmt=spf"I"fmtinletwspffmt=spf"W"fmtinletespffmt=spf"E"fmtinletformat_resultpathresult=letpath_str=string_of_pathpathinmatchresultwith|RTimeouttest_length->espf"Test %s timed out after %.1fs"path_str(delay_of_lengthtest_length)|RError(msg,backtrace_opt)->espf"Test %s exited with an error."path_str;espf"%s in test %s."msgpath_str;OUnitUtils.opt(espf"%s")backtrace_opt|RFailure(msg,_,backtrace_opt)->espf"Test %s has failed."path_str;espf"%s in test %s."msgpath_str;OUnitUtils.opt(espf"%s")backtrace_opt|RTodomsg->wspf"TODO test %s: %s."path_strmsg|RSkipmsg->wspf"Skip test %s: %s."path_strmsg|RSuccess->ispf"Test %s is successful."path_strinbeginmatchev.eventwith|GlobalEvente->beginmatchewith|GConf(k,v)->ispf"Configuration %s = %S"kv|GLog(`Error,str)->espf"%s"str|GLog(`Warning,str)->wspf"%s"str|GLog(`Info,str)->ispf"%s"str|GStart->ispf"Start testing."|GEnd->ispf"End testing."|GResults(running_time,results,test_case_count)->letcounter=countresultsinispf"==============";ispf"Summary:";List.iter(fun(path,test_result,_)->format_resultpathtest_result)results;(* Print final verdict *)ispf"Ran: %d tests in: %.2f seconds."(List.lengthresults)running_time;ispf"Cases: %d."test_case_count;ispf"Tried: %d."(List.lengthresults);ispf"Errors: %d."(counteris_error);ispf"Failures: %d."(counteris_failure);ispf"Skip: %d."(counteris_skip);ispf"Todo: %d."(counteris_todo);ispf"Timeout: %d."(counteris_timeout)end|TestEvent(path,e)->beginletpath_str=string_of_pathpathinmatchewith|EStart->ispf"Start test %s."path_str|EEnd->ispf"End test %s."path_str|EResultresult->format_resultpathresult|ELog(`Error,str)->espf"%s"str|ELog(`Warning,str)->wspf"%s"str|ELog(`Info,str)->ispf"%s"str|ELogRawstr->ispf"%s"strendend;List.rev!rlstletfile_logger_shard_idfn=letchn=open_outfninletline=ref1inletfwriteev=List.iter(funl->output_stringchnl;output_charchn'\n';incrline)(format_log_eventev);flushchninletfpos()=Some{filename=fn;line=!line}inletfclose()=close_outchnin{lshard=shard_id;fwrite=fwrite;fpos=fpos;fclose=fclose;}letverbose=OUnitConf.make_bool"verbose"false"Run test in verbose mode."letdisplay=OUnitConf.make_bool"display"true"Output logs on screen."letstd_loggerconfshard_id=ifdisplayconfthenletverbose=verboseconfinletfwritelog_ev=ifverbosethenList.iterprint_endline(format_log_eventlog_ev)elseprint_string(format_display_eventconflog_ev);flushstdoutin{lshard=shard_id;fwrite=fwrite;fpos=(fun()->None);fclose=ignore;}elsenull_loggerletoutput_file=OUnitConf.make_string_subst_opt"output_file"(Some(Filename.concatOUnitUtils.buildir"oUnit-$(suite_name)-$(shard_id).log"))"Output verbose log in the given file."letis_output_file_shard_dependentconf=letfn1=output_file~extra_subst:["shard_id","foo"]confinletfn2=output_file~extra_subst:["shard_id","bar"]confinfn1<>fn2letcreate_file_loggerconfshard_id=matchoutput_file~extra_subst:["shard_id",shard_id]confwith|Somefn->file_loggerconfshard_idfn|None->null_loggerletcreateconfshard_id=letstd_logger=std_loggerconfshard_idinletfile_logger=create_file_loggerconfshard_idincombine[std_logger;file_logger]