Hi,
Recently I’ve started to use ppx_expect
accompanied by ppx_deriving
(show plugin) for writing unit tests. Alongside with the latest test integration in dune
this creates the great workflow, where I can easily review diffs and update tests.
There was one problem I encountered though, which I may need some help with. The function I’m testing returns the data structure which includes absolute file paths. Here is an example:
type resolved = (Fastpack.Module.location * string list) [@@deriving show]
let%expect_test "." =
resolve ".";
[%expect_exact {|
((File {
filename = (Some "/Users/zindel/ocaml/fastpack/test/resolve/index.js");
preprocessors = []
}),
[])
|}]
In order to make the test reproducible on other environments where the root path may be different , I am collecting the show_resolved
output and replacing project root with some constant string in it. The code above becomes:
type resolved = (Fastpack.Module.location * string list) [@@deriving show]
let%expect_test "." =
resolve ".";
[%expect_exact {|
((File {
filename = (Some "/.../test/resolve/index.js");
preprocessors = []
}),
[])
|}]
But then, I’ve hit another problem, which is the fact that ppx_deriving.show
uses the Format module and its output is highly dependent on the formatter’s margin
. Obviously, it would work well if values in the data structure were constants known in advance, but in my case those are absolute paths which depend on the environment. So, what I ended up doing is the set of nasty hacks:
let show resolved =
(* this is to make sure that pp_resolved will produce 1-liner*)
Format.(pp_set_margin str_formatter 100000);
pp_resolved Format.str_formatter resolved;
(* make it more friendly for diffing *)
Format.flush_str_formatter ()
|> String.replace ~sub:"{ " ~by:"{\n "
|> String.replace ~sub:"; " ~by:";\n "
|> String.replace ~sub:" }), " ~by:"\n}),\n"
|> String.replace ~sub:"[\"" ~by:"[\n \""
|> String.replace ~sub:"\"]" ~by:"\"\n]"
So, the question is: Is there idiomatic (or, at least, less hack-ish) way to make show_*/pp_*
produce pretty-printed values which disregard the formatter’s margin
? Or, maybe, it should be some specific formatter adapted to this use-case? I see the analogy with dumping JSON in JS/Python. It is, obviously, simpler than OCaml type-system, but still. If you specify indent
, it will return the pretty-printed string. Would something similar be possible with ppx_deriving.show
?