123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354(**************************************************************************)(* 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. *)(**************************************************************************)openOUnitUtilsopenOUnitBracketopenOUnitTestletskip_ifbmsg=ifbthenraise(Skipmsg)lettodomsg=raise(Todomsg)letassert_failuremsg=raise(OUnit_failuremsg)letassert_boolmsgb=ifnotbthenassert_failuremsgletassert_stringstr=ifnot(str="")thenassert_failurestrletrecseq_of_channelchannel()=matchinput_charchannelwith|exceptionEnd_of_file->Seq.Nil|char->Seq.Cons(char,seq_of_channelchannel)letassert_equal?ctxt?(cmp=(=))?printer?pp_diff?msgexpectedactual=letget_error_string()=letres=buff_format_printf(funfmt->Format.pp_open_vboxfmt0;beginmatchmsgwith|Somes->Format.pp_open_boxfmt0;Format.pp_print_stringfmts;Format.pp_close_boxfmt();Format.pp_print_cutfmt()|None->()end;beginmatchprinterwith|Somep->Format.fprintffmt"@[expected: @[%s@]@ but got: @[%s@]@]@,"(pexpected)(pactual)|None->Format.fprintffmt"@[not equal@]@,"end;beginmatchpp_diffwith|Somed->Format.fprintffmt"@[differences: %a@]@,"d(expected,actual)|None->()end;Format.pp_close_boxfmt())inletlen=String.lengthresiniflen>0&&res.[len-1]='\n'thenString.subres0(len-1)elseresinletlogffmt=matchctxtwith|Somectxt->OUnitLogger.Test.logfctxt.test_logger`Infofmt|None->Printf.ksprintfignorefmtinbeginmatchmsgwith|Somestr->logf"%s"str;|_->()end;beginmatchprinterwith|Somep->logf"Expected: %s"(pexpected);logf"Actual: %s"(pactual)|_->()end;ifnot(cmpexpectedactual)thenassert_failure(get_error_string())letassert_command?(exit_code=Unix.WEXITED0)?(sinput=Seq.empty)?(foutput=ignore)?(use_stderr=true)?(backtrace=true)?chdir?env~ctxtprgargs=letlog_environment_diff()=letmoduleSetString=Set.Make(structtypet=stringletcompare=String.compareend)inletset_of_arraya=letss=refSetString.emptyinfori=0to(Array.lengtha)-1doss:=SetString.add(Array.getai)!ssdone;!ssinletcurrent_environment=set_of_array(Unix.environment())inletinitial_environment=set_of_arrayctxt.initial_environmentinifSetString.equalcurrent_environmentinitial_environmentthenbeginOUnitLogger.Test.logfctxt.test_logger`Info"Environment is the same as original environment.";endelsebeginOUnitLogger.Test.logfctxt.test_logger`Info"Environment (diff with original environment):";SetString.iter(funs->OUnitLogger.Test.logfctxt.test_logger`Info"+%s"s)(SetString.diffcurrent_environmentinitial_environment);SetString.iter(funs->OUnitLogger.Test.logfctxt.test_logger`Info"-%s"s)(SetString.diffcurrent_environmentinitial_environment);endinbeginmatchenvwith|SomeawhenArray.lengtha=0&&Sys.os_type="Win32"->OUnitLogger.Test.logfctxt.test_logger`Info"%s"("Using an empty environment on Windows could cause "^"failure when running command.")|_->()end;OUnitTest.section_ctxtctxt(functxt->let(fn_out,chn_out)=bracket_tmpfilectxtinletcmd_printfmt=Format.pp_print_stringfmtprg;List.iter(Format.fprintffmt"@ %s")argsin(* Start the process *)letin_write=Unix.dup(Unix.descr_of_out_channelchn_out)inlet(out_read,out_write)=Unix.pipe()inleterr=ifuse_stderrthenin_writeelseUnix.stderrinletargs=Array.of_list(prg::args)inletenv=letparam="OCAMLRUNPARAM"inletanalyse_and_fixenv=letarr=Array.copyenvinletfixed=reffalseinletnew_var=ref""infori=0to(Array.lengtharr)-1doletreally_starts,current_value=OUnitUtils.start_substr~prefix:(param^"=")arr.(i)inifreally_startsthenbegin(* Rewrite the params. *)ifnot(String.containscurrent_value'b')thenbeginarr.(i)<-param^"="^current_value^"b"end;new_var:=arr.(i);fixed:=trueenddone;if!fixedthenarrelseArray.appendarr[|param^"=b"|]inifbacktracethenbegin(* Analyse of the provided environment. *)matchenvwith|Someenv->Some(analyse_and_fixenv)|None->Some(analyse_and_fix(Unix.environment()))endelsebeginenvendinletcommand_chdir,in_chdir=matchchdirwith|Somedn->dn,funf->with_bracketctxt(bracket_chdirdn)(fun__->f())|None->Sys.getcwd(),funf->f()inletpid=OUnitLogger.Test.logfctxt.test_logger`Info"%s"(buff_format_printf(funfmt->Format.fprintffmt"Starting command '%t'."cmd_print));OUnitLogger.Test.logfctxt.test_logger`Info"Working directory: %S"command_chdir;log_environment_diff();Unix.set_close_on_execout_write;matchenvwith|Somee->in_chdir(fun()->Unix.create_process_envprgargseout_readin_writeerr)|None->in_chdir(fun()->Unix.create_processprgargsout_readin_writeerr)inlet()=Unix.closeout_read;Unix.closein_writeinlet()=(* Dump sinput into the process stdin *)letbuff=Bytes.make1' 'inSeq.iter(func->let_i:int=Bytes.setbuff0c;Unix.writeout_writebuff01in())sinput;Unix.closeout_writeinlet_,real_exit_code=letrecwait_intr()=tryUnix.waitpid[]pidwithUnix.Unix_error(Unix.EINTR,_,_)->wait_intr()inwait_intr()in(* Dump process output to stderr *)beginletchn=open_in_binfn_outinletbuff=Bytes.make4096'X'inletlen=ref(-1)inwhile!len<>0dolen:=inputchnbuff0(Bytes.lengthbuff);OUnitLogger.Test.raw_printfctxt.test_logger"%s"Bytes.(to_string(subbuff0!len));done;close_inchnend;(* Check process status *)assert_equal~msg:(buff_format_printf(funfmt->Format.fprintffmt"@[Exit status of command '%t'@]"cmd_print))~printer:string_of_process_statusexit_codereal_exit_code;beginletchn=open_in_binfn_outintryfoutput(seq_of_channelchn)withe->close_inchn;raiseeend)letraisesf=trylet_=f()inNonewithe->Someeletassert_raises?msgexn(f:unit->'a)=letpexn=Printexc.to_stringinletget_error_string()=letstr=Format.sprintf"expected exception %s, but no exception was raised."(pexnexn)inmatchmsgwith|None->assert_failurestr|Somes->assert_failure(s^"\n"^str)inmatchraisesfwith|None->assert_failure(get_error_string())|Somee->assert_equal?msg~printer:pexnexne