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?