123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322(**************************************************************************)(* 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. *)(**************************************************************************)(*
Summary of the results, based on captured log events.
*)openOUnitUtilsopenOUnitTestopenOUnitLoggertypelog_entry=float(* time since start of the test *)*log_severityoption*string(* log entry without \n *)typetest_data={test_name:string;timestamp_start:float;(* UNIX timestamp *)timestamp_end:float;(* UNIX timestamp *)log_entries:log_entrylist;(* time sorted log entry, timestamp from
timestamp_start *)test_result:OUnitTest.result;}typet={suite_name:string;start_at:float;charset:string;conf:(string*string)list;running_time:float;global_results:OUnitTest.result_list;test_case_count:int;tests:test_datalist;errors:int;failures:int;skips:int;todos:int;timeouts:int;successes:int;}letis_success=function|RSuccess->true|RFailure_|RError_|RSkip_|RTodo_|RTimeout_->falseletis_failure=function|RFailure_->true|RSuccess|RError_|RSkip_|RTodo_|RTimeout_->falseletis_error=function|RError_->true|RSuccess|RFailure_|RSkip_|RTodo_|RTimeout_->falseletis_skip=function|RSkip_->true|RSuccess|RFailure_|RError_|RTodo_|RTimeout_->falseletis_todo=function|RTodo_->true|RSuccess|RFailure_|RError_|RSkip_|RTimeout_->falseletis_timeout=function|RTimeout_->true|RSuccess|RFailure_|RError_|RSkip_|RTodo_->falseletresult_flavour=function|RError_->"Error"|RFailure_->"Failure"|RSuccess->"Success"|RSkip_->"Skip"|RTodo_->"Todo"|RTimeout_->"Timeout"letresult_msg=function|RSuccess->"Success"|RError(msg,_)|RFailure(msg,_,_)|RSkipmsg|RTodomsg->msg|RTimeouttest_length->Printf.sprintf"Timeout after %.1fs"(delay_of_lengthtest_length)letworst_cmpresult1result2=letrank=function|RSuccess->0|RSkip_->1|RTodo_->2|RFailure_->3|RError_->4|RTimeout_->5in(rankresult1)-(rankresult2)letworst_result_fullresult_fulllst=letworst=List.fold_left(fun((_,result1,_)asresult_full1)((_,result2,_)asresult_full2)->ifworst_cmpresult1result2<0thenresult_full2elseresult_full1)result_fulllstinworst,List.filter(funresult_full->not(result_full==worst))(result_full::lst)letwas_successfullst=List.for_all(fun(_,rslt,_)->matchrsltwith|RSuccess|RSkip_->true|_->false)lstletencoding=OUnitConf.make_string"log_encoding""utf-8""Encoding of the log."letof_log_eventsconfevents=letglobal_conf=List.fold_left(funacclog_ev->matchlog_ev.eventwith|GlobalEvent(GConf(k,v))->(k,v)::acc|_->acc)[](List.revevents)inletrunning_time,global_results,test_case_count=letrecfind_results=function|{event=GlobalEvent(GResults(running_time,results,test_case_count));_}::_->running_time,results,test_case_count|_::tl->find_resultstl|[]->failwith"Cannot find results in OUnitResult.of_log_events."infind_resultseventsinlettests=letrecsplit_rawtmstpstrlst=tryletidx=String.indexstr'\n'insplit_rawtmstp(String.substr(idx+1)(String.lengthstr-idx-1))((tmstp,None,String.substr0idx)::lst)withNot_found->(tmstp,None,str)::lstinletfinalizet=letlog_entries=List.sort(fun(f1,_,_)(f2,_,_)->Stdlib.comparef2f1)t.log_entriesinletlog_entries=List.rev_map(fun(f,a,b)->f-.t.timestamp_start,a,b)log_entriesin{twithlog_entries=log_entries}inletdefault_timestamp=0.0inletrecprocess_log_eventtestslog_event=lettimestamp=log_event.timestampinmatchlog_event.eventwith|GlobalEvent_->tests|TestEvent(path,ev)->beginlett=tryMapPath.findpathtestswithNot_found->{test_name=string_of_pathpath;timestamp_start=default_timestamp;timestamp_end=default_timestamp;log_entries=[];test_result=RFailure("Not finished",None,None);}inletalt0t1t2=ift1=default_timestampthent2elset1inlett'=matchevwith|EStart->{twithtimestamp_start=timestamp;timestamp_end=alt0t.timestamp_endtimestamp}|EEnd->{twithtimestamp_end=timestamp;timestamp_start=alt0t.timestamp_starttimestamp}|EResultrslt->{twithtest_result=rslt}|ELog(svrt,str)->{twithlog_entries=(timestamp,Somesvrt,str)::t.log_entries}|ELogRawstr->{twithlog_entries=split_rawtimestampstrt.log_entries}inMapPath.addpatht'testsendandgroup_testtests=function|hd::tl->group_test(process_log_eventtestshd)tl|[]->letlst=MapPath.fold(fun_testlst->finalizetest::lst)tests[]inList.sort(funt1t2->Stdlib.comparet1.timestamp_startt2.timestamp_start)lstingroup_testMapPath.emptyeventsinletstart_at=List.fold_left(funstart_atlog_ev->minstart_atlog_ev.timestamp)(now())eventsinletsuite_name=matchglobal_resultswith|(path,_,_)::_->List.fold_left(funaccnd->matchndwith|ListItem_->acc|Labelstr->str)"noname"path|[]->"noname"inletcountf=List.length(List.filter(fun(_,test_result,_)->ftest_result)global_results)inletcharset=encodingconfin{suite_name=suite_name;start_at=start_at;charset=charset;conf=global_conf;running_time=running_time;global_results=global_results;test_case_count=test_case_count;tests=tests;errors=countis_error;failures=countis_failure;skips=countis_skip;todos=countis_todo;timeouts=countis_timeout;successes=countis_success;}