From 7ec6485ab402abe97b4f8d00b3a8b78751ba9859 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Tue, 10 Feb 2026 21:27:49 -0500 Subject: [PATCH] wip --- src/core/dune | 5 +- tests/core/t_cbor.ml | 285 +++++++++++++++++++++----------------- tests/core/t_list.ml | 285 ++++++++++++++++++++------------------ tests/core/t_result.ml | 307 ++++++++++++++++++++++++----------------- 4 files changed, 496 insertions(+), 386 deletions(-) diff --git a/src/core/dune b/src/core/dune index 3d5622e7..226d5902 100644 --- a/src/core/dune +++ b/src/core/dune @@ -3,10 +3,7 @@ (public_name containers) (wrapped false) (preprocess - (per_module - ((action (run %{project_root}/src/core/cpp/cpp.exe %{input-file})) - CCAtomic CCList CCVector) - ((pps bisect_ppx)))) + (action (run %{project_root}/src/core/cpp/cpp.exe %{input-file}))) (flags :standard -nolabels -open CCMonomorphic) (libraries either containers.monomorphic containers.domain)) diff --git a/tests/core/t_cbor.ml b/tests/core/t_cbor.ml index de69ddca..beadad0d 100644 --- a/tests/core/t_cbor.ml +++ b/tests/core/t_cbor.ml @@ -68,8 +68,8 @@ let gen_c : Cbor.t Q.Gen.t = let rec shrink (c : Cbor.t) : Cbor.t Q.Iter.t = let open Q.Iter in match c with - | `Null | `Undefined | (`Bool false) -> empty - | (`Bool true) -> return ((`Bool false)) + | `Null | `Undefined | `Bool false -> empty + | `Bool true -> return (`Bool false) | `Simple i -> let+ i = Q.Shrink.int i in `Simple i @@ -123,15 +123,16 @@ let c' = Cbor.decode_exn s in if not (eq_c c c') then Q.Test.fail_reportf "@[roundtrip failed:@ from %a@ to %a@]" Cbor.pp_diagnostic c Cbor.pp_diagnostic c'; -true;; +true +;; (* Additional edge case and error handling tests *) (* Test basic encoding/decoding *) t @@ fun () -> Cbor.decode_exn (Cbor.encode `Null) = `Null;; t @@ fun () -> Cbor.decode_exn (Cbor.encode `Undefined) = `Undefined;; -t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Bool true)) = (`Bool true);; -t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Bool false)) = (`Bool false);; +t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Bool true)) = `Bool true;; +t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Bool false)) = `Bool false;; (* Test integer edge cases *) t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Int 0L)) = `Int 0L;; @@ -141,114 +142,137 @@ t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Int 255L)) = `Int 255L;; t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Int 256L)) = `Int 256L;; t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Int 65535L)) = `Int 65535L;; t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Int 65536L)) = `Int 65536L;; -t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Int Int64.max_int)) = `Int Int64.max_int;; + +t @@ fun () -> +Cbor.decode_exn (Cbor.encode (`Int Int64.max_int)) = `Int Int64.max_int +;; (* Test negative integers *) t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Int (-1L))) = `Int (-1L);; t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Int (-23L))) = `Int (-23L);; t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Int (-24L))) = `Int (-24L);; t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Int (-256L))) = `Int (-256L);; -t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Int Int64.min_int)) = `Int Int64.min_int;; + +t @@ fun () -> +Cbor.decode_exn (Cbor.encode (`Int Int64.min_int)) = `Int Int64.min_int +;; (* Test floats *) t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Float 0.0)) = `Float 0.0;; t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Float 1.5)) = `Float 1.5;; t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Float (-1.5))) = `Float (-1.5);; + t @@ fun () -> - let result = Cbor.decode_exn (Cbor.encode (`Float infinity)) in - match result with - | `Float f -> classify_float f = FP_infinite && f > 0.0 - | _ -> false +let result = Cbor.decode_exn (Cbor.encode (`Float infinity)) in +match result with +| `Float f -> classify_float f = FP_infinite && f > 0.0 +| _ -> false ;; + t @@ fun () -> - let result = Cbor.decode_exn (Cbor.encode (`Float neg_infinity)) in - match result with - | `Float f -> classify_float f = FP_infinite && f < 0.0 - | _ -> false +let result = Cbor.decode_exn (Cbor.encode (`Float neg_infinity)) in +match result with +| `Float f -> classify_float f = FP_infinite && f < 0.0 +| _ -> false ;; + t @@ fun () -> - let result = Cbor.decode_exn (Cbor.encode (`Float nan)) in - match result with - | `Float f -> classify_float f = FP_nan - | _ -> false +let result = Cbor.decode_exn (Cbor.encode (`Float nan)) in +match result with +| `Float f -> classify_float f = FP_nan +| _ -> false ;; (* Test strings *) t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Text "")) = `Text "";; t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Text "hello")) = `Text "hello";; t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Text "a")) = `Text "a";; + t @@ fun () -> - let long = String.make 1000 'x' in - Cbor.decode_exn (Cbor.encode (`Text long)) = `Text long +let long = String.make 1000 'x' in +Cbor.decode_exn (Cbor.encode (`Text long)) = `Text long ;; (* Test UTF-8 strings *) -t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Text "hello 世界")) = `Text "hello 世界";; -t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Text "émoji 🎉")) = `Text "émoji 🎉";; -t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Text "Здравствуй")) = `Text "Здравствуй";; +t @@ fun () -> +Cbor.decode_exn (Cbor.encode (`Text "hello 世界")) = `Text "hello 世界" +;; + +t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Text "émoji 🎉")) = `Text "émoji 🎉" +;; + +t @@ fun () -> +Cbor.decode_exn (Cbor.encode (`Text "Здравствуй")) = `Text "Здравствуй" +;; (* Test bytes *) t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Bytes "")) = `Bytes "";; -t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Bytes "\x00\x01\x02")) = `Bytes "\x00\x01\x02";; + t @@ fun () -> - let bytes = String.init 256 char_of_int in - Cbor.decode_exn (Cbor.encode (`Bytes bytes)) = `Bytes bytes +Cbor.decode_exn (Cbor.encode (`Bytes "\x00\x01\x02")) = `Bytes "\x00\x01\x02" +;; + +t @@ fun () -> +let bytes = String.init 256 char_of_int in +Cbor.decode_exn (Cbor.encode (`Bytes bytes)) = `Bytes bytes ;; (* Test arrays *) t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Array [])) = `Array [];; -t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Array [`Int 1L])) = `Array [`Int 1L];; + t @@ fun () -> - Cbor.decode_exn (Cbor.encode (`Array [`Int 1L; `Int 2L; `Int 3L])) - = `Array [`Int 1L; `Int 2L; `Int 3L] +Cbor.decode_exn (Cbor.encode (`Array [ `Int 1L ])) = `Array [ `Int 1L ] ;; + t @@ fun () -> - Cbor.decode_exn (Cbor.encode (`Array [(`Bool true); `Text "a"; `Int 42L])) - = `Array [(`Bool true); `Text "a"; `Int 42L] +Cbor.decode_exn (Cbor.encode (`Array [ `Int 1L; `Int 2L; `Int 3L ])) += `Array [ `Int 1L; `Int 2L; `Int 3L ] +;; + +t @@ fun () -> +Cbor.decode_exn (Cbor.encode (`Array [ `Bool true; `Text "a"; `Int 42L ])) += `Array [ `Bool true; `Text "a"; `Int 42L ] ;; (* Test nested arrays *) t @@ fun () -> - let nested = `Array [`Array [`Int 1L; `Int 2L]; `Array [`Int 3L]] in - Cbor.decode_exn (Cbor.encode nested) = nested +let nested = `Array [ `Array [ `Int 1L; `Int 2L ]; `Array [ `Int 3L ] ] in +Cbor.decode_exn (Cbor.encode nested) = nested ;; (* Test maps *) t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Map [])) = `Map [];; + t @@ fun () -> - Cbor.decode_exn (Cbor.encode (`Map [(`Text "key", `Int 42L)])) - = `Map [(`Text "key", `Int 42L)] +Cbor.decode_exn (Cbor.encode (`Map [ `Text "key", `Int 42L ])) += `Map [ `Text "key", `Int 42L ] ;; + t @@ fun () -> - let map = `Map [ - (`Text "a", `Int 1L); - (`Text "b", `Int 2L); - (`Text "c", `Int 3L) - ] in - Cbor.decode_exn (Cbor.encode map) = map +let map = `Map [ `Text "a", `Int 1L; `Text "b", `Int 2L; `Text "c", `Int 3L ] in +Cbor.decode_exn (Cbor.encode map) = map ;; (* Test maps with various key types *) t @@ fun () -> - let map = `Map [ - (`Int 0L, `Text "zero"); - (`Int 1L, `Text "one"); - ] in - Cbor.decode_exn (Cbor.encode map) = map +let map = `Map [ `Int 0L, `Text "zero"; `Int 1L, `Text "one" ] in +Cbor.decode_exn (Cbor.encode map) = map ;; (* Test tags *) t @@ fun () -> - Cbor.decode_exn (Cbor.encode (`Tag (0, `Text "2013-03-21"))) - = `Tag (0, `Text "2013-03-21") +Cbor.decode_exn (Cbor.encode (`Tag (0, `Text "2013-03-21"))) += `Tag (0, `Text "2013-03-21") ;; + t @@ fun () -> - Cbor.decode_exn (Cbor.encode (`Tag (1, `Int 1363896240L))) - = `Tag (1, `Int 1363896240L) +Cbor.decode_exn (Cbor.encode (`Tag (1, `Int 1363896240L))) += `Tag (1, `Int 1363896240L) ;; + t @@ fun () -> - Cbor.decode_exn (Cbor.encode (`Tag (32, `Text "http://example.com"))) - = `Tag (32, `Text "http://example.com") +Cbor.decode_exn (Cbor.encode (`Tag (32, `Text "http://example.com"))) += `Tag (32, `Text "http://example.com") ;; (* Test simple values *) @@ -258,142 +282,149 @@ t @@ fun () -> Cbor.decode_exn (Cbor.encode (`Simple 255)) = `Simple 255;; (* Test error cases *) t @@ fun () -> - match Cbor.decode "" with - | Error _ -> true - | Ok _ -> false +match Cbor.decode "" with +| Error _ -> true +| Ok _ -> false ;; t @@ fun () -> - match Cbor.decode "\x1f" with (* invalid additional info *) - | Error _ -> true - | Ok _ -> false +match Cbor.decode "\x1f" with +(* invalid additional info *) +| Error _ -> true +| Ok _ -> false ;; t @@ fun () -> - match Cbor.decode "\x1c" with (* reserved additional info *) - | Error _ -> true - | Ok _ -> false +match Cbor.decode "\x1c" with +(* reserved additional info *) +| Error _ -> true +| Ok _ -> false ;; t @@ fun () -> - match Cbor.decode "\x5f\x42\x01\x02\x43\x03\x04\x05" with (* incomplete indefinite *) - | Error _ -> true - | Ok _ -> false +match Cbor.decode "\x5f\x42\x01\x02\x43\x03\x04\x05" with +(* incomplete indefinite *) +| Error _ -> true +| Ok _ -> false ;; (* Test that decode_exn raises on invalid input *) t @@ fun () -> - try - ignore (Cbor.decode_exn ""); - false - with Failure _ -> true +try + ignore (Cbor.decode_exn ""); + false +with Failure _ -> true ;; t @@ fun () -> - try - ignore (Cbor.decode_exn "\x1c"); - false - with Failure _ -> true +try + ignore (Cbor.decode_exn "\x1c"); + false +with Failure _ -> true ;; (* Test diagnostic string output *) t @@ fun () -> Cbor.to_string_diagnostic `Null = "null";; t @@ fun () -> Cbor.to_string_diagnostic `Undefined = "undefined";; -t @@ fun () -> Cbor.to_string_diagnostic ((`Bool true)) = "true";; -t @@ fun () -> Cbor.to_string_diagnostic ((`Bool false)) = "false";; +t @@ fun () -> Cbor.to_string_diagnostic (`Bool true) = "true";; +t @@ fun () -> Cbor.to_string_diagnostic (`Bool false) = "false";; t @@ fun () -> Cbor.to_string_diagnostic (`Int 42L) = "42";; t @@ fun () -> Cbor.to_string_diagnostic (`Int (-42L)) = "-42";; t @@ fun () -> Cbor.to_string_diagnostic (`Float 1.5) = "1.5";; t @@ fun () -> Cbor.to_string_diagnostic (`Text "hello") = "\"hello\"";; -t @@ fun () -> Cbor.to_string_diagnostic (`Array [`Int 1L; `Int 2L]) = "[1, 2]";; + t @@ fun () -> - Cbor.to_string_diagnostic (`Map [(`Text "a", `Int 1L)]) - |> String.contains_s ~sub:"\"a\"" +Cbor.to_string_diagnostic (`Array [ `Int 1L; `Int 2L ]) = "[1, 2]" +;; + +t @@ fun () -> +Cbor.to_string_diagnostic (`Map [ `Text "a", `Int 1L ]) +|> CCString.mem ~sub:"\"a\"" ;; (* Test deeply nested structures *) t @@ fun () -> - let rec make_nested n = - if n = 0 then `Int 0L - else `Array [make_nested (n - 1)] - in - let nested = make_nested 100 in - Cbor.decode_exn (Cbor.encode nested) = nested +let rec make_nested n = + if n = 0 then + `Int 0L + else + `Array [ make_nested (n - 1) ] +in +let nested = make_nested 100 in +Cbor.decode_exn (Cbor.encode nested) = nested ;; (* Test large collections *) t @@ fun () -> - let large_array = `Array (List.init 1000 (fun i -> `Int (Int64.of_int i))) in - Cbor.decode_exn (Cbor.encode large_array) = large_array +let large_array = `Array (List.init 1000 (fun i -> `Int (Int64.of_int i))) in +Cbor.decode_exn (Cbor.encode large_array) = large_array ;; t @@ fun () -> - let large_map = `Map (List.init 500 (fun i -> - (`Int (Int64.of_int i), `Text (string_of_int i)) - )) in - Cbor.decode_exn (Cbor.encode large_map) = large_map +let large_map = + `Map (List.init 500 (fun i -> `Int (Int64.of_int i), `Text (string_of_int i))) +in +Cbor.decode_exn (Cbor.encode large_map) = large_map ;; (* Test mixed nested structures *) t @@ fun () -> - let complex = `Map [ - (`Text "array", `Array [`Int 1L; `Int 2L; `Int 3L]); - (`Text "map", `Map [(`Text "nested", (`Bool true))]); - (`Text "tagged", `Tag (42, `Text "value")); - (`Text "null", `Null); - ] in - Cbor.decode_exn (Cbor.encode complex) = complex +let complex = + `Map + [ + `Text "array", `Array [ `Int 1L; `Int 2L; `Int 3L ]; + `Text "map", `Map [ `Text "nested", `Bool true ]; + `Text "tagged", `Tag (42, `Text "value"); + `Text "null", `Null; + ] +in +Cbor.decode_exn (Cbor.encode complex) = complex ;; (* Test that encoding is consistent *) t @@ fun () -> - let c = `Map [(`Text "a", `Int 1L); (`Text "b", `Int 2L)] in - let e1 = Cbor.encode c in - let e2 = Cbor.encode c in - e1 = e2 +let c = `Map [ `Text "a", `Int 1L; `Text "b", `Int 2L ] in +let e1 = Cbor.encode c in +let e2 = Cbor.encode c in +e1 = e2 ;; (* Test buffer reuse *) t @@ fun () -> - let buf = Buffer.create 16 in - let _ = Cbor.encode ~buf (`Int 1L) in - let s1 = Buffer.contents buf in - Buffer.clear buf; - let _ = Cbor.encode ~buf (`Int 1L) in - let s2 = Buffer.contents buf in - s1 = s2 +let buf = Buffer.create 16 in +let _ = Cbor.encode ~buf (`Int 1L) in +let s1 = Buffer.contents buf in +Buffer.clear buf; +let _ = Cbor.encode ~buf (`Int 1L) in +let s2 = Buffer.contents buf in +s1 = s2 ;; (* Property: encoding then decoding gives original value *) q ~count:5000 arb @@ fun c -> - match Cbor.decode (Cbor.encode c) with - | Ok c' -> eq_c c c' - | Error e -> - Q.Test.fail_reportf "decode failed: %s" e; - false +match Cbor.decode (Cbor.encode c) with +| Ok c' -> eq_c c c' +| Error e -> Q.Test.fail_reportf "decode failed: %s" e ;; (* Property: decode result equality *) q ~count:2000 arb @@ fun c -> - let s = Cbor.encode c in - match Cbor.decode s with - | Error e -> - Q.Test.fail_reportf "decode failed on encoded value: %s" e; - false - | Ok c1 -> - match Cbor.decode s with - | Error _ -> false - | Ok c2 -> eq_c c1 c2 +let s = Cbor.encode c in +match Cbor.decode s with +| Error e -> Q.Test.fail_reportf "decode failed on encoded value: %s" e +| Ok c1 -> + (match Cbor.decode s with + | Error _ -> false + | Ok c2 -> eq_c c1 c2) ;; (* Property: diagnostic string doesn't crash *) q ~count:1000 arb @@ fun c -> - let _ = Cbor.to_string_diagnostic c in - true +let _ = Cbor.to_string_diagnostic c in +true ;; (* Property: encoding size is reasonable *) q ~count:1000 arb @@ fun c -> - let s = Cbor.encode c in - String.length s < 1_000_000 (* Sanity check *) -;; +let s = Cbor.encode c in +String.length s < 1_000_000 (* Sanity check *) diff --git a/tests/core/t_list.ml b/tests/core/t_list.ml index 33c6bda7..6ca897eb 100644 --- a/tests/core/t_list.ml +++ b/tests/core/t_list.ml @@ -306,11 +306,10 @@ q Q.( let p = list_small int in pair p p) - (fun (l1, l2) -> - if List.length l1 = List.length l2 then - CCList.combine l1 l2 = List.combine l1 l2 - else - Q.assume_fail ()) + Q.( + fun (l1, l2) -> + List.length l1 = List.length l2 + ==> (CCList.combine l1 l2 = List.combine l1 l2)) ;; q @@ -1161,193 +1160,217 @@ eq ~pp_start:(fun fmt () -> Format.fprintf fmt "[") ~pp_stop:(fun fmt () -> Format.fprintf fmt "]") CCFormat.int)) - [ 1; 2; 3 ]);; + [ 1; 2; 3 ]) +;; (* Additional edge case and property tests *) (* Test interleave *) -t @@ fun () -> - CCList.interleave [1; 3; 5] [2; 4; 6] = [1; 2; 3; 4; 5; 6] +t ~name:__LOC__ @@ fun () -> +CCList.interleave [ 1; 3; 5 ] [ 2; 4; 6 ] = [ 1; 2; 3; 4; 5; 6 ] ;; -t @@ fun () -> - CCList.interleave [1; 2] [10; 20; 30; 40] = [1; 10; 2; 20; 30; 40] +t ~name:__LOC__ @@ fun () -> +CCList.interleave [ 1; 2 ] [ 10; 20; 30; 40 ] = [ 1; 10; 2; 20; 30; 40 ] ;; -t @@ fun () -> - CCList.interleave [1; 2; 3; 4] [10; 20] = [1; 10; 2; 20; 3; 4] +t ~name:__LOC__ @@ fun () -> +CCList.interleave [ 1; 2; 3; 4 ] [ 10; 20 ] = [ 1; 10; 2; 20; 3; 4 ] ;; -t @@ fun () -> - CCList.interleave [] [1; 2; 3] = [1; 2; 3] -;; - -t @@ fun () -> - CCList.interleave [1; 2; 3] [] = [1; 2; 3] -;; +t ~name:__LOC__ @@ fun () -> CCList.interleave [] [ 1; 2; 3 ] = [ 1; 2; 3 ];; +t ~name:__LOC__ @@ fun () -> CCList.interleave [ 1; 2; 3 ] [] = [ 1; 2; 3 ];; (* Test take_while and drop_while *) -eq [1; 2; 3] (CCList.take_while (fun x -> x < 4) [1; 2; 3; 4; 5]);; -eq [] (CCList.take_while (fun x -> x < 0) [1; 2; 3]);; -eq [1; 2; 3] (CCList.take_while (fun _ -> true) [1; 2; 3]);; - -eq [4; 5] (CCList.drop_while (fun x -> x < 4) [1; 2; 3; 4; 5]);; -eq [1; 2; 3] (CCList.drop_while (fun x -> x < 0) [1; 2; 3]);; -eq [] (CCList.drop_while (fun _ -> true) [1; 2; 3]);; - -(* Test find_map *) -eq (Some 4) - (CCList.find_map (fun x -> if x > 3 then Some (x * 2) else None) [1; 2; 3; 4; 5]) +eq ~name:__LOC__ [ 1; 2; 3 ] + (CCList.take_while (fun x -> x < 4) [ 1; 2; 3; 4; 5 ]) ;; -eq None - (CCList.find_map (fun x -> if x > 10 then Some x else None) [1; 2; 3]) +eq ~name:__LOC__ [] (CCList.take_while (fun x -> x < 0) [ 1; 2; 3 ]);; +eq ~name:__LOC__ [ 1; 2; 3 ] (CCList.take_while (fun _ -> true) [ 1; 2; 3 ]);; +eq ~name:__LOC__ [ 4; 5 ] (CCList.drop_while (fun x -> x < 4) [ 1; 2; 3; 4; 5 ]) +;; +eq ~name:__LOC__ [ 1; 2; 3 ] (CCList.drop_while (fun x -> x < 0) [ 1; 2; 3 ]);; +eq ~name:__LOC__ [] (CCList.drop_while (fun _ -> true) [ 1; 2; 3 ]);; + +(* Test find_map *) +eq ~name:__LOC__ (Some 8) + (CCList.find_map + (fun x -> + if x > 3 then + Some (x * 2) + else + None) + [ 1; 2; 3; 4; 5 ]) +;; + +eq ~name:__LOC__ None + (CCList.find_map + (fun x -> + if x > 10 then + Some x + else + None) + [ 1; 2; 3 ]) ;; (* Test find_mapi *) -eq (Some (2, 30)) - (CCList.find_mapi (fun i x -> if x = 30 then Some (i, x) else None) [10; 20; 30; 40]) +eq ~name:__LOC__ + (Some (2, 30)) + (CCList.find_mapi + (fun i x -> + if x = 30 then + Some (i, x) + else + None) + [ 10; 20; 30; 40 ]) ;; -eq None - (CCList.find_mapi (fun i x -> if x > 100 then Some (i, x) else None) [10; 20; 30]) +eq ~name:__LOC__ None + (CCList.find_mapi + (fun i x -> + if x > 100 then + Some (i, x) + else + None) + [ 10; 20; 30 ]) ;; (* Test partition_map *) -eq ([2; 4], ["1"; "3"; "5"]) - (CCList.partition_map (fun x -> if x mod 2 = 0 then `Left x else `Right (string_of_int x)) [1; 2; 3; 4; 5]) +eq ~name:__LOC__ + ([ 2; 4 ], [ "1"; "3"; "5" ]) + (CCList.partition_filter_map + (fun x -> + if x mod 2 = 0 then + `Left x + else + `Right (string_of_int x)) + [ 1; 2; 3; 4; 5 ]) ;; (* Test sublists_of_len *) -t @@ fun () -> - let result = CCList.sublists_of_len 2 [1; 2; 3; 4] in - List.length result = 6 +t ~name:__LOC__ @@ fun () -> +let result = CCList.sublists_of_len 2 [ 1; 2; 3; 4 ] in +result = [ [ 1; 2 ]; [ 3; 4 ] ] ;; -t @@ fun () -> - CCList.sublists_of_len 3 [1; 2; 3] = [[1; 2; 3]] -;; - -t @@ fun () -> - CCList.sublists_of_len 0 [1; 2; 3] = [[]] +t ~name:__LOC__ @@ fun () -> +CCList.sublists_of_len 3 [ 1; 2; 3 ] = [ [ 1; 2; 3 ] ] ;; (* Test take and drop with edge cases *) -eq [1; 2; 3] (CCList.take 3 [1; 2; 3; 4; 5]);; -eq [1; 2; 3] (CCList.take 10 [1; 2; 3]);; -eq [] (CCList.take 0 [1; 2; 3]);; -eq [] (CCList.take 5 []);; - -eq [4; 5] (CCList.drop 3 [1; 2; 3; 4; 5]);; -eq [] (CCList.drop 10 [1; 2; 3]);; -eq [1; 2; 3] (CCList.drop 0 [1; 2; 3]);; -eq [] (CCList.drop 5 []);; +eq ~name:__LOC__ [ 1; 2; 3 ] (CCList.take 3 [ 1; 2; 3; 4; 5 ]);; +eq ~name:__LOC__ [ 1; 2; 3 ] (CCList.take 10 [ 1; 2; 3 ]);; +eq ~name:__LOC__ [] (CCList.take 0 [ 1; 2; 3 ]);; +eq ~name:__LOC__ [] (CCList.take 5 []);; +eq ~name:__LOC__ [ 4; 5 ] (CCList.drop 3 [ 1; 2; 3; 4; 5 ]);; +eq ~name:__LOC__ [] (CCList.drop 10 [ 1; 2; 3 ]);; +eq ~name:__LOC__ [ 1; 2; 3 ] (CCList.drop 0 [ 1; 2; 3 ]);; +eq ~name:__LOC__ [] (CCList.drop 5 []);; (* Test range with negative numbers *) -eq [-5; -4; -3; -2; -1; 0] (CCList.range_by ~step:1 (-5) 0);; -eq [10; 8; 6; 4; 2; 0] (CCList.range_by ~step:(-2) 10 0);; +eq ~name:__LOC__ [ -5; -4; -3; -2; -1; 0 ] (CCList.range_by ~step:1 (-5) 0);; +eq ~name:__LOC__ [ 10; 8; 6; 4; 2; 0 ] (CCList.range_by ~step:(-2) 10 0);; (* Test sorted_merge *) -eq [1; 2; 3; 4; 5; 6] - (CCList.sorted_merge ~cmp:Int.compare [1; 3; 5] [2; 4; 6]) +eq ~name:__LOC__ [ 1; 2; 3; 4; 5; 6 ] + (CCList.sorted_merge ~cmp:Int.compare [ 1; 3; 5 ] [ 2; 4; 6 ]) ;; -eq [1; 1; 2; 2; 3] - (CCList.sorted_merge ~cmp:Int.compare [1; 2] [1; 2; 3]) +eq ~name:__LOC__ [ 1; 1; 2; 2; 3 ] + (CCList.sorted_merge ~cmp:Int.compare [ 1; 2 ] [ 1; 2; 3 ]) ;; -eq [1; 2; 3] - (CCList.sorted_merge ~cmp:Int.compare [] [1; 2; 3]) +eq ~name:__LOC__ [ 1; 2; 3 ] + (CCList.sorted_merge ~cmp:Int.compare [] [ 1; 2; 3 ]) ;; -eq [1; 2; 3] - (CCList.sorted_merge ~cmp:Int.compare [1; 2; 3] []) +eq ~name:__LOC__ [ 1; 2; 3 ] + (CCList.sorted_merge ~cmp:Int.compare [ 1; 2; 3 ] []) ;; -(* Test group_by *) -t @@ fun () -> - let groups = CCList.group_by ~eq:(fun a b -> a mod 2 = b mod 2) [1; 3; 2; 4; 5; 7; 6] in - List.length groups = 4 +eq ~name:__LOC__ + ~printer:Q.Print.(list (list int)) + [] + (CCList.group_by + ~eq:(fun a b -> a mod 2 = b mod 2) + ~hash:(fun a -> a mod 2) + [ 1; 3; 2; 4; 5; 7; 6 ] + |> List.sort Stdlib.compare) ;; (* Test uniq with custom equality *) -eq [1; 2; 3; 2; 1] - (CCList.uniq ~eq:Int.equal [1; 1; 2; 3; 3; 2; 1]) +eq ~name:__LOC__ [ 1; 2; 3; 2; 1 ] + (CCList.uniq_succ ~eq:Int.equal [ 1; 1; 2; 3; 3; 2; 1 ]) ;; (* Test sort_uniq *) -eq [1; 2; 3; 4] - (CCList.sort_uniq ~cmp:Int.compare [1; 1; 2; 2; 3; 3; 4; 4]) +eq ~name:__LOC__ [ 1; 2; 3; 4 ] + (CCList.sort_uniq ~cmp:Int.compare [ 1; 1; 2; 2; 3; 3; 4; 4 ]) ;; (* Test init with edge cases *) -eq [] (CCList.init 0 CCFun.id);; -eq [0; 1; 2; 3; 4] (CCList.init 5 CCFun.id);; -eq [0; 2; 4; 6; 8] (CCList.init 5 (fun i -> i * 2));; +eq ~name:__LOC__ [] (CCList.init 0 CCFun.id);; +eq ~name:__LOC__ [ 0; 1; 2; 3; 4 ] (CCList.init 5 CCFun.id);; +eq ~name:__LOC__ [ 0; 2; 4; 6; 8 ] (CCList.init 5 (fun i -> i * 2));; (* Test compare and equal *) -t @@ fun () -> - CCList.compare Int.compare [1; 2; 3] [1; 2; 3] = 0 +t ~name:__LOC__ @@ fun () -> +CCList.compare Int.compare [ 1; 2; 3 ] [ 1; 2; 3 ] = 0 ;; -t @@ fun () -> - CCList.compare Int.compare [1; 2] [1; 2; 3] < 0 +t ~name:__LOC__ @@ fun () -> CCList.compare Int.compare [ 1; 2 ] [ 1; 2; 3 ] < 0 +;; +t ~name:__LOC__ @@ fun () -> CCList.compare Int.compare [ 1; 2; 3 ] [ 1; 2 ] > 0 +;; +t ~name:__LOC__ @@ fun () -> CCList.compare Int.compare [ 1; 3 ] [ 1; 2 ] > 0;; +t ~name:__LOC__ @@ fun () -> CCList.equal Int.equal [ 1; 2; 3 ] [ 1; 2; 3 ];; + +t ~name:__LOC__ @@ fun () -> +not (CCList.equal Int.equal [ 1; 2; 3 ] [ 1; 2; 4 ]) ;; -t @@ fun () -> - CCList.compare Int.compare [1; 2; 3] [1; 2] > 0 -;; - -t @@ fun () -> - CCList.compare Int.compare [1; 3] [1; 2] > 0 -;; - -t @@ fun () -> - CCList.equal Int.equal [1; 2; 3] [1; 2; 3] -;; - -t @@ fun () -> - not (CCList.equal Int.equal [1; 2; 3] [1; 2; 4]) -;; - -t @@ fun () -> - not (CCList.equal Int.equal [1; 2] [1; 2; 3]) -;; +t ~name:__LOC__ @@ fun () -> not (CCList.equal Int.equal [ 1; 2 ] [ 1; 2; 3 ]);; (* Property tests for new functions *) -q Q.(list small_int) (fun l -> - let taken = CCList.take (List.length l / 2) l in - let dropped = CCList.drop (List.length l / 2) l in - taken @ dropped = l -);; +q ~name:__LOC__ + Q.(list small_int) + (fun l -> + let taken = CCList.take (List.length l / 2) l in + let dropped = CCList.drop (List.length l / 2) l in + taken @ dropped = l) +;; -q Q.(list small_int) (fun l -> - let sorted = List.sort Int.compare l in - let uniq = CCList.sort_uniq ~cmp:Int.compare sorted in - List.length uniq <= List.length l -);; +q ~name:__LOC__ + Q.(list small_int) + (fun l -> + let sorted = List.sort Int.compare l in + let uniq = CCList.sort_uniq ~cmp:Int.compare sorted in + List.length uniq <= List.length l) +;; -q Q.(pair (list small_int) (list small_int)) (fun (l1, l2) -> - let sorted1 = List.sort Int.compare l1 in - let sorted2 = List.sort Int.compare l2 in - let merged = CCList.sorted_merge ~cmp:Int.compare sorted1 sorted2 in - List.length merged = List.length l1 + List.length l2 -);; +q + Q.(pair (list small_int) (list small_int)) + (fun (l1, l2) -> + let sorted1 = List.sort Int.compare l1 in + let sorted2 = List.sort Int.compare l2 in + let merged = CCList.sorted_merge ~cmp:Int.compare sorted1 sorted2 in + List.length merged = List.length l1 + List.length l2) +;; -q Q.(list small_int) (fun l -> - CCList.equal Int.equal l l -);; +q ~name:__LOC__ Q.(list small_int) (fun l -> CCList.equal Int.equal l l);; +q ~name:__LOC__ Q.(list small_int) (fun l -> CCList.compare Int.compare l l = 0) +;; -q Q.(list small_int) (fun l -> - CCList.compare Int.compare l l = 0 -);; +q ~name:__LOC__ + Q.(pair small_nat (list small_int)) + (fun (n, l) -> + let taken = CCList.take n l in + List.length taken <= n && List.length taken <= List.length l) +;; -q Q.(pair small_nat (list small_int)) (fun (n, l) -> - let taken = CCList.take n l in - List.length taken <= n && List.length taken <= List.length l -);; - -q Q.(pair small_nat (list small_int)) (fun (n, l) -> - let dropped = CCList.drop n l in - List.length dropped = max 0 (List.length l - n) -);; +q ~name:__LOC__ + Q.(pair small_nat (list small_int)) + (fun (n, l) -> + let dropped = CCList.drop n l in + List.length dropped = max 0 (List.length l - n)) diff --git a/tests/core/t_result.ml b/tests/core/t_result.ml index 02ac33c2..a1589ed3 100644 --- a/tests/core/t_result.ml +++ b/tests/core/t_result.ml @@ -34,7 +34,7 @@ eq 42 (fold_ok ( + ) 2 (Ok 40));; eq 40 (fold_ok ( + ) 40 (Error "foo"));; eq (Ok []) (flatten_l []);; eq (Ok [ 1; 2; 3 ]) (flatten_l [ Ok 1; Ok 2; Ok 3 ]);; -eq (Error "ohno") (flatten_l [ Ok 1; Error "ohno"; Ok 2; Ok 3; Error "wut" ]) +eq (Error "ohno") (flatten_l [ Ok 1; Error "ohno"; Ok 2; Ok 3; Error "wut" ]);; (* Additional comprehensive tests for CCResult *) @@ -44,15 +44,15 @@ eq (Error "failed") (fail "failed");; (* Test of_exn and of_exn_trace *) t @@ fun () -> - match of_exn (Failure "test") with - | Error msg -> String.length msg > 0 - | Ok _ -> false +match of_exn (Failure "test") with +| Error msg -> String.length msg > 0 +| Ok _ -> false ;; t @@ fun () -> - match of_exn_trace (Failure "test") with - | Error msg -> String.length msg > 0 - | Ok _ -> false +match of_exn_trace (Failure "test") with +| Error msg -> String.length msg > 0 +| Ok _ -> false ;; (* Test opt_map *) @@ -70,30 +70,35 @@ eq (Ok 5) (map_err String.uppercase_ascii (Ok 5));; eq (Error "ERROR") (map_err String.uppercase_ascii (Error "error"));; (* Test map2 *) -eq (Ok "HELLO") (map2 String.uppercase_ascii String.uppercase_ascii (Ok "hello"));; -eq (Error "ERROR") (map2 String.uppercase_ascii String.uppercase_ascii (Error "error"));; +eq (Ok "HELLO") + (map2 String.uppercase_ascii String.uppercase_ascii (Ok "hello")) +;; + +eq (Error "ERROR") + (map2 String.uppercase_ascii String.uppercase_ascii (Error "error")) +;; (* Test iter *) t @@ fun () -> - let r = ref 0 in - iter (fun x -> r := x) (Ok 42); - !r = 42 +let r = ref 0 in +iter (fun x -> r := x) (Ok 42); +!r = 42 ;; t @@ fun () -> - let r = ref 0 in - iter (fun x -> r := x) (Error "e"); - !r = 0 +let r = ref 0 in +iter (fun x -> r := x) (Error "e"); +!r = 0 ;; (* Test get_exn *) eq 42 (get_exn (Ok 42));; t @@ fun () -> - try - ignore (get_exn (Error "error")); - false - with Invalid_argument _ -> true +try + ignore (get_exn (Error "error")); + false +with Invalid_argument _ -> true ;; (* Test get_or *) @@ -102,8 +107,28 @@ eq 0 (get_or (Error "e") ~default:0);; (* Test apply_or *) eq 10 (apply_or (fun x -> Ok (x * 2)) 5);; -t @@ fun () -> apply_or (fun x -> if x > 0 then Ok (x * 2) else Error "neg") 5 = 10;; -t @@ fun () -> apply_or (fun x -> if x > 0 then Ok (x * 2) else Error "neg") (-5) = -5;; + +t @@ fun () -> +apply_or + (fun x -> + if x > 0 then + Ok (x * 2) + else + Error "neg") + 5 += 10 +;; + +t @@ fun () -> +apply_or + (fun x -> + if x > 0 then + Ok (x * 2) + else + Error "neg") + (-5) += -5 +;; (* Test map_or *) eq 10 (map_or (fun x -> x * 2) (Ok 5) ~default:0);; @@ -112,7 +137,10 @@ eq 0 (map_or (fun x -> x * 2) (Error "e") ~default:0);; (* Test catch *) eq 5 (catch (Ok 5) ~ok:CCFun.id ~err:(fun _ -> 0));; eq 0 (catch (Error "e") ~ok:CCFun.id ~err:(fun _ -> 0));; -eq "ERROR: e" (catch (Error "e") ~ok:Int.to_string ~err:(fun e -> "ERROR: " ^ e));; + +eq "ERROR: e" + (catch (Error "e") ~ok:Int.to_string ~err:(fun e -> "ERROR: " ^ e)) +;; (* Test flat_map *) eq (Ok 3) (flat_map (fun x -> Ok (x + 1)) (Ok 2));; @@ -131,65 +159,65 @@ t @@ fun () -> not (is_error (Ok 1));; (* Test guard and guard_str *) t @@ fun () -> - match guard (fun () -> 42) with - | Ok 42 -> true - | _ -> false +match guard (fun () -> 42) with +| Ok 42 -> true +| _ -> false ;; t @@ fun () -> - match guard (fun () -> failwith "error") with - | Error _ -> true - | _ -> false +match guard (fun () -> failwith "error") with +| Error _ -> true +| _ -> false ;; t @@ fun () -> - match guard_str (fun () -> 42) with - | Ok 42 -> true - | _ -> false +match guard_str (fun () -> 42) with +| Ok 42 -> true +| _ -> false ;; t @@ fun () -> - match guard_str (fun () -> failwith "test error") with - | Error msg -> String.length msg > 0 - | _ -> false +match guard_str (fun () -> failwith "test error") with +| Error msg -> String.length msg > 0 +| _ -> false ;; (* Test guard_str_trace *) t @@ fun () -> - match guard_str_trace (fun () -> 42) with - | Ok 42 -> true - | _ -> false +match guard_str_trace (fun () -> 42) with +| Ok 42 -> true +| _ -> false ;; t @@ fun () -> - match guard_str_trace (fun () -> failwith "test error") with - | Error msg -> String.length msg > 0 - | _ -> false +match guard_str_trace (fun () -> failwith "test error") with +| Error msg -> String.length msg > 0 +| _ -> false ;; (* Test wrap functions *) eq (Ok 6) (wrap1 (( + ) 1) 5);; t @@ fun () -> - match wrap1 (fun _ -> failwith "error") () with - | Error _ -> true - | _ -> false +match wrap1 (fun _ -> failwith "error") () with +| Error _ -> true +| _ -> false ;; eq (Ok 7) (wrap2 ( + ) 3 4);; t @@ fun () -> - match wrap2 (fun _ _ -> failwith "error") 1 2 with - | Error _ -> true - | _ -> false +match wrap2 (fun _ _ -> failwith "error") 1 2 with +| Error _ -> true +| _ -> false ;; eq (Ok 10) (wrap3 (fun a b c -> a + b + c) 2 3 5);; t @@ fun () -> - match wrap3 (fun _ _ _ -> failwith "error") 1 2 3 with - | Error _ -> true - | _ -> false +match wrap3 (fun _ _ _ -> failwith "error") 1 2 3 with +| Error _ -> true +| _ -> false ;; (* Test pure *) @@ -207,42 +235,65 @@ eq (Error "e2") (both (Ok 3) (Error "e2"));; eq (Error "e1") (both (Error "e1") (Error "e2"));; (* Test map_l *) -eq (Ok [2; 3; 4]) (map_l (fun x -> Ok (x + 1)) [1; 2; 3]);; -eq (Error "e") (map_l (fun x -> if x > 0 then Ok x else Error "e") [1; -1; 2]);; +eq (Ok [ 2; 3; 4 ]) (map_l (fun x -> Ok (x + 1)) [ 1; 2; 3 ]);; + +eq (Error "e") + (map_l + (fun x -> + if x > 0 then + Ok x + else + Error "e") + [ 1; -1; 2 ]) +;; + eq (Ok []) (map_l (fun x -> Ok x) []);; (* Test fold_l *) -eq (Ok 6) (fold_l (fun acc x -> Ok (acc + x)) 0 [1; 2; 3]);; -eq (Error "e") (fold_l (fun _ x -> if x > 0 then Ok x else Error "e") 0 [1; -1; 2]);; +eq (Ok 6) (fold_l (fun acc x -> Ok (acc + x)) 0 [ 1; 2; 3 ]);; + +eq (Error "e") + (fold_l + (fun _ x -> + if x > 0 then + Ok x + else + Error "e") + 0 [ 1; -1; 2 ]) +;; (* Test choose *) -eq (Ok 1) (choose [Ok 1; Ok 2; Ok 3]);; -eq (Ok 2) (choose [Error "e1"; Ok 2; Ok 3]);; -eq (Ok 3) (choose [Error "e1"; Error "e2"; Ok 3]);; -eq (Error ["e1"; "e2"; "e3"]) (choose [Error "e1"; Error "e2"; Error "e3"]);; +eq (Ok 1) (choose [ Ok 1; Ok 2; Ok 3 ]);; +eq (Ok 2) (choose [ Error "e1"; Ok 2; Ok 3 ]);; +eq (Ok 3) (choose [ Error "e1"; Error "e2"; Ok 3 ]);; +eq (Error [ "e1"; "e2"; "e3" ]) (choose [ Error "e1"; Error "e2"; Error "e3" ]) +;; eq (Error []) (choose []);; (* Test retry *) t @@ fun () -> - let attempts = ref 0 in - let f () = - incr attempts; - if !attempts < 3 then Error "fail" else Ok "success" - in - match retry 5 f with - | Ok "success" -> !attempts = 3 - | _ -> false +let attempts = ref 0 in +let f () = + incr attempts; + if !attempts < 3 then + Error "fail" + else + Ok "success" +in +match retry 5 f with +| Ok "success" -> !attempts = 3 +| _ -> false ;; t @@ fun () -> - let attempts = ref 0 in - let f () = - incr attempts; - Error "always fails" - in - match retry 3 f with - | Error errs -> !attempts = 3 && List.length errs = 3 - | _ -> false +let attempts = ref 0 in +let f () = + incr attempts; + Error "always fails" +in +match retry 3 f with +| Error errs -> !attempts = 3 && List.length errs = 3 +| _ -> false ;; (* Test to_opt *) @@ -257,71 +308,79 @@ eq (Error "option is None") (of_opt None);; t @@ fun () -> equal ~err:String.equal Int.equal (Ok 5) (Ok 5);; t @@ fun () -> not (equal ~err:String.equal Int.equal (Ok 5) (Ok 6));; t @@ fun () -> equal ~err:String.equal Int.equal (Error "e") (Error "e");; -t @@ fun () -> not (equal ~err:String.equal Int.equal (Error "e1") (Error "e2"));; +t @@ fun () -> not (equal ~err:String.equal Int.equal (Error "e1") (Error "e2")) +;; t @@ fun () -> not (equal ~err:String.equal Int.equal (Ok 5) (Error "e"));; (* Test compare *) t @@ fun () -> compare ~err:String.compare Int.compare (Ok 5) (Ok 5) = 0;; t @@ fun () -> compare ~err:String.compare Int.compare (Ok 5) (Ok 6) < 0;; t @@ fun () -> compare ~err:String.compare Int.compare (Ok 6) (Ok 5) > 0;; -t @@ fun () -> compare ~err:String.compare Int.compare (Error "a") (Error "a") = 0;; -t @@ fun () -> compare ~err:String.compare Int.compare (Error "a") (Error "b") < 0;; + +t @@ fun () -> +compare ~err:String.compare Int.compare (Error "a") (Error "a") = 0 +;; + +t @@ fun () -> +compare ~err:String.compare Int.compare (Error "a") (Error "b") < 0 +;; + t @@ fun () -> compare ~err:String.compare Int.compare (Error "a") (Ok 5) < 0;; t @@ fun () -> compare ~err:String.compare Int.compare (Ok 5) (Error "a") > 0;; (* Property-based tests *) -q Q.int (fun x -> - return x = Ok x -);; +q Q.int (fun x -> return x = Ok x);; +q Q.(result int string) (fun r -> is_ok r = not (is_error r));; +q Q.(result int string) (fun r -> map CCFun.id r = r);; +q Q.(result int string) (fun r -> map_err CCFun.id r = r);; +q Q.(result int string) (fun r -> flat_map return r = r);; +q Q.(result int string) (fun r -> equal ~err:String.equal Int.equal r r);; -q Q.(result int string) (fun r -> - is_ok r = not (is_error r) -);; +q + Q.(result int string) + (fun r -> compare ~err:String.compare Int.compare r r = 0) +;; -q Q.(result int string) (fun r -> - map CCFun.id r = r -);; +q + Q.(result int string) + (fun r -> + of_opt (to_opt r) + = + match r with + | Ok x -> Ok x + | Error _ -> Error "option is None") +;; -q Q.(result int string) (fun r -> - map_err CCFun.id r = r -);; +q Q.int (fun x -> to_opt (Ok x) = Some x);; +q Q.string (fun e -> to_opt (Error e) = None);; -q Q.(result int string) (fun r -> - flat_map return r = r -);; +q + Q.(pair (result int string) int) + (fun (r, default) -> + let v = get_or r ~default in + match r with + | Ok x -> v = x + | Error _ -> v = default) +;; -q Q.(result int string) (fun r -> - equal ~err:String.equal Int.equal r r -);; - -q Q.(result int string) (fun r -> - compare ~err:String.compare Int.compare r r = 0 -);; - -q Q.(result int string) (fun r -> - of_opt (to_opt r) = (match r with Ok x -> Ok x | Error _ -> Error "option is None") -);; - -q Q.int (fun x -> - to_opt (Ok x) = Some x -);; - -q Q.string (fun e -> - to_opt (Error e) = None -);; - -q Q.(pair (result int string) int) (fun (r, default) -> - let v = get_or r ~default in - match r with - | Ok x -> v = x - | Error _ -> v = default -);; - -q Q.(list (result int string)) (fun l -> - match flatten_l l with - | Ok values -> List.for_all (function Ok _ -> true | Error _ -> false) l && List.length values <= List.length l - | Error _ -> List.exists (function Error _ -> true | Ok _ -> false) l -);; +q + Q.(list (result int string)) + (fun l -> + match flatten_l l with + | Ok values -> + List.for_all + (function + | Ok _ -> true + | Error _ -> false) + l + && List.length values <= List.length l + | Error _ -> + List.exists + (function + | Error _ -> true + | Ok _ -> false) + l) +;; (* Additional focused tests for high-value functions *) t @@ fun () -> map (( + ) 1) (Ok 2) = Ok 3;; @@ -329,4 +388,4 @@ t @@ fun () -> is_ok (Ok 1) && not (is_ok (Error "e"));; t @@ fun () -> to_opt (Ok 5) = Some 5 && to_opt (Error "e") = None;; t @@ fun () -> both (Ok 3) (Ok 5) = Ok (3, 5);; q Q.int (fun x -> return x = Ok x);; -q Q.int (fun x -> to_opt (Ok x) = Some x);; +q Q.int (fun x -> to_opt (Ok x) = Some x)