-
Notifications
You must be signed in to change notification settings - Fork 86
/
Copy pathmain.ml
276 lines (249 loc) · 10.1 KB
/
main.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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
(**************************************************************************)
(* *)
(* OCaml *)
(* *)
(* Sebastien Hinderer, projet Gallium, INRIA Paris *)
(* *)
(* Copyright 2016 Institut National de Recherche en Informatique et *)
(* en Automatique. *)
(* *)
(* All rights reserved. This file is distributed under the terms of *)
(* the GNU Lesser General Public License version 2.1, with the *)
(* special exception on linking described in the file LICENSE. *)
(* *)
(**************************************************************************)
(* Main program of the ocamltest test driver *)
open Ocamltest_stdlib
open Tsl_semantics
type behavior =
| Skip_all_tests
| Run of Environments.t
(*
let first_token filename =
let input_channel = open_in filename in
let lexbuf = Lexing.from_channel input_channel in
Location.init lexbuf filename;
let token =
try Tsl_lexer.token lexbuf with e -> close_in input_channel; raise e
in close_in input_channel; token
let is_test filename =
match first_token filename with
| exception _ -> false
| Tsl_parser.TSL_BEGIN_C_STYLE | TSL_BEGIN_OCAML_STYLE -> true
| _ -> false
*)
(* this primitive announce should be used for tests
that were aborted on system error before ocamltest
could parse them *)
let announce_test_error test_filename error =
Printf.printf " ... testing '%s' => unexpected error (%s)\n%!"
(Filename.basename test_filename) error
let tsl_block_of_file test_filename =
let input_channel = open_in test_filename in
let lexbuf = Lexing.from_channel input_channel in
Location.init lexbuf test_filename;
match Tsl_parser.tsl_block Tsl_lexer.token lexbuf with
| exception e -> close_in input_channel; raise e
| _ as tsl_block -> close_in input_channel; tsl_block
let tsl_block_of_file_safe test_filename =
try tsl_block_of_file test_filename with
| Sys_error message ->
Printf.eprintf "%s\n%!" message;
announce_test_error test_filename message;
exit 1
| Parsing.Parse_error ->
Printf.eprintf "Could not read test block in %s\n%!" test_filename;
announce_test_error test_filename "could not read test block";
exit 1
let print_usage () =
Printf.printf "%s\n%!" Options.usage
type result_summary = No_failure | Some_failure
let join_summaries sa sb =
match sa, sb with
| Some_failure, _ | _, Some_failure -> Some_failure
| No_failure, No_failure -> No_failure
let summary_of_result res =
let open Result in
match res.status with
| Pass -> No_failure
| Skip -> No_failure
| Fail -> Some_failure
let rec run_test log common_prefix path behavior = function
Node (testenvspec, test, env_modifiers, subtrees) ->
Printf.printf "%s %s (%s) => %!" common_prefix path test.Tests.test_name;
let (msg, children_behavior, summary) = match behavior with
| Skip_all_tests -> "n/a", Skip_all_tests, No_failure
| Run env ->
let testenv0 = interprete_environment_statements env testenvspec in
let testenv = List.fold_left apply_modifiers testenv0 env_modifiers in
let (result, newenv) = Tests.run log testenv test in
let msg = Result.string_of_result result in
let children_behavior =
if Result.is_pass result then Run newenv else Skip_all_tests in
let summary = summary_of_result result in
(msg, children_behavior, summary) in
Printf.printf "%s\n%!" msg;
join_summaries summary
(run_test_trees log common_prefix path children_behavior subtrees)
and run_test_trees log common_prefix path behavior trees =
List.fold_left join_summaries No_failure
(List.mapi (run_test_i log common_prefix path behavior) trees)
and run_test_i log common_prefix path behavior i test_tree =
let path_prefix = if path="" then "" else path ^ "." in
let new_path = Printf.sprintf "%s%d" path_prefix (i+1) in
run_test log common_prefix new_path behavior test_tree
let get_test_source_directory test_dirname =
if (Filename.is_relative test_dirname) then
Sys.with_chdir test_dirname Sys.getcwd
else test_dirname
let get_test_build_directory_prefix test_dirname =
let ocamltestdir_variable = "OCAMLTESTDIR" in
let root =
Sys.getenv_with_default_value ocamltestdir_variable
(Filename.concat (Sys.getcwd ()) "_ocamltest")
in
if test_dirname = "." then root
else Filename.concat root test_dirname
let tests_to_skip = ref []
let init_tests_to_skip () =
tests_to_skip := String.words (Sys.safe_getenv "OCAMLTEST_SKIP_TESTS")
let test_file test_filename =
let skip_test = List.mem test_filename !tests_to_skip in
let tsl_block = tsl_block_of_file_safe test_filename in
let (rootenv_statements, test_trees) = test_trees_of_tsl_block tsl_block in
let test_trees = match test_trees with
| [] ->
let default_tests = Tests.default_tests() in
let make_tree test = Node ([], test, [], []) in
List.map make_tree default_tests
| _ -> test_trees in
let used_tests = tests_in_trees test_trees in
let used_actions = actions_in_tests used_tests in
let action_names =
let f act names = String.Set.add (Actions.name act) names in
Actions.ActionSet.fold f used_actions String.Set.empty in
let test_dirname = Filename.dirname test_filename in
let test_basename = Filename.basename test_filename in
let test_prefix = Filename.chop_extension test_basename in
let test_directory =
if test_dirname="." then test_prefix
else Filename.concat test_dirname test_prefix in
let test_source_directory = get_test_source_directory test_dirname in
let hookname_prefix = Filename.concat test_source_directory test_prefix in
let test_build_directory_prefix =
get_test_build_directory_prefix test_directory in
let clean_test_build_directory () =
try
Sys.rm_rf test_build_directory_prefix
with Sys_error _ -> ()
in
clean_test_build_directory ();
Sys.make_directory test_build_directory_prefix;
let log_filename =
Filename.concat test_build_directory_prefix (test_prefix ^ ".log") in
let log =
if Options.log_to_stderr then stderr else begin
open_out log_filename
end in
let summary = Sys.with_chdir test_build_directory_prefix
(fun () ->
let promote = string_of_bool Options.promote in
let default_timeout = string_of_int Options.default_timeout in
let install_hook name =
let hook_name = Filename.make_filename hookname_prefix name in
if Sys.file_exists hook_name then begin
let hook = Actions_helpers.run_hook hook_name in
Actions.set_hook name hook
end in
String.Set.iter install_hook action_names;
let reference_filename = Filename.concat
test_source_directory (test_prefix ^ ".reference") in
let make = try Sys.getenv "MAKE" with Not_found -> "make" in
let initial_environment = Environments.from_bindings
[
Builtin_variables.make, make;
Builtin_variables.test_file, test_basename;
Builtin_variables.reference, reference_filename;
Builtin_variables.test_source_directory, test_source_directory;
Builtin_variables.test_build_directory_prefix,
test_build_directory_prefix;
Builtin_variables.promote, promote;
Builtin_variables.timeout, default_timeout;
] in
let rootenv =
Environments.initialize Environments.Pre log initial_environment in
let rootenv =
interprete_environment_statements
rootenv rootenv_statements in
let rootenv = Environments.initialize Environments.Post log rootenv in
let common_prefix = " ... testing '" ^ test_basename ^ "' with" in
let initial_status =
if skip_test then Skip_all_tests else Run rootenv
in
let summary =
run_test_trees log common_prefix "" initial_status test_trees in
Actions.clear_all_hooks();
summary
) in
if not Options.log_to_stderr then close_out log;
begin match summary with
| Some_failure ->
if not Options.log_to_stderr then
Sys.dump_file stderr ~prefix:"> " log_filename
| No_failure ->
if not Options.keep_test_dir_on_success then
clean_test_build_directory ()
end
let is_test s =
match tsl_block_of_file s with
| _ -> true
| exception _ -> false
let ignored s =
s = "" || s.[0] = '_' || s.[0] = '.'
let sort_strings = List.sort String.compare
let find_test_dirs dir =
let res = ref [] in
let rec loop dir =
let contains_tests = ref false in
Array.iter (fun s ->
if ignored s then ()
else begin
let s = dir ^ "/" ^ s in
if Sys.is_directory s then loop s
else if not !contains_tests && is_test s then contains_tests := true
end
) (Sys.readdir dir);
if !contains_tests then res := dir :: !res
in
loop dir;
sort_strings !res
let list_tests dir =
let res = ref [] in
if Sys.is_directory dir then begin
Array.iter (fun s ->
if ignored s then ()
else begin
let s' = dir ^ "/" ^ s in
if Sys.is_directory s' || not (is_test s') then ()
else res := s :: !res
end
) (Sys.readdir dir)
end;
sort_strings !res
let () =
init_tests_to_skip()
let () =
let failed = ref false in
let work_done = ref false in
let list_tests dir =
match list_tests dir with
| [] -> failed := true
| res -> List.iter print_endline res
in
let find_test_dirs dir = List.iter print_endline (find_test_dirs dir) in
let doit f x = work_done := true; f x in
List.iter (doit find_test_dirs) Options.find_test_dirs;
List.iter (doit list_tests) Options.list_tests;
List.iter (doit test_file) Options.files_to_test;
if not !work_done then print_usage();
if !failed || not !work_done then exit 1