In order to test an encoding library (à la json-typed) I'm having to generate values for a recursive type with some specific restrictions. Here's a simplified version:
type 'a e =
| Ranged_int: (int * int) -> int e
| List: 'a t -> 'a list e
| Tuple: 'a t * 'b t -> ('a * 'b) t
(* other constructors omitted *)
This type describes ways to encode/decode values and can be passed to the following functions:
val constr: 'a e -> 'a -> json
val destr: 'a e -> json -> 'a result
Note that in int list t, all integers must share the same range. And similarly, in int list list t, int list list list t, etc. However, in a tuple, each side can be of different rangedness.
This lends itself nicely to a generator such as:
let rec gengen: ('a e * 'a gen) gen = fix (fun gen ->
choose [
map [int; int] (fun min max -> Ranged_int (min, max), range ~min (max - min));
map [gen] (fun (e, g) -> List e, list g);
map [gen; gen] (fun (e1, g1) (e2, g2) -> Tuple (e1, e2), map [g1, g2] (fun v1 v2 -> (v1, v2)));
])
Which needs some form of bind to extricate the nested gen.
let gen =
bind gengen (fun (e, g) ->
bind g (fun v ->
return (e, v)
))
Is this doable with the current interface? I don't think it is, but maybe I missed some combinator trickery.
Is it possible to implement?
There are alternatives:
providing a join operator
providing a way to add more tests from within a test (e.g., a function gen_tests that's like add_test except it just queues more tests for later)
In order to test an encoding library (à la json-typed) I'm having to generate values for a recursive type with some specific restrictions. Here's a simplified version:
This type describes ways to encode/decode values and can be passed to the following functions:
Note that in
int list t
, all integers must share the same range. And similarly, inint list list t
,int list list list t
, etc. However, in a tuple, each side can be of different rangedness.This lends itself nicely to a generator such as:
Which needs some form of
bind
to extricate the nestedgen
.Is this doable with the current interface? I don't think it is, but maybe I missed some combinator trickery. Is it possible to implement?
There are alternatives:
join
operatorgen_tests
that's likeadd_test
except it just queues more tests for later)