123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256(**************************************************************************)(* 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. *)(**************************************************************************)(*
HTML logger for OUnit.
*)openOUnitLoggeropenOUnitUtilsopenOUnitTestopenOUnitResultSummarylethtml_escaperstr=letbuffer=Buffer.create(String.lengthstr)inletaddc=Buffer.add_charbufferinletaddsese=addc'&';Buffer.add_stringbufferse;addc';'inString.iter(function|'"'->addse"quot"|'&'->addse"amp"|'<'->addse"lt"|'>'->addse"gt"(*
| 'Œ' -> addse "OElig"
| 'œ' -> addse "oelig"
| 'Š' -> addse "Scaron"
| 'š' -> addse "scaron"
| 'Ÿ' -> addse "Yuml"
| 'ˆ' -> addse "circ"
| '˜' -> addse "tilde"
| ' ' -> addse "ensp"
| ' ' -> addse "emsp"
| ' ' -> addse "thinsp"
| '–' -> addse "ndash"
| '—' -> addse "mdash"
| '‘' -> addse "lsquo"
| '’' -> addse "rsquo"
| '‚' -> addse "sbquo"
| '“' -> addse "ldquo"
| '”' -> addse "rdquo"
| '„' -> addse "bdquo"
| '†' -> addse "dagger"
| '‡' -> addse "Dagger"
| '‰' -> addse "permil"
| '‹' -> addse "lsaquo"
| '›' -> addse "rsaquo"
| '€' -> addse "euro"
*)|'\''->addse"#39"|c->addcc)str;Buffer.contentsbufferletrenderconfdnevents=letsmr=OUnitResultSummary.of_log_eventsconfeventsinlet()=ifnot(Sys.file_existsdn)thenUnix.handle_unix_error(fun()->Unix.mkdirdn0o755)()inletchn=open_out(Filename.concatdn"oUnit.css")inlet()=output_stringchnOUnitLoggerHTMLData.oUnit_css;close_outchninletchn=open_out(Filename.concatdn"oUnit.js")inlet()=output_stringchnOUnitLoggerHTMLData.oUnit_js;close_outchninletchn=open_out(Filename.concatdn"index.html")inletprintffmt=Printf.fprintfchnfmtinprintf"\
<html>
<head>
<title>Test suite %s</title>
<meta http-equiv='Content-Type' content='text/html;charset=%s'/>
<link href='oUnit.css' rel='stylesheet' type='text/css'/>
<script language='javascript' src='oUnit.js'></script>
</head>
<body onload=\"displaySuccess('none');\">
<div id='navigation'>
<button id='toggleVisibiltySuccess'
onclick='toggleSuccess();'>Show success</button>
<button id='nextTest' onclick='nextTest();'>Next test</button>
<button id='gotoTop' onclick='gotoTop();'>Goto top</button>
</div>
<h1>Test suite %s</h1>
<div class='ounit-results'>
<h2>Results</h2>
<div class='ounit-results-content'>\n"(html_escapersmr.suite_name)smr.charset(html_escapersmr.suite_name);beginletprintf_resultclsslabelnum=printf"<div class='ounit-results-%s'>\n\
%s: <span class='number'>%d</span>\n\
</div>\n"clsslabelnuminletprintf_non0_resultclsslabelnum=ifnum>0thenprintf_resultclsslabelnuminprintf"<div id='ounit-results-started-at'>\
Started at: %s
</div>"(date_iso8601smr.start_at);printf"<div class='ounit-results-duration'>\
Total duration: <span class='number'>%.3fs</span>\
</div>"smr.running_time;printf_result"test-count""Tests count"smr.test_case_count;printf_non0_result"errors""Errors"smr.errors;printf_non0_result"failures""Failures"smr.failures;printf_non0_result"skips""Skipped"smr.skips;printf_non0_result"todos""TODO"smr.todos;printf_non0_result"timeouts""Timed out"smr.timeouts;printf_result"successes""Successes"smr.successes;(* Print final verdict *)ifwas_successfulsmr.global_resultsthenprintf"<div class='ounit-results-verdict'>Success</div>"elseprintf"<div class='ounit-results-verdict ounit-failure'>Failure</div>"end;printf"\
</div>
</div>
<div class='ounit-conf'>
<h2>Configuration</h2>
<div class='ounit-conf-content'>\n";List.iter(fun(k,v)->printf"%s=%S<br/>\n"(html_escaperk)(html_escaperv))smr.conf;printf("\
</div>
</div>
");List.iter(funtest_data->letclass_result,text_result=matchtest_data.test_resultwith|RSuccess->"ounit-success","succeed"|RFailure_->"ounit-failure","failed"|RError_->"ounit-error","error"|RSkip_->"ounit-skip","skipped"|RTodo_->"ounit-todo","TODO"|RTimeout_->"ounit-timeout","timeout"inletclass_severity_opt=function|Some`Error->"ounit-log-error"|Some`Warning->"ounit-log-warning"|Some`Info->"ounit-log-info"|None->""inprintf"
<div class='ounit-test %s'>
<h2>%s (%s)</h2>
<div class='ounit-started-at'>Started at: %s</div>
<div class='ounit-duration'>Test duration: %.3fs</div>
<div class='ounit-log'>\n"class_result(html_escapertest_data.test_name)(html_escapertext_result)(date_iso8601test_data.timestamp_start)(test_data.timestamp_end-.test_data.timestamp_start);printf"<span class='ounit-timestamp'>%.3fs</span>Start<br/>\n"0.0;List.iter(fun(tmstp,svrt,str)->printf"\
<span class='%s'>
<span class='ounit-timestamp'>%.3fs</span>%s</span><br/>\n"(class_severity_optsvrt)tmstp(html_escaperstr))test_data.log_entries;printf"<span class='ounit-timestamp'>%.3fs</span>End<br/>\n"(test_data.timestamp_end-.test_data.timestamp_start);printf"<div class='ounit-result'>";begin(* TODO: use backtrace *)matchtest_data.test_resultwith|RSuccess->printf"Success."|RFailure(str,_,_)->printf"Failure:<br/>%s"(html_escaperstr)|RError(str,_)->printf"Error:<br/>%s"(html_escaperstr)|RSkipstr->printf"Skipped:<br/>%s"(html_escaperstr)|RTodostr->printf"Todo:<br/>%s"(html_escaperstr)|RTimeouttest_length->printf"Timeout after %.1fs<br/>"(delay_of_lengthtest_length)end;printf"</div>";printf"\
</div>
</div>\n";(* TODO: results, end timestamp *))smr.tests;printf"\
</body>
</html>";close_outchnletoutput_html_dir=OUnitConf.make_string_subst_opt"output_html_dir"None"Output directory of the HTML files."letcreateconf=matchoutput_html_dirconfwith|Somedn->post_logger(renderconfdn)|None->null_logger