From 39cd8ff70df9eeed4d8dd8ed7e5cb0a2faf7e000 Mon Sep 17 00:00:00 2001 From: Valentin Perrelle <valentin.perrelle@cea.fr> Date: Fri, 5 Jul 2019 18:30:08 +0200 Subject: [PATCH] [Ptest] add a MODULE configuration option to build and load modules --- doc/developer/advance.tex | 5 + ptests/ptests.ml | 193 ++++++++++++++++++++---------------- tests/misc/behavior_names.i | 4 +- tests/misc/debug_category.i | 36 +++---- 4 files changed, 134 insertions(+), 104 deletions(-) diff --git a/doc/developer/advance.tex b/doc/developer/advance.tex index d6dceaa1bf7..87883549de6 100644 --- a/doc/developer/advance.tex +++ b/doc/developer/advance.tex @@ -928,6 +928,11 @@ file, run it only once. & Command used to filter results & \textit{None} \\ +& \texttt{MODULE}\sscodeidxdef{Test}{Directive}{FILTER} +& Register a dynamic module to be built and to be loaded with each subsequent +test +& \textit{None} +\\ \hline \multirow{2}{23mm}{\centering{Test suite}} & \texttt{DONTRUN}\sscodeidxdef{Test}{Directive}{DONTRUN} & Do not execute this test diff --git a/ptests/ptests.ml b/ptests/ptests.ml index d99f688a4ac..79e513c75a3 100644 --- a/ptests/ptests.ml +++ b/ptests/ptests.ml @@ -493,8 +493,6 @@ end = struct end -let macro_regex = Str.regexp "\\([^@]*\\)@\\([^@]*\\)@\\(.*\\)" - type execnow = { ex_cmd: string; (** command to launch *) @@ -510,7 +508,77 @@ type execnow = are duplicated using OCaml 'with' syntax. *) } -module StringMap = Map.Make(String) + +module Macros = +struct + module StringMap = Map.Make (String) + open StringMap + + type t = string StringMap.t + + let empty = StringMap.empty + + let macro_regex = Str.regexp "\\([^@]*\\)@\\([^@]*\\)@\\(.*\\)" + + let does_expand macros s = + if !verbosity >=2 then begin + lock_printf "looking for macros in string %s\n%!" s; + lock_printf "Existing macros:\n%!"; + iter (fun s1 s2 -> lock_printf "%s => %s\n%!" s1 s2) macros; + lock_printf "End macros\n%!"; + end; + let rec aux n (ptest_file_matched,s as acc) = + if Str.string_match macro_regex s n then begin + let macro = Str.matched_group 2 s in + let ptest_file_matched = ptest_file_matched || macro = "PTEST_FILE" in + let start = Str.matched_group 1 s in + let rest = Str.matched_group 3 s in + let new_n = Str.group_end 1 in + let n, new_s = + if macro = "" then begin + new_n + 1, String.sub s 0 new_n ^ "@" ^ rest + end else begin + try + if !verbosity >= 2 then lock_printf "macro is %s\n%!" macro; + let replacement = find macro macros in + if !verbosity >= 1 then + lock_printf "replacement for %s is %s\n%!" macro replacement; + new_n, + String.sub s 0 n ^ start ^ replacement ^ rest + with + | Not_found -> Str.group_end 2 + 1, s + end + in + if !verbosity >= 2 then lock_printf "new string is %s\n%!" new_s; + let new_acc = ptest_file_matched, new_s in + if n <= String.length new_s then aux n new_acc else new_acc + end else acc + in + Mutex.lock str_mutex; + try + let res = aux 0 (false,s) in + Mutex.unlock str_mutex; res + with e -> + lock_eprintf "Uncaught exception %s\n%!" (Printexc.to_string e); + Mutex.unlock str_mutex; + raise e + + let expand macros s = + snd (does_expand macros s) + + let get ?(default="") name macros = + try find name macros with Not_found -> default + + let add_list l map = + List.fold_left (fun acc (k,v) -> add k v acc) map l + + let add_expand name def macros = + add name (expand macros def) macros + + let append_expand name def macros = + add name (get name macros ^ expand macros def) macros +end + (** configuration of a directory/test. *) type config = @@ -519,7 +587,7 @@ type config = dc_execnow : execnow list; (** command to be launched before the toplevel(s) *) - dc_macros: string StringMap.t; (** existing macros. *) + dc_macros: Macros.t; (** existing macros. *) dc_default_toplevel : string; (** full path of the default toplevel. *) dc_filter : string option; (** optional filter to apply to @@ -532,7 +600,11 @@ type config = } let default_macros () = - StringMap.add "frama-c" !toplevel_path StringMap.empty + let l = [ + "frama-c", !toplevel_path; + "PTEST_MAKE_MODULE", "make -s" + ] in + Macros.add_list l Macros.empty let default_config () = { dc_test_regexp = test_file_regexp ; @@ -570,48 +642,6 @@ let launch command_string = s command_string; exit 1 -let replace_macros macros s = - if !verbosity >=2 then begin - lock_printf "looking for macros in string %s\n%!" s; - lock_printf "Existing macros:\n%!"; - StringMap.iter (fun s1 s2 -> lock_printf "%s => %s\n%!" s1 s2) macros; - lock_printf "End macros\n%!"; - end; - let rec aux n (ptest_file_matched,s as acc) = - if Str.string_match macro_regex s n then begin - let macro = Str.matched_group 2 s in - let ptest_file_matched = ptest_file_matched || macro = "PTEST_FILE" in - let start = Str.matched_group 1 s in - let rest = Str.matched_group 3 s in - let new_n = Str.group_end 1 in - let n, new_s = - if macro = "" then begin - new_n + 1, String.sub s 0 new_n ^ "@" ^ rest - end else begin - try - if !verbosity >= 2 then lock_printf "macro is %s\n%!" macro; - let replacement = StringMap.find macro macros in - if !verbosity >= 1 then - lock_printf "replacement for %s is %s\n%!" macro replacement; - new_n, - String.sub s 0 n ^ start ^ replacement ^ rest - with - | Not_found -> Str.group_end 2 + 1, s - end - in - if !verbosity >= 2 then lock_printf "new string is %s\n%!" new_s; - let new_acc = ptest_file_matched, new_s in - if n <= String.length new_s then aux n new_acc else new_acc - end else acc - in - Mutex.lock str_mutex; - try - let res = aux 0 (false,s) in - Mutex.unlock str_mutex; res - with e -> - lock_eprintf "Uncaught exception %s\n%!" (Printexc.to_string e); - Mutex.unlock str_mutex; - raise e let scan_execnow ~once dir (s:string) = let rec aux (s:execnow) = @@ -675,7 +705,12 @@ let make_custom_opts = (* preserve options ordering *) List.fold_right (fun x s -> s ^ " " ^ x) opts "" -let add_macro s macros = + +(* how to process options *) +let config_exec ~once dir s current = + { current with dc_execnow = scan_execnow ~once dir s :: current.dc_execnow } + +let config_macro _dir s current = let regex = Str.regexp "[ \t]*\\([^ \t@]+\\)\\([ \t]+\\(.*\\)\\|$\\)" in Mutex.lock str_mutex; if Str.string_match regex s 0 then begin @@ -686,14 +721,20 @@ let add_macro s macros = Mutex.unlock str_mutex; if !verbosity >= 1 then lock_printf "new macro %s with definition %s\n%!" name def; - StringMap.add name (snd (replace_macros macros def)) macros + { current with dc_macros = Macros.add_expand name def current.dc_macros } end else begin Mutex.unlock str_mutex; lock_eprintf "cannot understand MACRO definition: %s\n%!" s; - macros + current end -(* how to process options *) +let config_module dir s current = + let make_cmd = "@PTEST_MAKE_MODULE@ " ^ s in + let make_cmd = Macros.expand current.dc_macros make_cmd in + let current = config_exec ~once:true dir make_cmd current in + let k = "PTEST_LOAD_MODULES" and v = " -load-module " ^ s in + { current with dc_macros = Macros.append_expand k v current.dc_macros } + let config_options = [ "CMD", (fun _ s current -> @@ -733,21 +774,14 @@ let config_options = "DONTRUN", (fun _ s current -> { current with dc_dont_run = true }); - "EXECNOW", - (fun dir s current -> - let execnow = scan_execnow ~once:true dir s in - { current with dc_execnow = execnow::current.dc_execnow }); - - "EXEC", - (fun dir s current -> - let execnow = scan_execnow ~once:false dir s in - { current with dc_execnow = execnow::current.dc_execnow }); - - "MACRO", (fun _ s current -> - { current with dc_macros = add_macro s current.dc_macros }); + "EXECNOW", config_exec ~once:true; + "EXEC", config_exec ~once:false; + "MACRO", config_macro; + "MODULE", config_module; "LOG", (fun _ s current -> { current with dc_default_log = s :: current.dc_default_log }) + ] let scan_options dir scan_buffer default = @@ -825,7 +859,7 @@ let scan_test_file default dir f = { default with dc_dont_run = true } type toplevel_command = - { macros: string StringMap.t; + { macros: Macros.t; mutable log_files: string list; file : string ; nb_files : int ; @@ -934,9 +968,7 @@ let get_macros cmd = "PTEST_NUMBER", string_of_int cmd.n; ] in - List.fold_left - (fun acc (macro,replace) -> StringMap.add macro replace acc) - cmd.macros macros + Macros.add_list macros cmd.macros let basic_command_string = let contains_toplevel_or_frama_c = @@ -944,22 +976,19 @@ let basic_command_string = in fun command -> let macros = get_macros command in - let logfiles = - List.fold_left - (fun acc s -> snd (replace_macros macros s) :: acc) - [] - command.log_files - in + let logfiles = List.map (Macros.expand macros) command.log_files in command.log_files <- logfiles; - let has_ptest_file_t, toplevel = replace_macros macros command.toplevel in - let has_ptest_file_o, options = replace_macros macros command.options in + let has_ptest_file_t, toplevel = Macros.does_expand macros command.toplevel in + let has_ptest_file_o, options = Macros.does_expand macros command.options in let toplevel = if !use_byte then opt_to_byte toplevel else toplevel in let options = if str_string_match contains_toplevel_or_frama_c command.toplevel 0 then begin - let opt_pre = snd (replace_macros macros !additional_options_pre) in - let opt_post = snd (replace_macros macros !additional_options) in - "-check " ^ opt_pre ^ " " ^ options ^ " " ^ opt_post + let opt_modules = Macros.expand macros + (Macros.get "PTEST_LOAD_MODULES" macros) in + let opt_pre = Macros.expand macros !additional_options_pre in + let opt_post = Macros.expand macros !additional_options in + "-check " ^ opt_modules ^ " " ^ opt_pre ^ " " ^ options ^ " " ^ opt_post end else options in let options = if !use_byte then opt_to_byte_options options else options in @@ -1083,11 +1112,7 @@ let update_toplevel_command command = Unix.Unix_error _ -> () end; let macros = get_macros command in - let log_files = - List.fold_left - (fun acc s -> snd (replace_macros macros s) :: acc) - [] - command.log_files + let log_files = List.map (Macros.expand macros) command.log_files in List.iter (update_log_files command.directory) log_files @@ -1605,7 +1630,7 @@ let dispatcher () = macros = config.dc_macros; execnow = true; } in - let process_macros s = snd (replace_macros config.dc_macros s) in + let process_macros s = Macros.expand config.dc_macros s in let make_execnow_cmd execnow = let res = { diff --git a/tests/misc/behavior_names.i b/tests/misc/behavior_names.i index d4e48cb5bf6..20a66a89448 100644 --- a/tests/misc/behavior_names.i +++ b/tests/misc/behavior_names.i @@ -1,6 +1,6 @@ /* run.config - EXECNOW: make -s @PTEST_DIR@/@PTEST_NAME@.cmxs - OPT: -no-autoload-plugins -load-module @PTEST_DIR@/@PTEST_NAME@.cmxs + MODULE: @PTEST_DIR@/@PTEST_NAME@.cmxs + OPT: -no-autoload-plugins */ /*@ behavior foo: ensures \true; */ diff --git a/tests/misc/debug_category.i b/tests/misc/debug_category.i index 4773466c671..5646776c8be 100644 --- a/tests/misc/debug_category.i +++ b/tests/misc/debug_category.i @@ -1,21 +1,21 @@ /* run.config -EXECNOW: make -s tests/misc/Debug_category.cmxs -OPT: -load-module tests/misc/Debug_category.cmxs -test-msg-key help -test-warn-key="a=inactive" -OPT: -load-module tests/misc/Debug_category.cmxs -test-msg-key a -test-warn-key="a=inactive" -OPT: -load-module tests/misc/Debug_category.cmxs -test-msg-key a -test-msg-key="-a:b" -test-warn-key="a=inactive" -OPT: -load-module tests/misc/Debug_category.cmxs -test-msg-key a -test-msg-key="-a:b" -test-msg-key a:b:c -test-warn-key="a=inactive" -OPT: -load-module tests/misc/Debug_category.cmxs -test-msg-key "a:b:c,d" -test-warn-key="a=inactive" -OPT: -load-module tests/misc/Debug_category.cmxs -test-msg-key "*" -test-warn-key="a=inactive" -OPT: -load-module tests/misc/Debug_category.cmxs -OPT: -load-module tests/misc/Debug_category.cmxs -test-warn-key a=error -OPT: -load-module tests/misc/Debug_category.cmxs -test-warn-key a=abort -OPT: -load-module tests/misc/Debug_category.cmxs -test-warn-key a=feedback -OPT: -load-module tests/misc/Debug_category.cmxs -test-warn-key="*=abort" -OPT: -load-module tests/misc/Debug_category.cmxs -test-warn-key=a=once -OPT: -load-module tests/misc/Debug_category.cmxs -test-warn-key a=feedback-once -OPT: -load-module tests/misc/Debug_category.cmxs -test-warn-key a=err-once -OPT: -load-module tests/misc/Debug_category.cmxs -test-warn-key test-vis-err -OPT: -load-module tests/misc/Debug_category.cmxs -test-warn-key test-inv-err -OPT: -load-module tests/misc/Debug_category.cmxs -test-warn-key test-failure +MODULE: tests/misc/Debug_category.cmxs +OPT: -test-msg-key help -test-warn-key="a=inactive" +OPT: -test-msg-key a -test-warn-key="a=inactive" +OPT: -test-msg-key a -test-msg-key="-a:b" -test-warn-key="a=inactive" +OPT: -test-msg-key a -test-msg-key="-a:b" -test-msg-key a:b:c -test-warn-key="a=inactive" +OPT: -test-msg-key "a:b:c,d" -test-warn-key="a=inactive" +OPT: -test-msg-key "*" -test-warn-key="a=inactive" +OPT: +OPT: -test-warn-key a=error +OPT: -test-warn-key a=abort +OPT: -test-warn-key a=feedback +OPT: -test-warn-key="*=abort" +OPT: -test-warn-key=a=once +OPT: -test-warn-key a=feedback-once +OPT: -test-warn-key a=err-once +OPT: -test-warn-key test-vis-err +OPT: -test-warn-key test-inv-err +OPT: -test-warn-key test-failure FILTER: sed 's|Your Frama-C version is.*|Your Frama-C version is VERSION|' */ -- GitLab