18

I have a function of type in_channel -> out_channel -> unit which will output something to an out_channel. Now I'd like to get its output as a string. Creating temporary files to write and read it back seems ugly, so how can I do that? Is there any other methods to create out_channel besides Pervasives.open_out family?

Actually, this function implemented a repl. What I really need is to test it programmatically, so I'd like to first wrap it to a function of type string -> string. For creating the in_channel, it seems I can use Scanf.Scanning.from_string, but I don't know how to create the out_channel parameter.

Tianyi Cui
  • 3,933
  • 3
  • 21
  • 18
  • 1
    I don't think there's a way to do this. It would be tricky, because strings have a fixed length in OCaml. They're not really suitable as an expandable place to store characters. You can use Printf.sprintf to create a string with the same contents that Printf.fprintf would write to an output channel. But other than that, you might have to build your own mechanism. – Jeffrey Scofield Sep 22 '12 at 03:49

2 Answers2

7

OCaml Batteries Included has output_string and output_buffer functions in its BatIO module which seem to do what you want: http://ocaml-batteries-team.github.com/batteries-included/hdoc/BatIO.html

It might require you to use their input/output types.

newacct
  • 119,665
  • 29
  • 163
  • 224
  • 1
    for futur readers, this is now located in the BatBuffer library : http://ocaml-batteries-team.github.io/batteries-included/hdoc2/BatBuffer.html – yago Apr 14 '16 at 11:39
4

If you don't mind your tests relying on the Unix module, then you can use Unix.pipe to create a file descriptor pair, create an in_channel from the readable side, an out_channel from the writable side, and then write the string to the writable side and pass the in_channel to the code under test.

val pipe : unit -> file_descr * file_descr

Create a pipe. The first component of the result is opened for reading, that's the exit to the pipe. The second component is opened for writing, that's the entrance to the pipe.

val in_channel_of_descr : file_descr -> Pervasives.in_channel

Create an input channel reading from the given descriptor. The channel is initially in binary mode; use set_binary_mode_in ic false if text mode is desired.

val out_channel_of_descr : file_descr -> Pervasives.out_channel

Create an output channel writing on the given descriptor. The channel is initially in binary mode; use set_binary_mode_out oc false if text mode is desired.

Unix pipes are a bit heavy-weight for anything with high throughput, but they should be fine for a test-harness.

Mike Samuel
  • 118,113
  • 30
  • 216
  • 245