mirror of
https://github.com/c-cube/linol.git
synced 2025-12-12 05:58:49 -05:00
223 lines
6.5 KiB
OCaml
223 lines
6.5 KiB
OCaml
open! Stdune
|
|
open Fiber.O
|
|
open Lev_fiber
|
|
|
|
let%expect_test "pipe" =
|
|
let run () =
|
|
let* input, output = Io.pipe ~cloexec:true () in
|
|
let write () =
|
|
let+ () =
|
|
Io.with_write output ~f:(fun writer ->
|
|
Io.Writer.add_string writer "foobar";
|
|
Io.Writer.flush writer)
|
|
in
|
|
Io.close output;
|
|
printfn "writer: finished"
|
|
in
|
|
let read () =
|
|
let+ contents = Io.with_read input ~f:Io.Reader.to_string in
|
|
printfn "read: %S" contents;
|
|
Io.close input
|
|
in
|
|
Fiber.fork_and_join_unit read write
|
|
in
|
|
let print_errors f () =
|
|
Fiber.with_error_handler
|
|
~on_error:(fun exn ->
|
|
Format.eprintf "%a@." Exn_with_backtrace.pp_uncaught exn;
|
|
Exn_with_backtrace.reraise exn)
|
|
f
|
|
in
|
|
Lev_fiber.run (print_errors run) |> Lev_fiber.Error.ok_exn;
|
|
[%expect {|
|
|
writer: finished
|
|
read: "foobar" |}]
|
|
|
|
let%expect_test "write with resize" =
|
|
let run () =
|
|
let* input, output = Io.pipe ~cloexec:true () in
|
|
let len = 6120 in
|
|
let write () =
|
|
let+ () =
|
|
Io.with_write output ~f:(fun writer ->
|
|
Io.Writer.add_string writer (String.make len '1');
|
|
Io.Writer.flush writer)
|
|
in
|
|
Io.close output;
|
|
printfn "writer: finished"
|
|
in
|
|
let read () =
|
|
let+ contents = Io.with_read input ~f:Io.Reader.to_string in
|
|
let len' = String.length contents in
|
|
printfn "read: %d length" len';
|
|
assert (len = len');
|
|
Io.close input
|
|
in
|
|
Fiber.fork_and_join_unit read write
|
|
in
|
|
let print_errors f () =
|
|
Fiber.with_error_handler
|
|
~on_error:(fun exn ->
|
|
Format.eprintf "%a@." Exn_with_backtrace.pp_uncaught exn;
|
|
Exn_with_backtrace.reraise exn)
|
|
f
|
|
in
|
|
print_errors run |> Lev_fiber.run |> Lev_fiber.Error.ok_exn;
|
|
[%expect {|
|
|
writer: finished
|
|
read: 6120 length |}]
|
|
|
|
let%expect_test "blocking pipe" =
|
|
let fdr, fdw = Unix.pipe ~cloexec:true () in
|
|
let run () =
|
|
let* r = Io.create (Fd.create fdr `Blocking) Input in
|
|
let* w = Io.create (Fd.create fdw `Blocking) Output in
|
|
let writer () =
|
|
let+ () =
|
|
Io.with_write w ~f:(fun writer ->
|
|
Io.Writer.add_string writer "foo bar baz";
|
|
Io.Writer.flush writer)
|
|
in
|
|
printfn "writer: finished";
|
|
Io.close w
|
|
in
|
|
let reader () =
|
|
let+ read = Io.with_read r ~f:Io.Reader.to_string in
|
|
printfn "read: %S" read;
|
|
Io.close r
|
|
in
|
|
Fiber.fork_and_join_unit reader writer
|
|
in
|
|
Lev_fiber.run run |> Lev_fiber.Error.ok_exn;
|
|
[%expect {|
|
|
writer: finished
|
|
read: "foo bar baz" |}]
|
|
|
|
let with_pipe_test output f =
|
|
let run () =
|
|
let* ic, oc = Io.pipe ~cloexec:true () in
|
|
let writer () =
|
|
let+ () =
|
|
Io.with_write oc ~f:(fun writer ->
|
|
let len_output = String.length output in
|
|
let rec loop pos =
|
|
if pos = len_output then Fiber.return ()
|
|
else
|
|
let available = Io.Writer.Expert.available writer in
|
|
if available = 0 then
|
|
let* () = Io.Writer.flush writer in
|
|
loop pos
|
|
else
|
|
let len = min available (len_output - pos) in
|
|
Io.Writer.add_substring writer output ~pos ~len;
|
|
loop (pos + len)
|
|
in
|
|
let* () = loop 0 in
|
|
Io.Writer.flush writer)
|
|
in
|
|
Io.close oc
|
|
in
|
|
Fiber.fork_and_join_unit
|
|
(fun () ->
|
|
let+ () = f ic in
|
|
Io.close ic)
|
|
writer
|
|
in
|
|
Lev_fiber.run run
|
|
|
|
let%expect_test "read lines" =
|
|
with_pipe_test "foo\nbar\r\n\nbaz\r\r\neof" (fun r ->
|
|
Io.with_read r
|
|
~f:
|
|
(let rec loop reader =
|
|
let* res = Io.Reader.read_line reader in
|
|
match res with
|
|
| Ok line ->
|
|
printfn "line: %S" line;
|
|
loop reader
|
|
| Error (`Partial_eof s) ->
|
|
printfn "eof: %S" s;
|
|
Fiber.return ()
|
|
in
|
|
loop))
|
|
|> Lev_fiber.Error.ok_exn;
|
|
[%expect
|
|
{|
|
|
line: "foo"
|
|
line: "bar"
|
|
line: ""
|
|
line: "baz\r"
|
|
eof: "eof" |}]
|
|
|
|
let%expect_test "read exactly - sufficient" =
|
|
let len = 6 in
|
|
with_pipe_test "foobarbaz" (fun r ->
|
|
Io.with_read r ~f:(fun reader ->
|
|
let+ res = Io.Reader.read_exactly reader len in
|
|
match res with
|
|
| Error (`Partial_eof s) -> printfn "eof: %S" s
|
|
| Ok s ->
|
|
assert (String.length s = len);
|
|
printfn "success: %S\n" s))
|
|
|> Lev_fiber.Error.ok_exn;
|
|
[%expect {| success: "foobar" |}]
|
|
|
|
let%expect_test "read exactly - insufficient" =
|
|
let str = "foobarbaz" in
|
|
let len = String.length str + 10 in
|
|
with_pipe_test str (fun r ->
|
|
Io.with_read r ~f:(fun reader ->
|
|
let+ res = Io.Reader.read_exactly reader len in
|
|
match res with
|
|
| Error (`Partial_eof s) -> printfn "eof: %S" s
|
|
| Ok s ->
|
|
assert (String.length s = len);
|
|
printfn "success: %S\n" s))
|
|
|> Lev_fiber.Error.ok_exn;
|
|
[%expect {| eof: "foobarbaz" |}]
|
|
|
|
let%expect_test "reading from closed pipe" =
|
|
let r, w = Unix.pipe () in
|
|
( Lev_fiber.run @@ fun () ->
|
|
let* io = Io.create (Fd.create r `Blocking) Input in
|
|
let close () =
|
|
let+ () = Timer.sleepf 0.3 in
|
|
Unix.close w
|
|
in
|
|
let read () =
|
|
let+ contents = Io.with_read io ~f:Io.Reader.to_string in
|
|
printfn "contents: %S" contents;
|
|
Io.close io
|
|
in
|
|
Fiber.fork_and_join_unit close read )
|
|
|> Lev_fiber.Error.ok_exn;
|
|
[%expect {| contents: "" |}]
|
|
|
|
let%expect_test "writing to a closed pipe" =
|
|
let r, w = Unix.pipe () in
|
|
Unix.close r;
|
|
( Lev_fiber.run ~sigpipe:`Ignore @@ fun () ->
|
|
let* io = Io.create (Fd.create w `Blocking) Output in
|
|
print_endline "writing to closed pipe";
|
|
let+ res =
|
|
let on_error (exn : Exn_with_backtrace.t) =
|
|
match exn.exn with
|
|
| Code_error.E e ->
|
|
printfn "error: %s" @@ Dyn.to_string
|
|
@@ Code_error.to_dyn_without_loc e;
|
|
Fiber.return ()
|
|
| _ -> Exn_with_backtrace.reraise exn
|
|
in
|
|
Fiber.map_reduce_errors (module Monoid.Unit) ~on_error @@ fun () ->
|
|
Io.with_write io ~f:(fun w ->
|
|
Io.Writer.add_string w "foobar";
|
|
Io.Writer.flush w)
|
|
in
|
|
(match res with Error () -> () | Ok () -> assert false);
|
|
print_endline "finished writing" )
|
|
|> Lev_fiber.Error.ok_exn;
|
|
[%expect{|
|
|
writing to closed pipe
|
|
error: ("fd closed unflushed", { remaining = 6; contents = "foobar\n\
|
|
" })
|
|
finished writing |}]
|