Source file junit_xml.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
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
  }

type properties = property list

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 ] []
;;

let properties_to_xml properties = node "properties" (List.map property_to_xml properties)

type error =
  { message : string option
  ; typ : string
  ; description : string
  }

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 =
    match error.message with
    | None -> attributes
    | Some m ->
      let message = string_attrib "message" m in
      message :: attributes
  in
  let description = pcdata error.description in
  node "error" ~a:attributes [ description ]
;;

type failure =
  { message : string option
  ; typ : string
  ; description : string
  }

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 =
    match failure.message with
    | None -> attributes
    | Some m ->
      let message = string_attrib "message" m in
      message :: attributes
  in
  let description = pcdata failure.description in
  node "failure" ~a:attributes [ description ]
;;

type result =
  | Error of error
  | Failure of failure
  | Pass
  | Skipped

let result_to_xml : result -> Tyxml.Xml.elt = function
  | Error e -> error_to_xml e
  | Failure f -> failure_to_xml f
  | Pass -> Tyxml.Xml.empty ()
  | Skipped -> node "skipped" []
;;

type testcase =
  { name : string
  ; classname : token
  ; time : float
  ; result : result
  }

type testcases = testcase list

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 ]
;;

type testsuite =
  { package : token
  ; id : int
  ; name : token
  ; timestamp : timestamp
  ; hostname : token
  ; tests : int
  ; failures : int
  ; errors : int
  ; skipped : 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
      ~skipped
      ~time
      properties
      testcases
  =
  { package
  ; id
  ; name
  ; timestamp
  ; hostname
  ; tests
  ; failures
  ; errors
  ; skipped
  ; time
  ; properties
  ; testcases
  ; system_out
  ; system_err
  }
;;

let testsuite_to_xml testsuite =
  let package = string_attrib "package" testsuite.package in
  let id = int_attrib "id" testsuite.id in
  let name = string_attrib "name" testsuite.name in
  let timestamp = string_attrib "timestamp" testsuite.timestamp in
  let hostname = string_attrib "hostname" testsuite.hostname in
  let tests = int_attrib "tests" testsuite.tests in
  let failures = int_attrib "failures" testsuite.failures in
  let errors = int_attrib "errors" testsuite.errors in
  let skipped = int_attrib "skipped" testsuite.skipped in
  let time = float_attrib "time" testsuite.time in
  let attributes =
    [ package; id; name; timestamp; hostname; tests; failures; errors; skipped; time ]
  in
  let system_out =
    match testsuite.system_out with
    | None -> empty ()
    | 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 ]
  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)
;;

let to_xml testsuites =
  let elements = List.map testsuite_to_xml testsuites in
  node "testsuites" elements
;;