ocaml-containers/tests/core/t_option.ml
Simon Cruanes 84c3270718
more tests
2026-02-11 20:18:41 -05:00

332 lines
8.2 KiB
OCaml

open CCOption
module T = (val Containers_testlib.make ~__FILE__ ())
include T;;
eq None (filter (( = ) 0) (Some 1));;
eq (Some 0) (filter (( = ) 0) (Some 0));;
eq None (filter (fun _ -> true) None);;
eq
(try
get_exn_or "ohno" (None : unit option);
false
with Invalid_argument s -> s = "ohno")
;;
t @@ fun () -> 123 = get_exn_or "yes" (Some 123);;
t @@ fun () -> sequence_l [ None; Some 1; Some 2 ] = None;;
t @@ fun () -> sequence_l [ Some 1; Some 2; Some 3 ] = Some [ 1; 2; 3 ];;
t @@ fun () -> sequence_l [] = Some [];;
t @@ fun () -> choice_iter (Iter.of_list [ None; Some 1; Some 2 ]) = Some 1;;
t @@ fun () -> choice_iter Iter.empty = None;;
t @@ fun () -> choice_iter (Iter.repeat None |> Iter.take 100) = None;;
t @@ fun () -> choice_seq (CCSeq.of_list [ None; Some 1; Some 2 ]) = Some 1;;
t @@ fun () -> choice_seq CCSeq.empty = None;;
t @@ fun () -> choice_seq (CCSeq.repeat None |> CCSeq.take 100) = None;;
t @@ fun () -> flatten None = None;;
t @@ fun () -> flatten (Some None) = None;;
t @@ fun () -> flatten (Some (Some 1)) = Some 1;;
t @@ fun () -> return_if false 1 = None;;
t @@ fun () -> return_if true 1 = Some 1;;
(* Additional comprehensive tests for CCOption *)
(* Test map *)
eq (Some 2) (map (( + ) 1) (Some 1));;
eq None (map (( + ) 1) None);;
t @@ fun () -> map (fun x -> x * 2) (Some 5) = Some 10;;
(* Test map_or *)
eq 10 (map_or ~default:0 (fun x -> x * 2) (Some 5));;
eq 0 (map_or ~default:0 (fun x -> x * 2) None);;
t @@ fun () -> map_or ~default:"empty" String.uppercase_ascii (Some "hello") = "HELLO";;
t @@ fun () -> map_or ~default:"empty" String.uppercase_ascii None = "empty";;
(* Test map_lazy *)
t @@ fun () ->
let called = ref false in
let result = map_lazy (fun () -> called := true; 0) (fun x -> x * 2) (Some 5) in
result = 10 && not !called
;;
t @@ fun () ->
let called = ref false in
let result = map_lazy (fun () -> called := true; 0) (fun x -> x * 2) None in
result = 0 && !called
;;
(* Test is_some and is_none *)
t @@ fun () -> is_some (Some 1);;
t @@ fun () -> not (is_some None);;
t @@ fun () -> is_none None;;
t @@ fun () -> not (is_none (Some 1));;
(* Test compare *)
t @@ fun () -> compare Int.compare (Some 1) (Some 1) = 0;;
t @@ fun () -> compare Int.compare (Some 1) (Some 2) < 0;;
t @@ fun () -> compare Int.compare (Some 2) (Some 1) > 0;;
t @@ fun () -> compare Int.compare None None = 0;;
t @@ fun () -> compare Int.compare None (Some 1) < 0;;
t @@ fun () -> compare Int.compare (Some 1) None > 0;;
(* Test equal *)
t @@ fun () -> equal Int.equal (Some 1) (Some 1);;
t @@ fun () -> not (equal Int.equal (Some 1) (Some 2));;
t @@ fun () -> equal Int.equal None None;;
t @@ fun () -> not (equal Int.equal None (Some 1));;
t @@ fun () -> not (equal Int.equal (Some 1) None);;
(* Test return and some *)
eq (Some 42) (return 42);;
eq (Some "hello") (some "hello");;
t @@ fun () -> return 5 = Some 5;;
(* Test none *)
t @@ fun () -> (none : int option) = None;;
(* Test flat_map / bind *)
eq (Some 2) (flat_map (fun x -> Some (x + 1)) (Some 1));;
eq None (flat_map (fun x -> Some (x + 1)) None);;
eq None (flat_map (fun _ -> None) (Some 1));;
eq (Some 2) (bind (Some 1) (fun x -> Some (x + 1)));;
eq None (bind None (fun x -> Some (x + 1)));;
(* Test flat_map_l *)
eq [1; 2; 3] (flat_map_l (fun x -> [x; x+1; x+2]) (Some 1));;
eq [] (flat_map_l (fun x -> [x; x+1]) None);;
(* Test map2 *)
eq (Some 5) (map2 ( + ) (Some 2) (Some 3));;
eq None (map2 ( + ) None (Some 3));;
eq None (map2 ( + ) (Some 2) None);;
eq None (map2 ( + ) None None);;
(* Test iter *)
t @@ fun () ->
let r = ref 0 in
iter (fun x -> r := x) (Some 42);
!r = 42
;;
t @@ fun () ->
let r = ref 0 in
iter (fun x -> r := x) None;
!r = 0
;;
(* Test fold *)
eq 10 (fold (fun acc x -> acc + x) 5 (Some 5));;
eq 5 (fold (fun acc x -> acc + x) 5 None);;
(* Test if_ *)
eq (Some 5) (if_ (fun x -> x > 0) 5);;
eq None (if_ (fun x -> x > 0) (-5));;
eq (Some "hello") (if_ (fun s -> String.length s > 0) "hello");;
eq None (if_ (fun s -> String.length s > 0) "");;
(* Test exists *)
t @@ fun () -> exists (fun x -> x > 0) (Some 5);;
t @@ fun () -> not (exists (fun x -> x > 0) (Some (-5)));;
t @@ fun () -> not (exists (fun x -> x > 0) None);;
(* Test for_all *)
t @@ fun () -> for_all (fun x -> x > 0) (Some 5);;
t @@ fun () -> not (for_all (fun x -> x > 0) (Some (-5)));;
t @@ fun () -> for_all (fun x -> x > 0) None;;
(* Test get_or *)
eq 5 (get_or ~default:0 (Some 5));;
eq 0 (get_or ~default:0 None);;
(* Test value *)
eq 5 (value (Some 5) ~default:0);;
eq 0 (value None ~default:0);;
(* Test apply_or *)
eq 10 (apply_or (fun x -> Some (x * 2)) 5);;
t @@ fun () -> apply_or (fun x -> if x > 0 then Some (x * 2) else None) 5 = 10;;
t @@ fun () -> apply_or (fun x -> if x > 0 then Some (x * 2) else None) (-5) = -5;;
(* Test get_exn *)
eq 42 (get_exn (Some 42));;
t @@ fun () ->
try
ignore (get_exn None);
false
with Invalid_argument _ -> true
;;
(* Test get_lazy *)
eq 5 (get_lazy (fun () -> 0) (Some 5));;
eq 0 (get_lazy (fun () -> 0) None);;
t @@ fun () ->
let called = ref false in
let _ = get_lazy (fun () -> called := true; 0) (Some 5) in
not !called
;;
t @@ fun () ->
let called = ref false in
let _ = get_lazy (fun () -> called := true; 0) None in
!called
;;
(* Test wrap *)
t @@ fun () ->
wrap (fun x -> x + 1) 5 = Some 6
;;
t @@ fun () ->
wrap (fun _ -> failwith "error") () = None
;;
t @@ fun () ->
wrap ~handler:(fun _ -> true) (fun x -> if x = 0 then failwith "div by zero" else 10 / x) 0 = None
;;
t @@ fun () ->
wrap ~handler:(function Division_by_zero -> true | _ -> false)
(fun x -> 10 / x) 2 = Some 5
;;
(* Test wrap2 *)
t @@ fun () ->
wrap2 ( + ) 2 3 = Some 5
;;
t @@ fun () ->
wrap2 (fun _ _ -> failwith "error") 1 2 = None
;;
(* Test pure *)
eq (Some 42) (pure 42);;
(* Test or_ *)
eq (Some 1) (or_ ~else_:(Some 2) (Some 1));;
eq (Some 2) (or_ ~else_:(Some 2) None);;
eq None (or_ ~else_:None None);;
(* Test or_lazy *)
t @@ fun () ->
let called = ref false in
let result = or_lazy ~else_:(fun () -> called := true; Some 2) (Some 1) in
result = Some 1 && not !called
;;
t @@ fun () ->
let called = ref false in
let result = or_lazy ~else_:(fun () -> called := true; Some 2) None in
result = Some 2 && !called
;;
(* Test choice *)
eq (Some 1) (choice [Some 1; Some 2; Some 3]);;
eq (Some 2) (choice [None; Some 2; Some 3]);;
eq (Some 3) (choice [None; None; Some 3]);;
eq None (choice [None; None; None]);;
eq None (choice []);;
(* Test to_list *)
eq [42] (to_list (Some 42));;
eq [] (to_list None);;
(* Test of_list *)
eq (Some 1) (of_list [1]);;
eq (Some 1) (of_list [1; 2; 3]);;
eq None (of_list []);;
(* Test to_result *)
eq (Ok 5) (to_result "error" (Some 5));;
eq (Error "error") (to_result "error" None);;
(* Test to_result_lazy *)
t @@ fun () ->
let called = ref false in
let result = to_result_lazy (fun () -> called := true; "error") (Some 5) in
result = Ok 5 && not !called
;;
t @@ fun () ->
let called = ref false in
let result = to_result_lazy (fun () -> called := true; "error") None in
result = Error "error" && !called
;;
(* Test of_result *)
eq (Some 5) (of_result (Ok 5));;
eq None (of_result (Error "error"));;
(* Property-based tests *)
q Q.int (fun x ->
return x = Some x
);;
q Q.(option int) (fun o ->
is_some o = not (is_none o)
);;
q Q.(option int) (fun o ->
map CCFun.id o = o
);;
q Q.(option int) (fun o ->
flat_map return o = o
);;
q Q.(option int) (fun o ->
bind o return = o
);;
q Q.(option int) (fun o ->
equal Int.equal o o
);;
q Q.(option int) (fun o ->
compare Int.compare o o = 0
);;
q Q.(pair (option int) int) (fun (o, default) ->
let v = get_or ~default o in
match o with
| Some x -> v = x
| None -> v = default
);;
q Q.int (fun x ->
to_list (Some x) = [x]
);;
q Q.(list int) (fun l ->
match of_list l with
| Some x -> List.mem x l
| None -> l = []
);;
q Q.(option int) (fun o ->
match o with
| Some x -> of_list (to_list o) = Some x
| None -> of_list (to_list o) = None
);;
q Q.(option int) (fun o ->
of_result (to_result "err" o) = o
);;
q Q.int (fun x ->
let o1 = Some x in
let o2 = Some x in
or_ ~else_:o2 o1 = o1
);;
q Q.int (fun x ->
or_ ~else_:(Some x) None = Some x
);;
q Q.(pair (option int) (option int)) (fun (o1, o2) ->
match choice [o1; o2] with
| Some _ -> is_some o1 || is_some o2
| None -> is_none o1 && is_none o2
);;