ounit-2.0.0/0000755000175000017500000000000012222142072012163 5ustar gildorgildorounit-2.0.0/README.txt0000644000175000017500000000107612222142072013665 0ustar gildorgildor(* OASIS_START *) (* DO NOT EDIT (digest: ac260da3dc5dbc8b63343daec02e41ac) *) This is the README file for the ounit distribution. (C) 2002-2008 Maas-Maarten Zeeman (C) 2010 OCamlCore SARL Unit testing framework OUnit is a unit testing framework for OCaml, inspired by the JUnit tool for Java, and the HUnit tool for Haskell. More information on [HUnit](http://hunit.sourceforge.net) See the files INSTALL.txt for building and installation instructions. See the file LICENSE.txt for copying conditions. Home page: http://ounit.forge.ocamlcore.org (* OASIS_STOP *) ounit-2.0.0/INSTALL.txt0000644000175000017500000000161612222142072014036 0ustar gildorgildor(* OASIS_START *) (* DO NOT EDIT (digest: 6437cd9729746ca802a297a2cbec36cf) *) This is the INSTALL file for the ounit distribution. This package uses OASIS to generate its build system. See section OASIS for full information. Dependencies ============ In order to compile this package, you will need: * ocaml (>= 3.11.0) for all, test main, doc api-ounit * findlib * xmllint for test main Installing ========== 1. Uncompress the source archive and go to the root of the package 2. Run 'ocaml setup.ml -configure' 3. Run 'ocaml setup.ml -build' 4. Run 'ocaml setup.ml -install' Uninstalling ============ 1. Go to the root of the package 2. Run 'ocaml setup.ml -uninstall' OASIS ===== OASIS is a program that generates a setup.ml file using a simple '_oasis' configuration file. The generated setup only depends on the standard OCaml installation: no additional library is required. (* OASIS_STOP *) ounit-2.0.0/AUTHORS.txt0000644000175000017500000000022512222142072014050 0ustar gildorgildor(* OASIS_START *) (* DO NOT EDIT (digest: 2915822545ee2a6c6708508e9418550d) *) Authors of ounit Maas-Maarten Zeeman Sylvain Le Gall (* OASIS_STOP *) ounit-2.0.0/doc/0000755000175000017500000000000012222142072012730 5ustar gildorgildorounit-2.0.0/doc/manual.txt0000644000175000017500000002043312222142072014750 0ustar gildorgildor{!indexlist} {2 What is unit Testing?} A test-oriented methodology for software development is most effective whent tests are easy to create, change, and execute. The JUnit tool pioneerded for test-first development in Java. OUnit is an adaptation of JUnit to OCaml. With OUnit, as with JUnit, you can easily create tests, name them, group them into suites, and execute them, with the framework checking the results automatically. {2 Getting Started} The basic principle of a test suite is to have a file {i test.ml} which will contain the tests, and an OCaml module under test, named {i foo.ml}. File {i foo.ml}: {[ (* The functions we wish to test *) let unity x = x;; let funix ()= 0;; let fgeneric () = failwith "Not implemented";; ]} The main point of a test is to check that the function under test has the expected behavior. You check the behavior using assert functions. The most simple one is {!OUnit2.assert_equal}. This function compares the result of the function with an expected result. The most useful functions are: - {!OUnit2.assert_equal} the basic assert function - {!OUnit2.(>:::)} to define a list of tests - {!OUnit2.(>::)} to name a test - {!OUnit2.run_test_tt_main} to run the test suite you define - {!OUnit2.bracket_tmpfile} that create a temporary filename. - {!OUnit2.bracket_tmpdir} that create a temporary directory. File {i test.ml}: {[ open OUnit2;; let test1 test_ctxt = assert_equal "x" (Foo.unity "x");; let test2 test_ctxt = assert_equal 100 (Foo.unity 100);; (* Name the test cases and group them together *) let suite = "suite">::: ["test1">:: test1; "test2">:: test2] ;; let () = run_test_tt_main suite ;; ]} And compile the module {[ $ ocamlfind ocamlc -o test -package oUnit -linkpkg -g foo.ml test.ml ]} A executable named "test" will be created. When run it produces the following output. {[ $ ./tests .. Ran: 2 tests in: 0.00 Seconds OK ]} When using {!OUnit2.run_test_tt_main}, a non zero exit code signals that the test suite was not successful. {2 Advanced usage} The topics, cover here, are only for advanced users who wish to unravel the power of OUnit. {!modules: OUnit2} {3 Error reporting} The error reporting part of OUnit is quite important. If you want to identify the failure, you should tune the display of the value and the test. Here is a list of thing you can display: - name of the test: OUnit use numbers to define path's test. But an error reporting about a failed test "0:1:2" is less explicit than "OUnit:0:comparator:1:float_comparator:2" - [~msg] parameter: it allows you to define say which assert has failed in your test. When you have more than one assert in a test, you should provide a [~msg] to be able to make the difference - [~printer] parameter: {!OUnit2.assert_equal} allows you to define a printer for compared values. A message ["abcd" is not equal to "defg"] is better than [not equal] {[ open OUnit2;; let _ = "mytest">:: (fun test_ctxt -> assert_equal ~msg:"int value" ~printer:string_of_int 1 (Foo.unity 1)) ;; ]} {3 Command line arguments} {!OUnit2.run_test_tt_main} already provides a set of command line argument to help user to run only the test he wants: - [-only-test]: skip all the tests except this one, you can use this flag several time to select more than one test to run - [-list-test]: list all the available tests and exit - [-help]: display help message and exit It is also possible to add your own command-line arguments, environment variable and config file variable. You should do it if you want to define some extra arguments. For example: {[ open OUnit2;; let my_program = Conf.make_exec "my_program" ;; let test1 test_ctxt = assert_command (my_program test_ctxt) [] ;; let () = run_test_tt_main ("test1" >:: test1) ;; ]} The [Conf.make_*] creates a command line argument, an environment variable and a config file variable. {3 Skip and todo tests} Tests are not always meaningful and can even fail because something is missing in the environment. In order to manage this, you can define a skip condition that will skip the test. If you start by defining your tests rather than implementing the functions under test, you know that some tests will just fail. You can mark these tests as to do tests, this way they will be reported differently in your test suite. {[ open OUnit2;; let _ = "allfuns" >::: [ "funix">:: (fun test_ctxt -> skip_if (Sys.os_type = "Win32") "Don't work on Windows"; assert_equal 0 (Foo.funix ())); "fgeneric">:: (fun test_ctxt -> todo "fgeneric not implemented"; assert_equal 0 (Foo.fgeneric ())); ] ;; ]} {3 Effective OUnit} This section is about general tips about unit testing and OUnit. It is the result of some years using OUnit in real world applications. - test everything: the more you create tests, the better chance you have to catch early an error in your program. Every submitted bugs to your application should have a matching tests. This is a good practice, but it is not always easy to implement. - test only what is really exported: on the long term, you have to maintain your test suite. If you test low-level functions, you'll have a lot of tests to rewrite. You should focus on creating tests for functions for which the behavior shouldn't change. - test fast: the best test suite is the one that runs after every single build. You should set your default Makefile target to run the test suite. It means that your test suite should be fast to run, typically, a 10s test suite is fine. - test long: contrary to the former tip, you should also have a complete test suite which can be very long to run. The best way to achieve both tips, is to define a command line arguments [-long] and skip the tests that are too long in your test suite according to it. When you do a release, you should use run your long test suite. - family tests: when testing behavior, most of the time you call exactly the same code with different arguments. In this case [List.map] and {!OUnit2.(>:::)} are your friends. For example: {[ open OUnit2;; let _ = "Family">::: (List.map (fun (arg,res) -> let title = Printf.sprintf "%s->%s" arg res in title >:: (fun test_ctxt -> assert_equal res (Foo.unity arg))) ["abcd", "abcd"; "defg", "defg"; "wxyz", "wxyz"]) ;; ]} - test failures and successes: the most obvious thing you want to test are successes, i.e. that you get the expected behavior in the normal case. But most of the errors arise in corner cases and in the code of the test itself. For example, you can have a partial application of your {!OUnit2.assert_equal} and never encounter any errors, just because the [assert_equal] is not called. In this case, if you test errors as well, you will have a missing errors as well. - set up and clean your environment in the test: you should not set up and clean your test environment outside the test. Ideally, if you run no tests, the program should do nothing. This is also a sane way to be sure that you are always testing in a clean environment, not polluted by the result of failed tests run before. This include the process environment, like current working directory. {[ open OUnit2;; let _ = (* We need to call a function in a particular directory *) "change-dir-and-run">:: (fun test_ctxt -> assert_command ~chdir:"/foo/test" "ls" []) ;; ]} - separate your test: OUnit test code should live outside the code under a directory called {i test}. This allow to drop the dependency on OUnit when distributing your library/application. This also enables people to easily make a difference from what really matters (the main code) and what are only tests. It is possible to have it directly in the code, like in Quickcheck style tests. The unit testing scope is always hard to define. Unit testing should be about testing a single features. But OUnit can help you to test higher level behavior, by running a full program for example. While it isn't real unit testing, you can use OUnit to do it and should not hesitate to do it. In term of line of codes, a test suite can represent from 10% to 150% of the code under test. With time, your test suite will grow faster than your program/library. A good ratio is 33%. @author Maas-Maarten Zeeman @author Sylvain Le Gall ounit-2.0.0/examples/0000755000175000017500000000000012222142072014001 5ustar gildorgildorounit-2.0.0/examples/Makefile0000644000175000017500000000532712222142072015450 0ustar gildorgildor############################################################################ # 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. # ############################################################################ TESTS = test_list.ml test_list2.ml test_stack.ml test: test_suite example -./test_suite -./example test_suite: $(TESTS) test_suite.ml ocamlfind ocamlc -o test_suite -package oUnit -linkpkg \ test_list.ml test_list2.ml test_stack.ml test_suite.ml example: example.ml ocamlfind ocamlc -o example -package oUnit -linkpkg \ example.ml clean: -$(RM) *.cmi *.cmo test_suite example ounit-2.0.0/examples/example.ml0000644000175000017500000000544712222142072016000 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnit let empty_list = [] let list_a = [1;2;3] let test_list_length _ = assert_equal 1 (List.length empty_list); assert_equal 3 (List.length list_a) (* etc, etc *) let test_list_append _ = let list_b = List.append empty_list [1;2;3] in assert_equal list_b list_a let suite = "OUnit Example" >::: ["test_list_length" >:: test_list_length; "test_list_append" >:: test_list_append] let _ = run_test_tt_main suite ounit-2.0.0/examples/test_list.ml0000644000175000017500000000545112222142072016352 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnit let empty_list = [] let list_a = [1;2;3] let test_list_length _ = assert_equal 1 (List.length empty_list); assert_equal 3 (List.length list_a) (* etc, etc *) let test_list_append _ = let list_b = List.append empty_list [1;2;3] in assert_equal list_b list_a let suite = "OUnit Example" >::: ["test_list_length" >:: test_list_length; "test_list_append" >:: test_list_append] let () = run_test_tt_main suite ounit-2.0.0/examples/test_list2.ml0000644000175000017500000000540312222142072016431 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnit let empty_list = [] let list_a = [1;2;3] let test_list_length _ = assert_equal 1 (List.length empty_list); assert_equal 3 (List.length list_a) (* etc, etc *) let test_list_append _ = let list_b = List.append empty_list [1;2;3] in assert_equal list_b list_a let suite = "Test_list2" >::: ["test_list_length2" >:: test_list_length; "test_list_append2" >:: test_list_append] ounit-2.0.0/examples/test_stack.ml0000644000175000017500000000624012222142072016501 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnit (* * This test shows how brackets can be used. They are handy to create * a so called fixture, which can be used for multiple tests *) (* prepare a stack for test *) let setup _ = let s = Stack.create () in Stack.push 1 s; Stack.push 2 s; Stack.push 3 s; s let teardown _ = () let test_top stack = assert_equal 3 (Stack.top stack) let test_clear stack = Stack.clear stack; assert_raises Stack.Empty (fun _ -> Stack.top stack) let test_pop stack = assert_equal 3 (Stack.pop stack); assert_equal 2 (Stack.pop stack); assert_equal 1 (Stack.pop stack); assert_raises Stack.Empty (fun _ -> Stack.pop stack) let suite = "Test Stack" >::: ["test_top" >:: (bracket setup test_top teardown); "test_clear" >:: (bracket setup test_clear teardown); "test_pop" >:: (bracket setup test_pop teardown)] ounit-2.0.0/examples/test_suite.ml0000644000175000017500000000504212222142072016524 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnit (* Collect the tests of different modules into one test suite *) let suite = "OUnit Example" >::: [Test_list.suite; Test_list2.suite; Test_stack.suite] let _ = run_test_tt_main suite ounit-2.0.0/src/0000755000175000017500000000000012222142072012752 5ustar gildorgildorounit-2.0.0/src/oUnitThreads.mllib0000644000175000017500000000016412222142072016405 0ustar gildorgildor# OASIS_START # DO NOT EDIT (digest: c233265d9f83eaa73923c9bdefb32777) OUnitThreads OUnitRunnerThreads # OASIS_STOP ounit-2.0.0/src/oUnitAdvanced.mllib0000644000175000017500000000061112222142072016515 0ustar gildorgildor# OASIS_START # DO NOT EDIT (digest: 63cc39f68c681144d83ffd81399dc187) OUnitUtils OUnitPropList OUnitPlugin OUnitChooser OUnitResultSummary OUnitLoggerStd OUnitLoggerHTML OUnitLoggerHTMLData OUnitLoggerJUnit OUnitAssert OUnitBracket OUnitTest OUnitState OUnitRunner OUnitRunnerProcesses OUnitCore OUnitLogger OUnitConf OUnitShared OUnitCache OUnitTestData OUnitCheckEnv OUnitDiff # OASIS_STOP ounit-2.0.0/src/oUnit.mllib0000644000175000017500000000014112222142072015065 0ustar gildorgildor# OASIS_START # DO NOT EDIT (digest: 1ad80d12b97eab491c61097067896fca) OUnit OUnit2 # OASIS_STOP ounit-2.0.0/src/api-ounit.odocl0000644000175000017500000000064312222142072015704 0ustar gildorgildor# OASIS_START # DO NOT EDIT (digest: 1852896df1df5ea91216b5992e35cb92) OUnit OUnit2 OUnitThreads OUnitUtils OUnitPropList OUnitPlugin OUnitChooser OUnitResultSummary OUnitLoggerStd OUnitLoggerHTML OUnitLoggerHTMLData OUnitLoggerJUnit OUnitAssert OUnitBracket OUnitTest OUnitState OUnitRunner OUnitRunnerProcesses OUnitCore OUnitLogger OUnitConf OUnitShared OUnitCache OUnitTestData OUnitCheckEnv OUnitDiff # OASIS_STOP ounit-2.0.0/src/META0000644000175000017500000000163612222142072013431 0ustar gildorgildor# OASIS_START # DO NOT EDIT (digest: ec034dc2b5280f95f8153b873aff4953) version = "2.0.0" description = "Unit testing framework" requires = "unix oUnit.advanced" archive(byte) = "oUnit.cma" archive(byte, plugin) = "oUnit.cma" archive(native) = "oUnit.cmxa" archive(native, plugin) = "oUnit.cmxs" exists_if = "oUnit.cma" package "threads" ( version = "2.0.0" description = "Unit testing framework" requires = "threads oUnit" archive(byte) = "oUnitThreads.cma" archive(byte, plugin) = "oUnitThreads.cma" archive(native) = "oUnitThreads.cmxa" archive(native, plugin) = "oUnitThreads.cmxs" exists_if = "oUnitThreads.cma" ) package "advanced" ( version = "2.0.0" description = "Unit testing framework" archive(byte) = "oUnitAdvanced.cma" archive(byte, plugin) = "oUnitAdvanced.cma" archive(native) = "oUnitAdvanced.cmxa" archive(native, plugin) = "oUnitAdvanced.cmxs" exists_if = "oUnitAdvanced.cma" ) # OASIS_STOP ounit-2.0.0/src/oUnit.css0000644000175000017500000000775512222142072014600 0ustar gildorgildor/**************************************************************************/ /* 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. */ /**************************************************************************/ h1 { font-size: 26px; margin-right: 15px; padding-left: 0px; } h2 { font-size: 20px; margin-right: 15px; padding-left: 5px; } #ounit-current h2 { text-decoration: underline; } #ounit-results-started-at { width: 100%; } .ounit-results-content div { width: 150px; margin-top: 1px; } .ounit-results-content .number { text-align: right; display: inline-block; float: right; width: 50px; } .ounit-results-verdict.ounit-failure { color: red; } .ounit-success h2, .ounit-results-successes .number { background-color: #4a4; } .ounit-failure h2, .ounit-results-failures .number { background-color: #f66; } .ounit-error h2, .ounit-results-errors .number { background-color: #000; color: #fff; } .ounit-skip h2, .ounit-results-skips .number { background-color: #fd0; } .ounit-todo h2, .ounit-results-todos .number { background-color: #aaf; } .ounit-timeout h2, .ounit-results-timeouts .number { background-color: #888; } .ounit-conf h2, .ounit-results h2 { background-color: #aaa; } .ounit-log, .ounit-conf-content { font-family: Lucida Console, Monaco, Courier New, monospace; white-space: nowrap; font-size: 16px; color: #666; margin-left: 20px; } .ounit-duration, .ounit-started-at, .ounit-results-content { margin-bottom: 10px; margin-left: 15px; } .ounit-started-at { margin-bottom: 0; } span.ounit-timestamp { display: inline-block; width: 70px; } .ounit-log .ounit-result, .ounit-results-verdict { font-weight: bold; margin-top: 5px; } #navigation { position: fixed; top: 0; right: 0; background-color: #fff; padding: 9px; border: 1px solid #000; border-top: none; border-right: none; }; ounit-2.0.0/src/oUnit.js0000644000175000017500000000740312222142072014412 0ustar gildorgildor/**************************************************************************/ /* 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. */ /**************************************************************************/ var successHidden = true; function displaySuccess(display) { var div = document.getElementsByClassName('ounit-success'); for (var i = 0; i < div.length; i++) { div[i].style.display = display; }; }; function toggleSuccess() { if (successHidden) { displaySuccess('block'); } else { displaySuccess('none'); }; successHidden = ! successHidden; var button = document.getElementById('toggleVisibiltySuccess'); if (successHidden) { button.textContent = 'Show success'; } else { button.textContent = 'Hide success'; }; }; function resetTestCurrent() { var div = document.getElementById('ounit-current'); if (div) { div.removeAttribute('id'); }; }; function setTestCurrent(div) { resetTestCurrent(); div.id = "ounit-current"; div.scrollIntoView(true); }; function nextTest() { var div = document.getElementsByClassName('ounit-test'); var found = false; var foundCurrent = false; var idx = 0; if (div) { for (; !found && idx < div.length; idx++) { if (foundCurrent && div[idx].style.display != 'none') { found = true; }; if (div[idx].id == "ounit-current") { foundCurrent = true; }; }; if (!foundCurrent && div.length > 0) { setTestCurrent(div[0]); } else if (found) { setTestCurrent(div[idx - 1]); } else { resetTestCurrent(); }; }; }; function gotoTop() { window.scrollTo(0,0); resetTestCurrent(); }; ounit-2.0.0/src/oUnit.ml0000644000175000017500000002653612222142072014416 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnitUtils let get_test_context, set_test_context, reset_test_context = let context_opt = ref None in (* get *) (fun () -> match !context_opt with | Some ctxt -> ctxt | None -> failwith "Function need to be called from inside a test."), (fun ctxt -> context_opt := Some ctxt), (fun ctxt -> context_opt := None) type node = ListItem of int | Label of string let node1_of_node = function | OUnitTest.ListItem i -> ListItem i | OUnitTest.Label s -> Label s let node_of_node1 = function | ListItem i -> OUnitTest.ListItem i | Label s -> OUnitTest.Label s type path = node list let path1_of_path pth = List.map node1_of_node pth type test_fun = unit -> unit type test = TestCase of test_fun | TestList of test list | TestLabel of string * test let rec test1_of_test = function | OUnitTest.TestCase (_, f) -> TestCase (fun () -> f (get_test_context ())) | OUnitTest.TestList lst -> TestList (List.map test1_of_test lst) | OUnitTest.TestLabel (str, tst) -> TestLabel (str, test1_of_test tst) let rec test_of_test1 = function | TestCase f -> OUnitTest.TestCase (OUnitTest.Short, fun ctxt -> set_test_context ctxt; f (); reset_test_context ()) | TestList lst -> OUnitTest.TestList (List.map test_of_test1 lst) | TestLabel (str, tst) -> OUnitTest.TestLabel (str, test_of_test1 tst) let rec ounit2_of_ounit1 = function | TestCase f -> OUnit2.test_case (fun ctxt -> set_test_context ctxt; f (); reset_test_context ()) | TestList lst -> OUnit2.test_list (List.map ounit2_of_ounit1 lst) | TestLabel (lbl, test) -> OUnit2.( >: ) lbl (ounit2_of_ounit1 test) type test_result = RSuccess of path | RFailure of path * string | RError of path * string | RSkip of path * string | RTodo of path * string let test_result1_of_test_result path rslt = let path1 = path1_of_path path in let rslt1 = match rslt with | OUnitTest.RSuccess -> RSuccess path1 | OUnitTest.RFailure (str, _, _) -> RFailure (path1, str) | OUnitTest.RError (str, _) -> RError (path1, str) | OUnitTest.RSkip str -> RSkip (path1, str) | OUnitTest.RTodo str -> RTodo (path1, str) | OUnitTest.RTimeout test_length -> RError (path1, (Printf.sprintf "timeout after %.1fs." (OUnitTest.delay_of_length test_length))) in rslt1 type test_event = EStart of path | EEnd of path | EResult of test_result let result_path = function | RSuccess path | RError (path, _) | RFailure (path, _) | RSkip (path, _) | RTodo (path, _) -> path type test_results = test_result list let list_result1_of_list_result = List.map (fun (pth, rslt, _) -> test_result1_of_test_result pth rslt) let assert_failure = OUnitAssert.assert_failure let assert_bool = OUnitAssert.assert_bool let ( @? ) = OUnitAssert.assert_bool let assert_string = OUnitAssert.assert_string let assert_command ?exit_code ?sinput ?foutput ?use_stderr ?env ?(verbose=false) prg args = let ctxt = let ctxt = get_test_context () in let conf' = Hashtbl.copy ctxt.OUnitTest.conf in OUnitConf.set ~origin:"OUnit.assert_command" conf' "verbose" (string_of_bool verbose); { ctxt with OUnitTest.test_logger = OUnitLogger.Test.create (OUnitLoggerStd.std_logger conf' OUnitLogger.shard_default) ctxt.OUnitTest.path; } in OUnitAssert.assert_command ?exit_code ?sinput ?foutput ?use_stderr ?env ~ctxt prg args let assert_equal ?cmp ?printer ?pp_diff ?msg a b = OUnitAssert.assert_equal ?cmp ?printer ?pp_diff ?msg a b let assert_raises ?msg exc f = OUnitAssert.assert_raises ?msg exc f let skip_if = OUnitAssert.skip_if let todo = OUnitAssert.todo let cmp_float ?epsilon f1 f2 = OUnitUtils.cmp_float ?epsilon f1 f2 let bracket pre f post () = OUnitTest.section_ctxt (get_test_context ()) (fun ctxt -> let fixture = OUnitBracket.create (fun _ -> pre ()) (fun fixture _ -> post fixture) ctxt in let () = f fixture in ()) let bracket_tmpfile ?prefix ?suffix ?mode gen () = OUnitTest.section_ctxt (get_test_context ()) (fun ctxt -> let fixture = OUnitBracket.bracket_tmpfile ?prefix ?suffix ?mode ctxt in gen fixture) let (>:) a b = test1_of_test (OUnitTest.(>:) a (test_of_test1 b)) let (>::) a b = test1_of_test (OUnitTest.(>::) a (fun _ -> b ())) let (>:::) a b = test1_of_test (OUnitTest.(>:::) a (List.map test_of_test1 b)) let test_decorate g tst = test1_of_test (OUnitTest.test_decorate (fun f -> let f1 = (fun () -> f (get_test_context ())) in let f1' = g f1 in (fun ctxt -> set_test_context ctxt; f1' (); reset_test_context ())) (test_of_test1 tst)) let test_filter ?skip lst test = let res = OUnitTest.test_filter ?skip lst (test_of_test1 test) in match res with | Some tst -> Some (test1_of_test tst) | None -> None let test_case_count tst = OUnitTest.test_case_count (test_of_test1 tst) let string_of_node nd = OUnitTest.string_of_node (node_of_node1 nd) let string_of_path pth = OUnitTest.string_of_path (List.map node_of_node1 pth) let test_case_paths tst = let lst = OUnitTest.test_case_paths (test_of_test1 tst) in List.map (List.map node1_of_node) lst let default_v1_conf ?(verbose=false) () = OUnitConf.default ~preset: [ "chooser", "simple"; "runner", "sequential"; "results_style_1_X", "true"; "verbose", (string_of_bool verbose); "output_file", "none"; ] () let perform_test logger1 tst = let logger = OUnitLogger.fun_logger (function | {OUnitLogger.event = OUnitLogger.GlobalEvent _} -> () | {OUnitLogger.event = OUnitLogger.TestEvent (path, test_event)} -> begin let path1 = path1_of_path path in match test_event with | OUnitLogger.EStart -> logger1 (EStart path1) | OUnitLogger.EEnd -> logger1 (EEnd path1) | OUnitLogger.EResult rslt -> logger1 (EResult (test_result1_of_test_result path rslt)) | OUnitLogger.ELog _ | OUnitLogger.ELogRaw _ -> () end) ignore in let conf = default_v1_conf () in list_result1_of_list_result (OUnitCore.perform_test conf logger (snd (OUnitRunner.choice conf)) (snd (OUnitChooser.choice conf)) (test_of_test1 tst)) let run_test_tt ?verbose test = let conf = default_v1_conf ?verbose () in list_result1_of_list_result (OUnitCore.run_test_tt conf (OUnitLoggerStd.create conf OUnitLogger.shard_default) (snd (OUnitRunner.choice conf)) (snd (OUnitChooser.choice conf)) (test_of_test1 test)) let run_test_tt_main ?(arg_specs=[]) ?(set_verbose=ignore) suite = let suite = test_of_test1 suite in let only_test = ref [] in let list_test = ref false in let verbose = ref false in let specs = [ "-verbose", Arg.Set verbose, " Rather than displaying dots while running the test, be more verbose."; "-only-test", Arg.String (fun str -> only_test := str :: !only_test), "path Run only the selected tests."; "-list-test", Arg.Set list_test, " List tests"; ] @ arg_specs in let () = Arg.parse (Arg.align specs) (fun x -> raise (Arg.Bad ("Bad argument : " ^ x))) ("usage: " ^ Sys.argv.(0) ^ " [options] [-only-test path]*") in let conf = default_v1_conf ~verbose:!verbose () in set_verbose (OUnitLoggerStd.verbose conf); if !list_test then begin List.iter (fun pth -> print_endline (OUnitTest.string_of_path pth)) (OUnitTest.test_case_paths suite); [] end else begin let nsuite = if !only_test = [] then suite else begin match OUnitTest.test_filter ~skip:true !only_test suite with | Some test -> test | None -> failwithf "Filtering test %s lead to no tests." (String.concat ", " !only_test) end in let test_results = OUnitCore.run_test_tt conf (OUnitLoggerStd.std_logger conf OUnitLogger.shard_default) (snd (OUnitRunner.choice conf)) (snd (OUnitChooser.choice conf)) nsuite in list_result1_of_list_result test_results end ounit-2.0.0/src/oUnit.mli0000644000175000017500000002335612222142072014564 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) (** Unit test building blocks @author Maas-Maarten Zeeman @author Sylvain Le Gall *) (** {2 Assertions} Assertions are the basic building blocks of unittests. *) (** Signals a failure. This will raise an exception with the specified string. @raise Failure signal a failure *) val assert_failure : string -> 'a (** Signals a failure when bool is false. The string identifies the failure. @raise Failure signal a failure *) val assert_bool : string -> bool -> unit (** Shorthand for assert_bool @raise Failure to signal a failure *) val ( @? ) : string -> bool -> unit (** Signals a failure when the string is non-empty. The string identifies the failure. @raise Failure signal a failure *) val assert_string : string -> unit (** [assert_command prg args] Run the command provided. @param exit_code expected exit code @param sinput provide this [char Stream.t] as input of the process @param foutput run this function on output, it can contains an [assert_equal] to check it @param use_stderr redirect [stderr] to [stdout] @param env Unix environment @param verbose if failed, dump stdout/stderr of the process to stderr @since 1.1.0 *) val assert_command : ?exit_code:Unix.process_status -> ?sinput:char Stream.t -> ?foutput:(char Stream.t -> unit) -> ?use_stderr:bool -> ?env:string array -> ?verbose:bool -> string -> string list -> unit (** [assert_equal expected real] Compares two values, when they are not equal a failure is signaled. @param cmp customize function to compare, default is [=] @param printer value printer, don't print value otherwise @param pp_diff if not equal, ask a custom display of the difference using [diff fmt exp real] where [fmt] is the formatter to use @param msg custom message to identify the failure @raise Failure signal a failure @version 1.1.0 *) val assert_equal : ?cmp:('a -> 'a -> bool) -> ?printer:('a -> string) -> ?pp_diff:(Format.formatter -> ('a * 'a) -> unit) -> ?msg:string -> 'a -> 'a -> unit (** Asserts if the expected exception was raised. @param msg identify the failure @raise Failure description *) val assert_raises : ?msg:string -> exn -> (unit -> 'a) -> unit (** {2 Skipping tests } In certain condition test can be written but there is no point running it, because they are not significant (missing OS features for example). In this case this is not a failure nor a success. Following functions allow you to escape test, just as assertion but without the same error status. A test skipped is counted as success. A test todo is counted as failure. *) (** [skip cond msg] If [cond] is true, skip the test for the reason explain in [msg]. For example [skip_if (Sys.os_type = "Win32") "Test a doesn't run on windows"]. @since 1.0.3 *) val skip_if : bool -> string -> unit (** The associated test is still to be done, for the reason given. @since 1.0.3 *) val todo : string -> unit (** {2 Compare Functions} *) (** Compare floats up to a given relative error. @param epsilon if the difference is smaller [epsilon] values are equal *) val cmp_float : ?epsilon:float -> float -> float -> bool (** {2 Bracket} A bracket is a functional implementation of the commonly used setUp and tearDown feature in unittests. It can be used like this: ["MyTestCase" >:: (bracket test_set_up test_fun test_tear_down)] *) (** [bracket set_up test tear_down] The [set_up] function runs first, then the [test] function runs and at the end [tear_down] runs. The [tear_down] function runs even if the [test] failed and help to clean the environment. *) val bracket: (unit -> 'a) -> ('a -> unit) -> ('a -> unit) -> unit -> unit (** [bracket_tmpfile test] The [test] function takes a temporary filename and matching output channel as arguments. The temporary file is created before the test and removed after the test. @param prefix see [Filename.open_temp_file] @param suffix see [Filename.open_temp_file] @param mode see [Filename.open_temp_file] @since 1.1.0 *) val bracket_tmpfile: ?prefix:string -> ?suffix:string -> ?mode:open_flag list -> ((string * out_channel) -> unit) -> unit -> unit (** {2 Constructing Tests} *) (** The type of test function *) type test_fun = unit -> unit (** The type of tests *) type test = TestCase of test_fun | TestList of test list | TestLabel of string * test (** Create a TestLabel for a test *) val (>:) : string -> test -> test (** Create a TestLabel for a TestCase *) val (>::) : string -> test_fun -> test (** Create a TestLabel for a TestList *) val (>:::) : string -> test list -> test (** Some shorthands which allows easy test construction. Examples: - ["test1" >: TestCase((fun _ -> ()))] => [TestLabel("test2", TestCase((fun _ -> ())))] - ["test2" >:: (fun _ -> ())] => [TestLabel("test2", TestCase((fun _ -> ())))] - ["test-suite" >::: ["test2" >:: (fun _ -> ());]] => [TestLabel("test-suite", TestSuite([TestLabel("test2", TestCase((fun _ -> ())))]))] *) (** [test_decorate g tst] Apply [g] to test function contains in [tst] tree. @since 1.0.3 *) val test_decorate : (test_fun -> test_fun) -> test -> test (** [test_filter paths tst] Filter test based on their path string representation. @param skip if set, just use [skip_if] for the matching tests. @since 1.0.3 *) val test_filter : ?skip:bool -> string list -> test -> test option (** {2 Retrieve Information from Tests} *) (** Returns the number of available test cases *) val test_case_count : test -> int (** Types which represent the path of a test *) type node = ListItem of int | Label of string type path = node list (** The path to the test (in reverse order). *) (** Make a string from a node *) val string_of_node : node -> string (** Make a string from a path. The path will be reversed before it is tranlated into a string *) val string_of_path : path -> string (** Returns a list with paths of the test *) val test_case_paths : test -> path list (** {2 Performing Tests} *) (** The possible results of a test *) type test_result = RSuccess of path | RFailure of path * string | RError of path * string | RSkip of path * string | RTodo of path * string (** Events which occur during a test run. *) type test_event = EStart of path (** A test start. *) | EEnd of path (** A test end. *) | EResult of test_result (** Result of a test. *) (** Results of a test run. *) type test_results = test_result list (** Perform the test, allows you to build your own test runner *) val perform_test : (test_event -> unit) -> test -> test_results (** A simple text based test runner. @param verbose print verbose message *) val run_test_tt : ?verbose:bool -> test -> test_results (** Main version of the text based test runner. It reads the supplied command line arguments to set the verbose level and limit the number of test to run. @param arg_specs add extra command line arguments @param set_verbose call a function to set verbosity @param fexit call a final function after test, by default exit 1. @version 1.1.0 *) val run_test_tt_main : ?arg_specs:(Arg.key * Arg.spec * Arg.doc) list -> ?set_verbose:(bool -> unit) -> test -> test_results val ounit2_of_ounit1 : test -> OUnit2.test ounit-2.0.0/src/oUnit2.ml0000644000175000017500000001061512222142072014467 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnitCore open OUnitTest let (>:) = OUnitTest.(>:) let (>::) = OUnitTest.(>::) let (>:::) = OUnitTest.(>:::) type test_ctxt = OUnitTest.ctxt type test_fun = OUnitTest.test_fun type test_length = OUnitTest.test_length type test = OUnitTest.test let test_case ?(length=Short) f = TestCase(length, f) let test_list lst = TestList lst type log_severity = OUnitLogger.log_severity let assert_failure = OUnitAssert.assert_failure let assert_bool = OUnitAssert.assert_bool let assert_string = OUnitAssert.assert_string (* Upgrade to OUnit v2, using logger. *) (* let assert_command = OUnitAssert.assert_command *) let assert_command ?exit_code ?sinput ?foutput ?use_stderr ?backtrace ?chdir ?env ~ctxt prg args = OUnitAssert.assert_command ?exit_code ?sinput ?foutput ?use_stderr ?backtrace ?chdir ?env ~ctxt prg args let assert_equal = OUnitAssert.assert_equal let assert_raises = OUnitAssert.assert_raises let skip_if = OUnitAssert.skip_if let todo = OUnitAssert.todo let cmp_float = OUnitUtils.cmp_float let bracket = OUnitBracket.create let bracket_tmpfile = OUnitBracket.bracket_tmpfile let bracket_tmpdir = OUnitBracket.bracket_tmpdir let with_bracket_chdir test_ctxt dn f = OUnitBracket.with_bracket test_ctxt (OUnitBracket.bracket_chdir dn) (fun () -> f) let non_fatal = OUnitTest.non_fatal let run_test_tt_main = OUnitCore.run_test_tt_main let logf ctxt log_severity fmt = OUnitLogger.Test.logf ctxt.test_logger log_severity fmt let in_testdata_dir ctxt path = OUnitTestData.in_testdata_dir ctxt.conf path let conf_wrap f name default help = let get = f name default help in fun ctxt -> get ctxt.conf module Conf = struct type 'a conf_t = string -> 'a -> Arg.doc -> test_ctxt -> 'a let make_string = conf_wrap OUnitConf.make_string let make_string_opt = conf_wrap OUnitConf.make_string_opt let make_int = conf_wrap OUnitConf.make_int let make_float = conf_wrap OUnitConf.make_float let make_bool = conf_wrap OUnitConf.make_bool let make_exec name = let get = OUnitConf.make_exec name in fun ctxt -> get ctxt.conf end ounit-2.0.0/src/oUnit2.mli0000644000175000017500000002566412222142072014652 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) (** Unit test building blocks (v2). @author Sylvain Le Gall *) (** {2 Types} *) (** Context of a test. *) type test_ctxt = OUnitTest.ctxt (** The type of test function. *) type test_fun = test_ctxt -> unit (** The type of test. *) type test = OUnitTest.test (** The expected length of the test. *) type test_length = OUnitTest.test_length (** {2 Assertions} Assertions are the basic building blocks of unittests. *) (** Signals a failure. This will raise an exception with the specified string. @raise Failure signal a failure *) val assert_failure : string -> 'a (** Signals a failure when bool is false. The string identifies the failure. @raise Failure signal a failure *) val assert_bool : string -> bool -> unit (** Signals a failure when the string is non-empty. The string identifies the failure. @raise Failure signal a failure *) val assert_string : string -> unit (** [assert_command prg args] Run the command provided. @param exit_code expected exit code @param sinput provide this [char Stream.t] as input of the process @param foutput run this function on output, it can contains an [assert_equal] to check it @param use_stderr redirect [stderr] to [stdout] @param backtrace Set OCAMLRUNPARAM=b @param chdir Chdir into a directory before running the command. @param env Unix environment @param verbose if a failed, dump stdout/stderr of the process to stderr *) val assert_command : ?exit_code:Unix.process_status -> ?sinput:char Stream.t -> ?foutput:(char Stream.t -> unit) -> ?use_stderr:bool -> ?backtrace:bool -> ?chdir:string -> ?env:string array -> ctxt:test_ctxt -> string -> string list -> unit (** [assert_equal expected real] Compares two values, when they are not equal a failure is signaled. @param cmp customize function to compare, default is [=] @param printer value printer, don't print value otherwise @param pp_diff if not equal, ask a custom display of the difference using [diff fmt exp real] where [fmt] is the formatter to use @param msg custom message to identify the failure @param ctxt if provided, always print expected and real value @raise Failure signal a failure *) val assert_equal : ?ctxt:test_ctxt -> ?cmp:('a -> 'a -> bool) -> ?printer:('a -> string) -> ?pp_diff:(Format.formatter -> ('a * 'a) -> unit) -> ?msg:string -> 'a -> 'a -> unit (** Asserts if the expected exception was raised. @param msg identify the failure @raise Failure description *) val assert_raises : ?msg:string -> exn -> (unit -> 'a) -> unit (** {2 Skipping tests } In certain condition test can be written but there is no point running it, because they are not significant (missing OS features for example). In this case this is not a failure nor a success. Following functions allow you to escape test, just as assertion but without the same error status. A test skipped is counted as success. A test todo is counted as failure. *) (** [skip cond msg] If [cond] is true, skip the test for the reason explain in [msg]. For example [skip_if (Sys.os_type = "Win32") "Test a doesn't run on windows"]. *) val skip_if : bool -> string -> unit (** The associated test is still to be done, for the reason given. *) val todo : string -> unit (** {2 Compare Functions} *) (** Compare floats up to a given relative error. @param epsilon if the difference is smaller [epsilon] values are equal *) val cmp_float : ?epsilon:float -> float -> float -> bool (** {2 Bracket} A bracket is a registered object with setUp and tearDown in unit tests. Data generated during the setUp will be automatically tearDown when the test ends. *) (** [bracket set_up tear_down test_ctxt] set up an object and register it to be tore down in [test_ctxt]. *) val bracket : (test_ctxt -> 'a) -> ('a -> test_ctxt -> unit) -> test_ctxt -> 'a (** [bracket_tmpfile test_ctxt] Create a temporary filename and matching output channel. The temporary file is removed after the test. @param prefix see [Filename.open_temp_file] @param suffix see [Filename.open_temp_file] @param mode see [Filename.open_temp_file] *) val bracket_tmpfile: ?prefix:string -> ?suffix:string -> ?mode:open_flag list -> test_ctxt -> (string * out_channel) (** [bracket_tmpdir test_ctxt] Create a temporary dirname. The temporary directory is removed after the test. @param prefix see [Filename.open_temp_file] @param suffix see [Filename.open_temp_file] *) val bracket_tmpdir: ?prefix:string -> ?suffix:string -> test_ctxt -> string (** [with_bracket_chdir test_ctxt dn f] change directory to [dn] during execution of function [f]. In order to [Sys.chdir], we need to take a lock to avoid other tests trying to do change the current directory at the same time. So this bracket is not directly accessible in order to use it only on shorter piece of code. *) val with_bracket_chdir: test_ctxt -> string -> (test_ctxt -> 'a) -> 'a (** {2 Constructing Tests} *) (** Create a TestLabel for a test *) val (>:) : string -> test -> test (** Create a TestLabel for a TestCase *) val (>::) : string -> test_fun -> test (** Create a TestLabel for a TestList *) val (>:::) : string -> test list -> test (** Generic function to create a test case. *) val test_case : ?length:test_length -> test_fun -> test (** Generic function to create a test list. *) val test_list : test list -> test (** Some shorthands which allows easy test construction. Examples: - ["test1" >: TestCase((fun _ -> ()))] => [TestLabel("test2", TestCase((fun _ -> ())))] - ["test2" >:: (fun _ -> ())] => [TestLabel("test2", TestCase((fun _ -> ())))] - ["test-suite" >::: ["test2" >:: (fun _ -> ());]] => [TestLabel("test-suite", TestSuite([TestLabel("test2", TestCase((fun _ -> ())))]))] *) (** {2 Performing Tests} *) (** Severity level for log. *) type log_severity = [ `Error | `Warning | `Info ] (** Log into OUnit logging system. *) val logf: test_ctxt -> log_severity -> ('a, unit, string, unit) format4 -> 'a (** Build a filename for a file that should be located in the test data dir. The test data dir, can be defined on the command line (preferably absolute) The default option is to locate it in topsrcdir/test/data. *) val in_testdata_dir: test_ctxt -> string list -> string (** [non_fatal ctxt f] Run [f] but if an exception is raised or an assert fails, don't stop, just register the result. The global test running result will mix in the non fatal result to determine the success or failure of the test. *) val non_fatal: test_ctxt -> (test_ctxt -> unit) -> unit (** Define command line options, environment variables and file configuration. This module helps to define configuration options that are translated to command line options et al. The name defined for the variable is: - should be a valid OCaml identifier - kept as is for use in configuration file. (foo_bar = "") - '_' are replaced by '-' and a leading '-' is added for command line (-foo "") - capitalized and prefixed by OUNIT_ for environment (OUNIT_FOO_BAR="") *) module Conf: sig (** The default type of function that create a configuration option of type 'a. *) type 'a conf_t = string -> 'a -> Arg.doc -> test_ctxt -> 'a (** [make_string name default help] Create a string configuration option with default value [default] and a short help string. The result of the partial application of the function can be used inside tests to be evaluated to a value. {[ let my_option = Conf.make_string "my_option" "the default" "A default option." let tests = "ATest" >:: (fun test_ctxt -> let option_value = my_option test_ctxt in ()) ]} *) val make_string: string conf_t (** Create a [string option] configuration option. See [!make_string]. *) val make_string_opt: (string option) conf_t (** Create an [int] configuration option. See [!make_string]. *) val make_int: int conf_t (** Create a [float] configuration option. See [!make_string]. *) val make_float: float conf_t (** Create a [bool] configuration option. See [!make_string]. *) val make_bool: bool conf_t (** [make_exec execname] Create a option to define an executable. *) val make_exec: string -> test_ctxt -> string end (** Main version of the text based test runner. It reads the supplied command line arguments to set the verbose level and limit the number of test to run. @param test the test suite to run. *) val run_test_tt_main : ?exit:(int -> unit) -> test -> unit ounit-2.0.0/src/oUnitAssert.ml0000644000175000017500000002420012222142072015562 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnitUtils open OUnitBracket open OUnitTest let skip_if b msg = if b then raise (Skip msg) let todo msg = raise (Todo msg) let assert_failure msg = raise (OUnit_failure msg) let assert_bool msg b = if not b then assert_failure msg let assert_string str = if not (str = "") then assert_failure str let assert_equal ?ctxt ?(cmp = ( = )) ?printer ?pp_diff ?msg expected actual = let get_error_string () = let res = buff_format_printf (fun fmt -> Format.pp_open_vbox fmt 0; begin match msg with | Some s -> Format.pp_open_box fmt 0; Format.pp_print_string fmt s; Format.pp_close_box fmt (); Format.pp_print_cut fmt () | None -> () end; begin match printer with | Some p -> Format.fprintf fmt "@[expected: @[%s@]@ but got: @[%s@]@]@," (p expected) (p actual) | None -> Format.fprintf fmt "@[not equal@]@," end; begin match pp_diff with | Some d -> Format.fprintf fmt "@[differences: %a@]@," d (expected, actual) | None -> () end; Format.pp_close_box fmt ()) in let len = String.length res in if len > 0 && res.[len - 1] = '\n' then String.sub res 0 (len - 1) else res in let logf fmt = match ctxt with | Some ctxt -> OUnitLogger.Test.logf ctxt.test_logger `Info fmt | None -> Printf.ksprintf ignore fmt in begin match msg with | Some str -> logf "%s" str; | _ -> () end; begin match printer with | Some p -> logf "Expected: %s" (p expected); logf "Actual: %s" (p actual) | _ -> () end; if not (cmp expected actual) then assert_failure (get_error_string ()) let assert_command ?(exit_code=Unix.WEXITED 0) ?(sinput=Stream.of_list []) ?(foutput=ignore) ?(use_stderr=true) ?(backtrace=true) ?chdir ?env ~ctxt prg args = OUnitTest.section_ctxt ctxt (fun ctxt -> let (fn_out, chn_out) = bracket_tmpfile ctxt in let cmd_print fmt = Format.pp_print_string fmt prg; List.iter (Format.fprintf fmt "@ %s") args in (* Start the process *) let in_write = Unix.dup (Unix.descr_of_out_channel chn_out) in let (out_read, out_write) = Unix.pipe () in let err = if use_stderr then in_write else Unix.stderr in let args = Array.of_list (prg :: args) in let env = let param = "OCAMLRUNPARAM" in let analyse_and_fix env = let arr = Array.copy env in let fixed = ref false in let new_var = ref "" in for i = 0 to (Array.length arr) - 1 do let really_starts, current_value = OUnitUtils.start_substr ~prefix:(param^"=") arr.(i) in if really_starts then begin (* Rewrite the params. *) if not (String.contains current_value 'b') then begin arr.(i) <- param^"="^current_value^"b" end; new_var := arr.(i); fixed := true end done; if !fixed then arr else Array.append arr [|param^"=b"|] in if backtrace then begin (* Analyse of the provided environment. *) match env with | Some env -> Some (analyse_and_fix env) | None -> Some (analyse_and_fix (Unix.environment ())) end else begin env end in let command_chdir, in_chdir = match chdir with | Some dn -> dn, fun f -> with_bracket ctxt (bracket_chdir dn) (fun () _ -> f ()) | None -> Sys.getcwd (), fun f -> f () in let pid = OUnitLogger.Test.logf ctxt.test_logger `Info "%s" (buff_format_printf (fun fmt -> Format.fprintf fmt "Starting command '%t'." cmd_print)); OUnitLogger.Test.logf ctxt.test_logger `Info "Working directory: %S" command_chdir; OUnitLogger.Test.logf ctxt.test_logger `Info "Environment: "; Array.iter (fun v -> OUnitLogger.Test.logf ctxt.test_logger `Info "%s" v) (match env with | Some e -> e | None -> Unix.environment ()); Unix.set_close_on_exec out_write; match env with | Some e -> in_chdir (fun () -> Unix.create_process_env prg args e out_read in_write err) | None -> in_chdir (fun () -> Unix.create_process prg args out_read in_write err) in let () = Unix.close out_read; Unix.close in_write in let () = (* Dump sinput into the process stdin *) let buff = " " in Stream.iter (fun c -> let _i : int = buff.[0] <- c; Unix.write out_write buff 0 1 in ()) sinput; Unix.close out_write in let _, real_exit_code = let rec wait_intr () = try Unix.waitpid [] pid with Unix.Unix_error (Unix.EINTR, _, _) -> wait_intr () in wait_intr () in (* Dump process output to stderr *) begin let chn = open_in fn_out in let buff = String.make 4096 'X' in let len = ref (-1) in while !len <> 0 do len := input chn buff 0 (String.length buff); OUnitLogger.Test.raw_printf ctxt.test_logger "%s" (String.sub buff 0 !len); done; close_in chn end; (* Check process status *) assert_equal ~msg:(buff_format_printf (fun fmt -> Format.fprintf fmt "@[Exit status of command '%t'@]" cmd_print)) ~printer:string_of_process_status exit_code real_exit_code; begin let chn = open_in fn_out in try foutput (Stream.of_channel chn) with e -> close_in chn; raise e end) let raises f = try f (); None with e -> Some e let assert_raises ?msg exn (f: unit -> 'a) = let pexn = Printexc.to_string in let get_error_string () = let str = Format.sprintf "expected exception %s, but no exception was raised." (pexn exn) in match msg with | None -> assert_failure str | Some s -> assert_failure (s^"\n"^str) in match raises f with | None -> assert_failure (get_error_string ()) | Some e -> assert_equal ?msg ~printer:pexn exn e ounit-2.0.0/src/oUnitBracket.ml0000644000175000017500000001313012222142072015674 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnitTest type t = (unit -> unit) list let create set_up tear_down test_ctxt = let fixture = set_up test_ctxt in let tear_down test_ctxt = tear_down fixture test_ctxt in OUnitShared.Mutex.with_lock test_ctxt.shared test_ctxt.tear_down_mutex (fun () -> test_ctxt.tear_down <- tear_down :: test_ctxt.tear_down); fixture let logf logger lvl fmt = OUnitLogger.Test.logf logger lvl fmt let bracket_tmpfile ?(prefix="ounit-") ?(suffix=".txt") ?mode test_ctxt = create (fun test_ctxt -> let suffix = "-"^(OUnitTest.get_shard_id test_ctxt)^suffix in let (fn, chn) = Filename.open_temp_file ?mode prefix suffix in logf test_ctxt.test_logger `Info "Created a temporary file: %S." fn; (fn, chn)) (fun (fn, chn) test_ctxt -> (try close_out chn with _ -> ()); try Sys.remove fn; logf test_ctxt.test_logger `Info "Removed a temporary file: %S." fn with _ -> ()) test_ctxt let bracket_tmpdir ?(prefix="ounit-") ?(suffix=".dir") test_ctxt = let max_attempt = 10 in let rec try_hard_mkdir attempt = if max_attempt = attempt then begin OUnitUtils.failwithf "Unable to create temporary directory after %d attempts." attempt end else begin try let suffix = "-"^(OUnitTest.get_shard_id test_ctxt)^suffix in let tmpdn = Filename.temp_file prefix suffix in Sys.remove tmpdn; Unix.mkdir tmpdn 0o755; tmpdn with Unix.Unix_error (Unix.EEXIST, "mkdir", _) -> try_hard_mkdir (max_attempt + 1) end in create (fun test_ctxt -> let tmpdn = try_hard_mkdir 0 in logf test_ctxt.test_logger `Info "Create a temporary directory: %S." tmpdn; tmpdn) (fun tmpdn test_ctxt -> let log_delete fn = logf test_ctxt.test_logger `Info "Delete in a temporary directory: %S." fn in let safe_run f a = try f a with _ -> () in let rec rmdir fn = Array.iter (fun bn -> let fn' = Filename.concat fn bn in let is_dir = try Sys.is_directory fn' with _ -> false in if is_dir then begin rmdir fn'; safe_run Unix.rmdir fn'; log_delete fn' end else begin safe_run Sys.remove fn'; log_delete fn' end) (try Sys.readdir fn with _ -> [||]) in rmdir tmpdn; safe_run Unix.rmdir tmpdn; log_delete tmpdn) test_ctxt let chdir_mutex = OUnitShared.Mutex.create OUnitShared.ScopeProcess let bracket_chdir dir test_ctxt = let () = OUnitLogger.infof test_ctxt.logger "Change directory to %S" dir; in let () = try OUnitShared.Mutex.lock test_ctxt.shared chdir_mutex; with OUnitShared.Lock_failure -> failwith "Trying to do a nested chdir." in let cur_pwd = Sys.getcwd () in create (fun test_ctxt -> Unix.chdir dir) (fun () test_ctxt -> Unix.chdir cur_pwd; OUnitShared.Mutex.unlock test_ctxt.shared chdir_mutex) test_ctxt let with_bracket test_ctxt bracket f = section_ctxt test_ctxt (fun test_ctxt -> let res = bracket test_ctxt in f res test_ctxt) ounit-2.0.0/src/oUnitCache.ml0000644000175000017500000000676712222142072015346 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnitTest type cache = OUnitTest.result MapPath.t let cache_filename = OUnitConf.make_string_subst_opt "cache_filename" (* TODO: oUnit-$(name).cache *) (Some (Filename.concat OUnitUtils.buildir "oUnit-$(suite_name).cache")) "Cache file to store previous results." let default = MapPath.empty let load conf = match cache_filename conf with | Some fn -> begin try let chn = open_in fn in let cache : cache = try Marshal.from_channel chn with e -> default in close_in chn; cache with _ -> default end | None -> default let dump conf cache = match cache_filename conf with | Some fn -> begin try let chn = open_out fn in Marshal.to_channel chn cache []; close_out chn with _ -> () end | None -> () let get_result path cache = try Some (MapPath.find path cache) with Not_found -> None let add_result path result cache = MapPath.add path result cache ounit-2.0.0/src/oUnitCheckEnv.ml0000644000175000017500000000647212222142072016022 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) (* Check environment after and before tests, to check isolation. *) open OUnitTest open OUnitAssert type t = { pwd: string; env: string array; } let create () = { pwd = Sys.getcwd (); env = Unix.environment (); } module EnvElement = struct type t = string let pp_printer = Format.pp_print_string let compare = String.compare let pp_print_sep = OUnitDiff.pp_comma_separator end module SetEnv = OUnitDiff.SetMake(EnvElement) let check test_ctxt t = let t' = create () in List.iter (fun f -> non_fatal test_ctxt (fun _ -> f ())) [ (fun () -> assert_equal ~msg:"Current working dir (check env)." ~printer:(fun s -> s) t.pwd t'.pwd); (fun () -> let convert t = SetEnv.of_list (Array.to_list t.env) in SetEnv.assert_equal ~msg:"Environment (check env)." (convert t) (convert t')); ] ounit-2.0.0/src/oUnitChooser.ml0000644000175000017500000001203112222142072015722 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) (** Heuristic to pick a test to run. @author Sylvain Le Gall *) open OUnitTest type t = { tests_planned: path list; tests_running: path list; tests_passed: result_list; cache: OUnitCache.cache; } type choice = | ChooseToSkip of path | ChooseToPostpone | Choose of path | NoChoice let string_of_choice = function | ChooseToSkip path -> Printf.sprintf "ChooseToSkip %S" (string_of_path path) | ChooseToPostpone -> "ChooseToPostpone" | Choose path -> Printf.sprintf "Choose %S" (string_of_path path) | NoChoice -> "NoChoice" type chooser = t -> choice (** Most simple heuristic, just pick the first test. *) let simple t = match t.tests_planned with | hd :: _ -> Choose hd | [] -> NoChoice module Plugin = OUnitPlugin.Make (struct type t = chooser let name = "chooser" let conf_help = "Select the method to choose tests to run." let default_name = "simple" let default_value = simple end) include Plugin let allskip t = match t.tests_planned with | hd :: _ -> ChooseToSkip hd | [] -> NoChoice let failfirst t = let was_successful = OUnitResultSummary.was_successful in let rec find_failing = function | path :: tl -> begin match OUnitCache.get_result path t.cache with | Some result -> (* Find the first formerly failing test. *) if was_successful [path, result, None] then find_failing tl else Choose path | None -> Choose path end | [] -> begin let wait_results_running = List.fold_left (fun wait path -> match OUnitCache.get_result path t.cache with | Some result -> (not (was_successful [path, result, None])) || wait | None -> (* No former result, we need the result of * this test. *) true) false t.tests_running in if wait_results_running then (* We need more data about currently running tests. *) ChooseToPostpone else if was_successful t.tests_passed then (* All tests that were red has become green, continue. *) simple t else (* Some tests still fail, skip the rest. *) allskip t end in find_failing t.tests_planned let () = register "failfirst" ~-1 failfirst ounit-2.0.0/src/oUnitConf.ml0000644000175000017500000002661012222142072015215 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnitUtils exception Parse_error of string type conf = OUnitPropList.t type metadata = { help: string; get_print: conf -> string; parse_set: string -> conf -> unit; cli: conf -> (string * Arg.spec * string) list; } let metaconf = Hashtbl.create 13 let check_variable_name str = let () = if String.length str = 0 then failwith "'' is not a valid name." in let () = match str.[0] with | '0' .. '9' | '_' -> failwithf "%S is not a valid variable name. It must not start with %C." str str.[0] | _ -> () in String.iter (function | 'A' .. 'Z' | 'a' .. 'z' | '_' | '0' .. '9' -> () | c -> failwithf "%S is not a valid variable name. It must not contain %C." str c) str let cli_name name = let cli_name = "-" ^ name in for i = 1 to String.length name do match cli_name.[i] with | '_' -> cli_name.[i] <- '-' | _ -> () done; cli_name let subst conf extra_subst str = let substitutions = Hashtbl.create (Hashtbl.length metaconf) in let () = (* Fill the substitutions table. *) Hashtbl.iter (fun name metadata -> Hashtbl.add substitutions name (metadata.get_print conf)) metaconf; List.iter (fun (k, v) -> Hashtbl.add substitutions k v) extra_subst in let buff = Buffer.create (String.length str) in Buffer.add_substitute buff (fun var -> try Hashtbl.find substitutions var with Not_found -> failwithf "Unknown substitution variable %S in %S." var str) str; Buffer.contents buff let make ~name ~parse ~print ~default ~help ~fcli () = let () = check_variable_name name; if Hashtbl.mem metaconf name then failwithf "Duplicate definition for configuration variable %S." name in let set, get = OUnitPropList.new_property default in let parse_set str conf = set conf (parse str) in let get_print conf = print (get conf) in Hashtbl.add metaconf name {help = help; get_print = get_print; parse_set = parse_set; cli = (fun conf -> fcli (get conf) (set conf))}; get let make_string name default help = make ~name ~parse:(fun s -> s) ~print:(fun s -> s) ~default ~help ~fcli: (fun get set -> [cli_name name, Arg.String set, "str "^help]) () let make_string_subst name default help = let get = make_string name default help in (fun ?(extra_subst=[]) conf -> subst conf extra_subst (get conf)) let make_string_opt name default help = make ~name ~parse: (function | "none" -> None | str -> Some str) ~print: (function | Some x -> x | None -> "none") ~default ~help ~fcli: (fun get set -> [cli_name name, Arg.String (fun str -> set (Some str)), "str "^help; cli_name ("no_"^name), Arg.Unit (fun () -> set None), Printf.sprintf " Reset value of %s." name]) () let make_string_subst_opt name default opt = let get = make_string_opt name default opt in (fun ?(extra_subst=[]) conf -> match get conf with | Some str -> Some (subst conf extra_subst str) | None -> None) let make_int name default help = make ~name ~parse: (fun str -> try int_of_string str with Failure _ -> raise (Parse_error (Printf.sprintf "%S is not an integer." str))) ~print:string_of_int ~default ~help ~fcli: (fun get set -> [cli_name name, Arg.Int set, "i "^help]) () let make_float name default help = make ~name ~parse: (fun str -> try float_of_string str with Failure _ -> raise (Parse_error (Printf.sprintf "%S is not a float." str))) ~print:string_of_float ~default ~help ~fcli: (fun get set -> [cli_name name, Arg.Float set, "f "^help]) () let make_bool name default help = make ~name ~parse: (fun str -> try bool_of_string str with Failure _ -> raise (Parse_error (Printf.sprintf "%S is not a boolean (true or false)." str))) ~print:string_of_bool ~default ~help ~fcli: (fun get set -> [cli_name name, Arg.Bool set, "{true|false} "^help]) () let make_enum name get_enums default help = let parse str = let enum_lst = get_enums () in if not (List.exists (fun (str', _) -> str = str') enum_lst) then raise (Parse_error (Printf.sprintf "%S is not an allowed value for %s." str name)); str in let get = make ~name ~parse ~print:(fun s -> s) ~default ~help ~fcli: (fun get set -> [cli_name name, Arg.Symbol (List.map fst (get_enums ()), set), " "^help]) () in fun conf -> try get conf, List.assoc (get conf) (get_enums ()) with Not_found -> failwithf "Enums list for %s has changed during execution." name let make_exec name = let default = let pwd = Sys.getcwd () in let bn = Filename.concat pwd name in if Sys.file_exists (bn^".native") then bn^".native" else if Sys.file_exists (bn^".byte") then bn^".byte" else name in make_string name default (Printf.sprintf "Executable %s." name) let set ~origin conf name value = try (Hashtbl.find metaconf name).parse_set value conf with | Not_found -> failwithf "Variable %S is not defined in the application.\n%s" name origin | Parse_error str -> failwith (str ^ "\n" ^ origin) let file_parse conf fn = let parse lineno line = let origin = Printf.sprintf "File \"%s\", line %d." fn lineno in match trim (trim_comment line) with | "" -> () | str -> begin let name, value = try Scanf.sscanf str "%s = %S" (fun name value -> name, value) with Scanf.Scan_failure _ -> begin try Scanf.sscanf str "%s = %s" (fun name value -> name, value) with Scanf.Scan_failure _ -> failwithf "Unparseable line: %s\n%s" line origin end in set ~origin conf name value end in let chn = open_in fn in let lineno = ref 0 in try while true do let line = input_line chn in incr lineno; parse !lineno line done; () with | End_of_file -> close_in chn | e -> close_in chn; raise e let env_parse conf = let parse name = let env_name = "OUNIT_" ^ (String.uppercase name) in try let value = Sys.getenv env_name in (* Check and translate double quoted variable. *) let value = try Scanf.sscanf value "%S" (fun s -> s) with Scanf.Scan_failure _ -> value in let origin = Printf.sprintf "Environment variable %s=%S." env_name value in set ~origin conf name value with Not_found -> () in Hashtbl.iter (fun name _ -> parse name) metaconf let cli_parse ?argv extra_specs conf = let specs = Hashtbl.fold (fun name metadata lst -> let cli_lst = match metadata.cli conf with | (key, spec, doc) :: tl -> (key, spec, doc ^ (Printf.sprintf " (default: %s)" (metadata.get_print conf))) :: tl | [] -> [] in cli_lst @ lst) metaconf [] in let all_specs = Arg.align ([ "-conf", Arg.String (file_parse conf), "fn Read configuration file." ] @ (List.sort Pervasives.compare specs) @ extra_specs) in let arg_parse = match argv with | Some arr -> Arg.parse_argv ~current:(ref 0) arr | None -> Arg.parse in arg_parse all_specs (fun x -> raise (Arg.Bad ("Unexpected argument: " ^ x))) ("usage: " ^ Sys.argv.(0) ^ " options*") let default ?(preset=[]) () = let conf = OUnitPropList.create () in List.iter (fun (name, value) -> set ~origin:"Preset by program." conf name value) preset; conf (** Load test options from file, environment and command line (in this order). Not that [extra_specs] is here for historical reason, better use [make] to create command line options. *) let load ?preset ?argv extra_specs = let conf = default ?preset () in if Sys.file_exists "ounit.conf" then file_parse conf "ounit.conf"; env_parse conf; cli_parse ?argv extra_specs conf; conf let dump conf = Hashtbl.fold (fun name metadata lst -> (name, metadata.get_print conf) :: lst) metaconf [] ounit-2.0.0/src/oUnitCore.ml0000644000175000017500000001422512222142072015217 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnitUtils open OUnitTest open OUnitLogger (* Plugin initialisation. *) let () = OUnitRunnerProcesses.init () (* * Types and global states. *) (* Run all tests, report starts, errors, failures, and return the results *) let perform_test conf logger runner chooser test = let rec flatten_test path acc = function | TestCase(l, f) -> (path, l, f) :: acc | TestList (tests) -> fold_lefti (fun acc t cnt -> flatten_test ((ListItem cnt)::path) acc t) acc tests | TestLabel (label, t) -> flatten_test ((Label label)::path) acc t in let test_cases = List.rev (flatten_test [] [] test) in runner conf logger chooser test_cases (* A simple (currently too simple) text based test runner *) let run_test_tt conf logger runner chooser test = let () = Printexc.record_backtrace true in let () = (* TODO: move into perform test. *) List.iter (fun (k, v) -> OUnitLogger.report logger (GlobalEvent (GConf (k, v)))) (OUnitConf.dump conf) in (* Now start the test *) let running_time, test_results = time_fun (perform_test conf logger runner chooser) test in (* TODO: move into perform test. *) (* Print test report *) OUnitLogger.report logger (GlobalEvent (GResults (running_time, test_results, OUnitTest.test_case_count test))); (* Reset logger. *) OUnitLogger.close logger; (* Return the results possibly for further processing *) test_results (* Test-only override. *) let run_test_tt_main_conf = ref (fun ?(preset=[]) ?argv extra_specs -> OUnitConf.load ?argv ~preset:(OUnitChooser.preset (OUnitRunner.preset preset)) extra_specs) let suite_name = OUnitConf.make_string "suite_name" "anon" "The name of the test suite running." (* Call this one to act as your main() function. *) let run_test_tt_main ?(exit=Pervasives.exit) suite = let only_test = ref [] in let list_test = ref false in let extra_specs = [ "-only-test", Arg.String (fun str -> only_test := str :: !only_test), "path Run only the selected tests."; "-list-test", Arg.Set list_test, " List tests"; ] in let preset = match suite with | OUnitTest.TestLabel (suite_name, _) -> ["suite_name", suite_name] | OUnitTest.TestCase _ | OUnitTest.TestList _ -> [] in let conf = !run_test_tt_main_conf ~preset extra_specs in if !list_test then begin List.iter (fun pth -> print_endline (OUnitTest.string_of_path pth)) (OUnitTest.test_case_paths suite) end else begin let nsuite = if !only_test = [] then suite else begin match OUnitTest.test_filter ~skip:true !only_test suite with | Some test -> test | None -> failwithf "Filtering test %s lead to no tests." (String.concat ", " !only_test) end in let logger = OUnitLogger.combine [ OUnitLoggerStd.create conf shard_default; OUnitLoggerHTML.create conf; OUnitLoggerJUnit.create conf; ] in let runner_name, runner = OUnitRunner.choice conf in let chooser_name, chooser = OUnitChooser.choice conf in let test_results = OUnitLogger.infof logger "Runner: %s" runner_name; OUnitLogger.infof logger "Chooser: %s" chooser_name; run_test_tt conf logger runner chooser nsuite in if not (OUnitResultSummary.was_successful test_results) then exit 1 end ounit-2.0.0/src/oUnitDiff.ml0000644000175000017500000001370112222142072015175 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open Format module type DIFF_ELEMENT = sig type t val pp_printer: Format.formatter -> t -> unit val compare: t -> t -> int val pp_print_sep: Format.formatter -> unit -> unit end module type S = sig type e type t val compare: t -> t -> int val pp_printer: Format.formatter -> t -> unit val pp_diff: Format.formatter -> (t * t) -> unit val assert_equal: ?msg:string -> t -> t -> unit val of_list: e list -> t end let assert_equal ?msg compare pp_printer pp_diff exp act = OUnitAssert.assert_equal ~cmp:(fun t1 t2 -> (compare t1 t2) = 0) ~printer:(fun t -> let buff = Buffer.create 13 in let fmt = formatter_of_buffer buff in pp_printer fmt t; pp_print_flush fmt (); Buffer.contents buff) ~pp_diff ?msg exp act module SetMake (D: DIFF_ELEMENT) : S with type e = D.t = struct module Set = Set.Make(D) type e = D.t type t = Set.t let compare = Set.compare let pp_printer fmt t = let first = ref true in pp_open_box fmt 0; Set.iter (fun e -> if not !first then D.pp_print_sep fmt (); D.pp_printer fmt e; first := false) t; pp_close_box fmt () let pp_diff fmt (t1, t2) = let first = ref true in let print_list c t = Set.iter (fun e -> if not !first then D.pp_print_sep fmt (); pp_print_char fmt c; D.pp_printer fmt e; first := false) t in pp_open_box fmt 0; print_list '+' (Set.diff t2 t1); print_list '-' (Set.diff t1 t2); pp_close_box fmt () let assert_equal ?msg exp act = assert_equal ?msg compare pp_printer pp_diff exp act let of_list lst = List.fold_left (fun acc e -> Set.add e acc) Set.empty lst end module ListSimpleMake (D: DIFF_ELEMENT) : S with type e = D.t and type t = D.t list = struct type e = D.t type t = e list let rec compare t1 t2 = match t1, t2 with | e1 :: tl1, e2 :: tl2 -> begin match D.compare e1 e2 with | 0 -> compare tl1 tl2 | n -> n end | [], [] -> 0 | _, [] -> -1 | [], _ -> 1 let pp_print_gen pre fmt t = let first = ref true in pp_open_box fmt 0; List.iter (fun e -> if not !first then D.pp_print_sep fmt (); fprintf fmt "%s%a" pre D.pp_printer e; first := false) t; pp_close_box fmt () let pp_printer fmt t = pp_print_gen "" fmt t let pp_diff fmt (t1, t2) = let rec pp_diff' n t1 t2 = match t1, t2 with | e1 :: tl1, e2 :: tl2 -> begin match D.compare e1 e2 with | 0 -> pp_diff' (n + 1) tl1 tl2 | _ -> fprintf fmt "element number %d differ (%a <> %a)" n D.pp_printer e1 D.pp_printer e2 end | [], [] -> () | [], lst -> fprintf fmt "at end,@ "; pp_print_gen "+" fmt lst | lst, [] -> fprintf fmt "at end,@ "; pp_print_gen "-" fmt lst in pp_open_box fmt 0; pp_diff' 0 t1 t2; pp_close_box fmt () let assert_equal ?msg exp act = assert_equal ?msg compare pp_printer pp_diff exp act let of_list lst = lst end let pp_comma_separator fmt () = fprintf fmt ",@ " ounit-2.0.0/src/oUnitDiff.mli0000644000175000017500000001140012222142072015340 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) (** Unit tests for collection of elements This module allows to define a more precise way to display differences between collection of elements. When collection differ, the tester is interested by what are the missing/extra elements. This module provides a [diff] operation to spot the difference quickly between two sets of elements. Example: {[ open OUnit;; module EInt = struct type t = int let compare = ( - ) let pp_printer = Format.pp_print_int let pp_print_sep = OUnitDiff.pp_comma_separator end module ListInt = OUnitDiff.ListSimpleMake(EInt);; let test_diff () = ListInt.assert_equal [1; 2; 3; 4; 5] [1; 2; 5; 4] ;; let _ = run_test_tt_main ("test_diff" >:: test_diff) ;; ]} when run this test outputs: {[ OUnit: expected: 1, 2, 3, 4, 5 but got: 1, 2, 5, 4 differences: element number 2 differ (3 <> 5) ]} @since 1.1.0 @author Sylvain Le Gall *) (** {2 Signatures} *) (** Definition of an element *) module type DIFF_ELEMENT = sig (** Type of an element *) type t (** Pretty printer for an element *) val pp_printer : Format.formatter -> t -> unit (** Element comparison *) val compare : t -> t -> int (** Pretty print element separator *) val pp_print_sep : Format.formatter -> unit -> unit end (** Definition of standard operations *) module type S = sig (** Type of an element *) type e (** Type of a collection of element *) type t (** Compare a collection of element *) val compare : t -> t -> int (** Pretty printer a collection of element *) val pp_printer : Format.formatter -> t -> unit (** Pretty printer for collection differences *) val pp_diff : Format.formatter -> t * t -> unit (** {!assert_equal} with [~diff], [~cmp] and [~printer] predefined for this collection events *) val assert_equal : ?msg:string -> t -> t -> unit (** Create [t] using of list *) val of_list : e list -> t end (** {2 Implementations} *) (** Collection of elements based on a Set, elements order doesn't matter *) module SetMake : functor (D : DIFF_ELEMENT) -> S with type e = D.t (** Collection of elements based on a List, order matters but difference display is very simple. It stops at the first element which differs. *) module ListSimpleMake : functor (D: DIFF_ELEMENT) -> S with type e = D.t and type t = D.t list val pp_comma_separator : Format.formatter -> unit -> unit ounit-2.0.0/src/oUnitLogger.ml0000644000175000017500000001542712222142072015553 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) (* Logger for information and various OUnit events. *) open OUnitUtils (* See OUnit.mli. *) type position = { filename: string; line: int; } (** See OUnit.mli. *) type log_severity = [`Error | `Warning | `Info] (** See OUnit.mli. *) type 'result test_event = | EStart | EEnd | EResult of 'result | ELog of log_severity * string | ELogRaw of string type ('path, 'result) result_full = ('path * 'result * position option) (** Events which occur at the global level. *) type ('path, 'result) global_event = | GConf of string * string (** Dump a configuration options. *) | GLog of log_severity * string | GStart (** Start running the tests. *) | GEnd (** Finish running the tests. *) | GResults of (float * ('path, 'result) result_full list * int) type ('path, 'result) log_event_t = | GlobalEvent of ('path, 'result) global_event | TestEvent of 'path * 'result test_event type ('path, 'result) log_event = { shard: string; timestamp: float; event: ('path, 'result) log_event_t; } type ('path, 'result) logger = { lshard: string; fwrite: ('path, 'result) log_event -> unit; fpos: unit -> position option; fclose: unit -> unit; } let shard_default = OUnitUtils.shardf 0 let string_of_event ev = let spf fmt = Printf.sprintf fmt in let string_of_log_severity = function | `Error -> "`Error" | `Warning -> "`Warning" | `Info -> "`Info" in match ev with | GlobalEvent e -> begin match e with | GConf (k, v) -> spf "GConf (%S, %S)" k v | GLog (lvl, s) -> spf "GLog (%s, %S)" (string_of_log_severity lvl) s | GStart -> "GStart" | GEnd -> "GEnd" | GResults _ -> "GResults" end | TestEvent (path, e) -> begin match e with | EStart -> "EStart" | EEnd -> "EEnd" | EResult result -> "EResult (_)" | ELog (lvl, str) -> spf "ELog (%s, %S)" (string_of_log_severity lvl) str | ELogRaw str -> spf "ELogRaw %S" str end let null_logger = { lshard = shard_default; fwrite = ignore; fpos = (fun () -> None); fclose = ignore; } let fun_logger fwrite fclose = { lshard = shard_default; fwrite = (fun log_ev -> fwrite log_ev); fpos = (fun () -> None); fclose = fclose; } let post_logger fpost = let data = ref [] in let fwrite ev = data := ev :: !data in let fclose () = fpost (List.rev !data) in { lshard = shard_default; fwrite = fwrite; fpos = (fun () -> None); fclose = fclose; } let set_shard shard logger = {logger with lshard = shard} let report logger ev = logger.fwrite { shard = logger.lshard; timestamp = now (); event = ev; } let infof logger fmt = Printf.ksprintf (fun str -> report logger (GlobalEvent (GLog (`Info, str)))) fmt let warningf logger fmt = Printf.ksprintf (fun str -> report logger (GlobalEvent (GLog (`Warning, str)))) fmt let errorf logger fmt = Printf.ksprintf (fun str -> report logger (GlobalEvent (GLog (`Error, str)))) fmt let position logger = logger.fpos () let close logger = logger.fclose () let combine lst = let rec fpos = function | logger :: tl -> begin match position logger with | Some _ as pos -> pos | None -> fpos tl end | [] -> None in let lshard = match lst with hd :: _ -> hd.lshard | [] -> shard_default in { lshard = lshard; fwrite = (fun log_ev -> List.iter (fun logger -> logger.fwrite log_ev) lst); fpos = (fun () -> fpos lst); fclose = (fun () -> List.iter (fun logger -> close logger) (List.rev lst)); } module Test = struct type 'result t = 'result test_event -> unit let create logger path = fun ev -> logger.fwrite { shard = logger.lshard; timestamp = now (); event = TestEvent (path, ev) } let raw_printf t fmt = Printf.ksprintf (fun s -> t (ELogRaw s)) fmt let logf t lvl fmt = Printf.ksprintf (fun s -> t (ELog (lvl, s))) fmt end ounit-2.0.0/src/oUnitLoggerHTML.ml0000644000175000017500000002234312222142072016233 0ustar gildorgildor(**************************************************************************) (* 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. *) open OUnitLogger open OUnitUtils open OUnitTest open OUnitResultSummary let html_escaper str = let buffer = Buffer.create (String.length str) in let addc = Buffer.add_char buffer in let addse se = addc '&'; Buffer.add_string buffer se; addc ';' in String.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 -> addc c) str; Buffer.contents buffer let render conf dn events = let smr = OUnitResultSummary.of_log_events conf events in let () = if not (Sys.file_exists dn) then Unix.handle_unix_error (fun () -> Unix.mkdir dn 0o755) () in let chn = open_out (Filename.concat dn "oUnit.css") in let () = output_string chn OUnitLoggerHTMLData.oUnit_css; close_out chn in let chn = open_out (Filename.concat dn "oUnit.js") in let () = output_string chn OUnitLoggerHTMLData.oUnit_js; close_out chn in let chn = open_out (Filename.concat dn "index.html") in let printf fmt = Printf.fprintf chn fmt in printf "\ Test suite %s

Test suite %s

Results

\n" (html_escaper smr.suite_name) smr.charset (html_escaper smr.suite_name); begin let printf_result clss label num = printf "
\n\ %s: %d\n\
\n" clss label num in let printf_non0_result clss label num = if num > 0 then printf_result clss label num in printf "
\ Started at: %s
" (date_iso8601 smr.start_at); printf "
\ Total duration: %.3fs\
" 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 *) if was_successful smr.global_results then printf "
Success
" else printf "
Failure
" end; printf "\

Configuration

\n"; List.iter (fun (k, v) -> printf "%s=%S
\n" (html_escaper k) (html_escaper v)) smr.conf; printf ("\
"); List.iter (fun test_data -> let class_result, text_result = match test_data.test_result with | RSuccess -> "ounit-success", "succeed" | RFailure _ -> "ounit-failure", "failed" | RError _ -> "ounit-error", "error" | RSkip _ -> "ounit-skip", "skipped" | RTodo _ -> "ounit-todo", "TODO" | RTimeout _ -> "ounit-timeout", "timeout" in let class_severity_opt = function | Some `Error -> "ounit-log-error" | Some `Warning -> "ounit-log-warning" | Some `Info -> "ounit-log-info" | None -> "" in printf "

%s (%s)

Started at: %s
Test duration: %0.3fs
\n" class_result (html_escaper test_data.test_name) (html_escaper text_result) (date_iso8601 test_data.timestamp_start) (test_data.timestamp_end -. test_data.timestamp_start); printf "%0.3fsStart
\n" 0.0; List.iter (fun (tmstp, svrt, str) -> printf "\ %0.3fs%s
\n" (class_severity_opt svrt) tmstp (html_escaper str)) test_data.log_entries; printf "%0.3fsEnd
\n" (test_data.timestamp_end -. test_data.timestamp_start); printf "
"; begin (* TODO: use backtrace *) match test_data.test_result with | RSuccess -> printf "Success." | RFailure (str, _, backtrace) -> printf "Failure:
%s" (html_escaper str) | RError (str, backtrace) -> printf "Error:
%s" (html_escaper str) | RSkip str -> printf "Skipped:
%s" (html_escaper str) | RTodo str -> printf "Todo:
%s" (html_escaper str) | RTimeout test_length -> printf "Timeout after %.1fs
" (delay_of_length test_length) end; printf "
"; printf "\
\n"; (* TODO: results, end timestamp *)) smr.tests; printf "\ "; close_out chn let output_html_dir = OUnitConf.make_string_subst_opt "output_html_dir" None "Output directory of the HTML files." let create conf = match output_html_dir conf with | Some dn -> post_logger (render conf dn) | None -> null_logger ounit-2.0.0/src/oUnitLoggerJUnit.ml0000644000175000017500000001251212222142072016515 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) (* JUnit logger for OUnit. *) open OUnitLogger open OUnitUtils open OUnitTest open OUnitResultSummary let xml_escaper = OUnitLoggerHTML.html_escaper let render conf fn events = let smr = OUnitResultSummary.of_log_events conf events in let chn = open_out fn in let string_of_failure = function | msg, None -> msg^"\nNo backtrace." | msg, Some backtrace -> msg^"\n"^backtrace in let printf fmt = Printf.fprintf chn fmt in printf "\ \n" smr.charset (xml_escaper smr.suite_name) (xml_escaper smr.suite_name) (xml_escaper (date_iso8601 ~tz:false smr.start_at)) (xml_escaper (fqdn ())) smr.test_case_count (smr.failures + smr.todos) smr.errors smr.running_time; printf "\ \ \n"; List.iter (fun (k, v) -> printf "\ \ \n" (xml_escaper k) (xml_escaper v)) smr.conf; printf "\ \ \n"; List.iter (fun test_data -> printf "\ \ \n" (xml_escaper test_data.test_name) (xml_escaper test_data.test_name) (test_data.timestamp_end -. test_data.timestamp_start); begin match test_data.test_result with | RSuccess | RSkip _ -> () | RError (msg, backtrace) -> printf "\ \ %s\n" (xml_escaper msg) (xml_escaper (string_of_failure (msg, backtrace))) | RFailure (msg, _, backtrace) -> printf "\ \ %s\n" (xml_escaper msg) (xml_escaper (string_of_failure (msg, backtrace))) | RTodo msg -> printf "\ \ \n" (xml_escaper msg) | RTimeout test_length -> printf "\ \ \n" (delay_of_length test_length) end; printf "\ \ \n") smr.tests; printf "\ \ \n"; List.iter (fun log_event -> List.iter (fun s -> printf "%s\n" (xml_escaper s)) (OUnitLoggerStd.format_log_event log_event)) events; printf "\ \ "; close_out chn let output_junit_file = OUnitConf.make_string_subst_opt "output_junit_file" None "Output file for JUnit." let create conf = match output_junit_file conf with | Some fn -> post_logger (render conf fn) | None -> null_logger ounit-2.0.0/src/oUnitLoggerStd.ml0000644000175000017500000003013212222142072016214 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnitLogger open OUnitTest open OUnitResultSummary let ocaml_position pos = Printf.sprintf "File \"%s\", line %d, characters 1-1:" pos.filename pos.line let multiline f str = if String.length str > 0 then let buf = Buffer.create 80 in let flush () = f (Buffer.contents buf); Buffer.clear buf in String.iter (function '\n' -> flush () | c -> Buffer.add_char buf c) str; flush () let count results f = List.fold_left (fun count (_, test_result, _) -> if f test_result then count + 1 else count) 0 results (* TODO: deprecate in 2.1.0. *) let results_style_1_X = OUnitConf.make_bool "results_style_1_X" false "Use OUnit 1.X results printer (will be deprecated in 2.1.0+)." let format_display_event conf log_event = match log_event.event with | GlobalEvent e -> begin match e with | GConf (_, _) | GLog _ | GStart | GEnd -> "" | GResults (running_time, results, test_case_count) -> let separator1 = String.make (Format.get_margin ()) '=' in let separator2 = String.make (Format.get_margin ()) '-' in let buf = Buffer.create 1024 in let bprintf fmt = Printf.bprintf buf fmt in let print_results = List.iter (fun (path, test_result, pos_opt) -> bprintf "%s\n" separator1; if results_style_1_X conf then begin bprintf "%s: %s\n\n" (result_flavour test_result) (string_of_path path); end else begin bprintf "Error: %s.\n\n" (string_of_path path); begin match pos_opt with | Some pos -> bprintf "%s\nError: %s (in the log).\n\n" (ocaml_position pos) (string_of_path path) | None -> () end; begin match test_result with | RError (_, Some backtrace) -> bprintf "%s\n" backtrace | RFailure (_, Some pos, _) -> bprintf "%s\nError: %s (in the code).\n\n" (ocaml_position pos) (string_of_path path) | RFailure (_, _, Some backtrace) -> bprintf "%s\n" backtrace | _ -> () end; end; bprintf "%s\n" (result_msg test_result); bprintf "%s\n" separator2) in let filter f = let lst = List.filter (fun (_, test_result, _) -> f test_result) results in lst, List.length lst in let errors, nerrors = filter is_error in let failures, nfailures = filter is_failure in let skips, nskips = filter is_skip in let todos, ntodos = filter is_todo in let timeouts, ntimeouts = filter is_timeout in bprintf "\n"; print_results errors; print_results failures; print_results timeouts; bprintf "Ran: %d tests in: %.2f seconds.\n" (List.length results) running_time; (* Print final verdict *) if was_successful results then begin if skips = [] then bprintf "OK" else bprintf "OK: Cases: %d Skip: %d" test_case_count nskips end else begin bprintf "FAILED: Cases: %d Tried: %d Errors: %d \ Failures: %d Skip: %d Todo: %d \ Timeouts: %d." test_case_count (List.length results) nerrors nfailures nskips ntodos ntimeouts; end; bprintf "\n"; Buffer.contents buf end | TestEvent (_, e) -> begin match e with | EStart _ | EEnd _ | ELog _ | ELogRaw _ -> "" | EResult RSuccess -> "." | EResult (RFailure _) -> "F" | EResult (RError _) -> "E" | EResult (RSkip _) -> "S" | EResult (RTodo _) -> "T" | EResult (RTimeout _) -> "~" end let format_log_event ev = let rlst = ref [] in let timestamp_str = OUnitUtils.date_iso8601 ev.timestamp in let spf pre fmt = Printf.ksprintf (multiline (fun l -> rlst := (timestamp_str^" "^ev.shard^" "^pre^": "^l) :: !rlst)) fmt in let ispf fmt = spf "I" fmt in let wspf fmt = spf "W" fmt in let espf fmt = spf "E" fmt in let format_result path result = let path_str = string_of_path path in match result with | RTimeout test_length -> espf "Test %s timed out after %.1fs" path_str (delay_of_length test_length) | RError (msg, backtrace_opt) -> espf "Test %s exited with an error." path_str; espf "%s in test %s." msg path_str; OUnitUtils.opt (espf "%s") backtrace_opt | RFailure (msg, _, backtrace_opt) -> espf "Test %s has failed." path_str; espf "%s in test %s." msg path_str; OUnitUtils.opt (espf "%s") backtrace_opt | RTodo msg -> wspf "TODO test %s: %s." path_str msg | RSkip msg -> wspf "Skip test %s: %s." path_str msg | RSuccess -> ispf "Test %s is successful." path_str in begin match ev.event with | GlobalEvent e -> begin match e with | GConf (k, v) -> ispf "Configuration %s = %S" k v | 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) -> let countr = count results in ispf "=============="; ispf "Summary:"; List.iter (fun (path, test_result, _) -> format_result path test_result) results; (* Print final verdict *) ispf "Ran: %d tests in: %.2f seconds." (List.length results) running_time; ispf "Cases: %d." test_case_count; ispf "Tried: %d." (List.length results); ispf "Errors: %d." (countr is_error); ispf "Failures: %d." (countr is_failure); ispf "Skip: %d." (countr is_skip); ispf "Todo: %d." (countr is_todo); ispf "Timeout: %d." (countr is_timeout) end | TestEvent (path, e) -> begin let path_str = string_of_path path in match e with | EStart -> ispf "Start test %s." path_str | EEnd -> ispf "End test %s." path_str | EResult result -> format_result path result | ELog (`Error, str) -> espf "%s" str | ELog (`Warning, str) -> wspf "%s" str | ELog (`Info, str) -> ispf "%s" str | ELogRaw str -> ispf "%s" str end end; List.rev !rlst let file_logger conf shard_id fn = let chn = open_out fn in let line = ref 1 in let fwrite ev = List.iter (fun l -> output_string chn l; output_char chn '\n'; incr line) (format_log_event ev); flush chn in let fpos () = Some { filename = fn; line = !line } in let fclose () = close_out chn in { lshard = shard_id; fwrite = fwrite; fpos = fpos; fclose = fclose; } let verbose = OUnitConf.make_bool "verbose" false "Run test in verbose mode." let display = OUnitConf.make_bool "display" true "Output logs on screen." let std_logger conf shard_id = if display conf then let verbose = verbose conf in let fwrite log_ev = if verbose then List.iter print_endline (format_log_event log_ev) else print_string (format_display_event conf log_ev); flush stdout in { lshard = shard_id; fwrite = fwrite; fpos = (fun () -> None); fclose = ignore; } else null_logger let output_file = OUnitConf.make_string_subst_opt "output_file" (Some (Filename.concat OUnitUtils.buildir "oUnit-$(suite_name)-$(shard_id).log")) "Output verbose log in the given file." let is_output_file_shard_dependent conf = let fn1 = output_file ~extra_subst:["shard_id", "foo"] conf in let fn2 = output_file ~extra_subst:["shard_id", "bar"] conf in fn1 <> fn2 let create_file_logger conf shard_id = match output_file ~extra_subst:["shard_id", shard_id] conf with | Some fn -> file_logger conf shard_id fn | None -> null_logger let create conf shard_id = let std_logger = std_logger conf shard_id in let file_logger = create_file_logger conf shard_id in combine [std_logger; file_logger] ounit-2.0.0/src/oUnitPlugin.ml0000644000175000017500000000621612222142072015566 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) (** Standard functions for plugin (register, choose). *) module type SETTINGS = sig type t val name: string val conf_help: string val default_name: string val default_value: t end module Make(Settings: SETTINGS) = struct let all = ref [0, (Settings.default_name, Settings.default_value)] let register name pref f = all := (pref, (name, f)) :: !all let of_name s = try List.assoc s (List.map snd !all) with Not_found -> OUnitUtils.failwithf "Unable to find %s '%s'." Settings.name s let choice = OUnitConf.make_enum Settings.name (fun () -> List.map snd !all) Settings.default_name Settings.conf_help let preset lst = let _, (default, _) = List.fold_left max (List.hd !all) (List.tl !all) in (Settings.name, default) :: lst end ounit-2.0.0/src/oUnitPropList.ml0000644000175000017500000000550412222142072016103 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) (** Property list. @see Eigenclass Article on property list. *) type t = (int, unit -> unit) Hashtbl.t let create () = Hashtbl.create 13 let new_property default = let id = Oo.id (object end) in let v = ref default in let set t x = Hashtbl.replace t id (fun () -> v := x) in let get t = try let x = (Hashtbl.find t id) (); !v in v := default; x with Not_found -> default in (set, get) ounit-2.0.0/src/oUnitResultSummary.ml0000644000175000017500000002410612222142072017162 0ustar gildorgildor(**************************************************************************) (* 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. *) open OUnitUtils open OUnitTest open OUnitLogger type log_entry = float (* time since start of the test *) * log_severity option * string (* log entry without \n *) type test_data = { test_name: string; timestamp_start: float; (* UNIX timestamp *) timestamp_end: float; (* UNIX timestamp *) log_entries: log_entry list; (* time sorted log entry, timestamp from timestamp_start *) test_result: OUnitTest.result; } type t = { 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_data list; errors: int; failures: int; skips: int; todos: int; timeouts: int; successes: int; } let is_success = function | RSuccess -> true | RFailure _ | RError _ | RSkip _ | RTodo _ | RTimeout _ -> false let is_failure = function | RFailure _ -> true | RSuccess | RError _ | RSkip _ | RTodo _ | RTimeout _ -> false let is_error = function | RError _ -> true | RSuccess | RFailure _ | RSkip _ | RTodo _ | RTimeout _ -> false let is_skip = function | RSkip _ -> true | RSuccess | RFailure _ | RError _ | RTodo _ | RTimeout _ -> false let is_todo = function | RTodo _ -> true | RSuccess | RFailure _ | RError _ | RSkip _ | RTimeout _ -> false let is_timeout = function | RTimeout _ -> true | RSuccess | RFailure _ | RError _ | RSkip _ | RTodo _ -> false let result_flavour = function | RError _ -> "Error" | RFailure _ -> "Failure" | RSuccess -> "Success" | RSkip _ -> "Skip" | RTodo _ -> "Todo" | RTimeout _ -> "Timeout" let result_msg = function | RSuccess -> "Success" | RError (msg, _) | RFailure (msg, _, _) | RSkip msg | RTodo msg -> msg | RTimeout test_length -> Printf.sprintf "Timeout after %.1fs" (delay_of_length test_length) let worst_cmp result1 result2 = let rank = function | RSuccess -> 0 | RSkip _ -> 1 | RTodo _ -> 2 | RFailure _ -> 3 | RError _ -> 4 | RTimeout _ -> 5 in (rank result1) - (rank result2) let worst_result_full result_full lst = let worst = List.fold_left (fun ((_, result1, _) as result_full1) ((_, result2, _) as result_full2) -> if worst_cmp result1 result2 < 0 then result_full2 else result_full1) result_full lst in worst, List.filter (fun result_full -> not (result_full == worst)) (result_full :: lst) let was_successful lst = List.for_all (fun (_, rslt, _) -> match rslt with | RSuccess | RSkip _ -> true | _ -> false) lst let encoding = OUnitConf.make_string "log_encoding" "utf-8" "Encoding of the log." let of_log_events conf events = let global_conf = List.fold_left (fun acc log_ev -> match log_ev.event with | GlobalEvent (GConf (k, v)) -> (k, v) :: acc | _ -> acc) [] (List.rev events) in let running_time, global_results, test_case_count = let rec find_results = function | {event = GlobalEvent (GResults (running_time, results, test_case_count))} :: _ -> running_time, results, test_case_count | _ :: tl -> find_results tl | [] -> failwith "Cannot find results in OUnitResult.of_log_events." in find_results events in let tests = let rec split_raw tmstp str lst = try let idx = String.index str '\n' in split_raw tmstp (String.sub str (idx + 1) (String.length str - idx - 1)) ((tmstp, None, String.sub str 0 idx) :: lst) with Not_found -> (tmstp, None, str) :: lst in let finalize t = let log_entries = List.sort (fun (f1, _, _) (f2, _, _) -> Pervasives.compare f2 f1) t.log_entries in let log_entries = List.rev_map (fun (f, a, b) -> f -. t.timestamp_start, a, b) log_entries in {t with log_entries = log_entries} in let default_timestamp = 0.0 in let rec process_log_event tests log_event = let timestamp = log_event.timestamp in match log_event.event with | GlobalEvent _ -> tests | TestEvent (path, ev) -> begin let t = try MapPath.find path tests with Not_found -> { test_name = string_of_path path; timestamp_start = default_timestamp; timestamp_end = default_timestamp; log_entries = []; test_result = RFailure ("Not finished", None, None); } in let alt0 t1 t2 = if t1 = default_timestamp then t2 else t1 in let t' = match ev with | EStart -> {t with timestamp_start = timestamp; timestamp_end = alt0 t.timestamp_end timestamp} | EEnd -> {t with timestamp_end = timestamp; timestamp_start = alt0 t.timestamp_start timestamp} | EResult rslt -> {t with test_result = rslt} | ELog (svrt, str) -> {t with log_entries = (timestamp, Some svrt, str) :: t.log_entries} | ELogRaw str -> {t with log_entries = split_raw timestamp str t.log_entries} in MapPath.add path t' tests end and group_test tests = function | hd :: tl -> group_test (process_log_event tests hd) tl | [] -> let lst = MapPath.fold (fun _ test lst -> finalize test :: lst) tests [] in List.sort (fun t1 t2 -> Pervasives.compare t1.timestamp_start t2.timestamp_start) lst in group_test MapPath.empty events in let start_at = List.fold_left (fun start_at log_ev -> min start_at log_ev.timestamp) (now ()) events in let suite_name = match global_results with | (path, _, _) :: _ -> List.fold_left (fun acc nd -> match nd with | ListItem _ -> acc | Label str -> str) "noname" path | [] -> "noname" in let count f = List.length (List.filter (fun (_, test_result, _) -> f test_result) global_results) in let charset = encoding conf in { 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 = count is_error; failures = count is_failure; skips = count is_skip; todos = count is_todo; timeouts = count is_timeout; successes = count is_success; } ounit-2.0.0/src/oUnitRunner.ml0000644000175000017500000004125212222142072015600 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnitTest open OUnitLogger (** Common utilities to run test. *) let run_one_test conf logger shared test_path test_fun = let () = OUnitLogger.report logger (TestEvent (test_path, EStart)) in let non_fatal = ref [] in let main_result_full = with_ctxt conf logger shared non_fatal test_path (fun ctxt -> let check_env = OUnitCheckEnv.create () in let result_full = try test_fun ctxt; OUnitCheckEnv.check ctxt check_env; test_path, RSuccess, None with e -> OUnitTest.result_full_of_exception ctxt e in report_result_full ctxt result_full) in let result_full, other_result_fulls = match main_result_full, List.rev !non_fatal with | (_, RSuccess, _), [] -> main_result_full, [] | (_, RSuccess, _), hd :: tl -> OUnitResultSummary.worst_result_full hd tl | _, lst -> OUnitResultSummary.worst_result_full main_result_full lst in OUnitLogger.report logger (TestEvent (test_path, EEnd)); result_full, other_result_fulls type runner = OUnitConf.conf -> OUnitTest.logger -> OUnitChooser.chooser -> (path * test_length * test_fun) list -> OUnitTest.result_list (* The simplest runner possible, run test one after the other in a single * process, without threads. *) (* Run all tests, sequential version *) let sequential_runner conf logger chooser test_cases = let shared = OUnitShared.create () in let rec iter state = match OUnitState.next_test_case conf logger state with | OUnitState.Finished, state -> OUnitState.get_results state | OUnitState.Next_test_case (test_path, test_fun, worker), state -> iter (OUnitState.test_finished conf (run_one_test conf logger shared test_path test_fun) worker state) | (OUnitState.Try_again | OUnitState.Not_enough_worker), _ -> assert false in let state = OUnitState.add_worker () (OUnitState.create conf chooser test_cases) in iter state (* Plugin interface. *) module Plugin = OUnitPlugin.Make (struct type t = runner let name = "runner" let conf_help = "Select a the method to run tests." let default_name = "sequential" let default_value = sequential_runner end) include Plugin let shards = let shards = ref 2 in if Sys.os_type = "Unix" then begin if Sys.file_exists "/proc/cpuinfo" then begin let chn_in = open_in "/proc/cpuinfo" in let () = try while true do try let line = input_line chn_in in Scanf.sscanf line "cpu cores : %d" (fun i -> shards := i) with Scanf.Scan_failure _ -> () done with End_of_file -> () in close_in chn_in end end; OUnitConf.make_int "shards" !shards "Number of shards to use as worker (threads or processes)." (** Build worker based runner. *) module GenericWorker = struct open OUnitState type message_to_worker = | Exit | AckLock of bool | RunTest of path let string_of_message_to_worker = function | Exit -> "Exit" | AckLock _ -> "AckLock _" | RunTest _ -> "RunTest _" type message_from_worker = | AckExit | Log of OUnitTest.log_event_t | Lock of int | Unlock of int | TestDone of (OUnitTest.result_full * OUnitTest.result_list) let string_of_message_from_worker = function | AckExit -> "AckExit" | Log _ -> "Log _" | Lock _ -> "Lock _" | Unlock _ -> "Unlock _" | TestDone _ -> "TestDone _" module MapPath = Map.Make (struct type t = path let rec compare lst1 lst2 = match lst1, lst2 with | hd1 :: tl1, hd2 :: tl2 -> begin match Pervasives.compare hd1 hd2 with | 0 -> compare tl1 tl2 | n -> n end | [], _ :: _ -> -1 | _ :: _, [] -> 1 | [], [] -> 0 end) type ('a, 'b) channel = { send_data: 'a -> unit; receive_data: unit -> 'b; close: unit -> unit; } (* Add some extra feature to channel. *) let wrap_channel shard_id string_of_read_message string_of_written_message channel = (* Turn on to debug communication in channel. *) let debug_communication = false in if debug_communication then begin let debugf fmt = Printf.ksprintf (fun s -> if debug_communication then prerr_endline ("D("^shard_id^"): "^s)) fmt in let send_data msg = debugf "Sending message %S" (string_of_written_message msg); channel.send_data msg; debugf "Message transmitted, continuing." in let receive_data () = let () = debugf "Waiting to receive data." in let msg = channel.receive_data () in debugf "Received message %S" (string_of_read_message msg); msg in { send_data = send_data; receive_data = receive_data; close = channel.close; } end else begin channel end (* Run a worker, react to message receive from parent. *) let main_worker_loop conf yield channel shard_id map_test_cases worker_log_file = let logger = let master_logger = set_shard shard_id (OUnitLogger.fun_logger (fun {event = log_ev} -> channel.send_data (Log log_ev)) ignore) in let base_logger = if worker_log_file then OUnitLoggerStd.create_file_logger conf shard_id else OUnitLogger.null_logger in OUnitLogger.combine [base_logger; master_logger] in let shared = let try_lock id = channel.send_data (Lock id); match channel.receive_data () with | AckLock b -> b | Exit | RunTest _ -> assert false in let rec lock id = if not (try_lock id) then begin yield (); lock id end else begin () end in let unlock id = channel.send_data (Unlock id); in let global = { OUnitShared. lock = lock; try_lock = try_lock; unlock = unlock; } in { OUnitShared. global = global; process = OUnitShared.noscope_create (); } in let rec loop () = match channel.receive_data () with | Exit -> channel.send_data AckExit | RunTest test_path -> let test_path, _, test_fun = MapPath.find test_path map_test_cases in let res = run_one_test conf logger shared test_path test_fun in channel.send_data (TestDone res); loop () | AckLock _ -> loop () in loop () type 'a worker = { channel: (message_to_worker, message_from_worker) channel; close_worker: unit -> string option; select_fd: 'a; shard_id: string; is_running: unit -> bool; } (* Run all tests. *) let runner create_worker workers_waiting conf logger chooser test_cases = let map_test_cases = List.fold_left (fun mp ((test_path, _, _) as test_case) -> MapPath.add test_path test_case mp) MapPath.empty test_cases in let state = OUnitState.create conf chooser test_cases in let shards = max (shards conf) 1 in let master_id = logger.OUnitLogger.lshard in let worker_idx = ref 1 in let test_per_worker, incr_tests_per_worker = OUnitUtils.make_counter () in let health_check_per_worker, incr_health_check_per_worker = OUnitUtils.make_counter () in let () = infof logger "Using %d workers maximum." shards; in let worker_log_file = if not (OUnitLoggerStd.is_output_file_shard_dependent conf) then begin warningf logger "-output-file doesn't include $(shard_id), \ shards won't have file log."; false end else begin true end in let master_shared = OUnitShared.noscope_create () in (* Act depending on the received message. *) let process_message worker msg state = match msg with | AckExit -> let msg_opt = infof logger "Worker %s has ended." worker.shard_id; worker.close_worker () in OUnitUtils.opt (errorf logger "Worker return status: %s") msg_opt; remove_idle_worker worker state | Log log_ev -> OUnitLogger.report (set_shard worker.shard_id logger) log_ev; state | Lock id -> worker.channel.send_data (AckLock (master_shared.OUnitShared.try_lock id)); state | Unlock id -> master_shared.OUnitShared.unlock id; state | TestDone test_result -> OUnitState.test_finished conf test_result worker state in (* Report a worker dead and unregister it. *) let declare_dead_worker test_path worker result state = let log_pos = position logger in report logger (TestEvent (test_path, EResult result)); report logger (TestEvent (test_path, EEnd)); remove_idle_worker worker (test_finished conf ((test_path, result, log_pos), []) worker state) in (* Kill the worker that has timed out. *) let kill_timeout state = List.fold_left (fun state (test_path, test_length, worker) -> let _msg : string option = errorf logger "Worker %s, running test %s has timed out." worker.shard_id (string_of_path test_path); worker.close_worker () in declare_dead_worker test_path worker (RTimeout test_length) state) state (get_worker_timed_out state) in (* Check that worker are healthy (i.e. still running). *) let check_health state = List.fold_left (fun state (test_path, worker) -> incr_health_check_per_worker worker.shard_id; if worker.is_running () then begin update_test_activity test_path state end else begin (* Argh, a test failed badly! *) let result_msg = errorf logger "Worker %s, running test %s is not running anymore." worker.shard_id (string_of_path test_path); match worker.close_worker () with | Some msg -> Printf.sprintf "Worker stops running: %s" msg | None -> "Worker stops running for unknown reason." in declare_dead_worker test_path worker (RError (result_msg, None)) state end) state (get_worker_need_health_check state) in (* Main wait loop. *) let rec wait_test_done state = let state = (check_health (kill_timeout state)) in if get_workers state <> [] then begin let workers_waiting_lst = infof logger "%d tests running: %s." (count_tests_running state) (String.concat ", " (List.map string_of_path (get_tests_running state))); workers_waiting (get_workers state) (timeout state) in List.fold_left (fun state worker -> process_message worker (worker.channel.receive_data ()) state) state workers_waiting_lst end else begin state end in (* Wait for every worker to stop. *) let rec wait_stopped state = if OUnitState.get_workers state = [] then state else wait_stopped (wait_test_done state) in let rec iter state = match OUnitState.next_test_case conf logger state with | Not_enough_worker, state -> if OUnitState.count_worker state < shards then begin (* Start a worker. *) let shard_id = OUnitUtils.shardf !worker_idx in let () = infof logger "Starting worker number %s." shard_id in let worker = create_worker conf map_test_cases shard_id master_id worker_log_file in let () = infof logger "Worker %s started." worker.shard_id in let state = add_worker worker state in incr worker_idx; iter state end else begin iter (wait_test_done state) end | Try_again, state -> iter (wait_test_done state) | Next_test_case (test_path, _, worker), state -> incr_tests_per_worker worker.shard_id; worker.channel.send_data (RunTest test_path); iter state | Finished, state -> let count_tests_running = OUnitState.count_tests_running state in if count_tests_running = 0 then begin let state = List.iter (fun worker -> worker.channel.send_data Exit) (OUnitState.get_workers state); wait_stopped state in infof logger "Used %d worker during test execution." (!worker_idx - 1); List.iter (fun (shard_id, count) -> infof logger "Run %d tests with shard %s." count shard_id) (test_per_worker ()); List.iter (fun (shard_id, count) -> infof logger "Check health of shard %s, %d times." shard_id count) (health_check_per_worker ()); OUnitState.get_results state end else begin infof logger "Still %d tests running : %s." count_tests_running (String.concat ", " (List.map string_of_path (get_tests_running state))); iter (wait_test_done state) end in iter state end ounit-2.0.0/src/oUnitRunnerProcesses.ml0000644000175000017500000002054312222142072017467 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) (** Use processes to run several tests in parallel. * * Run processes that handle running tests. The processes read test, execute * it, and communicate back to the master the log. * * This need to be done in another process because ocaml Threads are not truly * concurrent. Moreover we cannot use Unix.fork because it's not portable *) open OUnitLogger open OUnitTest open OUnitState open Unix open OUnitRunner.GenericWorker (* Create functions to handle sending and receiving data over a file descriptor. *) let make_channel shard_id string_of_read_message string_of_written_message fd_read fd_write = let () = set_nonblock fd_read; set_close_on_exec fd_read; set_close_on_exec fd_write in let chn_write = out_channel_of_descr fd_write in let really_read fd str = let off = ref 0 in let read = ref 0 in while !read < String.length str do try let one_read = Unix.read fd str !off (String.length str - !off) in read := !read + one_read; off := !off + one_read with Unix_error(EAGAIN, _, _) -> () done; str in let header_str = String.create Marshal.header_size in let send_data msg = Marshal.to_channel chn_write msg []; Pervasives.flush chn_write in let receive_data () = try let data_size = Marshal.data_size (really_read fd_read header_str) 0 in let data_str = really_read fd_read (String.create data_size) in let msg = Marshal.from_string (header_str ^ data_str) 0 in msg with Failure(msg) -> OUnitUtils.failwithf "Communication error with worker processes: %s" msg in let close () = close_out chn_write; in wrap_channel shard_id string_of_read_message string_of_written_message { send_data = send_data; receive_data = receive_data; close = close } let processes_grace_period = OUnitConf.make_float "processes_grace_period" 5.0 "Delay to wait for a process to stop." let processes_kill_period = OUnitConf.make_float "processes_kill_period" 5.0 "Delay to wait for a process to stop after killing it." let create_worker conf map_test_cases shard_id master_id worker_log_file = let safe_close fd = try close fd with Unix_error _ -> () in let pipe_read_from_worker, pipe_write_to_master = Unix.pipe () in let pipe_read_from_master, pipe_write_to_worker = Unix.pipe () in match Unix.fork () with | 0 -> (* Child process. *) let () = safe_close pipe_read_from_worker; safe_close pipe_write_to_worker; (* stdin/stdout/stderr remain open and shared with master. *) () in let channel = make_channel shard_id string_of_message_to_worker string_of_message_from_worker pipe_read_from_master pipe_write_to_master in main_worker_loop conf ignore channel shard_id map_test_cases worker_log_file; channel.close (); safe_close pipe_read_from_master; safe_close pipe_write_to_master; exit 0 | pid -> let channel = make_channel master_id string_of_message_from_worker string_of_message_to_worker pipe_read_from_worker pipe_write_to_worker in let rstatus = ref None in let msg_of_process_status status = if status = WEXITED 0 then None else Some (OUnitUtils.string_of_process_status status) in let is_running () = match !rstatus with | None -> let pid, status = waitpid [WNOHANG] pid in if pid <> 0 then begin rstatus := Some status; false end else begin true end | Some _ -> false in let close_worker () = let rec wait_end timeout = if timeout < 0.0 then begin false, None end else begin let running = is_running () in if running then (* Wait 0.1 seconds and continue. *) let _, _, _ = Unix.select [] [] [] 0.1 in wait_end (timeout -. 0.1) else match !rstatus with | Some status -> true, msg_of_process_status status | None -> true, None end in let ended, msg_opt = channel.close (); safe_close pipe_read_from_worker; safe_close pipe_write_to_worker; (* Recovery for worker going wild and not dying. *) List.fold_left (fun (ended, msg_opt) signal -> if ended then begin ended, msg_opt end else begin kill pid signal; wait_end (processes_kill_period conf) end) (wait_end (processes_grace_period conf)) [15 (* SIGTERM *); 9 (* SIGKILL *)] in if ended then msg_opt else Some (Printf.sprintf "unable to kill process %d" pid) in { channel = channel; close_worker = close_worker; select_fd = pipe_read_from_worker; shard_id = shard_id; is_running = is_running; } (* Filter running workers waiting data. *) let workers_waiting workers timeout = let workers_fd_lst = List.rev_map (fun worker -> worker.select_fd) workers in let workers_fd_waiting_lst, _, _ = Unix.select workers_fd_lst [] [] timeout in List.filter (fun workers -> List.memq workers.select_fd workers_fd_waiting_lst) workers let init () = if Sys.os_type = "Unix" then OUnitRunner.register "processes" 100 (runner create_worker workers_waiting) ounit-2.0.0/src/oUnitRunnerThreads.ml0000644000175000017500000001672712222142072017124 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) (** Use threads to run several tests concurrently. * * Run threads that handle running tests. It works the same way * as processes. Due to the non-parallel threads behavior in OCaml, you cannot * truly use the power of parallelism with threads, except when you have a lot * of disk and process operation. *) open OUnitRunner.GenericWorker let make_channel shard_id sync_send_data (string_of_read_message: 'read -> string) (string_of_written_message: 'written -> string) (chan_read: 'read Event.channel) (chan_write: 'written Event.channel) = let chan_sync_send_data = Event.new_channel () in let send_data msg = if sync_send_data then Event.sync (Event.send chan_sync_send_data shard_id); Event.sync (Event.send chan_write msg) in let receive_data msg = Event.sync (Event.receive chan_read) in chan_sync_send_data, wrap_channel shard_id string_of_read_message string_of_written_message { send_data = send_data; receive_data = receive_data; close = ignore; } let create_worker conf map_test_cases shard_id master_id worker_log_file = (* Threads will get message from master by there. *) let master_to_worker = Event.new_channel () in (* Threads will send message to master by there. *) let worker_to_master = Event.new_channel () in (* Signal end of the worker. *) let worker_finished = ref false in let worker_finished_mutex = Mutex.create () in let worker_finished_cond = Condition.create () in let select_fd, channel_worker = make_channel shard_id true string_of_message_to_worker string_of_message_from_worker master_to_worker worker_to_master in let thread_main_worker () = let at_end () = channel_worker.close (); Mutex.lock worker_finished_mutex; worker_finished := true; Condition.broadcast worker_finished_cond; Mutex.unlock worker_finished_mutex in try main_worker_loop conf Thread.yield channel_worker shard_id map_test_cases worker_log_file; at_end () with e -> at_end (); raise e in let thread = Thread.create thread_main_worker () in let _, channel_master = make_channel master_id false string_of_message_from_worker string_of_message_to_worker worker_to_master master_to_worker in let is_running () = let res = Mutex.lock worker_finished_mutex; not !worker_finished in Mutex.unlock worker_finished_mutex; res in let close_worker () = let killer () = let total_wait = ref 0.0 in let step = 0.1 in Mutex.lock worker_finished_mutex; while !total_wait < 5.0 && not !worker_finished do Mutex.unlock worker_finished_mutex; Thread.delay step; total_wait := !total_wait +. step; Mutex.lock worker_finished_mutex done; if not !worker_finished then begin (* This will fail... because probably not implemented. *) Thread.kill thread; worker_finished := true; Condition.broadcast worker_finished_cond end; Mutex.unlock worker_finished_mutex in let killer_thread = Thread.create killer () in Mutex.lock worker_finished_mutex; while not !worker_finished do Condition.wait worker_finished_cond worker_finished_mutex done; Mutex.unlock worker_finished_mutex; try Thread.join killer_thread; Thread.join thread; None with e -> Some (Printf.sprintf "Exception raised: %s." (Printexc.to_string e)) in { channel = channel_master; close_worker = close_worker; select_fd = select_fd; shard_id = shard_id; is_running = is_running; } let workers_waiting workers timeout = let channel_timeout = Event.new_channel () in (* TODO: clean implementation of the timeout. * Timeout not implemented, because it should be killed in most cases and * actually Thread.kill is not implemented for systhreads. * We could do either of this: * - Thread.time_read + mkpipe * - use signal ALARM * * Patch welcome. * * Sylvain Le Gall -- 2013/09/18. let thread_timeout = Thread.create (fun () -> Thread.delay timeout; Event.sync (Event.send channel_timeout None)) () in *) let worker_id_ready = Event.select (Event.receive channel_timeout :: (List.rev_map (fun worker -> Event.wrap (Event.receive worker.select_fd) (fun s -> Some s)) workers)) in match worker_id_ready with | None -> (* Thread.join thread_timeout; *) [] | Some worker_id -> (* Thread.kill thread_timeout; *) try let worker = List.find (fun worker -> worker.shard_id = worker_id) workers in [worker] with Not_found -> assert false let init () = OUnitRunner.register "threads" 70 (runner create_worker workers_waiting) ounit-2.0.0/src/oUnitShared.ml0000644000175000017500000001112412222142072015530 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) exception Lock_failure type scope = ScopeGlobal | ScopeProcess type 'a shared_noscope = { lock: 'a -> unit; unlock: 'a -> unit; try_lock: 'a -> bool; } type shared = { global: int shared_noscope; process: int shared_noscope; } let get_scoped shared = function | ScopeGlobal -> shared.global | ScopeProcess -> shared.process (* Global variable that need to be set for threads. *) let mutex_create = ref (fun () -> let r = ref false in let try_lock () = if !r then begin false end else begin r := true; true end in let lock () = if not (try_lock ()) then raise Lock_failure in let unlock () = r := false in { lock = lock; try_lock = try_lock; unlock = unlock; }) module Mutex = struct type t = int * scope let create scope = (Oo.id (object end), scope) let lock shared (id, scope) = (get_scoped shared scope).lock id let try_lock shared (id, scope) = (get_scoped shared scope).try_lock id let unlock shared (id, scope) = (get_scoped shared scope).unlock id let with_lock shared mutex f = try let res = lock shared mutex; f () in unlock shared mutex; res with e -> unlock shared mutex; raise e end (* A simple shared_noscope that works only for 1 process. *) let noscope_create () = let state = Hashtbl.create 13 in let state_mutex = !mutex_create () in let get_mutex id = let mutex = state_mutex.lock (); try Hashtbl.find state id with Not_found -> let mutex = !mutex_create () in Hashtbl.add state id mutex; mutex in state_mutex.unlock (); mutex in let try_lock id = (get_mutex id).try_lock () in let lock id = (get_mutex id).lock () in let unlock id = (get_mutex id).unlock () in { lock = lock; unlock = unlock; try_lock = try_lock; } (* Create a shared, for 1 process. *) let create () = let scoped = noscope_create () in { global = scoped; process = scoped; } ounit-2.0.0/src/oUnitState.ml0000644000175000017500000002365712222142072015420 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) (** Manipulate the state of OUnit runner. *) open OUnitLogger open OUnitTest open OUnitChooser type 'worker next_test_case_t = | Not_enough_worker | Try_again | Next_test_case of path * test_fun * 'worker | Finished type time = float type 'worker test_running = { test_length: test_length; deadline: time; next_health_check: time; worker: 'worker; } type 'worker t = { tests_planned: (path * (test_length * test_fun)) list; tests_running: (path * ('worker test_running)) list; tests_passed: (OUnitTest.result_full * OUnitTest.result_list) list; idle_workers: 'worker list; chooser: OUnitChooser.chooser; cache: OUnitCache.cache; health_check_interval: time; } let health_check_interval = OUnitConf.make_float "health_check_interval" 1.0 "Seconds between checking health of workers." let create conf chooser test_cases = { tests_passed = []; tests_planned = List.map (fun (test_path, test_length, test_fun) -> test_path, (test_length, test_fun)) test_cases; tests_running = []; idle_workers = []; chooser = chooser; cache = OUnitCache.load conf; health_check_interval = health_check_interval conf; } let filter_out e lst = List.filter (fun (e', _) -> e <> e') lst let maybe_dump_cache conf state = if state.tests_running = [] && state.tests_planned = [] then (* We are finished, all results are in, flush the cache. *) OUnitCache.dump conf (List.fold_left (fun cache (path, test_result, _) -> OUnitCache.add_result path test_result cache) state.cache (List.map fst state.tests_passed)); state let add_test_results conf all_test_results state = let ((test_path, _, _), _) = all_test_results in let state = {state with tests_passed = all_test_results :: state.tests_passed; tests_planned = filter_out test_path state.tests_planned}; in maybe_dump_cache conf state let test_finished conf all_test_results worker state = let ((test_path, _, _), _) = all_test_results in let state = {(add_test_results conf all_test_results state) with tests_running = filter_out test_path state.tests_running; idle_workers = worker :: state.idle_workers} in maybe_dump_cache conf state let add_worker worker state = {state with idle_workers = worker :: state.idle_workers} let remove_idle_worker worker state = let found, idle_workers = List.fold_left (fun (found, lst) worker' -> if worker' == worker then true, lst else found, worker' :: lst) (false, []) state.idle_workers in if not found then raise Not_found; {state with idle_workers = idle_workers} let count_worker state = List.length state.idle_workers + List.length state.tests_running let count_tests_running state = List.length state.tests_running let get_workers state = List.rev_append state.idle_workers (List.rev_map (fun (_, {worker = worker}) -> worker) state.tests_running) let get_idle_workers state = state.idle_workers let is_idle_worker worker state = List.exists (fun worker' -> worker == worker') state.idle_workers let get_tests_running state = List.map fst state.tests_running let rec next_test_case conf logger state = match state.tests_planned, state.idle_workers with | [], _ -> Finished, state | _, worker :: tl_workers -> begin let choice = state.chooser { OUnitChooser. tests_planned = List.map fst state.tests_planned; tests_running = List.map fst state.tests_running; tests_passed = List.map fst state.tests_passed; cache = state.cache; } in match choice with | Choose test_path -> begin try let test_length, test_fun = List.assoc test_path state.tests_planned in let now = OUnitUtils.now () in Next_test_case (test_path, test_fun, worker), {state with tests_running = (test_path, { test_length = test_length; deadline = now +. delay_of_length test_length; next_health_check = now +. state.health_check_interval; worker = worker; }) :: state.tests_running; tests_planned = filter_out test_path state.tests_planned; idle_workers = tl_workers} with Not_found -> assert false end | ChooseToPostpone -> Try_again, state | ChooseToSkip path -> let skipped_result = RSkip "Skipped by the chooser." in OUnitLogger.report logger (TestEvent (path, EStart)); OUnitLogger.report logger (TestEvent (path, EResult skipped_result)); OUnitLogger.report logger (TestEvent (path, EEnd)); next_test_case conf logger (add_test_results conf ((path, skipped_result, None), []) state) | NoChoice -> Finished, state end | _, [] -> Not_enough_worker, state (** Get all the results. *) let get_results state = List.fold_right (fun (result, other_results) res -> result :: other_results @ res) state.tests_passed [] (** Get all the workers that need to be checked for their health. *) let get_worker_need_health_check state = let now = OUnitUtils.now () in List.fold_left (fun lst (test_path, test_running) -> if test_running.next_health_check <= now then (test_path, test_running.worker) :: lst else lst) [] state.tests_running (** Update the activity of a worker, this postpone the next health check. *) let update_test_activity test_path state = let now = OUnitUtils.now () in let tests_running = List.fold_right (fun (test_path', test_running) lst -> let test_running = if test_path' = test_path then {test_running with next_health_check = now +. state.health_check_interval} else test_running in (test_path', test_running) :: lst) state.tests_running [] in {state with tests_running = tests_running} (** Get all the workers that are timed out, i.e. that need to be stopped. *) let get_worker_timed_out state = let now = OUnitUtils.now () in List.fold_left (fun lst (test_path, test_running) -> if test_running.deadline <= now then (test_path, test_running.test_length, test_running.worker) :: lst else lst) [] state.tests_running (** Compute when is the next time, we should either run health check or timeout a test. *) let timeout state = let now = OUnitUtils.now () in let next_event_time = List.fold_left (fun next_event_time (_, test_running) -> min test_running.next_health_check (min test_running.deadline next_event_time)) (now +. state.health_check_interval) state.tests_running in max 0.1 (next_event_time -. now) ounit-2.0.0/src/oUnitTest.ml0000644000175000017500000002712712222142072015253 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnitUtils exception Skip of string exception Todo of string exception OUnit_failure of string (** See OUnit.mli. *) type node = ListItem of int | Label of string (** See OUnit.mli. *) type path = node list (** See OUnit2.mli. *) type backtrace = string option (* The type of length of a test. *) type test_length = | Immediate (* < 1s *) | Short (* < 1min *) | Long (* < 10min *) | Huge (* < 30min *) | Custom_length of float (** See OUnit.mli. *) type result = | RSuccess | RFailure of string * OUnitLogger.position option * backtrace | RError of string * backtrace | RSkip of string | RTodo of string | RTimeout of test_length (* See OUnit.mli. *) type result_full = (path * result * OUnitLogger.position option) type result_list = result_full list type ctxt = (* TODO: hide this to avoid building a context outside. *) { conf: OUnitConf.conf; logger: (path, result) OUnitLogger.logger; shared: OUnitShared.shared; path: path; test_logger: result OUnitLogger.Test.t; (* TODO: Still a race condition possible, what if another threads * modify anything during the process (e.g. register tear down). *) mutable tear_down: (ctxt -> unit) list; tear_down_mutex: OUnitShared.Mutex.t; non_fatal: result_full list ref; non_fatal_mutex: OUnitShared.Mutex.t; } type log_event_t = (path, result) OUnitLogger.log_event_t type logger = (path, result) OUnitLogger.logger type test_fun = ctxt -> unit (* The type of tests. *) type test = | TestCase of test_length * test_fun | TestList of test list | TestLabel of string * test let delay_of_length = function | Immediate -> 1.0 | Short -> 60.0 | Long -> 600.0 | Huge -> 1800.0 | Custom_length f -> f let get_shard_id test_ctxt = test_ctxt.logger.OUnitLogger.lshard (** Isolate a function inside a context. All the added tear down will run before returning. *) let section_ctxt ctxt f = let old_tear_down = OUnitShared.Mutex.with_lock ctxt.shared ctxt.tear_down_mutex (fun () -> ctxt.tear_down) in let clean_exit () = OUnitShared.Mutex.with_lock ctxt.shared ctxt.tear_down_mutex (fun () -> List.iter (fun tear_down -> tear_down ctxt) ctxt.tear_down; ctxt.tear_down <- old_tear_down) in OUnitShared.Mutex.with_lock ctxt.shared ctxt.tear_down_mutex (fun () -> ctxt.tear_down <- []); try let res = f ctxt in clean_exit (); res with e -> clean_exit (); raise e (** Create a context and run the function. *) let with_ctxt conf logger shared non_fatal test_path f = let ctxt = { conf = conf; logger = logger; path = test_path; shared = shared; test_logger = OUnitLogger.Test.create logger test_path; tear_down = []; tear_down_mutex = OUnitShared.Mutex.create OUnitShared.ScopeProcess; non_fatal = non_fatal; non_fatal_mutex = OUnitShared.Mutex.create OUnitShared.ScopeProcess; } in section_ctxt ctxt f let standard_modules = [ "arg.ml"; "arrayLabels.ml"; "array.ml"; "buffer.ml"; "callback.ml"; "camlinternalLazy.ml"; "camlinternalMod.ml"; "camlinternalOO.ml"; "char.ml"; "complex.ml"; "digest.ml"; "filename.ml"; "format.ml"; "gc.ml"; "genlex.ml"; "hashtbl.ml"; "int32.ml"; "int64.ml"; "lazy.ml"; "lexing.ml"; "listLabels.ml"; "list.ml"; "map.ml"; "marshal.ml"; "moreLabels.ml"; "nativeint.ml"; "obj.ml"; "oo.ml"; "parsing.ml"; "pervasives.ml"; "printexc.ml"; "printf.ml"; "queue.ml"; "random.ml"; "scanf.ml"; "set.ml"; "sort.ml"; "stack.ml"; "std_exit.ml"; "stdLabels.ml"; "stream.ml"; "stringLabels.ml"; "string.ml"; "sys.ml"; "weak.ml"; "unix.ml"; ] (** Transform an exception in a result. *) let result_full_of_exception ctxt e = let backtrace () = if Printexc.backtrace_status () then Some (Printexc.get_backtrace ()) else None in let locate_exn () = if Printexc.backtrace_status () then begin let lst = extract_backtrace_position (Printexc.get_backtrace ()) in let pos_opt = try List.find (function | None -> false | Some (fn, _) -> not (starts_with ~prefix:"oUnit" (Filename.basename fn)) && not (List.mem fn standard_modules)) lst with Not_found -> None in match pos_opt with | Some (filename, line) -> Some {OUnitLogger.filename = filename; line = line} | None -> None end else None in let result = match e with | OUnit_failure s -> RFailure (s, locate_exn (), backtrace ()) | Skip s -> RSkip s | Todo s -> RTodo s | s -> RError (Printexc.to_string s, backtrace ()) in let position = match result with | RSuccess | RSkip _ | RTodo _ | RTimeout _ -> None | RFailure _ | RError _ -> OUnitLogger.position ctxt.logger in ctxt.path, result, position let report_result_full ctxt result_full = let test_path, result, _ = result_full in OUnitLogger.report ctxt.logger (OUnitLogger.TestEvent (test_path, OUnitLogger.EResult result)); result_full (** Isolate a function inside a context, just as [!section_ctxt] but don't propagate a failure, register it for later. *) let non_fatal ctxt f = try section_ctxt ctxt f with e -> let result_full = report_result_full ctxt (result_full_of_exception ctxt e) in OUnitShared.Mutex.with_lock ctxt.shared ctxt.non_fatal_mutex (fun () -> ctxt.non_fatal := result_full :: !(ctxt.non_fatal)) (* Some shorthands which allows easy test construction *) let (>:) s t = TestLabel(s, t) (* infix *) let (>::) s f = TestLabel(s, TestCase(Short, f)) (* infix *) let (>:::) s l = TestLabel(s, TestList(l)) (* infix *) (* Utility function to manipulate test *) let rec test_decorate g = function | TestCase(l, f) -> TestCase (l, g f) | TestList tst_lst -> TestList (List.map (test_decorate g) tst_lst) | TestLabel (str, tst) -> TestLabel (str, test_decorate g tst) (* Return the number of available tests *) let rec test_case_count = function | TestCase _ -> 1 | TestLabel (_, t) -> test_case_count t | TestList l -> List.fold_left (fun c t -> c + test_case_count t) 0 l let string_of_node = function | ListItem n -> string_of_int n | Label s -> s module Path = struct type t = path let compare p1 p2 = Pervasives.compare p1 p2 let to_string p = String.concat ":" (List.rev_map string_of_node p) end module MapPath = Map.Make(Path) let string_of_path = Path.to_string (* Returns all possible paths in the test. The order is from test case to root. *) let test_case_paths test = let rec tcps path test = match test with | TestCase _ -> [path] | TestList tests -> List.concat (mapi (fun t i -> tcps ((ListItem i)::path) t) tests) | TestLabel (l, t) -> tcps ((Label l)::path) t in tcps [] test (* Test filtering with their path *) module SetTestPath = Set.Make(String) let test_filter ?(skip=false) only test = let set_test = List.fold_left (fun st str -> SetTestPath.add str st) SetTestPath.empty only in let rec filter_test path tst = if SetTestPath.mem (string_of_path path) set_test then begin Some tst end else begin match tst with | TestCase (l, f) -> begin if skip then Some (TestCase (l, fun ctxt -> raise (Skip "Test disabled"))) else None end | TestList tst_lst -> begin let ntst_lst = fold_lefti (fun ntst_lst tst i -> let nntst_lst = match filter_test ((ListItem i) :: path) tst with | Some tst -> tst :: ntst_lst | None -> ntst_lst in nntst_lst) [] tst_lst in if not skip && ntst_lst = [] then None else Some (TestList (List.rev ntst_lst)) end | TestLabel (lbl, tst) -> begin let ntst_opt = filter_test ((Label lbl) :: path) tst in match ntst_opt with | Some ntst -> Some (TestLabel (lbl, ntst)) | None -> if skip then Some (TestLabel (lbl, tst)) else None end end in filter_test [] test ounit-2.0.0/src/oUnitTestData.ml0000644000175000017500000000611412222142072016036 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) let make_filename = List.fold_left Filename.concat let testdata_default = let pwd = Sys.getcwd () in let is_dir lst = let dn = make_filename pwd lst in Sys.file_exists dn && Sys.is_directory dn in try let path = List.find is_dir [ ["test"; "data"]; ["tests"; "data"]; ["data"] ] in Some (make_filename pwd path) with Not_found -> None let testdata_dir = OUnitConf.make_string_opt "testdata_dir" testdata_default "Location of the test data directory (absolute path)." let in_testdata_dir conf path = match testdata_dir conf with | Some fn -> make_filename fn path | None -> failwith "Test data dir not defined." ounit-2.0.0/src/oUnitThreads.ml0000644000175000017500000000520312222142072015715 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) let init () = OUnitShared.mutex_create := (fun () -> let mutex = Mutex.create () in { OUnitShared. lock = (fun () -> Mutex.lock mutex); try_lock = (fun () -> Mutex.try_lock mutex); unlock = (fun () -> Mutex.unlock mutex); }); OUnitRunnerThreads.init () ounit-2.0.0/src/oUnitUtils.ml0000644000175000017500000001631512222142072015431 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) (** * Utilities for OUnit * * @author Sylvain Le Gall *) let is_blank = function | ' ' | '\012' | '\n' | '\r' | '\t' -> true | _ -> false let rec trim s = let strlen = String.length s in if strlen = 0 then "" else if is_blank s.[0] then trim (String.sub s 1 (strlen - 1)) else if is_blank s.[strlen - 1] then trim (String.sub s 0 (strlen - 1)) else s let trim_comment s = let buff = Buffer.create (String.length s) in let idx = ref 0 in while !idx < String.length s && s.[!idx] != '#' do Buffer.add_char buff s.[!idx]; incr idx done; Buffer.contents buff let split_lines s = let rev_lst = ref [] in let buff = Buffer.create 13 in let flush () = rev_lst := Buffer.contents buff :: !rev_lst; Buffer.clear buff in if String.length s > 0 then begin String.iter (function | '\n' -> flush () | c -> Buffer.add_char buff c) s; flush (); List.rev !rev_lst end else [] let starts_with ~prefix s = if String.length s >= String.length prefix then String.sub s 0 (String.length prefix) = prefix else false let start_substr ~prefix s = if starts_with ~prefix s then begin let prefix_len = String.length prefix in true, String.sub s prefix_len (String.length s - prefix_len) end else begin false, s end let extract_backtrace_position str = let prefixes = [ "Raised at "; "Re-raised at "; "Raised by primitive operation at "; "Called from "; ] in let rec extract_one_line s prefixes = match prefixes with | [] -> None | prefix :: tl -> let really_starts, eol = start_substr ~prefix s in if really_starts then begin if eol = "unknown location" then None else try Scanf.sscanf eol "file \"%s@\", line %d, characters %d-%d" (fun fn line _ _ -> Some (fn, line)) with Scanf.Scan_failure msg -> None end else begin extract_one_line s tl end in List.map (fun s -> extract_one_line s prefixes) (split_lines str) let cmp_float ?(epsilon = 0.00001) a b = abs_float (a -. b) <= epsilon *. (abs_float a) || abs_float (a -. b) <= epsilon *. (abs_float b) let buff_format_printf f = let buff = Buffer.create 13 in let fmt = Format.formatter_of_buffer buff in f fmt; Format.pp_print_flush fmt (); Buffer.contents buff (* Applies function f in turn to each element in list. Function f takes one element, and integer indicating its location in the list *) let mapi f l = let rec rmapi cnt l = match l with | [] -> [] | h :: t -> (f h cnt) :: (rmapi (cnt + 1) t) in rmapi 0 l let fold_lefti f accu l = let rec rfold_lefti cnt accup l = match l with | [] -> accup | h::t -> rfold_lefti (cnt + 1) (f accup h cnt) t in rfold_lefti 0 accu l let now () = Unix.gettimeofday () (* Function which runs the given function and returns the running time of the function, and the original result in a tuple *) let time_fun f x = let begin_time = now () in let res = f x in (now () -. begin_time, res) let date_iso8601 ?(tz=true) timestamp = let tm = Unix.gmtime timestamp in let res = Printf.sprintf "%04d-%02d-%02dT%02d:%02d:%02d" (1900 + tm.Unix.tm_year) (1 + tm.Unix.tm_mon) tm.Unix.tm_mday tm.Unix.tm_hour tm.Unix.tm_min tm.Unix.tm_sec in if tz then res ^ "+00:00" else res let buildir = (* Detect a location where we can store semi-temporary data: - it must survive a compilation - it must be removed with 'make clean' *) let pwd = Sys.getcwd () in let dir_exists fn = Sys.file_exists fn && Sys.is_directory fn in let concat, dirname = Filename.concat, Filename.dirname in List.find dir_exists [ concat pwd "_build"; concat (dirname pwd) "_build"; concat (dirname (dirname pwd)) "_build"; pwd ] let failwithf fmt = Printf.ksprintf failwith fmt let opt f = function Some v -> f v | None -> () let fqdn () = (Unix.gethostbyname (Unix.gethostname ())).Unix.h_name let shardf = Printf.sprintf "%s#%02d" (Unix.gethostname ()) let string_of_process_status = function | Unix.WEXITED n -> Printf.sprintf "Exited with code %d" n | Unix.WSIGNALED n -> Printf.sprintf "Killed by signal %d" n | Unix.WSTOPPED n -> Printf.sprintf "Stopped by signal %d" n let make_counter () = let data = Hashtbl.create 13 in let all () = Hashtbl.fold (fun k v lst -> (k, v) :: lst) data [] in let incr k = let v = try Hashtbl.find data k with Not_found -> 0 in Hashtbl.replace data k (v + 1) in all, incr ounit-2.0.0/test/0000755000175000017500000000000012222142072013142 5ustar gildorgildorounit-2.0.0/test/JUnit.xsd0000644000175000017500000002356212222142072014723 0ustar gildorgildor JUnit test result schema for the Apache Ant JUnit and JUnitReport tasks Copyright © 2011, Windy Road Technology Pty. Limited The Apache Ant JUnit XML Schema is distributed under the terms of the GNU Lesser General Public License (LGPL) http://www.gnu.org/licenses/lgpl.html Permission to waive conditions of this license may be requested from Windy Road Support (http://windyroad.org/support). Contains an aggregation of testsuite results Derived from testsuite/@name in the non-aggregated documents Starts at '0' for the first testsuite and is incremented by 1 for each following testsuite Contains the results of exexuting a testsuite Properties (e.g., environment settings) set during test execution Indicates that the test errored. An errored test is one that had an unanticipated problem. e.g., an unchecked throwable; or a problem with the implementation of the test. Contains as a text node relevant data for the error, e.g., a stack trace The error message. e.g., if a java exception is thrown, the return value of getMessage() The type of error that occured. e.g., if a java execption is thrown the full class name of the exception. Indicates that the test failed. A failure is a test which the code has explicitly failed by using the mechanisms for that purpose. e.g., via an assertEquals. Contains as a text node relevant data for the failure, e.g., a stack trace The message specified in the assert The type of the assert. Name of the test method Full class name for the class the test method is in. Time taken (in seconds) to execute the test Data that was written to standard out while the test was executed Data that was written to standard error while the test was executed Full class name of the test for non-aggregated testsuite documents. Class name without the package for aggregated testsuites documents when the test was executed. Timezone may not be specified. Host on which the tests were executed. 'localhost' should be used if the hostname cannot be determined. The total number of tests in the suite The total number of tests in the suite that failed. A failure is a test which the code has explicitly failed by using the mechanisms for that purpose. e.g., via an assertEquals The total number of tests in the suite that errorrd. An errored test is one that had an unanticipated problem. e.g., an unchecked throwable; or a problem with the implementation of the test. Time taken (in seconds) to execute the tests in the suite ounit-2.0.0/test/test.ml0000644000175000017500000000534212222142072014457 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnit2 let () = run_test_tt_main ("OUnit" >::: [ OUnit.ounit2_of_ounit1 TestOUnit1.tests; TestOUnit2.tests; TestConf.tests; TestOUnitTest.tests; TestOUnitAssert.tests; TestOUnitDiff.tests; TestOtherTests.tests; TestRunner.tests; TestShared.tests; TestOUnitBracket.tests; TestOUnitChooser.tests; ]) ounit-2.0.0/test/testCommon.ml0000644000175000017500000001046712222142072015634 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnitTest open OUnit2 let perform_test test = let null_logger = OUnitLogger.null_logger in let conf = OUnitConf.default () in OUnitCore.perform_test conf null_logger OUnitRunner.sequential_runner OUnitChooser.simple test let assert_equal_test_result exp res = let norm lst = let norm_one (path, test_result, pos) = let test_result' = match test_result with | RSuccess -> RSuccess | RFailure (str, _, _) -> RFailure (str, None, None) | RError (str, _) -> RError(str, None) | RSkip str -> RSkip str | RTodo str -> RTodo str | RTimeout test_length -> RTimeout test_length in (path, test_result', pos) in List.sort Pervasives.compare (List.rev_map norm_one lst) in assert_equal ~cmp: (fun a b -> norm a = norm b) ~printer: (fun results -> String.concat "; " (List.map (fun (path, test_result, _) -> let spf fmt = Printf.sprintf fmt in let string_of_backtrace = function | Some str -> spf "Some (%S)" str | None -> "None" in let test_result_string = match test_result with | RSuccess -> "RSuccess" | RFailure (str, pos_opt, backtrace) -> spf "RFailure(%S, _, %s)" str (string_of_backtrace backtrace) | RError (str, backtrace) -> spf "RError(%S, %s)" str (string_of_backtrace backtrace) | RSkip str -> spf "RSkip(%S)" str | RTodo str -> spf "RTodo(%S)" str | RTimeout _ -> "RTimeout(_)" in Printf.sprintf "%S, %s" (OUnitTest.string_of_path path) test_result_string) (norm results))) exp res ounit-2.0.0/test/testConf.ml0000644000175000017500000001032512222142072015262 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnit2 open OUnitConf type t = { vint: OUnitConf.conf -> int; vstring: OUnitConf.conf -> string; } let bracket_ounitconf = bracket (fun ctxt -> (* TODO: we need a lock here. *) { vint = make_int "int" 0 ""; vstring = make_string "string" "" ""; }) (fun _ t -> Hashtbl.remove metaconf "int"; Hashtbl.remove metaconf "string"; (* TODO: release the lock. *) ()) let tests = "OUnitConf" >::: [ "CLI" >:: (fun test_ctxt -> let t = bracket_ounitconf test_ctxt in let conf = load ~argv:[|"foo"; "-int"; "2"; "-string"; "foo bar"|] [] in assert_equal ~printer:string_of_int 2 (t.vint conf); assert_equal ~printer:(fun s -> s) "foo bar" (t.vstring conf)); "File" >:: (fun test_ctxt -> let fn, chn = bracket_tmpfile test_ctxt in let t = bracket_ounitconf test_ctxt in let () = output_string chn "int = 1\n\ string = \"abcd ef\""; close_out chn in let conf = load ~argv:[|"foo"; "-conf"; fn|] [] in assert_equal ~printer:string_of_int 1 (t.vint conf); assert_equal ~printer:(fun s -> s) "abcd ef" (t.vstring conf)); "Substitution" >:: (fun test_ctxt -> let _ = bracket_ounitconf test_ctxt in let conf = load ~argv:[|"foo"; "-int"; "10"|] [] in assert_equal ~printer:(fun s -> s) "foo-10" (subst conf [] "foo-$int")); "NoDoubleInject" >:: (fun test_ctxt -> let _ = bracket_ounitconf test_ctxt in try let _option: conf -> string = make_string "string" "" "" in assert_failure "Should not be able to inject duplicate configuration \ option 'string'." with Failure _ -> ()); ] ounit-2.0.0/test/testFakeHTML.ml0000644000175000017500000000563712222142072015742 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) (* * Fake tests, to test HTML output. *) open OUnit2 let suite = "OUnitLoggerHTML" >::: [ "first test" >:: (fun ctxt -> assert_equal 0 1); "second test" >:: (fun ctxt -> assert_equal 0 0); "third test" >:: (fun ctxt -> skip_if true "skipped because of me"); "fourth test" >:: (fun ctxt -> todo "need to make this function"); "fifth test" >:: (fun ctxt -> raise Not_found); "with symbol" >:: (fun ctxt -> failwith "this is a bad message: '\"&<>") ] let () = run_test_tt_main suite ounit-2.0.0/test/testFakeRunner.ml0000644000175000017500000000632712222142072016444 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) (* * Fake tests, to test runner behavior in some situation. *) open OUnit2 let sigsegv = Conf.make_bool "sigsegv" false "Fail with SIGSEGV." let timeout = Conf.make_bool "timeout" false "Time out." let suite = "TestFakeRunner" >::: [ "success" >:: (fun ctxt -> assert_equal 0 0); "failure" >:: (fun ctxt -> assert_equal 0 1); "todo" >:: (fun ctxt -> skip_if true "skipped because of me"); "skip" >:: (fun ctxt -> todo "need to make this function"); "error" >:: (fun ctxt -> raise Not_found); "SIGSEGV" >:: (fun ctxt -> if sigsegv ctxt then Unix.kill (Unix.getpid ()) 11); "Timeout" >: (test_case ~length:(OUnitTest.Custom_length 0.1) (fun ctxt -> if timeout ctxt then Unix.sleep 1)) ] let () = OUnitThreads.init (); run_test_tt_main suite ounit-2.0.0/test/testFakeShared.ml0000644000175000017500000000605412222142072016376 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) (* * Fake tests, to test mutex behavior with different runner. *) open OUnit2 open OUnitShared let test_mutex ctxt mutex = let shared = ctxt.OUnitTest.shared in Mutex.lock shared mutex; assert_bool "Cannot acquire a locked mutex." (not (Mutex.try_lock shared mutex)); Mutex.unlock shared mutex; assert_bool "Can acquire an unlocked mutex." (Mutex.try_lock shared mutex); Mutex.unlock shared mutex let tests = "Shared" >::: [ "MutexGlobal" >:: (fun ctxt -> test_mutex ctxt (Mutex.create ScopeGlobal)); "MutexProcess" >:: (fun ctxt -> test_mutex ctxt (Mutex.create ScopeProcess)); ] let () = OUnitThreads.init (); run_test_tt_main tests ounit-2.0.0/test/testOUnit1.ml0000644000175000017500000002453012222142072015517 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnit let test_case = TestCase (fun () -> ()) let labeled_test_case = "label" >: test_case let suite_a = "suite_a" >: TestList [test_case] let suite_b = "suite_b" >: TestList [labeled_test_case] let suite_c = "suite_c" >: TestList [test_case; labeled_test_case] let suite_d = "suite_d" >: TestList [suite_a; suite_c] let rec string_of_paths = function [] -> "" | h::t -> (string_of_path h) ^ "\n" ^ (string_of_paths t) (* Test which checks if the test case count function works correctly *) let test_case_count _ = let assert_equal ?msg = assert_equal ?msg ~printer:string_of_int in assert_equal 0 (test_case_count (TestList [])); assert_equal 0 (test_case_count (TestLabel("label", TestList []))); assert_equal 0 (test_case_count (TestList [TestList []; TestList [TestList []]])); assert_equal 1 (test_case_count test_case); assert_equal 1 (test_case_count labeled_test_case); assert_equal 1 (test_case_count suite_a); assert_equal 1 (test_case_count suite_b); assert_equal 1 (test_case_count (TestList [suite_a; TestList []])); assert_equal 1 (test_case_count (TestList [TestList []; TestList [suite_b]])); assert_equal 2 (test_case_count suite_c); assert_equal 3 (test_case_count suite_d) (* Test which checks if the paths are correctly constructed *) let test_case_paths _ = (* A single testcase results in a list countaining an empty list *) let assert_equal ?msg = assert_equal ?msg ~printer:string_of_paths in assert_equal [[]] (test_case_paths test_case); assert_equal [[Label "label"]] (test_case_paths labeled_test_case); assert_equal [[ListItem 0; Label "suite_a"]] (test_case_paths suite_a); assert_equal [[Label "label"; ListItem 0; Label "suite_b"]] (test_case_paths suite_b); assert_equal [[ListItem 0; Label "suite_c"]; [Label "label"; ListItem 1; Label "suite_c"]] (test_case_paths suite_c); assert_equal [[ListItem 0; Label "suite_a"; ListItem 0; Label "suite_d"]; [ListItem 0; Label "suite_c"; ListItem 1; Label "suite_d"]; [Label "label"; ListItem 1; Label "suite_c"; ListItem 1; Label "suite_d"]] (test_case_paths suite_d) let test_assert_raises _ = assert_raises (OUnitTest.OUnit_failure "expected: Failure(\"Boo\") but got: Failure(\"Foo\")") (fun _ -> (assert_raises (Failure "Boo") (fun _ -> raise (Failure "Foo")))); assert_raises (OUnitTest.OUnit_failure "A label\nexpected: Failure(\"Boo\") \ but got: Failure(\"Foo\")") (fun _ -> (assert_raises ~msg:"A label" (Failure "Boo") (fun _ -> raise (Failure "Foo")))); assert_raises (OUnitTest.OUnit_failure "expected exception Failure(\"Boo\"), \ but no exception was raised.") (fun _ -> (assert_raises (Failure "Boo") (fun _ -> ()))); assert_raises (OUnitTest.OUnit_failure "A label\nexpected exception Failure(\"Boo\"), \ but no exception was raised.") (fun _ -> (assert_raises ~msg:"A label" (Failure "Boo") (fun _ -> ()))) (* Test the float compare, and use the cmp label *) let test_cmp_float _ = assert_equal ~cmp: cmp_float 0.0001 0.0001; assert_equal ~cmp: (cmp_float ~epsilon: 0.001) 1.0001 1.00001; assert_raises (OUnitTest.OUnit_failure "not equal") (fun _ -> assert_equal ~cmp: cmp_float 100.0001 101.001) let test_assert_string _ = assert_string ""; assert_raises (OUnitTest.OUnit_failure "A string") (fun _ -> assert_string "A string") let test_assert_bool _ = assert_bool "true" true; assert_raises (OUnitTest.OUnit_failure "false") (fun _ -> assert_bool "false" false) let test_case_filter () = let assert_test_case_count res tst_opt = match tst_opt with | Some tst -> assert_equal res (OUnit.test_case_count tst) | None -> assert_failure "Unexpected empty filter result" in assert_equal None (test_filter [] suite_a); assert_equal None (test_filter [] suite_b); assert_equal None (test_filter [] suite_c); assert_equal None (test_filter [] suite_d); assert_test_case_count 1 (test_filter ["suite_a"] suite_a); assert_test_case_count 1 (test_filter ["suite_a:0"] suite_a); assert_test_case_count 1 (test_filter ["suite_b:0:label"] suite_b); assert_test_case_count 1 (test_filter ["suite_c:0"] suite_c); assert_test_case_count 2 (test_filter ["suite_c:0";"suite_c:1:label"] suite_c) let assert_equal_test_result = assert_equal ~printer:(fun tst_results -> String.concat "; " (List.map (function | RSuccess path -> Printf.sprintf "RSuccess %S" (string_of_path path) | RFailure (path, str) -> Printf.sprintf "RFailure(%S, %S)" (string_of_path path) str | RError (path, str) -> Printf.sprintf "RError(%S, %S)" (string_of_path path) str | RSkip (path, str) -> Printf.sprintf "RSkip(%S, %S)" (string_of_path path) str | RTodo (path, str) -> Printf.sprintf "RTodo(%S, %S)" (string_of_path path) str ) tst_results )) let null_logger = OUnitLogger.null_logger let test_case_decorate () = assert_equal_test_result [RSuccess [Label "label"; ListItem 1; Label "suite_c"]; RSuccess [ListItem 0; Label "suite_c"]] (perform_test ignore suite_c); assert_equal_test_result [RFailure([Label "label"; ListItem 1; Label "suite_c"], "fail"); RFailure([ListItem 0; Label "suite_c"], "fail")] (perform_test ignore (test_decorate (fun _ -> (fun () -> assert_failure "fail")) suite_c)) let test_case_skip () = assert_equal_test_result [RSkip ([Label "skip"], "test")] (perform_test ignore ("skip" >:: (fun () -> skip_if true "test"))) let test_case_todo () = assert_equal_test_result [RTodo ([Label "todo"], "test")] (perform_test ignore ("todo" >:: (fun () -> todo "test"))) let test_assert_command () = assert_command Sys.executable_name ["-help"] module EInt = struct type t = int let compare = ( - ) let pp_printer = Format.pp_print_int let pp_print_sep = OUnitDiff.pp_comma_separator end module DiffSetInt = OUnitDiff.SetMake(EInt) module DiffListSimpleInt = OUnitDiff.ListSimpleMake(EInt) let test_diff () = let lst_exp = [1; 2; 3; 4; 5] in let lst_real = [1; 2; 5; 4] in assert_raises (OUnitTest.OUnit_failure "expected: 1, 2, 3, 4, 5 but got: 1, 2, 4, 5\n\ differences: -3") (fun () -> DiffSetInt.assert_equal (DiffSetInt.of_list lst_exp) (DiffSetInt.of_list lst_real)); DiffSetInt.assert_equal (DiffSetInt.of_list lst_exp) (DiffSetInt.of_list lst_exp); assert_raises (OUnitTest.OUnit_failure "expected: 1, 2, 3, 4, 5 but got: 1, 2, 5, 4\n\ differences: element number 2 differ (3 <> 5)") (fun () -> DiffListSimpleInt.assert_equal lst_exp lst_real); DiffListSimpleInt.assert_equal lst_exp lst_exp (* Construct the test suite *) let tests = "OUnit1" >::: [ "test_case_count" >:: test_case_count; "test_case_paths" >:: test_case_paths; "test_assert_raises" >:: test_assert_raises; "test_assert_string" >:: test_assert_string; "test_assert_bool" >:: test_assert_bool; "test_cmp_float" >:: test_cmp_float; "test_case_filter" >:: test_case_filter; "test_case_decorate" >:: test_case_decorate; "test_case_skip" >:: test_case_skip; "test_case_todo" >:: test_case_todo; "test_assert_command" >:: test_assert_command; "test_diff" >:: test_diff; ] ounit-2.0.0/test/testOUnit2.ml0000644000175000017500000001013512222142072015514 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnit2 let test_normal = "Normal" >:: (fun ctxt -> ()) let test_assert = "Assert" >:: (fun ctxt -> assert_equal 1 1) let test_todo = "Todo" >:: (fun ctxt -> todo "test") let test_skip = "Skip" >:: (fun ctxt -> skip_if true "to be skipped") let test_fail = "Fail" >:: (fun ctxt -> assert_equal 1 2) let test_error = "Error" >:: (fun ctxt -> failwith "Not expected") let test_ounit2 suite test_ctxt = let log_fn, _ = bracket_tmpfile test_ctxt in let conf = OUnitConf.default ~preset:["chooser", "simple"; "runner", "sequential"; "output_file", log_fn; "display", "false"] () in let old_get_conf = (* TODO: acquire lock *) !OUnitCore.run_test_tt_main_conf in let override_conf ?preset ?argv extra_specs = OUnitCore.run_test_tt_main_conf := old_get_conf; (* TODO: release lock *) conf in let exit_code = ref 0 in OUnitCore.run_test_tt_main_conf := override_conf; run_test_tt_main ~exit:(fun i -> exit_code := i) suite; !exit_code, log_fn let test_ok ctxt = let exit_code, _ = test_ounit2 ("OK" >::: [test_normal; test_assert; test_skip]) ctxt in assert_equal ~printer:string_of_int 0 exit_code let test_ko = let one lst ctxt = let exit_code, _ = test_ounit2 ("KO" >::: [test_normal; test_assert; test_skip] @ lst) ctxt in assert_equal ~printer:string_of_int 1 exit_code in List.map (fun lst -> test_case (one lst)) [ [test_todo]; [test_fail]; [test_error]; [test_todo; test_fail; test_error]; ] (* Construct the test suite *) let tests = "OUnit2" >::: [ "test_ok" >:: test_ok; "test_ko" >::: test_ko; ] ounit-2.0.0/test/testOUnitAssert.ml0000644000175000017500000001067412222142072016624 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnitTest open OUnitAssert open OUnit2 let test_assert_raises _ = assert_raises (OUnit_failure "expected: Failure(\"Boo\") but got: Failure(\"Foo\")") (fun _ -> (assert_raises (Failure "Boo") (fun _ -> raise (Failure "Foo")))); assert_raises (OUnit_failure "A label\nexpected: Failure(\"Boo\") but got: Failure(\"Foo\")") (fun _ -> (assert_raises ~msg:"A label" (Failure "Boo") (fun _ -> raise (Failure "Foo")))); assert_raises (OUnit_failure "expected exception Failure(\"Boo\"), \ but no exception was raised.") (fun _ -> (assert_raises (Failure "Boo") (fun _ -> ()))); assert_raises (OUnit_failure "A label\nexpected exception Failure(\"Boo\"), \ but no exception was raised.") (fun _ -> (assert_raises ~msg:"A label" (Failure "Boo") (fun _ -> ()))) (* Test the float compare, and use the cmp label *) let test_cmp_float _ = assert_equal ~cmp: cmp_float 0.0001 0.0001; assert_equal ~cmp: (cmp_float ~epsilon: 0.001) 1.0001 1.00001; assert_raises (OUnit_failure "not equal") (fun _ -> assert_equal ~cmp: cmp_float 100.0001 101.001) let test_assert_string _ = assert_string ""; assert_raises (OUnit_failure "A string") (fun _ -> assert_string "A string") let test_assert_bool _ = assert_bool "true" true; assert_raises (OUnit_failure "false") (fun _ -> assert_bool "false" false) let test_case_skip ctxt = begin try skip_if false "test" with _ -> assert_failure "Should not skip this test." end; assert_raises (Skip "test") (fun _ -> skip_if true "test") let test_case_todo ctxt = assert_raises (Todo "test") (fun _ -> todo "test") let test_assert_command ctxt = assert_command ~ctxt Sys.executable_name ["-help"] let tests = "OUnitAssert" >::: [ "test_assert_raises" >:: test_assert_raises; "test_assert_string" >:: test_assert_string; "test_assert_bool" >:: test_assert_bool; "test_cmp_float" >:: test_cmp_float; "test_case_skip" >:: test_case_skip; "test_case_todo" >:: test_case_todo; "test_assert_command" >:: test_assert_command; ] ounit-2.0.0/test/testOUnitBracket.ml0000644000175000017500000000767512222142072016745 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnit2 open OUnitBracket (* Retain bracket return for further testing. *) let with_bracket_holder test_ctxt bracket f = let rres = ref None in with_bracket test_ctxt bracket (fun res _ -> rres := Some res; f res); match !rres with | None -> assert_failure "Bracket holder not initialized." | Some res -> res let tests = "OUnitBracket" >::: [ "tmpfile" >:: (fun test_ctxt -> let fn, _ = with_bracket_holder test_ctxt bracket_tmpfile (fun (fn, _) -> assert_bool "Temporary file exists." (Sys.file_exists fn)) in assert_bool "Temporary file doesn't exist anymore." (not (Sys.file_exists fn))); "tmpdir" >:: (fun test_ctxt -> let dn = with_bracket_holder test_ctxt bracket_tmpdir (fun dn -> assert_bool "Temporary directory exists." (Sys.is_directory dn)) in assert_bool "Temporary directory doesn't exist anymore." (not (Sys.file_exists dn))); "chdir" >:: (fun test_ctxt -> let tmpdn = bracket_tmpdir test_ctxt in let () = with_bracket test_ctxt (bracket_chdir tmpdn) (fun () (test_ctxt : OUnitTest.ctxt) -> assert_equal ~printer:(fun s -> s) tmpdn (Sys.getcwd ())) in assert_bool "Not in temporary directory anymore." (tmpdn <> Sys.getcwd ())); ] ounit-2.0.0/test/testOUnitChooser.ml0000644000175000017500000001300612222142072016755 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnit2 open OUnitChooser open OUnitTest module MapString = Map.Make(String) let choose label = Choose [Label label] let postpone = ChooseToPostpone let skip label = ChooseToSkip [Label label] let check_choices chooser tests expected_choices = let result_of_test = List.fold_left (fun mp (path, _, result) -> MapString.add path result mp) MapString.empty tests in let add_result path result t = {t with tests_passed = (path, result, None) :: t.tests_passed} in let not_planned path t = {t with tests_planned = List.filter ((<>) path) t.tests_planned} in let rec virtual_run choices t = (* Choose with 1+ test still running. *) let choice = chooser t in (* Finish the running test. *) let t = match t.tests_running with | path :: tl -> let result = MapString.find (string_of_path path) result_of_test in let t = add_result path result t in {t with tests_running = tl} | [] -> t in (* Apply the choice. *) let choices = choice :: choices in match choice with | ChooseToSkip path -> virtual_run choices (not_planned path (add_result path (RSkip "") t)) | ChooseToPostpone -> virtual_run choices t | Choose path -> virtual_run choices (not_planned path {t with tests_running = path :: t.tests_running}) | NoChoice -> choices, t in let t = { tests_planned = List.map (fun (path, _, _) -> [Label path]) tests; tests_running = []; tests_passed = []; cache = List.fold_left (fun cache (path, was_result_opt, _) -> match was_result_opt with | Some result -> OUnitCache.add_result [Label path] result cache | None -> cache) OUnitCache.default tests } in let actual_choices, t = virtual_run [] t in assert_equal ~msg:"All tests passed." ~printer:string_of_int (List.length tests) (List.length t.tests_passed); assert_equal ~msg:"Right choices made." ~printer:(fun choices -> String.concat ", " (List.map string_of_choice choices)) (expected_choices @ [NoChoice]) (List.rev actual_choices) let test ?(run=true) ?(failed=false) ?(still=true) label = label, begin if run && failed then Some (RFailure ("", None, None)) else if run then Some RSuccess else None end, begin let now_failed = if still then failed else not failed in if now_failed then RFailure ("", None, None) else RSuccess end let tests = "Chooser" >::: [ "failfirst" >:: (fun test_ctxt -> check_choices failfirst [test "foo"] [choose "foo"]; check_choices failfirst [test "foo"; test ~failed:true ~still:false "bar"] [choose "bar"; postpone; choose "foo"]; check_choices failfirst [test "foo"; test ~failed:true "bar"] [choose "bar"; postpone; skip "foo"]) ] ounit-2.0.0/test/testOUnitDiff.ml0000644000175000017500000000671112222142072016230 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnit2 module EInt = struct type t = int let compare = ( - ) let pp_printer = Format.pp_print_int let pp_print_sep = OUnitDiff.pp_comma_separator end module DiffSetInt = OUnitDiff.SetMake(EInt) module DiffListSimpleInt = OUnitDiff.ListSimpleMake(EInt) let test_diff ctxt = let lst_exp = [1; 2; 3; 4; 5] in let lst_real = [1; 2; 5; 4] in assert_raises (OUnitTest.OUnit_failure "expected: 1, 2, 3, 4, 5 but got: 1, 2, 4, 5\n\ differences: -3") (fun () -> DiffSetInt.assert_equal (DiffSetInt.of_list lst_exp) (DiffSetInt.of_list lst_real)); DiffSetInt.assert_equal (DiffSetInt.of_list lst_exp) (DiffSetInt.of_list lst_exp); assert_raises (OUnitTest.OUnit_failure "expected: 1, 2, 3, 4, 5 but got: 1, 2, 5, 4\n\ differences: element number 2 differ (3 <> 5)") (fun () -> DiffListSimpleInt.assert_equal lst_exp lst_real); DiffListSimpleInt.assert_equal lst_exp lst_exp (* Construct the test suite *) let tests = "OUnitDiff" >::: ["test_diff" >:: test_diff] ounit-2.0.0/test/testOUnitTest.ml0000644000175000017500000001703012222142072016273 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnitTest open TestCommon open OUnit2 let test_case = TestCase (Short, fun ctxt -> ()) let labeled_test_case = TestLabel ("label", test_case) let suite_a = TestLabel ("suite_a", TestList [test_case]) let suite_b = TestLabel ("suite_b", TestList [labeled_test_case]) let suite_c = TestLabel ("suite_c", TestList [test_case; labeled_test_case]) let suite_d = TestLabel ("suite_d", TestList [suite_a; suite_c]) let rec string_of_paths = function [] -> "" | h::t -> (string_of_path h) ^ "\n" ^ (string_of_paths t) let test_case_filter ctxt = let assert_test_case_count exp tst_opt = match tst_opt with | Some tst -> assert_equal exp (test_case_count tst) | None -> assert_failure "Unexpected empty filter result" in assert_equal None (test_filter [] suite_a); assert_equal None (test_filter [] suite_b); assert_equal None (test_filter [] suite_c); assert_equal None (test_filter [] suite_d); assert_test_case_count 1 (test_filter ["suite_a"] suite_a); assert_test_case_count 1 (test_filter ["suite_a:0"] suite_a); assert_test_case_count 1 (test_filter ["suite_b:0:label"] suite_b); assert_test_case_count 1 (test_filter ["suite_c:0"] suite_c); assert_test_case_count 2 (test_filter ["suite_c:0";"suite_c:1:label"] suite_c) let test_case_decorate ctxt = assert_equal_test_result [ [Label "label"; ListItem 1; Label "suite_c"], RSuccess, None; [ListItem 0; Label "suite_c"], RSuccess, None ] (perform_test suite_c); assert_equal_test_result [ [Label "label"; ListItem 1; Label "suite_c"], RFailure("fail", None, None), None; [ListItem 0; Label "suite_c"], RFailure("fail", None, None), None; ] (perform_test (test_decorate (fun _ -> (fun ctxt -> assert_failure "fail")) suite_c)) (* Test which checks if the test case count function works correctly *) let test_case_count ctxt = let assert_equal ?msg = assert_equal ?msg ~printer:string_of_int in assert_equal 0 (test_case_count (TestList [])); assert_equal 0 (test_case_count (TestLabel("label", TestList []))); assert_equal 0 (test_case_count (TestList [TestList []; TestList [TestList []]])); assert_equal 1 (test_case_count test_case); assert_equal 1 (test_case_count labeled_test_case); assert_equal 1 (test_case_count suite_a); assert_equal 1 (test_case_count suite_b); assert_equal 1 (test_case_count (TestList [suite_a; TestList []])); assert_equal 1 (test_case_count (TestList [TestList []; TestList [suite_b]])); assert_equal 2 (test_case_count suite_c); assert_equal 3 (test_case_count suite_d) (* Test which checks if the paths are correctly constructed *) let test_case_paths _ = (* A single testcase results in a list countaining an empty list *) let assert_equal ?msg = assert_equal ?msg ~printer:string_of_paths in assert_equal [[]] (test_case_paths test_case); assert_equal [[Label "label"]] (test_case_paths labeled_test_case); assert_equal [[ListItem 0; Label "suite_a"]] (test_case_paths suite_a); assert_equal [[Label "label"; ListItem 0; Label "suite_b"]] (test_case_paths suite_b); assert_equal [[ListItem 0; Label "suite_c"]; [Label "label"; ListItem 1; Label "suite_c"]] (test_case_paths suite_c); assert_equal [[ListItem 0; Label "suite_a"; ListItem 0; Label "suite_d"]; [ListItem 0; Label "suite_c"; ListItem 1; Label "suite_d"]; [Label "label"; ListItem 1; Label "suite_c"; ListItem 1; Label "suite_d"]] (test_case_paths suite_d) let test_non_fatal _ = assert_equal_test_result [ [ListItem 0], RSuccess, None; [ListItem 1], RFailure("fail", None, None), None; [ListItem 2], RError("Failure(\"error\")", None), None; [ListItem 2], RFailure("fail", None, None), None; [ListItem 3], RError("Failure(\"error\")", None), None; [ListItem 3], RFailure("fail", None, None), None; ] (perform_test (TestList [ (* success *) TestCase (Short, ignore); (* failure *) TestCase (Short, fun _ -> assert_failure "fail"); (* error + failure *) TestCase (Short, fun ctxt -> OUnitTest.non_fatal ctxt (fun _ -> failwith "error"); assert_failure "fail"); (* failure + error *) TestCase (Short, fun ctxt -> OUnitTest.non_fatal ctxt (fun _ -> assert_failure "fail"); failwith "error"); ])) let tests = "OUnitTest" >::: [ "test_case_count" >:: test_case_count; "test_case_paths" >:: test_case_paths; "test_case_filter" >:: test_case_filter; "test_case_decorate" >:: test_case_decorate; "test_non_fatal" >:: test_non_fatal; ] ounit-2.0.0/test/testOtherTests.ml0000644000175000017500000001562112222142072016505 0ustar gildorgildor(**************************************************************************) (* 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. *) (**************************************************************************) open OUnit2 open OUnitUtils let xmllint = Conf.make_exec "xmllint" let testFakeHTML = Conf.make_exec "testFakeHTML" let tests = "OtherTests" >::: [ "TestFakeHTML" >:: (fun ctxt -> (* For easier dev. we don't use a temporary directory but a permanent * one, so that we can see the result. *) let () = skip_if (Sys.os_type = "Win32") "Don't run on Win32." in let html_dir = "log-html" in let junit_xml = Filename.concat html_dir "junit.xml" in let index_html = Filename.concat html_dir "index.html" in let link_to_source bn = Sys.remove (Filename.concat html_dir bn); Unix.symlink (Filename.concat (Sys.getcwd ()) (Filename.concat "src" bn)) (Filename.concat html_dir bn) in let grep_wc fn f = let count = ref 0 in let chn = open_in fn in let () = try while true do let line = input_line chn in if f line then incr count done; with End_of_file -> close_in chn in !count in if not (Sys.file_exists html_dir) then Unix.mkdir html_dir 0o750; assert_command ~ctxt ~exit_code:(Unix.WEXITED 1) (testFakeHTML ctxt) ["-output-file"; Filename.concat html_dir "fake-html.log"; "-output-html-dir"; html_dir; "-output-junit-file"; junit_xml]; assert_equal ~msg:"Number of test case in junit.xml." ~printer:string_of_int 6 (grep_wc junit_xml (fun line -> starts_with ~prefix:" starts_with ~prefix:"