From 9510a6d19ff4a87352e5b060d920bcc886e368c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Louis=20Roch=C3=A9?= Date: Sat, 23 Dec 2023 12:15:34 +0100 Subject: [PATCH] update dune lang to 3.0 --- .ocamlformat | 2 + alcotest/dune | 3 +- alcotest/junit_alcotest.ml | 28 ++-- alcotest/junit_alcotest.mli | 58 ++++--- alcotest/test/alcotest_report.ml | 74 ++++----- alcotest/test/dune | 11 +- dune-project | 2 +- junit.opam | 2 +- junit/dune | 3 +- junit/junit.ml | 258 +++++++++++++------------------ junit/junit.mli | 156 +++++++++---------- junit/junit_xml.ml | 182 +++++++++------------- junit/junit_xml.mli | 195 +++++++++++------------ junit/test/dune | 10 +- junit/test/simple.ml | 73 ++++----- junit_alcotest.opam | 2 +- junit_ounit.opam | 2 +- ounit/dune | 3 +- ounit/junit_ounit.ml | 30 ++-- ounit/junit_ounit.mli | 5 +- 20 files changed, 480 insertions(+), 619 deletions(-) create mode 100644 .ocamlformat diff --git a/.ocamlformat b/.ocamlformat new file mode 100644 index 0000000..eb69b6d --- /dev/null +++ b/.ocamlformat @@ -0,0 +1,2 @@ +profile=janestreet +version=0.26.1 diff --git a/alcotest/dune b/alcotest/dune index 1bbedff..519f10b 100644 --- a/alcotest/dune +++ b/alcotest/dune @@ -3,5 +3,4 @@ (public_name junit_alcotest) (wrapped false) (synopsis "JUnit XML reports generation for alcotest tests") - (libraries junit alcotest) - (flags :standard -safe-string -short-paths)) + (libraries junit alcotest)) diff --git a/alcotest/junit_alcotest.ml b/alcotest/junit_alcotest.ml index d275a8c..814b602 100644 --- a/alcotest/junit_alcotest.ml +++ b/alcotest/junit_alcotest.ml @@ -18,11 +18,7 @@ let wrap_test ?classname handle_result (name, s, test) = let test () = try test (); - Junit.Testcase.pass - ~name - ~classname - ~time:0. - |> handle_result + Junit.Testcase.pass ~name ~classname ~time:0. |> handle_result with | Failure exn_msg as exn -> Junit.Testcase.failure @@ -46,25 +42,27 @@ let wrap_test ?classname handle_result (name, s, test) = |> handle_result; raise exn in - (name, s, test) + name, s, test +;; -let run ?argv name tl = - A.run ~and_exit:false ?argv name tl +let run ?argv name tl = A.run ~and_exit:false ?argv name tl -let run_and_report ?(and_exit=true) ?package ?timestamp ?argv name tests = +let run_and_report ?(and_exit = true) ?package ?timestamp ?argv name tests = let testcases = ref [] in let testsuite = Junit.Testsuite.make ?package ?timestamp ~name () in let tests = - List.map (fun (title, test_set) -> - let classname = Printf.sprintf "%s.%s" name title in - (title, List.map (wrap_test ~classname (push testcases)) test_set) - ) tests + List.map + (fun (title, test_set) -> + let classname = Printf.sprintf "%s.%s" name title in + title, List.map (wrap_test ~classname (push testcases)) test_set) + tests in let exit = try run ?argv name tests; fun () -> if and_exit then exit 0 else () - with A.Test_error -> - fun () -> if and_exit then exit 1 else raise A.Test_error + with + | A.Test_error -> fun () -> if and_exit then exit 1 else raise A.Test_error in Junit.Testsuite.add_testcases !testcases testsuite, exit +;; diff --git a/alcotest/junit_alcotest.mli b/alcotest/junit_alcotest.mli index 2e6a177..0005f5e 100644 --- a/alcotest/junit_alcotest.mli +++ b/alcotest/junit_alcotest.mli @@ -1,49 +1,38 @@ (** Interface to product JUnit reports for Alcotest It tries to provide a layer as thin as possible on top of Alcotest - to allow to port existing test without writing a lot a boilerplate. -*) - -val wrap_test : - ?classname:string -> - (Junit.Testcase.t -> unit) -> - unit Alcotest.test_case -> - unit Alcotest.test_case + to allow to port existing test without writing a lot a boilerplate. *) + (** [wrap_test handle_result test_cases] wraps test cases to create Junit testcases and pass them to [handle_result]. Can be used with {!run} to create customized Junit testsuites if the output of {!run_and_report} is not as expected. - @param classname will populate the 'classname' attribute - for the test case. For best hierarchic rendering in Jenkins, it - should contain a period. For example, "foo.bar.baz" will be rendered - a package "foo.bar" that contains a class "baz", which contains the - current test case and others. Defaults to the name of the test case. -*) + @param classname + will populate the 'classname' attribute + for the test case. For best hierarchic rendering in Jenkins, it + should contain a period. For example, "foo.bar.baz" will be rendered + a package "foo.bar" that contains a class "baz", which contains the + current test case and others. Defaults to the name of the test case. *) +val wrap_test + : ?classname:string + -> (Junit.Testcase.t -> unit) + -> unit Alcotest.test_case + -> unit Alcotest.test_case -val run: ?argv:string array -> string -> unit Alcotest.test list -> unit (** [run ?argv n t] is a wrapper around {!Alcotest.run}, only setting [and_exit] to false. It is mandatory to be able to process results after the end of the run. - Low level function. It is easier to use {!run_and_report}. -*) + Low level function. It is easier to use {!run_and_report}. *) +val run : ?argv:string array -> string -> unit Alcotest.test list -> unit -type exit = unit -> unit (** [exit ()] exists with appropriate code if {!run_and_report}'s [and_exit] was [true] or raise {!Alcotest.Test_error} in case of - error. -*) - -val run_and_report: - ?and_exit:bool -> - ?package:string -> - ?timestamp:Ptime.t -> - ?argv:string array -> - string -> - (string * unit Alcotest.test_case list) list -> - (Junit.Testsuite.t * exit) + error. *) +type exit = unit -> unit + (** [run name tests] is a wrapper around {!run} and {!wrap_test}. It runs the tests and creates a Junit testsuite from the results. @@ -58,5 +47,12 @@ val run_and_report: raises [Test_error] on error. [?argv] is forwarded to {!run}. [?package] and [?timestamp] are - forwarded to {!Junit.Testsuite.make}. -*) + forwarded to {!Junit.Testsuite.make}. *) +val run_and_report + : ?and_exit:bool + -> ?package:string + -> ?timestamp:Ptime.t + -> ?argv:string array + -> string + -> (string * unit Alcotest.test_case list) list + -> Junit.Testsuite.t * exit diff --git a/alcotest/test/alcotest_report.ml b/alcotest/test/alcotest_report.ml index 3659343..d8f1b93 100644 --- a/alcotest/test/alcotest_report.ml +++ b/alcotest/test/alcotest_report.ml @@ -6,59 +6,61 @@ module To_test = struct let plus int_list = List.fold_left (fun a b -> a + b) 0 int_list end -let capit () = - A.(check char) "Check A" 'A' (To_test.capit 'a') - -let plus () = - A.(check int)"Sum equals to 7" 7 (To_test.plus [1;1;2;3]) - -let wrong_result () = - A.(check string) "string_of_int equals to '7'" "7" (string_of_int 8) +let capit () = A.(check char) "Check A" 'A' (To_test.capit 'a') +let plus () = A.(check int) "Sum equals to 7" 7 (To_test.plus [ 1; 1; 2; 3 ]) +let wrong_result () = A.(check string) "string_of_int equals to '7'" "7" (string_of_int 8) let raise_unexpected_exn () = A.(check int) "int_of_string equals to 7" 7 (invalid_arg "7") +;; -let test_set = [ - A.test_case "Test with unexpected exception" `Quick raise_unexpected_exn; - A.test_case "Capitalize" `Quick capit; - A.test_case "Add entries" `Slow plus; - A.test_case "Test with wrong result" `Quick wrong_result; -] +let test_set = + [ A.test_case "Test with unexpected exception" `Quick raise_unexpected_exn + ; A.test_case "Capitalize" `Quick capit + ; A.test_case "Add entries" `Slow plus + ; A.test_case "Test with wrong result" `Quick wrong_result + ] +;; -let success_test_set = [ - A.test_case "Capitalize" `Quick capit; - A.test_case "Add entries" `Slow plus; -] +let success_test_set = + [ A.test_case "Capitalize" `Quick capit; A.test_case "Add entries" `Slow plus ] +;; let timestamp = match Ptime.of_date_time ((2013, 5, 24), ((10, 23, 58), 0)) with | Some t -> t | None -> assert false +;; let alcotest path = let package = "junit_alcotest" in - let (testsuite1, _) = JA.run_and_report ~package ~timestamp "My first test" [ - "Basic tests", test_set; - ] + let testsuite1, _ = + JA.run_and_report ~package ~timestamp "My first test" [ "Basic tests", test_set ] in - let (testsuite2, _) = JA.run_and_report ~package ~timestamp "My second test" [ - "Basic tests", test_set; - ] + let testsuite2, _ = + JA.run_and_report ~package ~timestamp "My second test" [ "Basic tests", test_set ] in - let (testsuite3, exit) = JA.run_and_report ~and_exit:false ~package ~timestamp "Success test suite" [ - "Good tests", success_test_set; - ] + let testsuite3, exit = + JA.run_and_report + ~and_exit:false + ~package + ~timestamp + "Success test suite" + [ "Good tests", success_test_set ] in - let report = Junit.make [testsuite1; testsuite2; testsuite3] in - begin match path with - | None -> - let xml_report = Junit.to_xml report in - Format.printf "%a\n" (Tyxml.Xml.pp ()) xml_report - | Some path -> - Junit.to_file report path - end; + let report = Junit.make [ testsuite1; testsuite2; testsuite3 ] in + (match path with + | None -> + let xml_report = Junit.to_xml report in + Format.printf "%a\n" (Tyxml.Xml.pp ()) xml_report + | Some path -> Junit.to_file report path); exit () +;; let () = - let path = try Some (Sys.getenv "REPORT_PATH") with _ -> None in + let path = + try Some (Sys.getenv "REPORT_PATH") with + | _ -> None + in alcotest path +;; diff --git a/alcotest/test/dune b/alcotest/test/dune index c949ae8..00e74f5 100644 --- a/alcotest/test/dune +++ b/alcotest/test/dune @@ -1,17 +1,18 @@ (executable (name alcotest_report) (modules alcotest_report) - (libraries junit junit_alcotest) - (flags :standard -safe-string -short-paths)) + (libraries junit junit_alcotest)) (rule (targets alcotest_report.xml) (action - (setenv REPORT_PATH %{targets} + (setenv + REPORT_PATH + %{targets} (run %{dep:alcotest_report.exe})))) -(alias - (name runtest) +(rule + (alias runtest) (package junit_alcotest) (action (diff %{dep:alcotest_report.expected} %{dep:alcotest_report.xml})) diff --git a/dune-project b/dune-project index 9027281..8ccb3c9 100644 --- a/dune-project +++ b/dune-project @@ -1,2 +1,2 @@ -(lang dune 1.0) +(lang dune 3.0) (name junit) diff --git a/junit.opam b/junit.opam index dfd98ea..ea68acc 100644 --- a/junit.opam +++ b/junit.opam @@ -8,7 +8,7 @@ dev-repo: "git+https://github.com/Khady/ocaml-junit.git" doc: "https://khady.github.io/ocaml-junit/" tags: ["junit" "jenkins"] depends: [ - "dune" {>= "1.0"} + "dune" {>= "3.0"} "ptime" "tyxml" {>= "4.0.0"} "odoc" {with-doc & >= "1.1.1"} diff --git a/junit/dune b/junit/dune index c106e1a..65db5c3 100644 --- a/junit/dune +++ b/junit/dune @@ -3,5 +3,4 @@ (public_name junit) (wrapped false) (synopsis "JUnit XML reports generation library") - (libraries tyxml ptime ptime.clock.os) - (flags :standard -safe-string -short-paths)) + (libraries tyxml ptime ptime.clock.os)) diff --git a/junit/junit.ml b/junit/junit.ml index 212339e..9a615d9 100644 --- a/junit/junit.ml +++ b/junit/junit.ml @@ -1,30 +1,23 @@ module Property = struct type t = - { - name: string; - value: string; + { name : string + ; value : string } - let make ~name ~value = - { - name; - value; - } + let make ~name ~value = { name; value } end module Testcase = struct type error = Junit_xml.error = - { - message: string option; - typ: string; - description: string; + { message : string option + ; typ : string + ; description : string } type failure = Junit_xml.failure = - { - message: string option; - typ: string; - description: string; + { message : string option + ; typ : string + ; description : string } type result = Junit_xml.result = @@ -34,76 +27,46 @@ module Testcase = struct | Skipped type t = - { - name: string; - classname: string; - time: float; - result: result; + { name : string + ; classname : string + ; time : float + ; result : result } - let make ~name ~classname ~time result = - { - name; - classname; - time; - result - } + let make ~name ~classname ~time result = { name; classname; time; result } - let error ?message ~typ ~name ~classname ~time description = - let result = - Error { - message; - typ; - description; - } - in + let error ?message ~typ ~name ~classname ~time description = + let result = Error { message; typ; description } in make ~name ~classname ~time result + ;; - - let failure ?message ~typ ~name ~classname ~time description = - let result = - Failure { - message; - typ; - description; - } - in + let failure ?message ~typ ~name ~classname ~time description = + let result = Failure { message; typ; description } in make ~name ~classname ~time result + ;; - let skipped ~name ~classname ~time = - make ~name ~classname ~time Skipped - - let pass ~name ~classname ~time = - make ~name ~classname ~time Pass + let skipped ~name ~classname ~time = make ~name ~classname ~time Skipped + let pass ~name ~classname ~time = make ~name ~classname ~time Pass end module Testsuite = struct type t = - { - package: string; - id: int; - name: string; - timestamp: Ptime.t; - hostname: string; - tests: int; - failures: int; - errors: int; - time: float; - system_out: string option; - system_err: string option; - properties: Property.t list; - testcases: Testcase.t list; + { package : string + ; id : int + ; name : string + ; timestamp : Ptime.t + ; hostname : string + ; tests : int + ; failures : int + ; errors : int + ; time : float + ; system_out : string option + ; system_err : string option + ; properties : Property.t list + ; testcases : Testcase.t list } - let make - ?package - ?timestamp - ?(hostname="localhost") - ?system_out - ?system_err - ~name - () - = + let make ?package ?timestamp ?(hostname = "localhost") ?system_out ?system_err ~name () = let package = match package with | None -> name @@ -114,114 +77,105 @@ module Testsuite = struct | None -> Ptime_clock.now () | Some t -> t in - { - package = package; - id = 0; - name; - timestamp; - hostname; - tests = 0; - failures = 0; - errors = 0; - time = 0.; - system_out; - system_err; - properties = []; - testcases = []; + { package + ; id = 0 + ; name + ; timestamp + ; hostname + ; tests = 0 + ; failures = 0 + ; errors = 0 + ; time = 0. + ; system_out + ; system_err + ; properties = [] + ; testcases = [] } + ;; let add_testcase testcase t = let t = - { - t with - tests = t.tests + 1; - time = t.time +. testcase.Testcase.time; - testcases = testcase :: t.testcases + { t with + tests = t.tests + 1 + ; time = t.time +. testcase.Testcase.time + ; testcases = testcase :: t.testcases } in match testcase.Testcase.result with - | Testcase.Pass - | Testcase.Skipped -> t - | Testcase.Error _ -> - { t with errors = t.errors + 1; } - | Testcase.Failure _ -> - { t with failures = t.failures + 1; } + | Testcase.Pass | Testcase.Skipped -> t + | Testcase.Error _ -> { t with errors = t.errors + 1 } + | Testcase.Failure _ -> { t with failures = t.failures + 1 } + ;; let add_testcases testcases t = List.fold_left (fun t tc -> add_testcase tc t) t testcases + ;; - let add_property properties t = - { t with properties = properties :: t.properties} + let add_property properties t = { t with properties = properties :: t.properties } let add_properties properties t = List.fold_left (fun t tc -> add_property tc t) t properties + ;; end type t = - { - next_id: int; - testsuites: Testsuite.t list; + { next_id : int + ; testsuites : Testsuite.t list } let make testsuites = - let testsuites = List.mapi (fun i t -> - Testsuite.{ t with id = i; } - ) testsuites - in + let testsuites = List.mapi (fun i t -> Testsuite.{ t with id = i }) testsuites in let length = List.length testsuites in - { - next_id = length; - testsuites; - } + { next_id = length; testsuites } +;; let add_testsuite testsuite t = - let ts = Testsuite.{ testsuite with id = t.next_id; } in - { - next_id = succ t.next_id; - testsuites = ts :: t.testsuites; - } - -let to_xml (t:t) = - let testsuites = List.map (fun t -> - let properties = - let open Property in - List.map (fun p -> - Junit_xml.property ~name:p.name ~value:p.value - ) t.Testsuite.properties - in - let testcases = - let open Testcase in - List.map (fun p -> - Junit_xml.testcase - ~name:p.name - ~classname:p.classname - ~time:p.time - p.result - ) t.Testsuite.testcases - in - let open Testsuite in - Junit_xml.testsuite - ?system_out:t.system_out - ?system_err:t.system_err - ~package:t.package - ~id:t.id - ~name:t.name - ~timestamp:(Junit_xml.timestamp t.timestamp) - ~hostname:t.hostname - ~tests:t.tests - ~failures:t.failures - ~errors:t.errors - ~time:t.time - properties - testcases - ) t.testsuites + let ts = Testsuite.{ testsuite with id = t.next_id } in + { next_id = succ t.next_id; testsuites = ts :: t.testsuites } +;; + +let to_xml (t : t) = + let testsuites = + List.map + (fun t -> + let properties = + let open Property in + List.map + (fun p -> Junit_xml.property ~name:p.name ~value:p.value) + t.Testsuite.properties + in + let testcases = + let open Testcase in + List.map + (fun p -> + Junit_xml.testcase ~name:p.name ~classname:p.classname ~time:p.time p.result) + t.Testsuite.testcases + in + let open Testsuite in + Junit_xml.testsuite + ?system_out:t.system_out + ?system_err:t.system_err + ~package:t.package + ~id:t.id + ~name:t.name + ~timestamp:(Junit_xml.timestamp t.timestamp) + ~hostname:t.hostname + ~tests:t.tests + ~failures:t.failures + ~errors:t.errors + ~time:t.time + properties + testcases) + t.testsuites in Junit_xml.to_xml testsuites +;; -let to_file (t:t) filename = +let to_file (t : t) filename = let xml_report = to_xml t in let oc = open_out filename in let fmt = Format.formatter_of_out_channel oc in Format.fprintf fmt "@[%a@]@." (Tyxml.Xml.pp ()) xml_report; close_out oc; () +;; diff --git a/junit/junit.mli b/junit/junit.mli index c404456..d70aef8 100644 --- a/junit/junit.mli +++ b/junit/junit.mli @@ -1,33 +1,19 @@ (** High level interface to produce JUnit reports. *) (** This module defines functions to create JUnit reports and export - them to XML. This XML is supposed to be accepted by Jenkins. -*) + them to XML. This XML is supposed to be accepted by Jenkins. *) -module Property : -sig +module Property : sig (** Properties (e.g., environment settings) set during test execution. *) type t - val make : - name:string -> - value:string -> - t + val make : name:string -> value:string -> t end -module Testcase : -sig +module Testcase : sig type t - val error : - ?message:string -> - typ:string -> - name:string -> - classname:string -> - time:float -> - string -> - t (** [error ?message ~typ ~name ~classname ~time description] creates an error element. @@ -36,30 +22,31 @@ sig problem with the implementation of the test. Contains as a text node relevant data for the error, e.g., a stack trace. - @param message The error message. e.g., if a java exception is - thrown, the return value of getMessage(). + @param message + The error message. e.g., if a java exception is + thrown, the return value of getMessage(). - @param typ The type of error that occured. e.g., if a java - execption is thrown the full class name of the exception. + @param typ + The type of error that occured. e.g., if a java + execption is thrown the full class name of the exception. @param description Description of the error. @param name Name of the test method. @param classname Full class name for the class the test method is - in. - - @param time Time taken (in seconds) to execute the test. - *) - - val failure : - ?message:string -> - typ:string -> - name:string -> - classname:string -> - time:float -> - string -> - t + in. + + @param time Time taken (in seconds) to execute the test. *) + val error + : ?message:string + -> typ:string + -> name:string + -> classname:string + -> time:float + -> string + -> t + (** [failure ?message ~typ ~name ~classname ~time description] creates a failure element. @@ -77,16 +64,18 @@ sig @param name Name of the test method. @param classname Full class name for the class the test method is - in. - - @param time Time taken (in seconds) to execute the test. - *) + in. + + @param time Time taken (in seconds) to execute the test. *) + val failure + : ?message:string + -> typ:string + -> name:string + -> classname:string + -> time:float + -> string + -> t - val skipped : - name:string -> - classname:string -> - time:float -> - t (** [skipped ~name ~classname ~time] creates a skipped element. Indicates that the test has not been launched. @@ -94,16 +83,11 @@ sig @param name Name of the test method. @param classname Full class name for the class the test method is - in. + in. - @param time Time taken (in seconds) to execute the test. - *) + @param time Time taken (in seconds) to execute the test. *) + val skipped : name:string -> classname:string -> time:float -> t - val pass : - name:string -> - classname:string -> - time:float -> - t (** [pass ~name ~classname ~time] creates a pass element. Indicates that the test is a success. @@ -111,63 +95,61 @@ sig @param name Name of the test method. @param classname Full class name for the class the test method is - in. + in. - @param time Time taken (in seconds) to execute the test. - *) + @param time Time taken (in seconds) to execute the test. *) + val pass : name:string -> classname:string -> time:float -> t end -module Testsuite : -sig +module Testsuite : sig (** Contains the results of executing a testsuite. *) type t - val make : - ?package:string -> - ?timestamp:Ptime.t -> - ?hostname:string -> - ?system_out:string -> - ?system_err:string -> - name:string -> - unit -> - t (** [make ?package ?timestamp ?hostname ?system_out ?system_err ~name ()] creates a testsuite. Attributes @param package Derived from the testsuite name in the - non-aggregated documents. + non-aggregated documents. - @param timestamp When the test was executed. Timezone may not be - specified. Uses the current time by default. + @param timestamp + When the test was executed. Timezone may not be + specified. Uses the current time by default. @param hostname Host on which the tests were executed. Uses - [localhost] by default. + [localhost] by default. @param system_out Data that was written to standard out while - the test was executed. - - @param system_err Data that was written to standard error while - the test was executed. - - @param name Full class name of the test for non-aggregated - testsuite documents. Class name without the package for - aggregated testsuites documents. - *) - - val add_testcases : - Testcase.t list -> t -> t - - val add_properties : - Property.t list -> t -> t + the test was executed. + + @param system_err + Data that was written to standard error while + the test was executed. + + @param name + Full class name of the test for non-aggregated + testsuite documents. Class name without the package for + aggregated testsuites documents. *) + val make + : ?package:string + -> ?timestamp:Ptime.t + -> ?hostname:string + -> ?system_out:string + -> ?system_err:string + -> name:string + -> unit + -> t + + val add_testcases : Testcase.t list -> t -> t + val add_properties : Property.t list -> t -> t end -type t (** Contains an aggregation of testsuite results. *) +type t -val make : Testsuite.t list -> t +val make : Testsuite.t list -> t val add_testsuite : Testsuite.t -> t -> t val to_xml : t -> Tyxml.Xml.elt val to_file : t -> string -> unit diff --git a/junit/junit_xml.ml b/junit/junit_xml.ml index d636b42..870a1aa 100644 --- a/junit/junit_xml.ml +++ b/junit/junit_xml.ml @@ -1,52 +1,41 @@ open Tyxml.Xml type token = string - type timestamp = string let timestamp time = let (y, m, d), ((hh, ss, mm), _) = Ptime.to_date_time time in Printf.sprintf "%04d-%02d-%02dT%02d:%02d:%02d" y m d hh ss mm +;; type property = - { - name : token; - value : string; + { name : token + ; value : string } type properties = property list -let property ~name ~value = - { - name; - value; - } +let property ~name ~value = { name; value } let property_to_xml property = let name = string_attrib "name" property.name in let value = string_attrib "value" property.value in - node "property" ~a:[name; value] [] + node "property" ~a:[ name; value ] [] +;; -let properties_to_xml properties = - node "properties" (List.map property_to_xml properties) +let properties_to_xml properties = node "properties" (List.map property_to_xml properties) type error = - { - message : string option; - typ : string; - description : string; + { message : string option + ; typ : string + ; description : string } -let error ?message ~typ description : error = - { - message; - typ; - description; - } +let error ?message ~typ description : error = { message; typ; description } let error_to_xml (error : error) = let typ = string_attrib "type" error.typ in - let attributes = [typ] in + let attributes = [ typ ] in let attributes = match error.message with | None -> attributes @@ -55,25 +44,20 @@ let error_to_xml (error : error) = message :: attributes in let description = pcdata error.description in - node "error" ~a:attributes [description] + node "error" ~a:attributes [ description ] +;; type failure = - { - message : string option; - typ : string; - description : string; + { message : string option + ; typ : string + ; description : string } -let failure ?message ~typ description : failure = - { - message; - typ; - description; - } +let failure ?message ~typ description : failure = { message; typ; description } let failure_to_xml (failure : failure) = let typ = string_attrib "type" failure.typ in - let attributes = [typ] in + let attributes = [ typ ] in let attributes = match failure.message with | None -> attributes @@ -82,7 +66,8 @@ let failure_to_xml (failure : failure) = message :: attributes in let description = pcdata failure.description in - node "failure" ~a:attributes [description] + node "failure" ~a:attributes [ description ] +;; type result = | Error of error @@ -95,81 +80,75 @@ let result_to_xml : result -> Tyxml.Xml.elt = function | Failure f -> failure_to_xml f | Pass -> Tyxml.Xml.empty () | Skipped -> node "skipped" [] +;; type testcase = - { - name : string; - classname : token; - time : float; - result : result; + { name : string + ; classname : token + ; time : float + ; result : result } type testcases = testcase list -let testcase ~name ~classname ~time result = - { - name; - classname; - time; - result; - } +let testcase ~name ~classname ~time result = { name; classname; time; result } let testcase_to_xml (testcase : testcase) = let name = string_attrib "name" testcase.name in let classname = string_attrib "classname" testcase.classname in let time = float_attrib "time" testcase.time in let result = result_to_xml testcase.result in - node "testcase" ~a:[name; classname; time] [result] + node "testcase" ~a:[ name; classname; time ] [ result ] +;; type testsuite = - { - package : token; - id : int; - name : token; - timestamp : timestamp; - hostname : token; - tests : int; - failures : int; - errors : int; - time : float; - properties : properties; - testcases : testcases; - system_out : string option; - system_err : string option; + { package : token + ; id : int + ; name : token + ; timestamp : timestamp + ; hostname : token + ; tests : int + ; failures : int + ; errors : int + ; time : float + ; properties : properties + ; testcases : testcases + ; system_out : string option + ; system_err : string option } type testsuites = testsuite list let testsuite - ?system_out - ?system_err - ~package - ~id - ~name - ~timestamp - ~hostname - ~tests - ~failures - ~errors - ~time - properties - testcases + ?system_out + ?system_err + ~package + ~id + ~name + ~timestamp + ~hostname + ~tests + ~failures + ~errors + ~time + properties + testcases = - { - package; - id; - name; - timestamp; - hostname; - tests; - failures; - errors; - time; - properties; - testcases; - system_out; - system_err; + { package + ; id + ; name + ; timestamp + ; hostname + ; tests + ; failures + ; errors + ; time + ; properties + ; testcases + ; system_out + ; system_err } +;; let testsuite_to_xml testsuite = let package = string_attrib "package" testsuite.package in @@ -182,35 +161,24 @@ let testsuite_to_xml testsuite = let errors = int_attrib "errors" testsuite.errors in let time = float_attrib "time" testsuite.time in let attributes = - [ - package; - id; - name; - timestamp; - hostname; - tests; - failures; - errors; - time; - ] + [ package; id; name; timestamp; hostname; tests; failures; errors; time ] in let system_out = match testsuite.system_out with | None -> empty () - | Some so -> node "system_out" [pcdata so] + | Some so -> node "system_out" [ pcdata so ] in let system_err = match testsuite.system_err with | None -> empty () - | Some se -> node "system_err" [pcdata se] + | Some se -> node "system_err" [ pcdata se ] in let properties = properties_to_xml testsuite.properties in let testcases = List.map testcase_to_xml testsuite.testcases in - node - "testsuite" - ~a:attributes - (properties :: system_out :: system_err :: testcases) + node "testsuite" ~a:attributes (properties :: system_out :: system_err :: testcases) +;; let to_xml testsuites = let elements = List.map testsuite_to_xml testsuites in node "testsuites" elements +;; diff --git a/junit/junit_xml.mli b/junit/junit_xml.mli index 097aa9d..3af2c71 100644 --- a/junit/junit_xml.mli +++ b/junit/junit_xml.mli @@ -11,8 +11,7 @@ [tests] will not be checked. It allows you to build a report by hand if the facilities that are - offered by {!module:Junit} do not suit your needs. -*) + offered by {!module:Junit} do not suit your needs. *) (** {2 Categories of elements and attributes} *) @@ -20,7 +19,6 @@ (** {3 Attributes} *) -type token = string (** https://www.w3.org/TR/xmlschema-2/#token [Definition:] token represents tokenized strings. The ·value space· of @@ -31,8 +29,8 @@ type token = string the set of strings that do not contain the carriage return (#xD), line feed (#xA) nor tab (#x9) characters, that have no leading or trailing spaces (#x20) and that have no internal sequences of two - or more spaces. The ·base type· of token is normalizedString. -*) + or more spaces. The ·base type· of token is normalizedString. *) +type token = string type timestamp @@ -40,190 +38,173 @@ val timestamp : Ptime.t -> timestamp (** {3 Elements} *) -(** {4 Properties} *) +(** {4 Properties} *) type property -type properties = property list (** Properties (e.g., environment settings) set during test execution. *) +type properties = property list -val property : - name:token -> - value:string -> - property +val property : name:token -> value:string -> property -val property_to_xml : property -> Tyxml.Xml.elt (** Builds an XML element from a property. *) +val property_to_xml : property -> Tyxml.Xml.elt (** {4 Testcases} *) -type error = - { - message : string option; - typ : string; - description : string; - } (** 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. -*) - -val error : - ?message:string -> - typ:string -> - string -> - error + relevant data for the error, e.g., a stack trace. *) +type error = + { message : string option + ; typ : string + ; description : string + } + (** [error ?message ~typ description] creates an error element. - @param message The error message. e.g., if a java exception is - thrown, the return value of getMessage(). + @param message + The error message. e.g., if a java exception is + thrown, the return value of getMessage(). - @param typ The type of error that occured. e.g., if a java - execption is thrown the full class name of the exception. + @param typ + The type of error that occured. e.g., if a java + execption is thrown the full class name of the exception. - @param description Description of the error. -*) + @param description Description of the error. *) +val error : ?message:string -> typ:string -> string -> error -val error_to_xml : error -> Tyxml.Xml.elt (** Builds an XML element from a error. *) +val error_to_xml : error -> Tyxml.Xml.elt -type failure = - { - message : string option; - typ : string; - description : string; - } (** 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. -*) - -val failure : - ?message:string -> - typ:string -> - string -> - failure + failure, e.g., a stack trace. *) +type failure = + { message : string option + ; typ : string + ; description : string + } + (** [failure ?message ~typ description] creates a failure element. @param message The message specified in the assert. @param typ The type of the assert. - @param description Description of the failure. -*) + @param description Description of the failure. *) +val failure : ?message:string -> typ:string -> string -> failure -val failure_to_xml : failure -> Tyxml.Xml.elt (** Builds an XML element from a failure. *) +val failure_to_xml : failure -> Tyxml.Xml.elt type result = | Error of error | Failure of failure | Pass - | Skipped (** Not part of the spec, but available in jenkins. *) + | Skipped (** Not part of the spec, but available in jenkins. *) -val result_to_xml : result -> Tyxml.Xml.elt (** Builds an XML element from a result. *) +val result_to_xml : result -> Tyxml.Xml.elt type testcase - type testcases = testcase list -val testcase : - name:token -> - classname:token -> - time:float -> - result -> - testcase (** Creates a testcase. @param name Name of the test method. @param classname Full class name for the class the test method is - in. + in. @param time Time taken (in seconds) to execute the test. - @param result Result of the test. -*) + @param result Result of the test. *) +val testcase : name:token -> classname:token -> time:float -> result -> testcase -val testcase_to_xml : testcase -> Tyxml.Xml.elt (** Builds an XML element from a testcase. *) +val testcase_to_xml : testcase -> Tyxml.Xml.elt (** {4 Testsuites} *) -type testsuite (** Contains the results of executing a testsuite. *) +type testsuite -type testsuites = testsuite list (** Contains an aggregation of testsuite results. *) +type testsuites = testsuite list -val testsuite : - ?system_out:string -> - ?system_err:string -> - package:token -> - id:int -> - name:token -> - timestamp:timestamp -> - hostname:token -> - tests:int -> - failures:int -> - errors:int -> - time:float -> - properties -> - testcases -> - testsuite (** Creates a testsuite. Attributes @param package Derived from the testsuite name in the non-aggregated - documents. + documents. - @param id Starts at 0 for the first testsuite and is incremented - by 1 for each following testsuite. + @param id + Starts at 0 for the first testsuite and is incremented + by 1 for each following testsuite. - @param name Full class name of the test for non-aggregated - testsuite documents. Class name without the package for aggregated - testsuites documents. + @param name + Full class name of the test for non-aggregated + testsuite documents. Class name without the package for aggregated + testsuites documents. @param timestamp When the test was executed. Timezone may not be - specified. + specified. - @param hostname Host on which the tests were executed. 'localhost' - should be used if the hostname cannot be determined. + @param hostname + Host on which the tests were executed. 'localhost' + should be used if the hostname cannot be determined. - @param tests The total number of tests in the suite.The total - number of tests in the suite. + @param tests + The total number of tests in the suite.The total + number of tests in the suite. - @param failures 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. + @param failures + 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. - @param errors The total number of tests in the suite that - 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. + @param errors + The total number of tests in the suite that + 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. @param time Time taken (in seconds) to execute the tests in the - suite. + suite. - Elements + Elements @param properties Properties (e.g., environment settings) set - during test execution. + during test execution. @param testcases List of test executed. @param system_out Data that was written to standard out while the - test was executed. + test was executed. @param system_err Data that was written to standard error while - the test was executed. -*) + the test was executed. *) +val testsuite + : ?system_out:string + -> ?system_err:string + -> package:token + -> id:int + -> name:token + -> timestamp:timestamp + -> hostname:token + -> tests:int + -> failures:int + -> errors:int + -> time:float + -> properties + -> testcases + -> testsuite -val testsuite_to_xml : testsuite -> Tyxml.Xml.elt (** Builds an XML element from a testsuite. *) +val testsuite_to_xml : testsuite -> Tyxml.Xml.elt -val to_xml : testsuites -> Tyxml.Xml.elt (** Builds an XML element from a list of testsuites. *) +val to_xml : testsuites -> Tyxml.Xml.elt diff --git a/junit/test/dune b/junit/test/dune index 2b3ff8f..cc5af42 100644 --- a/junit/test/dune +++ b/junit/test/dune @@ -1,15 +1,15 @@ (executable (name simple) (modules simple) - (libraries junit) - (flags :standard -safe-string -short-paths)) + (libraries junit)) (rule (targets simple.xml) - (action (run %{dep:simple.exe} %{targets}))) + (action + (run %{dep:simple.exe} %{targets}))) -(alias - (name runtest) +(rule + (alias runtest) (deps simple.exe) (package junit) (action diff --git a/junit/test/simple.ml b/junit/test/simple.ml index 5627327..5a3db18 100644 --- a/junit/test/simple.ml +++ b/junit/test/simple.ml @@ -1,84 +1,77 @@ (** Encode this example (from http://help.catchsoftware.com/display/ET/JUnit+Format): - - - + + + - - - + + + - Assertion failed + name="should default path to an empty string" + time="0.006"> + Assertion failed - + name="should default consolidate to true" + time="0"> + - - - -*) + name="should default useDotNotation to true" + time="0" /> + + *) let timestamp = match Ptime.of_date_time ((2013, 5, 24), ((10, 23, 58), 0)) with | Some t -> t | None -> assert false +;; let simple path = let junitXmlReporter = Junit.Testsuite.make ~timestamp ~name:"JUnitXmlReporter" () in let junitXmlReportConstructor = let properties = - [ - Junit.Property.make ~name:"java.vendor" ~value:"Sun Microsystems Inc."; - Junit.Property.make ~name:"compiler.debug" ~value:"on"; - Junit.Property.make ~name:"project.jdk.classpath" ~value:"jdk.classpath.1.6"; + [ Junit.Property.make ~name:"java.vendor" ~value:"Sun Microsystems Inc." + ; Junit.Property.make ~name:"compiler.debug" ~value:"on" + ; Junit.Property.make ~name:"project.jdk.classpath" ~value:"jdk.classpath.1.6" ] in let testcases = - [ - Junit.Testcase.failure + [ Junit.Testcase.failure ~name:"should default path to an empty string" ~classname:"JUnitXmlReporter.constructor" ~time:0.006 ~message:"test failure" ~typ:"not equal" - "Assertion failed"; - Junit.Testcase.skipped + "Assertion failed" + ; Junit.Testcase.skipped ~name:"should default consolidate to true" ~classname:"JUnitXmlReporter.constructor" - ~time:0.; - Junit.Testcase.pass + ~time:0. + ; Junit.Testcase.pass ~name:"should default useDotNotation to true" ~classname:"JUnitXmlReporter.constructor" - ~time:0.; + ~time:0. ] in Junit.Testsuite.make ~timestamp ~name:"JUnitXmlReporter.constructor" () |> Junit.Testsuite.add_testcases testcases |> Junit.Testsuite.add_properties properties in - let report = Junit.make [junitXmlReporter; junitXmlReportConstructor] in + let report = Junit.make [ junitXmlReporter; junitXmlReportConstructor ] in match path with | None -> let xml_report = Junit.to_xml report in Format.printf "%a\n" (Tyxml.Xml.pp ()) xml_report - | Some path -> - Junit.to_file report path + | Some path -> Junit.to_file report path +;; let () = - let path = - if Array.length Sys.argv > 1 then - Some (Sys.argv.(1)) - else - None - in + let path = if Array.length Sys.argv > 1 then Some Sys.argv.(1) else None in simple path +;; diff --git a/junit_alcotest.opam b/junit_alcotest.opam index a63bde5..ffccb58 100644 --- a/junit_alcotest.opam +++ b/junit_alcotest.opam @@ -8,7 +8,7 @@ dev-repo: "git+https://github.com/Khady/ocaml-junit.git" doc: "https://khady.github.io/ocaml-junit/" tags: ["junit" "jenkins" "alcotest"] depends: [ - "dune" {>= "1.0"} + "dune" {>= "3.0"} "odoc" {with-doc & >= "1.1.1"} "alcotest" "junit" diff --git a/junit_ounit.opam b/junit_ounit.opam index b87644f..00a5bcf 100644 --- a/junit_ounit.opam +++ b/junit_ounit.opam @@ -8,7 +8,7 @@ dev-repo: "git+https://github.com/Khady/ocaml-junit.git" doc: "https://khady.github.io/ocaml-junit/" tags: ["junit" "jenkins" "ounit"] depends: [ - "dune" {>= "1.0"} + "dune" {>= "3.0"} "odoc" {with-doc & >= "1.1.1"} "ounit2" "junit" diff --git a/ounit/dune b/ounit/dune index e69adf1..66bed1e 100644 --- a/ounit/dune +++ b/ounit/dune @@ -3,5 +3,4 @@ (public_name junit_ounit) (wrapped false) (synopsis "JUnit XML reports generation for OUnit tests") - (libraries junit ounit2) - (flags :standard -safe-string -short-paths)) + (libraries junit ounit2)) diff --git a/ounit/junit_ounit.ml b/ounit/junit_ounit.ml index 83f59b4..0148ae1 100644 --- a/ounit/junit_ounit.ml +++ b/ounit/junit_ounit.ml @@ -9,41 +9,29 @@ let of_result o = let typ = "" in match o with | O.RError (path, msg) -> - J.Testcase.error - ~typ ~classname ~time - ~name:(O.string_of_path path) - ~message:msg - "" - | O.RSuccess path -> - J.Testcase.pass - ~classname ~time - ~name:(O.string_of_path path) + J.Testcase.error ~typ ~classname ~time ~name:(O.string_of_path path) ~message:msg "" + | O.RSuccess path -> J.Testcase.pass ~classname ~time ~name:(O.string_of_path path) | O.RFailure (path, msg) -> - J.Testcase.failure - ~typ ~classname ~time - ~message:msg - ~name:(O.string_of_path path) - "" + J.Testcase.failure ~typ ~classname ~time ~message:msg ~name:(O.string_of_path path) "" | O.RSkip (path, _msg) -> - J.Testcase.skipped - ~classname ~time - ~name:(O.string_of_path path) + J.Testcase.skipped ~classname ~time ~name:(O.string_of_path path) | O.RTodo (path, _msg) -> - J.Testcase.skipped - ~classname ~time - ~name:(O.string_of_path path ^ "(todo)") + J.Testcase.skipped ~classname ~time ~name:(O.string_of_path path ^ "(todo)") +;; let of_results ~name l = let l = List.map of_result l in let suite = J.Testsuite.make ~name () in J.Testsuite.add_testcases l suite +;; let to_file ~name file l = let suite = of_results ~name l in - let report = Junit.make [suite] in + let report = Junit.make [ suite ] in let xml_report = Junit.to_xml report in let oc = open_out file in let fmt = Format.formatter_of_out_channel oc in Format.fprintf fmt "@[%a@]@." (Tyxml.Xml.pp ()) xml_report; close_out oc; () +;; diff --git a/ounit/junit_ounit.mli b/ounit/junit_ounit.mli index 10c47b8..8ab9631 100644 --- a/ounit/junit_ounit.mli +++ b/ounit/junit_ounit.mli @@ -2,11 +2,10 @@ val of_result : OUnit.test_result -> Junit.Testcase.t -val of_results : name:string -> OUnit.test_results -> Junit.Testsuite.t (** [of_results ~name l] converts the list of results [l] into a Junit testsuite named [name]. *) +val of_results : name:string -> OUnit.test_results -> Junit.Testsuite.t -val to_file : name:string -> string -> OUnit.test_results -> unit (** Shortcut: converts the test results to a Junit testsuite, and dump it into the given file as XML. *) - +val to_file : name:string -> string -> OUnit.test_results -> unit