File: test_or_error.ml

package info (click to toggle)
janest-base 0.17.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,632 kB
  • sloc: ml: 48,653; ansic: 281; javascript: 126; makefile: 14
file content (134 lines) | stat: -rw-r--r-- 4,005 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
open! Import
open! Or_error

let%test _ = [%compare.equal: string t] (errorf "foo %d" 13) (error_string "foo 13")

let%test_unit _ =
  for i = 0 to 10 do
    assert (
      [%compare.equal: unit list t]
        (combine_errors (List.init i ~f:(fun _ -> Ok ())))
        (Ok (List.init i ~f:(fun _ -> ()))))
  done
;;

let%test _ = Result.is_error (combine_errors [ error_string "" ])
let%test _ = Result.is_error (combine_errors [ Ok (); error_string "" ])
let ( = ) = [%compare.equal: unit t]
let%test _ = combine_errors_unit [ Ok (); Ok () ] = Ok ()
let%test _ = combine_errors_unit [] = Ok ()

let%test _ =
  let a = Error.of_string "a"
  and b = Error.of_string "b" in
  match combine_errors_unit [ Ok (); Error a; Ok (); Error b ] with
  | Ok _ -> false
  | Error e ->
    String.equal (Error.to_string_hum e) (Error.to_string_hum (Error.of_list [ a; b ]))
;;

let%expect_test "map2" =
  let m t1 t2 =
    let result = Or_error.map2 ~f:(fun x y -> x + y) t1 t2 in
    print_s [%sexp (result : int Or_error.t)]
  in
  let foo = Error.of_string "foo" in
  let bar = Error.of_string "bar" in
  m (Error foo) (Error bar);
  [%expect {| (Error (foo bar)) |}];
  m (Ok 1) (Ok 2);
  [%expect {| (Ok 3) |}];
  m (Error foo) (Ok 1);
  [%expect {| (Error foo) |}];
  m (Ok 1) (Error bar);
  [%expect {| (Error bar) |}]
;;

(* These tests check for stack overflow, and that we don't time out, when given large
   lists. We also test that we preserve all errors, in order, so that performance-related
   changes don't accidentally change behavior.

   History: in [2023-02], [all] and [all_unit] had O(N) stack usage and O(N^2) time for
   lists of length N. These costs were hidden behind the [lazy] inside [Error] values, so
   they could occur far from where the error was constructed. *)
let%expect_test "behavior and performance on lists of or_error's" =
  let make_list len =
    (* We construct atoms with spaces in them to show sexp rendering with quotes, which is
       significant to [Error.to_string_hum]'s behavior below. *)
    List.init len ~f:(Or_error.errorf "at %d")
  in
  let short_lists = List.map ~f:make_list [ 0; 1; 2; 10 ] in
  let long_list = make_list 500_000 in
  let to_string = function
    | Ok _ -> "ok"
    | Error error ->
      (* Converting to string forces the [lazy] inside [Error.t]. Using [to_string_hum]
         also happens to observe whether the error was created via [Error.of_string]. *)
      Error.to_string_hum error
  in
  let test f =
    (* Show behavior on short lists. *)
    List.iter short_lists ~f:(fun list -> print_endline (to_string (f list)));
    (* Test for timeout / stack overflow on a long list. *)
    match to_string (f long_list) with
    | (_ : string) -> ()
    | exception Stack_overflow -> print_cr [%here] [%message "stack overflow"]
  in
  (* test functions that combine a list of or_errors *)
  test all;
  [%expect
    {|
    ok
    at 0
    ("at 0" "at 1")
    ("at 0" "at 1" "at 2" "at 3" "at 4" "at 5" "at 6" "at 7" "at 8" "at 9")
    |}];
  test all_unit;
  [%expect
    {|
    ok
    at 0
    ("at 0" "at 1")
    ("at 0" "at 1" "at 2" "at 3" "at 4" "at 5" "at 6" "at 7" "at 8" "at 9")
    |}];
  test combine_errors;
  [%expect
    {|
    ok
    "at 0"
    ("at 0" "at 1")
    ("at 0" "at 1" "at 2" "at 3" "at 4" "at 5" "at 6" "at 7" "at 8" "at 9")
    |}];
  test combine_errors_unit;
  [%expect
    {|
    ok
    "at 0"
    ("at 0" "at 1")
    ("at 0" "at 1" "at 2" "at 3" "at 4" "at 5" "at 6" "at 7" "at 8" "at 9")
    |}];
  test find_ok;
  [%expect
    {|
    ()
    "at 0"
    ("at 0" "at 1")
    ("at 0" "at 1" "at 2" "at 3" "at 4" "at 5" "at 6" "at 7" "at 8" "at 9")
    |}];
  test (find_map_ok ~f:Fn.id);
  [%expect
    {|
    ()
    "at 0"
    ("at 0" "at 1")
    ("at 0" "at 1" "at 2" "at 3" "at 4" "at 5" "at 6" "at 7" "at 8" "at 9")
    |}];
  test filter_ok_at_least_one;
  [%expect
    {|
    ()
    "at 0"
    ("at 0" "at 1")
    ("at 0" "at 1" "at 2" "at 3" "at 4" "at 5" "at 6" "at 7" "at 8" "at 9")
    |}]
;;