Source file rpc_genfake.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
(* Generate typed values *)

open Rpc.Types

type err = [ `Msg of string ]

let badstuff msg = failwith (Printf.sprintf "Failed to construct the record: %s" msg)

let rec gentest : type a. a typ -> a list =
 fun t ->
  match t with
  | Basic Int -> [ 0; 1; max_int; -1; 1000000 ]
  | Basic Int32 -> [ 0l; 1l; Int32.max_int; -1l; 999999l ]
  | Basic Int64 -> [ 0L; 1L; Int64.max_int; -1L; 999999999999L ]
  | Basic Bool -> [ true; false ]
  | Basic Float -> [ 0.0; max_float; min_float; -1.0 ]
  | Basic String ->
    [ "Test string"
    ; ""
    ; "ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ \
       ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ"
    ; "\000foo"
    ]
  | Basic Char -> [ '\000'; 'a'; 'z'; '\255' ]
  | DateTime -> [ "19700101T00:00:00Z" ]
  | Base64 -> [ "SGVsbG8sIHdvcmxkIQ==" (* "Hello, world!" *) ]
  | Array typ -> [ gentest typ |> Array.of_list; [||] ]
  | List typ -> [ gentest typ; [] ]
  | Dict (basic, typ) ->
    let keys = gentest (Basic basic) in
    let vs = gentest typ in
    let x =
      List.fold_left
        (fun (acc, l2) v ->
          match l2 with
          | x :: xs -> (v, x) :: acc, xs
          | [] -> (v, List.hd vs) :: acc, List.tl vs)
        ([], vs)
        keys
      |> fst
    in
    [ x ]
  | Unit -> [ () ]
  | Option t ->
    let vs = gentest t in
    None :: List.map (fun x -> Some x) vs
  | Tuple (t1, t2) ->
    let v1s = gentest t1 in
    let v2s = gentest t2 in
    List.map (fun v1 -> List.map (fun v2 -> v1, v2) v2s) v1s |> List.flatten
  | Tuple3 (t1, t2, t3) ->
    let v1s = gentest t1 in
    let v2s = gentest t2 in
    let v3s = gentest t3 in
    List.map (fun v1 -> List.map (fun v2 -> List.map (fun v3 -> v1, v2, v3) v3s) v2s) v1s
    |> List.flatten
    |> List.flatten
  | Tuple4 (t1, t2, t3, t4) ->
    let v1s = gentest t1 in
    let v2s = gentest t2 in
    let v3s = gentest t3 in
    let v4s = gentest t4 in
    List.map
      (fun v1 ->
        List.map
          (fun v2 -> List.map (fun v3 -> List.map (fun v4 -> v1, v2, v3, v4) v4s) v3s)
          v2s)
      v1s
    |> List.flatten
    |> List.flatten
    |> List.flatten
  | Struct { constructor; _ } ->
    let rec gen_n acc n =
      match n with
      | 0 -> acc
      | n ->
        let field_get : type a. string -> a typ -> (a, Rresult.R.msg) Result.t =
         fun _ ty ->
          let vs = gentest ty in
          Result.Ok (List.nth vs (Random.int (List.length vs)))
        in
        (match constructor { field_get } with
        | Result.Ok x -> gen_n (x :: acc) (n - 1)
        | Result.Error (`Msg y) -> badstuff y)
    in
    gen_n [] 10
  | Variant { variants; _ } ->
    List.map
      (function
        | Rpc.Types.BoxedTag v ->
          let contents = gentest v.tcontents in
          let content = List.nth contents (Random.int (List.length contents)) in
          v.treview content)
      variants
  | Abstract { test_data; _ } -> test_data


let thin d result = if d < 0 then [ List.hd result ] else result

let rec genall : type a. int -> string -> a typ -> a list =
 fun depth strhint t ->
  match t with
  | Basic Int -> [ 0 ]
  | Basic Int32 -> [ 0l ]
  | Basic Int64 -> [ 0L ]
  | Basic Bool -> thin depth [ true; false ]
  | Basic Float -> [ 0.0 ]
  | Basic String -> [ strhint ]
  | Basic Char -> [ 'a' ]
  | DateTime -> [ "19700101T00:00:00Z" ]
  | Base64 -> [ "SGVsbG8sIHdvcmxkIQ==" (* "Hello, world!" *) ]
  | Array typ -> thin depth [ genall (depth - 1) strhint typ |> Array.of_list; [||] ]
  | List typ -> thin depth [ genall (depth - 1) strhint typ; [] ]
  | Dict (basic, typ) ->
    let keys = genall (depth - 1) strhint (Basic basic) in
    let vs = genall (depth - 1) strhint typ in
    let x = List.map (fun k -> List.map (fun v -> [ k, v ]) vs) keys in
    List.flatten x |> thin depth
  | Unit -> [ () ]
  | Option t ->
    let vs = genall (depth - 1) strhint t in
    thin depth (List.map (fun x -> Some x) vs @ [ None ])
  | Tuple (t1, t2) ->
    let v1s = genall (depth - 1) strhint t1 in
    let v2s = genall (depth - 1) strhint t2 in
    List.map (fun v1 -> List.map (fun v2 -> v1, v2) v2s) v1s |> List.flatten |> thin depth
  | Tuple3 (t1, t2, t3) ->
    let v1s = genall (depth - 1) strhint t1 in
    let v2s = genall (depth - 1) strhint t2 in
    let v3s = genall (depth - 1) strhint t3 in
    let l =
      List.map
        (fun v1 -> List.map (fun v2 -> List.map (fun v3 -> v1, v2, v3) v3s) v2s)
        v1s
    in
    l |> List.flatten |> List.flatten |> thin depth
  | Tuple4 (t1, t2, t3, t4) ->
    let v1s = genall (depth - 1) strhint t1 in
    let v2s = genall (depth - 1) strhint t2 in
    let v3s = genall (depth - 1) strhint t3 in
    let v4s = genall (depth - 1) strhint t4 in
    let l =
      List.map
        (fun v1 ->
          List.map
            (fun v2 -> List.map (fun v3 -> List.map (fun v4 -> v1, v2, v3, v4) v4s) v3s)
            v2s)
        v1s
    in
    l |> List.flatten |> List.flatten |> List.flatten |> thin depth
  | Struct { constructor; fields; _ } ->
    let fields_maxes =
      List.map
        (function
          | BoxedField f ->
            let n = List.length (genall (depth - 1) strhint f.field) in
            f.fname, n)
        fields
    in
    let all_combinations =
      List.fold_left
        (fun acc (f, max) ->
          let rec inner n = if n = 0 then [] else (f, n) :: inner (n - 1) in
          let ns = inner max in
          List.map (fun (f, n) -> List.map (fun dict -> (f, n - 1) :: dict) acc) ns
          |> List.flatten)
        [ [] ]
        fields_maxes
    in
    List.map
      (fun combination ->
        let field_get : type a. string -> a typ -> (a, Rresult.R.msg) Result.t =
         fun fname ty ->
          let n = List.assoc fname combination in
          let vs = genall (depth - 1) fname ty in
          Result.Ok (List.nth vs n)
        in
        match constructor { field_get } with
        | Result.Ok x -> x
        | Result.Error (`Msg y) -> badstuff y)
      all_combinations
    |> thin depth
  | Variant { variants; _ } ->
    List.map
      (function
        | Rpc.Types.BoxedTag v ->
          let contents = genall (depth - 1) strhint v.tcontents in
          List.map (fun content -> v.treview content) contents)
      variants
    |> List.flatten
    |> thin depth
  | Abstract { test_data; _ } -> test_data


let rec gen_nice : type a. a typ -> string -> a =
 fun ty hint ->
  let narg n = Printf.sprintf "%s_%d" hint n in
  match ty with
  | Basic Int -> 0
  | Basic Int32 -> 0l
  | Basic Int64 -> 0L
  | Basic Bool -> true
  | Basic Float -> 0.0
  | Basic String -> hint
  | Basic Char -> 'a'
  | DateTime -> "19700101T00:00:00Z"
  | Base64 -> "SGVsbG8sIHdvcmxkIQ==" (* "Hello, world!" *)
  | Array typ -> [| gen_nice typ (narg 1); gen_nice typ (narg 2) |]
  | List (Tuple (Basic String, typ)) ->
    [ "field_1", gen_nice typ "value_1"; "field_2", gen_nice typ "value_2" ]
  | List typ -> [ gen_nice typ (narg 1); gen_nice typ (narg 2) ]
  | Dict (String, typ) ->
    [ "field_1", gen_nice typ "value_1"; "field_2", gen_nice typ "value_2" ]
  | Dict (basic, typ) ->
    [ gen_nice (Basic basic) "field_1", gen_nice typ (narg 1)
    ; gen_nice (Basic basic) "field_2", gen_nice typ (narg 2)
    ]
  | Unit -> ()
  | Option ty -> Some (gen_nice ty (Printf.sprintf "optional_%s" hint))
  | Tuple (x, y) -> gen_nice x (narg 1), gen_nice y (narg 2)
  | Tuple3 (x, y, z) -> gen_nice x (narg 1), gen_nice y (narg 2), gen_nice z (narg 3)
  | Tuple4 (x, y, z, a) ->
    gen_nice x (narg 1), gen_nice y (narg 2), gen_nice z (narg 3), gen_nice a (narg 4)
  | Struct { constructor; _ } ->
    let field_get : type a. string -> a typ -> (a, Rresult.R.msg) Result.t =
     fun name ty -> Result.Ok (gen_nice ty name)
    in
    (match constructor { field_get } with
    | Result.Ok x -> x
    | Result.Error (`Msg y) -> badstuff y)
  | Variant { variants; _ } ->
    List.hd variants
    |> (function
    | Rpc.Types.BoxedTag v ->
      let content = gen_nice v.tcontents v.tname in
      v.treview content)
  | Abstract { test_data; _ } -> List.hd test_data