From fb6fdca8d4986b099dd7afc0f1f05e2058997ddc Mon Sep 17 00:00:00 2001
From: Erwan Jahier <erwan.jahier@univ-grenoble-alpes.fr>
Date: Thu, 26 Jan 2023 16:44:06 +0100
Subject: [PATCH] test: add a few qtest tests

---
 Makefile                  |  2 +-
 Makefile.sasa             |  3 ---
 lib/qtest/dune            | 29 ++++++++++++++++++++++++++++
 lib/sasacore/daemon.ml    | 26 ++++++++++++++-----------
 lib/sasacore/daemon.mli   | 13 +++++++------
 lib/sasacore/dune         |  7 +++++--
 lib/sasacore/enumerate.ml | 25 +++++++++++++++++++-----
 lib/sasacore/worstInit.ml | 40 +++++++++++++++++++++------------------
 sasa.opam                 |  1 +
 9 files changed, 100 insertions(+), 46 deletions(-)
 create mode 100644 lib/qtest/dune

diff --git a/Makefile b/Makefile
index d1c5913d..0dbdbb93 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 
 
 build: lib/sasacore/sasaVersion.ml
-	dune build  @install
+	dune build  @install @runtest
 
 install:
 	dune install
diff --git a/Makefile.sasa b/Makefile.sasa
index 58072565..80d32457 100644
--- a/Makefile.sasa
+++ b/Makefile.sasa
@@ -1,8 +1,5 @@
 
 
-build: lib/sasacore/sasaVersion.ml
-	dune build  @install
-
 
 .PHONY:test
 test:
diff --git a/lib/qtest/dune b/lib/qtest/dune
new file mode 100644
index 00000000..85d7f9ae
--- /dev/null
+++ b/lib/qtest/dune
@@ -0,0 +1,29 @@
+;;; the qtest documentatiopn wrt its use of dune is helpless
+;; this file is my solution to do it by hand
+
+(rule
+ (targets run_qtest.ml)
+  (deps (source_tree ../sasacore))
+  ; here is where you need to tell qtest what files to consider
+
+  (action
+   (run qtest --preamble "open Sasacore\nopen Daemon\nopen Enumerate"
+	extract ../sasacore/daemon.ml ../sasacore/enumerate.ml -o %{targets})
+   )
+
+  )
+
+(executable
+  (name run_qtest)
+  (modules run_qtest)
+  ; disable some warnings in qtests
+  (flags :standard -warn-error -a -w -33-35-27-39)
+  (libraries qcheck  dynlink ocamlgraph lutils sasacore algo)
+
+;   (action  (run %{target}))
+  )
+
+(rule
+ (alias runtest)
+ (action
+  (run ./run_qtest.exe)))
diff --git a/lib/sasacore/daemon.ml b/lib/sasacore/daemon.ml
index 24781ad2..cace17b5 100644
--- a/lib/sasacore/daemon.ml
+++ b/lib/sasacore/daemon.ml
@@ -1,6 +1,6 @@
-(* Time-stamp: <modified the 21/10/2021 (at 14:17) by Erwan Jahier> *)
+(* Time-stamp: <modified the 25/01/2023 (at 16:47) by Erwan Jahier> *)
 
-(* Enabled processes (with its enabling action + neighbors) *)           
+(* Enabled processes (with its enabling action + neighbors) *)
 type 'v pna = 'v Process.t * 'v Register.neighbor list * Register.action
 type 'v enabled = 'v pna list list
 type 'v triggered = 'v pna list
@@ -16,14 +16,14 @@ let (random_list2 : 'a list -> 'a * 'a list) = fun l ->
   assert (l <> []);
   let rec split acc i = function
     | [] -> assert false (* sno *)
-    | x::l -> 
+    | x::l ->
       if i=0 then x, List.rev_append acc l else split (x::acc) (i-1) l
   in
   let i = Random.int (List.length l) in
   split [] i l
 
 let (central: 'a list list -> 'a list) =
-  fun all -> 
+  fun all ->
     if all = [] then [] else
       let al = List.map random_list all in
       let a = random_list al in
@@ -36,13 +36,13 @@ let rec (distributed: 'a list list -> 'a list) =
       let al = List.map random_list all in
       let al = List.filter (fun _ -> Random.bool ()) al in
       if al = [] then distributed all else al
-   
+
 let (synchrone: 'a list list -> 'a list) = fun all ->
   if all = [] then [] else
   let al = List.map random_list all in
   al
 
-(* LC= 2 neighbors cannot be activated at the same step 
+(* LC= 2 neighbors cannot be activated at the same step
 
 XXX this daemon is not fair: it is biased by the degree of nodes.
 *)
@@ -94,11 +94,15 @@ let rec map3 f l1 l2 l3 =
   | ([], _, _) -> invalid_arg "map3 (1st arg too short)"
   | (_, [], _) -> invalid_arg "map3 (2nd arg too short)"
   | (_, _, []) -> invalid_arg "map3 (3rd arg too short)"
-  
+
+(*$T map3
+  map3 (fun x y z -> x-y+z) [1;2;3] [1;2;3] [1;2;3] = [1;2;3]
+  map3 (fun x y z -> x-y+z) [] [] [] = []
+*)
 
 let (custom: 'v enabled -> 'v Process.t list -> bool list list ->
      (string -> string -> bool) -> bool list list * 'v triggered) =
-  fun pnall pl enab_ll get_action_value -> 
+  fun pnall pl enab_ll get_action_value ->
     let f p pnal enab_l =
       let actions = p.Process.actions in
       let trigger_l = List.map (get_action_value p.Process.pid) actions in
@@ -107,12 +111,12 @@ let (custom: 'v enabled -> 'v Process.t list -> bool list list ->
           (fun trig enab a ->
              let acti = trig && enab in
              acti, if acti
-             then List.filter (fun (_,_,a') -> a=a') pnal 
+             then List.filter (fun (_,_,a') -> a=a') pnal
              else []
           ) trigger_l enab_l actions
       in
       acti_l_al
-    in    
+    in
     let acti_l_all = map3 f pl pnall enab_ll in
     let acti_l_al = List.flatten acti_l_all in
     let al = snd (List.split acti_l_al) in
@@ -131,7 +135,7 @@ let (get_activate_val: 'v triggered -> 'v Process.t list -> bool list list)=
       List.map (fun p -> List.map (fun a -> p,a) p.Process.actions) pl
     in
     let al = List.map (fun (p,_,a) -> p,a) al in
-    List.map  (List.map (fun a -> List.mem a al)) actions 
+    List.map  (List.map (fun a -> List.mem a al)) actions
 
 let (f: bool -> bool -> DaemonType.t -> 'v Process.t list ->
      ('v SimuState.t -> string -> 'v * ('v Register.neighbor * string) list) ->
diff --git a/lib/sasacore/daemon.mli b/lib/sasacore/daemon.mli
index 487faa7d..1cc210ab 100644
--- a/lib/sasacore/daemon.mli
+++ b/lib/sasacore/daemon.mli
@@ -1,17 +1,17 @@
-(* Time-stamp: <modified the 15/10/2021 (at 11:04) by Erwan Jahier> *)
+(* Time-stamp: <modified the 25/01/2023 (at 16:07) by Erwan Jahier> *)
 
 type 'v pna = 'v Process.t * 'v Register.neighbor list * Register.action
 type 'v enabled = 'v pna list list
 type 'v triggered = 'v pna list
-            
+
 (** f dummy_input_flag verbose_mode daemon p_nl_l actions_ll enab
 
 inputs:
-- dummy_input_flag: true when used with --ignore-first-inputs 
+- dummy_input_flag: true when used with --ignore-first-inputs
 - verbose_mode: true when the verbose level is > 0
-- daemon: 
+- daemon:
 - p_nl_l: list of all processes, and their neighbors
-- actions_ll: list of list of existing actions 
+- actions_ll: list of list of existing actions
 - enab: list of list saying which actions are enabled
 
     At the inner list level, exactly one action ought to be chosen. At the
@@ -31,7 +31,7 @@ nb: it is possible that we read on stdin that an action should be
 *)
 
 type 'v step = 'v triggered -> 'v SimuState.t -> 'v SimuState.t
-            
+
 val f : bool -> bool -> DaemonType.t -> 'v Process.t list ->
   ('v SimuState.t -> string -> 'v * ('v Register.neighbor * string) list) ->
   'v SimuState.t -> 'v enabled -> bool list list ->
@@ -45,3 +45,4 @@ val distributed: 'a list list -> 'a list
 
 (* pid + its neighbors in input *)
 val locally_central: ('v * 'v list) list list -> 'v list
+val map3 : ('a -> 'b -> 'c -> 'd) -> 'a list -> 'b list -> 'c list  -> 'd list
diff --git a/lib/sasacore/dune b/lib/sasacore/dune
index 460dd67f..699e4afa 100644
--- a/lib/sasacore/dune
+++ b/lib/sasacore/dune
@@ -1,16 +1,19 @@
-;; Time-stamp: <modified the 05/10/2021 (at 09:59) by Erwan Jahier>
+;; Time-stamp: <modified the 26/01/2023 (at 16:42) by Erwan Jahier>
 
 (library
  (name     sasacore)
  (public_name  sasacore)
  (libraries dynlink ocamlgraph lutils psq functory)
  ; (flags -noassert)
-  ;; 
+  ;;
 ; (wrapped false)
+ ; (inline_tests (backend qtest.lib)) ;; does not work );
  (library_flags -linkall)
  (synopsis "The Sasa main files (shared by the sasa exec and the rdbg plugin)")
 )
 
+;; qtest does not work with dune anyway (would require 'wrapped false')
+;; cf ../qtest/dune for a workaround
 
 ; (modules_without_implementation algo)
 
diff --git a/lib/sasacore/enumerate.ml b/lib/sasacore/enumerate.ml
index 04313f26..841e360e 100644
--- a/lib/sasacore/enumerate.ml
+++ b/lib/sasacore/enumerate.ml
@@ -1,6 +1,6 @@
 
 
-(* Enumerate all schedules using continuations *) 
+(* Enumerate all schedules using continuations *)
 type 'a cont = NoMore | Elt of 'a * (unit -> 'a cont)
 
 (* compose continuations *)
@@ -8,9 +8,9 @@ let rec (comp : 'a cont -> 'a cont -> 'a cont) =
   fun c1 c2 ->
   match c1 with
   | NoMore -> c2
-  | Elt(x, c1) -> Elt(x, fun () -> comp (c1()) c2) 
-                             
-(* Enumerate all possible schedules (with one action per process at most) 
+  | Elt(x, c1) -> Elt(x, fun () -> comp (c1()) c2)
+
+(* Enumerate all possible schedules (with one action per process at most)
    nb: it can be a lot!
 *)
 let (all : 'a list list -> 'a list cont) = fun all ->
@@ -25,7 +25,7 @@ let (all : 'a list list -> 'a list cont) = fun all ->
              let cont_a = f (a::acc) tl in
              comp cont_a cont_acc
            )
-           (f acc tl) 
+           (f acc tl)
            al
     in
     res
@@ -39,6 +39,7 @@ let (central : 'a list list -> 'a cont) = fun all ->
   List.fold_left (fun acc a -> Elt(a, fun () -> acc)) NoMore al
 
 
+
 let (all_list : 'a list list -> 'a list list) = fun ll ->
   let rec f acc c =
     match c with
@@ -47,8 +48,22 @@ let (all_list : 'a list list -> 'a list list) = fun ll ->
   in
   f [] (all ll)
 
+let sort_ll ll =
+  ll |> List.map (List.sort compare) |> List.sort compare
+
+(*$T all_list
+   sort_ll (all_list [ [1] ;[2]; [3]; [] ]) = sort_ll [ [1]; [2]; [3]; [1;2]; [1;3]; [2;3]; [1;2;3] ];
+   sort_ll (all_list [ [1;2]; [3]; [] ])    = sort_ll [ [1]; [2]; [3]; [1;3]; [2;3] ];
+ *)
+
 let (central_list : 'a list list -> 'a list list) = fun all ->
   let al = List.flatten all in
   List.map (fun x -> [x]) al
 
 
+let string_of_int_ll ll =
+  "[" ^ (String.concat "," (List.map (fun l -> "[" ^ (String.concat "," l ^ "]")) ll)) ^ "]"
+
+(*$T central_list
+    List.sort compare (central_list [ [1;2]; [3]; [4;5] ]) = [ [1]; [2]; [3]; [4]; [5] ];
+ *)
diff --git a/lib/sasacore/worstInit.ml b/lib/sasacore/worstInit.ml
index c8826f2d..17827b39 100644
--- a/lib/sasacore/worstInit.ml
+++ b/lib/sasacore/worstInit.ml
@@ -1,4 +1,4 @@
-(* Time-stamp: <modified the 28/11/2022 (at 17:41) by Erwan Jahier> *)
+(* Time-stamp: <modified the 25/01/2023 (at 15:24) by Erwan Jahier> *)
 
 open Register
 
@@ -70,23 +70,27 @@ let all_dim_succ d n =
     p.(j) <- mutate_value d p.(j)
   done;
   p
-    
-      
+
+
 let tf = float_of_int
 let ti = int_of_float
-    
+
 let (choose : int -> point -> (point -> point) -> point list) =
   fun n p heuristic ->
-  (*choose n successors of p using heuristic *)  
+  (*choose n successors of p using heuristic *)
   assert (n>=0);
   let rec f acc i = if i <= 0 then acc else f ((heuristic p)::acc)  (i-1) in
   f [] n
 
+(*$T choose
+  List.length (choose 10 [| F(10.), F(42.) |] (one_dim_succ Close)) = 10
+*)
+
 (*****************************************************************************)
 (* XXX a ranger ailleurs !!! *)
 
 open Process
-    
+
 let (point_to_ss : point -> 'v SimuState.t -> 'v SimuState.t) =
   fun point ss ->
   let (state_to_values, values_to_state :
@@ -110,8 +114,8 @@ let (point_to_ss : point -> 'v SimuState.t -> 'v SimuState.t) =
     in
     f l i j
   in
-  let new_config, _ = 
-    List.fold_left 
+  let new_config, _ =
+    List.fold_left
     (fun (e,j) p ->
        let value = make_value [] state_size (j*state_size) in
        let st = values_to_state value (Conf.get e p.pid) in
@@ -124,7 +128,7 @@ let (point_to_ss : point -> 'v SimuState.t -> 'v SimuState.t) =
   if debug then Printf.printf "point_to_ss  ok\n%!";
   { ss with config = new_config }
 
-    
+
 let (ss_to_point : 'v SimuState.t -> point) =
   fun ss ->
   let (state_to_values : ('v -> Register.value list) ) =
@@ -152,7 +156,7 @@ let (ss_to_point : 'v SimuState.t -> point) =
     ss.network;
   point
 (*****************************************************************************)
-    
+
 open LocalSearch
 
 
@@ -189,10 +193,10 @@ let (fchc : out_channel -> ('v SimuState.t -> int) -> 'v SimuState.t -> int
   let step_cpt = ref 1 in
   let cost p = run (point_to_ss p ss_init) in
   let pinit = ss_to_point ss_init in
-  let percent_done = ref 0 in  
+  let percent_done = ref 0 in
   Functory.Cores.set_number_of_cores ss_init.sasarg.cores_nb;
   let g =
-    { 
+    {
       init = ({ st = pinit ; d = 0 ; cost = cost pinit ; cpt = 0 }, Q.empty, ());
       succ = (fun n ->
           (* let beam_size = min 50 (max 1 (dmax / 10)) in *)
@@ -206,7 +210,7 @@ let (fchc : out_channel -> ('v SimuState.t -> int) -> 'v SimuState.t -> int
           let beam_size = max 50 ss_init.sasarg.cores_nb in
           let percent_close = ((tf !cpt) /. (tf dmax)) ** 2.0 in
           let percent_far = 1.0 -. percent_close in
-          
+
           let far_nb = max 1 (ti ((tf beam_size) *. percent_far) / 6) in
           let close_nb = max 1 (ti ((tf beam_size) *. percent_close) / 6) in
           incr step_cpt;
@@ -264,10 +268,10 @@ let (fchc : out_channel -> ('v SimuState.t -> int) -> 'v SimuState.t -> int
         | LocalSearch.NoMore ->
           (* occurs if all successors are cut *)
           run_more psol more
-        | LocalSearch.Stopped -> 
+        | LocalSearch.Stopped ->
           Printf.printf "\nThe worst initial configuration costs %d :" psol.cost;
           point_to_ss psol.st ss_init
-        | LocalSearch.Sol (nsol, more) ->          
+        | LocalSearch.Sol (nsol, more) ->
             if nsol.cost > psol.cost then (
               Printf.printf "Hey, I've found a conf of cost %d! (simu #%d, depth %d)\n%!"
                 nsol.cost nsol.cpt nsol.d;
@@ -276,8 +280,8 @@ let (fchc : out_channel -> ('v SimuState.t -> int) -> 'v SimuState.t -> int
               run_more psol more
             )
       )
-  
-  in  
+
+  in
   match LocalSearch.run g None with
   | LocalSearch.Stopped -> assert false (* SNO *)
   | LocalSearch.NoMore-> assert false (* SNO *)
@@ -329,5 +333,5 @@ let (global : out_channel -> ('v SimuState.t -> int) -> 'v SimuState.t -> int
         n_percent_done dmax
     );
     if cpt > dmax then ss_worst else loop (cpt+1) (ss_worst, worst)
-  in 
+  in
   loop 1 (ss_init, run ss_init)
diff --git a/sasa.opam b/sasa.opam
index 6f74f287..92a8c50a 100644
--- a/sasa.opam
+++ b/sasa.opam
@@ -23,6 +23,7 @@ depends: [
   "conf-graphviz"
   "lutils"
   "psq"
+  "qtest"
   "functory"
   "ledit"
   "rdbg" { >= "1.200" }
-- 
GitLab