package ortac-dune

  1. Overview
  2. Docs

Source file qcheck_stm.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
type config = {
  interface_file : string;
  config_file : string option;
  ocaml_output : string option;
  library : string option;
  package_name : string option;
  dune_output : string option;
  module_prefix : string option;
  submodule : string option;
  fork_timeout : int option;
}

open Fmt

let get_optional proj suffix config =
  let default =
    str "%s_%s"
      Filename.(basename config.interface_file |> chop_extension)
      suffix
  in
  Option.value (proj config) ~default

let get_config_file = get_optional (fun cfg -> cfg.config_file) "config.ml"
let get_ocaml_output = get_optional (fun cfg -> cfg.ocaml_output) "tests.ml"

let msg ppf config =
  pf ppf
    "; This file is generated by ortac dune qcheck-stm@\n\
     ; It contains the rules for generating and running QCheck-STM tests for %s@\n"
    config.interface_file

let stanza k ppf config = pf ppf "@[<v 1>(%a)@]" k config
let stanza_rule k ppf config = pf ppf "%a@." (stanza k) config

let with_target k ppf config =
  let k ppf config = pf ppf "with-stdout-to@;%s@;%a" "%{targets}" k config in
  stanza k ppf config

let setenv var value k ppf =
  let k ppf config = pf ppf "setenv@;%s@;%s@;%a" var value k config in
  stanza k ppf

let action ppf k =
  let k ppf config = pf ppf "action@;%a" k config in
  stanza k ppf

let action_with_env var value ppf k =
  let k ppf = setenv var value k ppf in
  action ppf k

let rule ppf stanzas = pf ppf "rule@;%a" (concat stanzas)
let test ppf stanzas = pf ppf "test@;%a" (concat stanzas)
let run ppf args = pf ppf "run@;%a" (concat args)
let ortac ppf _ = pf ppf "ortac"
let qcheck_stm ppf _ = pf ppf "qcheck-stm"
let interface ppf config = pf ppf "%s" config.interface_file
let config_file ppf config = pf ppf "%s" (get_config_file config)
let runtest ppf _ = pf ppf "(alias runtest)"
let promote ppf _ = pf ppf "(mode promote)"

let name ppf config =
  pf ppf "(name %s)" (Filename.chop_extension @@ get_ocaml_output config)

let dep aux ppf config = pf ppf "%%{dep:%a}" aux config

let libraries =
  let library ppf config =
    pf ppf "%s@;"
      (Option.value config.library
         ~default:Filename.(basename config.interface_file |> chop_extension))
  in
  let k ppf config =
    pf ppf
      "libraries@ %aqcheck-stm.stm@ qcheck-stm.sequential@ \
       qcheck-multicoretests-util@ ortac-runtime-qcheck-stm"
      library config
  in
  stanza k

let package s ppf =
  let k ppf _ = pf ppf "package %s" s in
  stanza k ppf

let deps ppf = pf ppf "(deps@; %a)" (package "ortac-qcheck-stm")
let quiet ppf _ = pf ppf "--quiet"

let package config =
  match config.package_name with
  | None -> []
  | Some s -> [ (fun ppf _ -> pf ppf "(package %s)" s) ]

let targets_ml ppf config = pf ppf "(targets %s)" @@ get_ocaml_output config

let optional_argument s prj cfg =
  Option.to_list
  @@ Option.map (fun pref ppf _ -> pf ppf "%s=%s" s pref) (prj cfg)

let module_prefix =
  optional_argument "--module-prefix" (fun cfg -> cfg.module_prefix)

let submodule = optional_argument "--submodule" (fun cfg -> cfg.submodule)

let gen_ortac_rule ppf config =
  let args =
    ortac
    :: qcheck_stm
    :: dep interface
    :: dep config_file
    :: quiet
    :: module_prefix config
    @ submodule config
  in
  let run ppf = run ppf args in
  let run = stanza run in
  let action ppf =
    action_with_env "ORTAC_ONLY_PLUGIN" "qcheck-stm" ppf (with_target run)
  in
  let stanzas =
    [ runtest; promote ] @ package config @ [ deps; targets_ml; action ]
  in
  let rule ppf = rule ppf stanzas in
  stanza_rule rule ppf config

let gen_test_rule ppf config =
  let modules ppf config =
    pf ppf "(modules %s)" (Filename.chop_extension @@ get_ocaml_output config)
  in
  let run ppf =
    run ppf
      [
        (fun ppf _ -> pf ppf "%s" "%{test}"); (fun ppf _ -> pf ppf "--verbose");
      ]
  in
  let action ppf =
    match config.fork_timeout with
    | None -> action ppf (stanza run)
    | Some timeout ->
        action_with_env "ORTAC_QCHECK_STM_TIMEOUT" (string_of_int timeout) ppf
          (stanza run)
  in
  let test ppf =
    test ppf @@ [ name; modules; libraries ] @ package config @ [ action ]
  in
  stanza_rule test ppf config

let gen_dune_rules ppf config =
  let rules = [ msg; gen_ortac_rule; gen_test_rule ] in
  concat ~sep:cut rules ppf config
OCaml

Innovation. Community. Security.