let test_array_for_all2 () =
  let visited = ref [] in
  let p i s =
    visited := i :: !visited;
    String.make 1 (char_of_int ((int_of_char 'a') + i)) = s in
  assert (
    Stdcompat.Array.for_all2 p [| 0; 1; 2; 3 |] [| "a"; "b"; "c"; "d" |]);
  assert (List.rev !visited = [0; 1; 2; 3]);
  visited := [];
  let p i s =
    visited := i :: !visited;
    String.make 1 (char_of_int ((int_of_char 'a') + i)) = s && i <> 2 in
  assert (not (
    Stdcompat.Array.for_all2 p [| 0; 1; 2; 3 |] [| "a"; "b"; "c"; "d" |]));
  assert (List.rev !visited = [0; 1; 2]);
  visited := [];
  assert (
    try
      ignore (
        Stdcompat.Array.for_all2 p [| 0; 1; 2; 3 |] [| "a"; "b"; "c" |]);
      false
    with Invalid_argument _ -> true);
  assert (List.rev !visited = [])

let test_array_exists2 () =
  let visited = ref [] in
  let p i s =
    visited := i :: !visited;
    String.make 1 (char_of_int ((int_of_char 'a') + i)) <> s in
  assert (not (
    Stdcompat.Array.exists2 p [| 0; 1; 2; 3 |] [| "a"; "b"; "c"; "d" |]));
  assert (List.rev !visited = [0; 1; 2; 3]);
  visited := [];
  let p i s =
    visited := i :: !visited;
    String.make 1 (char_of_int ((int_of_char 'a') + i)) <> s || i = 2 in
  assert (
    Stdcompat.Array.exists2 p [| 0; 1; 2; 3 |] [| "a"; "b"; "c"; "d" |]);
  assert (List.rev !visited = [0; 1; 2]);
  visited := [];
  assert (
    try
      ignore (
        Stdcompat.Array.exists2 p [| 0; 1; 2; 3 |] [| "a"; "b"; "c" |]);
      false
    with Invalid_argument _ -> true);
  assert (List.rev !visited = [])

let test_list_filteri () =
  let visited = ref [] in
  let p i s =
    visited := i :: !visited;
    assert (string_of_int i = s);
    i mod 2 = 0 in
  assert (
    Stdcompat.List.filteri p (Stdcompat.List.init 6 string_of_int) =
      ["0"; "2"; "4"]);
  assert (List.rev !visited = [0; 1; 2; 3; 4; 5])

let test_list_fold_left_map () =
  let visited = ref [] in
  let f accu s =
    visited := s :: !visited;
    accu ^ s, "a" ^ s in
  assert (
    Stdcompat.List.fold_left_map f "" (Stdcompat.List.init 6 string_of_int) =
      ("012345", ["a0"; "a1"; "a2"; "a3"; "a4"; "a5"]));
  assert (List.rev !visited = ["0"; "1"; "2"; "3"; "4"; "5"])

let test_seq_cons () =
  assert (
    Stdcompat.List.of_seq (Stdcompat.Seq.cons 0 (Stdcompat.Seq.cons 1
      (Stdcompat.List.to_seq [2; 3]))) = [0; 1; 2; 3])

let test_seq_append () =
  assert (
    Stdcompat.List.of_seq (Stdcompat.Seq.append
      (Stdcompat.List.to_seq [0; 1; 2])
      (Stdcompat.List.to_seq [3; 4; 5])) = [0; 1; 2; 3; 4; 5])

let test_seq_unfold () =
  assert (
    Stdcompat.List.of_seq (Stdcompat.Seq.unfold (fun i ->
      if i < 5 then
        Some (string_of_int i, i + 1)
      else
        None) 0) = ["0"; "1"; "2"; "3"; "4"])

let test_set_filter_map () =
  let module Set = Stdcompat.Set.Make (Stdcompat.Int) in
  let visited = ref [] in
  assert (
    List.sort compare (Set.elements (Set.filter_map (fun i ->
      visited := i :: !visited;
      if i mod 2 = 0 then
        Some (6 - i / 2)
      else
        None)
      (Set.of_seq (Stdcompat.List.to_seq
        (Stdcompat.List.init 6 Stdcompat.Fun.id))))) = [4; 5; 6]);
  assert (List.rev !visited = [0; 1; 2; 3; 4; 5])

let test_map_filter_map () =
  let module Map = Stdcompat.Map.Make (Stdcompat.Int) in
  let visited = ref [] in
  assert (
    List.sort compare (Map.bindings (Map.filter_map (fun k s ->
      visited := k :: !visited;
      assert (string_of_int k = s);
      if k mod 2 = 0 then
        Some ("a" ^ s)
      else
        None)
      (Map.of_seq (Stdcompat.List.to_seq
        (Stdcompat.List.init 6 (fun i -> i, string_of_int i)))))) =
          [0, "a0"; 2, "a2"; 4, "a4"]);
  assert (List.rev !visited = [0; 1; 2; 3; 4; 5])

let test_mkdir_rmdir () =
  Stdcompat.Sys.mkdir "new_directory" 600;
  assert (Stdcompat.Sys.is_directory "new_directory");
  begin try
    Stdcompat.Sys.mkdir "new_directory" 600;
    assert false;
  with Sys_error _ ->
    assert true;
  end;
  Stdcompat.Sys.rmdir "new_directory";
  begin try
    Stdcompat.Sys.rmdir "new_directory";
    assert false;
  with Sys_error _ ->
    assert true;
  end

let test_set_to_seq_to_rev_seq () =
  let module M = Stdcompat.Set.Make (Stdcompat.Int) in
  let s = M.add 2 (M.add 1 (M.add 3 M.empty)) in
  assert (Stdcompat.List.of_seq (M.to_seq s) = [1; 2; 3]);
  assert (Stdcompat.List.of_seq (M.to_rev_seq s) = [3; 2; 1])

let test_map_to_seq_to_rev_seq () =
  let module M = Stdcompat.Map.Make (Stdcompat.Int) in
  let s = M.add 2 () (M.add 1 () (M.add 3 () M.empty)) in
  assert (Stdcompat.List.of_seq (M.to_seq s) = [1, (); 2, (); 3, ()]);
  assert (Stdcompat.List.of_seq (M.to_rev_seq s) = [3, (); 2, (); 1, ()])

let test_list_partition_map () =
  assert (Stdcompat.List.partition_map (fun i ->
    if i > 0 then
      Stdcompat.Either.Left i
    else
      Stdcompat.Either.Right (-i)) [1; -2; 3; -4; 5; -6]
    = ([1; 3; 5], [2; 4; 6]))

let test_list_compare () =
  let l1 = [1; 2; 3; 4] in
  let l2 = [1; 2; 4; 3] in
  let l3 = [1; 2; 5; 6] in
  assert (Stdcompat.List.compare Stdcompat.Int.compare l1 l1 = 0);
  assert (Stdcompat.List.compare Stdcompat.Int.compare l1 l2 < 0);
  assert (Stdcompat.List.compare Stdcompat.Int.compare l1 l3 < 0);
  assert (Stdcompat.List.compare Stdcompat.Int.compare l2 l1 > 0);
  assert (Stdcompat.List.compare Stdcompat.Int.compare l2 l2 = 0);
  assert (Stdcompat.List.compare Stdcompat.Int.compare l2 l3 < 0);
  assert (Stdcompat.List.compare Stdcompat.Int.compare l3 l1 > 0);
  assert (Stdcompat.List.compare Stdcompat.Int.compare l3 l2 > 0);
  assert (Stdcompat.List.compare Stdcompat.Int.compare l3 l3 = 0)

let test_list_equal () =
  let l1 = [1; 2; 3; 4] in
  let l2 = [1; 2; 4; 3] in
  let l3 = [1; 2; 5; 6] in
  assert (Stdcompat.List.equal Stdcompat.Int.equal l1 l1);
  assert (not (Stdcompat.List.equal Stdcompat.Int.equal l1 l2));
  assert (not (Stdcompat.List.equal Stdcompat.Int.equal l1 l3));
  assert (not (Stdcompat.List.equal Stdcompat.Int.equal l2 l1));
  assert (Stdcompat.List.equal Stdcompat.Int.equal l2 l2);
  assert (not (Stdcompat.List.equal Stdcompat.Int.equal l2 l3));
  assert (not (Stdcompat.List.equal Stdcompat.Int.equal l3 l1));
  assert (not (Stdcompat.List.equal Stdcompat.Int.equal l3 l2));
  assert (Stdcompat.List.equal Stdcompat.Int.equal l3 l3)

let test_hashtbl_rebuild () =
  let h = Hashtbl.create 17 in
  Hashtbl.add h 1 ();
  Hashtbl.add h 2 ();
  Hashtbl.add h 3 ();
  let h' = Stdcompat.Hashtbl.rebuild h in
  let module M = Stdcompat.Set.Make (Stdcompat.Int) in
  assert (
    M.equal
      (M.of_seq (Stdcompat.Seq.map fst (Stdcompat.Hashtbl.to_seq h')))
      (M.add 1 (M.add 2
         (M.add 3 M.empty))))

let test_format_pp_print_seq () =
  let buffer = Buffer.create 17 in
  Format.fprintf (Format.formatter_of_buffer buffer) "%a@."
    (Stdcompat.Format.pp_print_seq
      ~pp_sep:(fun fmt () -> Format.pp_print_string fmt ",")
      Format.pp_print_int) (Stdcompat.List.to_seq [1; 2; 3]);
  assert (Buffer.contents buffer = "1,2,3\n")

let test_either () =
  assert (Stdcompat.Either.compare
    ~left:Stdcompat.Int.compare ~right:Stdcompat.Int.compare
    (Stdcompat.Either.Left 1) (Stdcompat.Either.Left 1) = 0);
  assert (Stdcompat.Either.compare
    ~left:Stdcompat.Int.compare ~right:Stdcompat.Int.compare
    (Stdcompat.Either.Left 1) (Stdcompat.Either.Left 2) < 0);
  assert (Stdcompat.Either.compare
    ~left:Stdcompat.Int.compare ~right:Stdcompat.Int.compare
    (Stdcompat.Either.Left 1) (Stdcompat.Either.Right 2) < 0);
  assert (Stdcompat.Either.compare
    ~left:Stdcompat.Int.compare ~right:Stdcompat.Int.compare
    (Stdcompat.Either.Right 1) (Stdcompat.Either.Left 2) > 0);
  assert (Stdcompat.Either.compare
    ~left:Stdcompat.Int.compare ~right:Stdcompat.Int.compare
    (Stdcompat.Either.Right 1) (Stdcompat.Either.Right 2) < 0)

let () =
  assert (Stdcompat.hypot 3. 4. = 5.);
  assert (Stdcompat.copysign 1. 2. = 1.);
  assert (Stdcompat.copysign 1. (-. 2.) = -. 1.);
  assert (Stdcompat.copysign (-. 1.) 2. = 1.);
  assert (Stdcompat.copysign (-. 1.) (-. 2.) = -. 1.);
  assert (
    try
      ignore (Stdcompat.raise_notrace Exit);
      false
    with Exit -> true);
  assert (Stdcompat.bool_of_string_opt "true" = Some true);
  assert (Stdcompat.bool_of_string_opt "false" = Some false);
  assert (Stdcompat.bool_of_string_opt "foo" = None);
  assert (Stdcompat.int_of_string_opt "42" = Some 42);
  assert (Stdcompat.int_of_string_opt "foo" = None);
  assert (Stdcompat.float_of_string_opt "42." = Some 42.);
  assert (Stdcompat.float_of_string_opt "foo" = None);
  assert (Lazy.force (Stdcompat.Lazy.from_fun (fun () -> 42)) = 42);
  assert (Lazy.force (Stdcompat.Lazy.from_val 42) = 42);
  assert (Stdcompat.Char.lowercase_ascii 'A' = 'a');
  assert (Stdcompat.Char.uppercase_ascii 'a' = 'A');
  assert (Stdcompat.Char.equal 'a' 'a');
  assert (not (Stdcompat.Char.equal 'A' 'a'));
  assert (Stdcompat.String.init 2 (fun i -> char_of_int i) = "\000\001");
  assert
    (Stdcompat.String.mapi
       (fun i c -> char_of_int (i + int_of_char c)) "abc" = "ace");
  assert (
    let s = Stdcompat.Bytes.create 3 in
    Stdcompat.String.iteri (fun i c -> Stdcompat.Bytes.set s i c) "abc";
    s = Stdcompat.Bytes.of_string "abc");
  assert (Stdcompat.String.map Stdcompat.Char.uppercase_ascii "abc" = "ABC");
  assert (Stdcompat.String.trim " \t abc\n" = "abc");
  assert (Stdcompat.String.lowercase_ascii "AbcD" = "abcd");
  assert (Stdcompat.String.uppercase_ascii "AbcD" = "ABCD");
  assert (Stdcompat.String.capitalize_ascii "abcD" = "AbcD");
  assert (Stdcompat.String.uncapitalize_ascii "AbcD" = "abcD");
  assert (Stdcompat.String.equal "abc" "abc");
  assert (not (Stdcompat.String.equal "Abc" "abc"));
  assert (Stdcompat.String.split_on_char ' ' " abc  d ef  "
    = ["";"abc";"";"d";"ef";"";""]);
  assert (Stdcompat.String.index_opt "abaababa" 'a' = Some 0);
  assert (Stdcompat.String.index_opt "abaababa" 'c' = None);
  assert (Stdcompat.String.rindex_opt "abaababa" 'a' = Some 7);
  assert (Stdcompat.String.rindex_opt "abaababa" 'c' = None);
  assert (Stdcompat.String.index_from_opt "abaababa" 1 'a' = Some 2);
  assert (Stdcompat.String.index_from_opt "abaababa" 1 'c' = None);
  assert (Stdcompat.String.rindex_from_opt "abaababa" 4 'a' = Some 3);
  assert (Stdcompat.String.rindex_from_opt "abaababa" 4 'c' = None);
  assert (
    let s = Stack.create () in
    Stack.push 1 s;
    Stack.push 2 s;
    Stack.push 3 s;
    Stdcompat.Stack.fold ( + ) 0 s = 6 &&
    Stack.length s = 3);
  assert (
    let t = Hashtbl.create 17 in
    Hashtbl.add t 1 2;
    Hashtbl.add t 3 4;
    (Stdcompat.Hashtbl.stats t).Stdcompat.Hashtbl.num_bindings = 2);
  assert (
    let t = Hashtbl.create 17 in
    Hashtbl.add t 1 1;
    Hashtbl.add t 2 2;
    Hashtbl.add t 2 3;
    Hashtbl.add t 3 4;
    Stdcompat.Hashtbl.filter_map_inplace
        (fun k v -> if k = 3 then None else Some (pred v)) t;
    Hashtbl.find_all t 1 = [0] &&
    Hashtbl.find_all t 2 = [2; 1] &&
    Hashtbl.find_all t 3 = []);
  assert (
    let t = Hashtbl.create 17 in
    Hashtbl.add t 1 1;
    Hashtbl.add t 2 2;
    Stdcompat.Hashtbl.find_opt t 1 = Some 1 &&
    Stdcompat.Hashtbl.find_opt t 3 = None);
  assert (
    let module H = struct
      type t = int

      let equal : int -> int -> bool = ( = )

      let hash : int -> int = fun x -> x
    end in
    let module M = Hashtbl.Make (H) in
    let module M' = Stdcompat.Hashtbl.Make (H) in
    let t = M.create 17 in
    M.add t 1 1;
    M.add t 2 2;
    M'.find_opt t 1 = Some 1 &&
    M'.find_opt t 3 = None);
  assert (
    let module S = Set.Make (String) in
    let module S' = Stdcompat.Set.Make (String) in
    let s = S'.of_list ["a"; "b"; "c"] in
    S.compare
      (S'.map (fun s -> s ^ ".") s)
      (S'.of_list ["a."; "b."; "c."]) = 0 &&
    S'.find_opt "a" s = Some "a" &&
    S'.find_opt "d" s = None &&
    S'.find_first (fun s -> s >= "b") s = "b" &&
    S'.find_last (fun s -> s <= "b") s = "b");
  assert (
    let module M = Map.Make (String) in
    let module M' = Stdcompat.Map.Make (String) in
    let m = M.add "1" 2 M.empty in
    M'.compare compare (
      M'.update "1" (function None -> Some 0 | Some i -> Some (i + 1))
      (M'.update "2" (function None -> Some 0 | Some _ -> None)
         (M'.update "3" (function None -> None | Some i -> Some i) m)))
      (M.add "1" 3 (M.add "2" 0 M.empty)) = 0);
  assert (
    let b = Stdcompat.Bytes.of_string "hello" in
    let b = Stdcompat.Bytes.extend b (-1) 2 in
    Stdcompat.Bytes.sub_string b 0 4 = "ello" &&
    Stdcompat.Bytes.length b = 6);
  assert (
    let l = ref [] in
    let f a b =
      l := (a, b) :: !l in
    Stdcompat.List.iteri f [1; 2; 3];
    !l = [2, 3; 1, 2; 0, 1]);
  assert (
    let f a b =
      (a, b) in
    Stdcompat.List.mapi f  [1; 2; 3] = [0, 1; 1, 2; 2, 3]);
  assert (
    Stdcompat.List.sort_uniq compare  [2; 1; 3; 2; 1; 3]
    = [1; 2; 3]);
  assert (Stdcompat.List.cons 1 [2; 3] = [1; 2; 3]);
  assert (Stdcompat.List.compare_lengths [1] [2; 3] < 0);
  assert (Stdcompat.List.compare_lengths [1; 2] [2; 3] = 0);
  assert (Stdcompat.List.compare_lengths [1; 2; 3] [2; 3] > 0);
  assert (Stdcompat.List.compare_length_with [1] 2 < 0);
  assert (Stdcompat.List.compare_length_with [1; 2] 2 = 0);
  assert (Stdcompat.List.compare_length_with [1; 2; 3] 2 > 0);;
  assert (Stdcompat.List.nth_opt [1; 2; 3] 2 = Some 3);
  assert (Stdcompat.List.nth_opt [1; 2; 3] 3 = None);
  assert (
    try
      ignore (Stdcompat.List.nth_opt [1; 2; 3] (-1));
      false
    with Invalid_argument _ -> true);
  assert (Stdcompat.List.find_opt (fun i -> i mod 2 = 0) [1; 2; 3] = Some 2);
  assert (Stdcompat.List.find_opt (fun i -> i mod 4 = 0) [1; 2; 3] = None);
  assert (Stdcompat.List.assoc_opt 2 [1, 0; 2, 1; 3, 2] = Some 1);
  assert (Stdcompat.List.assoc_opt 4 [1, 0; 2, 1; 3, 2] = None);
  assert (Stdcompat.List.assq_opt 2 [1, 0; 2, 1; 3, 2] = Some 1);
  assert ("a" == "a" || (* "a" == "a" since OCaml 4.10.0 *)
    Stdcompat.List.assq_opt "a" ["a", 1; "b", 2; "c", 3] = None);
  assert (
    let r1 = ref 1 in
    let r1' = ref 1 in
    let r2 = ref 2 in
    let r3 = ref 3 in
    Stdcompat.List.assoc_opt r1' [r1, 1; r2, 2; r3, 3] = Some 1 &&
    Stdcompat.List.assq_opt r1' [r1, 1; r2, 2; r3, 3] = None);
  assert (Stdcompat.Filename.extension "a.b/c.de" = ".de");
  assert (Stdcompat.Filename.extension "a.b/cd" = "");
  assert (Stdcompat.Filename.remove_extension "a.b/c.de" = "a.b/c");
  assert (Stdcompat.Filename.remove_extension "a.b/cd" = "a.b/cd");
  
  assert (Stdcompat.Filename.remove_extension "a.b\\cd" = "a");
  
  (*
  assert (Stdcompat.Filename.remove_extension "a.b\\cd" = "a.b\\cd");
  *)
  assert (
    let array = Stdcompat.Array.Floatarray.create 2 in
    Stdcompat.Array.Floatarray.set array 0 1.;
    Stdcompat.Array.Floatarray.set array 1 2.;
    Stdcompat.Array.Floatarray.get array 0 = 1. &&
    Stdcompat.Array.Floatarray.get array 1 = 2.);
  assert (
    let l = ref [] in
    let f a b =
      l := (a, b) :: !l in
    Stdcompat.Array.iter2 f [| 0; 1 |] [| 2; 3 |];
    !l = [1, 3; 0, 2]);
  assert (
    let f a b =
      (a, b) in
    Stdcompat.Array.map2 f  [| 0; 1 |] [| 2; 3 |] = [| 0, 2; 1, 3 |]);
  assert (Stdcompat.Array.for_all (fun x -> x > 0) [| 1; 2; 3 |]);
  assert (not (Stdcompat.Array.for_all (fun x -> x > 0) [| 1; 2; 0; 3 |]));
  assert (Stdcompat.Array.exists (fun x -> x > 2) [| 1; 2; 3 |]);
  assert (not (Stdcompat.Array.exists (fun x -> x > 3) [| 1; 2; 3 |]));
  assert (Stdcompat.Array.mem "a" [| "a"; "b"; "c" |]);
  assert (not (Stdcompat.Array.mem "d" [| "a"; "b"; "c" |]));
  assert (Stdcompat.Array.memq 2 [| 1; 2; 3 |]);
  assert ("a" == "a" || (* "a" == "a" since OCaml 4.10.0 *)
    not (Stdcompat.Array.memq "a" [| "a"; "b"; "c" |]));
  assert (
    let r1 = ref 1 in
    let r1' = ref 1 in
    let r2 = ref 2 in
    let r3 = ref 3 in
    Stdcompat.List.mem r1' [r1; r2; r3] &&
    not (Stdcompat.List.memq r1' [r1; r2; r3]));
  assert (
    let q = Stdcompat.Queue.create () in
    Stdcompat.Array.of_seq (Stdcompat.Queue.to_seq q) = [| |]);
  assert (
    let q = Stdcompat.Queue.create () in
    Stdcompat.Queue.add_seq q (Stdcompat.List.to_seq ["a"; "b"; "c"]);
    Stdcompat.Array.of_seq (Stdcompat.Queue.to_seq q) = [| "a"; "b"; "c" |]);
  assert (
    let l = Stdcompat.List.to_seq ["a", 1; "b", 2; "c", 3] in
    let module M = Stdcompat.Map.Make (String) in
    let q = Stdcompat.Hashtbl.of_seq (M.to_seq (M.of_seq l)) in
    let m = M.of_seq (Stdcompat.Hashtbl.to_seq q) in
    M.cardinal m = 3 && M.find "a" m = 1 && M.find "b" m = 2
      && M.find "c" m = 3);
  assert (
    Stdcompat.Filename.chop_suffix_opt ~suffix:".txt" "readme.txt"
      = Some "readme");
  assert (
    Stdcompat.Filename.chop_suffix_opt ~suffix:".txt" "x"
      = None);
  assert (
    Stdcompat.Filename.chop_suffix_opt ~suffix:".txt" "readme.md"
      = None);
  (*
  assert (
    Stdcompat.Filename.chop_suffix_opt ~suffix:".txt" "readme.TXT"
      = Some "readme");
  *)
  
  assert (
    Stdcompat.Filename.chop_suffix_opt ~suffix:".txt" "readme.TXT"
      = None);
  
  (*
  assert (Stdcompat.Filename.dir_sep = "\\");
  *)
  
  assert (Stdcompat.Filename.dir_sep = "/");
  
  assert (not (Stdcompat.Float.sign_bit 1.));
  assert (not (Stdcompat.Float.sign_bit 0.));
  assert (not (Stdcompat.Float.is_nan 42.));
  assert (Stdcompat.Float.is_nan (0. /. 0.));
  assert (not (Stdcompat.Float.is_infinite 0.));
  assert (Stdcompat.Float.is_infinite (1. /. 0.));
  assert (not (Stdcompat.Float.is_infinite (0. /. 0.)));
  assert (Stdcompat.Float.is_finite 0.);
  assert (not (Stdcompat.Float.is_finite (1. /. 0.)));
  assert (not (Stdcompat.Float.is_finite (0. /. 0.)));
  assert (Stdcompat.Float.trunc 1.5 = 1.);
  assert (Stdcompat.Float.trunc (-2.6) = -2.);
  assert (Stdcompat.Float.is_infinite (Stdcompat.Float.trunc (1. /. 0.)));
  assert (Stdcompat.Float.is_nan (Stdcompat.Float.trunc (0. /. 0.)));
  assert (Stdcompat.Float.is_integer 1.);
  assert (not (Stdcompat.Float.is_integer 1.5));
  assert (Stdcompat.Float.is_infinite (Stdcompat.Float.trunc (1. /. 0.)));
  assert (Stdcompat.Float.is_nan (Stdcompat.Float.trunc (0. /. 0.)));
  assert (Stdcompat.Float.round 1.5 = 2.);
  assert (Stdcompat.Float.round 1.4 = 1.);
  assert (Stdcompat.Float.round (-2.6) = -3.);
  assert (Stdcompat.Float.round (-3.5) = -4.);
  assert (Stdcompat.Float.round (-4.4) = -4.);
  assert (Stdcompat.Float.is_infinite (Stdcompat.Float.round (1. /. 0.)));
  assert (Stdcompat.Float.is_nan (Stdcompat.Float.round (0. /. 0.)));
  assert (Stdcompat.Float.sign_bit (-1.));
  assert (Stdcompat.Float.min_num 1. (0. /. 0.) = 1.);
  assert (Stdcompat.Float.min_num (0. /. 0.) 1. = 1.);
  assert (Stdcompat.Float.min_num 1. (-1.) = (-1.));
  assert (Stdcompat.Float.min_num (-1.) 1. = (-1.));
  assert (Stdcompat.Float.sign_bit (Stdcompat.Float.min_num 0. (-0.)));
  assert (Stdcompat.Float.sign_bit (Stdcompat.Float.min_num (-0.) 0.));
  assert (Stdcompat.Float.is_nan (
    Stdcompat.Float.min_num (0. /. 0.) (0. /. 0.)));
  assert (Stdcompat.Float.max_num 1. (0. /. 0.) = 1.);
  assert (Stdcompat.Float.max_num (0. /. 0.) 1. = 1.);
  assert (Stdcompat.Float.max_num 1. (-1.) = 1.);
  assert (Stdcompat.Float.max_num (-1.) 1. = 1.);
  assert (not (Stdcompat.Float.sign_bit (Stdcompat.Float.max_num 0. (-0.))));
  assert (not (Stdcompat.Float.sign_bit (Stdcompat.Float.max_num (-0.) 0.)));
  assert (Stdcompat.Float.is_nan (
    Stdcompat.Float.max_num (0. /. 0.) (0. /. 0.)));
  assert (Stdcompat.Float.min_max_num 1. (0. /. 0.) = (1., 1.));
  assert (Stdcompat.Float.min_max_num (0. /. 0.) 1. = (1., 1.));
  assert (Stdcompat.Float.min_max_num 1. (-1.) = (-1., 1.));
  assert (Stdcompat.Float.min_max_num (-1.) 1. = (-1., 1.));
  assert (
    let min, max = Stdcompat.Float.min_max_num 0. (-0.) in
    Stdcompat.Float.sign_bit min &&
    not (Stdcompat.Float.sign_bit max));
  assert (
    let min, max = Stdcompat.Float.min_max_num (-0.) 0. in
    Stdcompat.Float.sign_bit min &&
    not (Stdcompat.Float.sign_bit max));
  assert (
    let min, max = Stdcompat.Float.min_max_num (0. /. 0.) (0. /. 0.) in
    Stdcompat.Float.is_nan min &&
    Stdcompat.Float.is_nan max);
  assert (Stdcompat.Float.is_nan (Stdcompat.Float.min 1. (0. /. 0.)));
  assert (Stdcompat.Float.is_nan (Stdcompat.Float.min (0. /. 0.) 1.));
  assert (Stdcompat.Float.min 1. (-1.) = (-1.));
  assert (Stdcompat.Float.min (-1.) 1. = (-1.));
  assert (Stdcompat.Float.sign_bit (Stdcompat.Float.min 0. (-0.)));
  assert (Stdcompat.Float.sign_bit (Stdcompat.Float.min (-0.) 0.));
  assert (Stdcompat.Float.is_nan (
    Stdcompat.Float.min (0. /. 0.) (0. /. 0.)));
  assert (Stdcompat.Float.is_nan (Stdcompat.Float.max 1. (0. /. 0.)));
  assert (Stdcompat.Float.is_nan (Stdcompat.Float.max (0. /. 0.) 1.));
  assert (Stdcompat.Float.max 1. (-1.) = 1.);
  assert (Stdcompat.Float.max (-1.) 1. = 1.);
  assert (not (Stdcompat.Float.sign_bit (Stdcompat.Float.max 0. (-0.))));
  assert (not (Stdcompat.Float.sign_bit (Stdcompat.Float.max (-0.) 0.)));
  assert (Stdcompat.Float.is_nan (
    Stdcompat.Float.max (0. /. 0.) (0. /. 0.)));
  assert (
    let min, max = Stdcompat.Float.min_max 1. (0. /. 0.) in
    Stdcompat.Float.is_nan min &&
    Stdcompat.Float.is_nan max);
  assert (
    let min, max = Stdcompat.Float.min_max (0. /. 0.) 1. in
    Stdcompat.Float.is_nan min &&
    Stdcompat.Float.is_nan max);
  assert (Stdcompat.Float.min_max 1. (-1.) = (-1., 1.));
  assert (Stdcompat.Float.min_max (-1.) 1. = (-1., 1.));
  assert (
    let min, max = Stdcompat.Float.min_max 0. (-0.) in
    Stdcompat.Float.sign_bit min &&
    not (Stdcompat.Float.sign_bit max));
  assert (
    let min, max = Stdcompat.Float.min_max (-0.) 0. in
    Stdcompat.Float.sign_bit min &&
    not (Stdcompat.Float.sign_bit max));
  assert (
    let min, max = Stdcompat.Float.min_max (0. /. 0.) (0. /. 0.) in
    Stdcompat.Float.is_nan min &&
    Stdcompat.Float.is_nan max);
  assert (Stdcompat.Float.next_after max_float infinity = infinity);
  assert (Stdcompat.Float.next_after 0. infinity = Int64.float_of_bits Stdcompat.Int64.one);
  assert (Stdcompat.Float.next_after (Int64.float_of_bits Stdcompat.Int64.one) 0. = 0.);
  assert (Stdcompat.Float.next_after 1. 1. = 1.);
  assert (Stdcompat.Float.is_nan (Stdcompat.Float.next_after (0. /. 0.) 1.));
  assert (Stdcompat.Float.is_nan (Stdcompat.Float.next_after 1. (0. /. 0.)));
  let b = Stdcompat.Bytes.of_string "\x20\x30\x40\x50\x60\x70\x80\x90" in
  assert (Stdcompat.Bytes.get_uint8 b 1 = 0x30);
  assert (Stdcompat.Bytes.get_int8 b 1 = 0x30);
  assert (Stdcompat.Bytes.get_uint8 b 6 = 0x80);
  assert (Stdcompat.Bytes.get_int8 b 6 = -0x80);
  assert (Stdcompat.Bytes.get_uint16_le b 4 = 0x7060);
  assert (Stdcompat.Bytes.get_uint16_be b 4 = 0x6070);
  assert (Stdcompat.Bytes.get_int16_le b 4 = 0x7060);
  assert (Stdcompat.Bytes.get_int16_be b 4 = 0x6070);
  assert (Stdcompat.Bytes.get_uint16_le b 6 = 0x9080);
  assert (Stdcompat.Bytes.get_uint16_be b 6 = 0x8090);
  assert (Stdcompat.Bytes.get_int16_le b 6 = -0x6F80);
  assert (Stdcompat.Bytes.get_int16_be b 6 = -0x7F70);
  assert (Stdcompat.Bytes.get_int32_le b 0 = 0x50403020l);
  assert (Stdcompat.Bytes.get_int32_be b 0 = 0x20304050l);
  assert (Stdcompat.Bytes.get_int64_le b 0 = 0x9080706050403020L);
  assert (Stdcompat.Bytes.get_int64_be b 0 = 0x2030405060708090L);
  let check_invalid_arg f =
    try
      f ();
      false
    with Invalid_argument _ ->
      true in
  assert (check_invalid_arg (fun () -> Stdcompat.Bytes.get_uint8 b (-1)));
  assert (check_invalid_arg (fun () -> Stdcompat.Bytes.get_uint8 b 8));
  assert (check_invalid_arg (fun () -> Stdcompat.Bytes.get_uint16_le b (-1)));
  assert (check_invalid_arg (fun () -> Stdcompat.Bytes.get_uint16_le b 7));
  assert (check_invalid_arg (fun () -> Stdcompat.Bytes.get_int32_le b (-1)));
  assert (check_invalid_arg (fun () -> Stdcompat.Bytes.get_int32_le b 5));
  assert (check_invalid_arg (fun () -> Stdcompat.Bytes.get_int64_le b (-1)));
  assert (check_invalid_arg (fun () -> Stdcompat.Bytes.get_int64_le b 1));
  assert (
    Stdcompat.Bytes.set_uint8 b 1 0x90;
    Stdcompat.Bytes.get_uint8 b 1 = 0x90);
  assert (
    Stdcompat.Bytes.set_int8 b 1 (-0x20);
    Stdcompat.Bytes.get_int8 b 1 = (-0x20));
  assert (
    Stdcompat.Bytes.set_uint16_le b 1 0x1234;
    Stdcompat.Bytes.get_uint16_le b 1 = 0x1234);
  assert (
    Stdcompat.Bytes.set_uint16_be b 1 0x1234;
    Stdcompat.Bytes.get_uint16_be b 1 = 0x1234);
  assert (
    Stdcompat.Bytes.set_int16_le b 1 (-0x1234);
    Stdcompat.Bytes.get_int16_le b 1 = (-0x1234));
  assert (
    Stdcompat.Bytes.set_int16_be b 1 (-0x1234);
    Stdcompat.Bytes.get_int16_be b 1 = (-0x1234));
  assert (
    Stdcompat.Bytes.set_int32_le b 1 0x12345678l;
    Stdcompat.Bytes.get_int32_le b 1 = 0x12345678l);
  assert (
    Stdcompat.Bytes.set_int32_be b 1 0x12345678l;
    Stdcompat.Bytes.get_int32_be b 1 = 0x12345678l);
  assert (
    Stdcompat.Bytes.set_int64_le b 0 0x123456789ABCDEF0L;
    Stdcompat.Bytes.get_int64_le b 0 = 0x123456789ABCDEF0L);
  assert (
    Stdcompat.Bytes.set_int64_be b 0 0x123456789ABCDEF0L;
    Stdcompat.Bytes.get_int64_be b 0 = 0x123456789ABCDEF0L);
  assert (check_invalid_arg (fun () -> Stdcompat.Bytes.set_uint8 b (-1) 0));
  assert (check_invalid_arg (fun () -> Stdcompat.Bytes.set_uint8 b 8 0));
  assert (check_invalid_arg (fun () -> Stdcompat.Bytes.set_uint16_le b (-1) 0));
  assert (check_invalid_arg (fun () -> Stdcompat.Bytes.set_uint16_le b 7 0));
  assert (check_invalid_arg (fun () -> Stdcompat.Bytes.set_int32_le b (-1) 0l));
  assert (check_invalid_arg (fun () -> Stdcompat.Bytes.set_int32_le b 5 0l));
  assert (check_invalid_arg (fun () -> Stdcompat.Bytes.set_int64_le b (-1) 0L));
  assert (check_invalid_arg (fun () -> Stdcompat.Bytes.set_int64_le b 1 0L));
  assert (Stdcompat.Bytes.get_int64_be b 0 = 0x123456789ABCDEF0L);
  assert (
    let finalized = ref false in
    Stdcompat.Fun.protect ~finally:(fun () -> finalized := true) (fun () -> true) &&
    !finalized);
  assert (
    try
      Stdcompat.Fun.protect ~finally:(fun () -> raise Exit) (fun () -> failwith "protect")
    with Stdcompat.Fun.Finally_raised Exit -> true | _ -> false);
  let (_ : 'a Stdcompat.Seq.t) = Stdcompat.Stdlib.Seq.empty in
  let (_ : 'a Stdcompat.Stdlib.Seq.t) = Stdcompat.Seq.empty in
  let (_ : (unit, 'a) Stdcompat.result) = Stdcompat.Ok () in
  let (_ : (unit, 'a) Stdcompat.Result.t) = Stdcompat.Ok () in
  let (_ : (unit, 'a) Stdcompat.Stdlib.Result.t) = Stdcompat.Ok () in
  let (_ : (unit, 'a) Stdcompat.result) = Stdcompat.Result.Ok () in
  let (_ : (unit, 'a) Stdcompat.Result.t) = Stdcompat.Result.Ok () in
  let (_ : (unit, 'a) Stdcompat.Stdlib.Result.t) = Stdcompat.Result.Ok () in
  let (_ : (unit, 'a) Stdcompat.result) = Stdcompat.Stdlib.Result.Ok () in
  let (_ : (unit, 'a) Stdcompat.Result.t) = Stdcompat.Stdlib.Result.Ok () in
  let (_ : (unit, 'a) Stdcompat.Stdlib.Result.t) = Stdcompat.Stdlib.Result.Ok () in
  assert (Stdcompat.Fun.id true);
  assert (Stdcompat.Fun.const true false);
  assert (Stdcompat.Fun.flip ( - ) 1 2 = 1);
  assert (Stdcompat.Fun.negate not true);
  assert (
    let bytes = Stdcompat.Bytes.of_string "abcde" in
    Stdcompat.Bytes.unsafe_blit_string "ABCDEF" 2 bytes 1 3;
    Stdcompat.Bytes.compare bytes (Stdcompat.Bytes.of_string "aCDEe") == 0);
  assert (
    Stdcompat.List.concat_map
      (fun x -> [x * 2; x - 1]) [1; 2; 3] = [2; 0; 4; 1; 6; 2]);
  assert (
    Stdcompat.List.find_map (Stdcompat.List.assoc_opt 1)
      [[2, 3; 4, 1]; [5, 2;1, 7]] = Some 7);
  assert (
    Stdcompat.List.find_map (Stdcompat.List.assoc_opt 1)
      [[2, 3; 4, 1]; [5, 2;2, 7]] = None);
  let check_quote_string s =
    let (file, channel) = Filename.open_temp_file "test_quote_command" ".ml" in
    Stdcompat.Fun.protect (fun () ->
      Stdcompat.Fun.protect (fun () ->
        Printf.fprintf channel "
          assert (Sys.argv.(1) = \"%s\")
        " (String.escaped s))
      ~finally:(fun () -> close_out channel);
      let file_exe = Filename.chop_suffix file ".ml" ^ ".exe" in
      assert (
        Sys.command (Stdcompat.Filename.quote_command "ocamlopt.opt"
          [file; "-o"; file_exe]) == 0);
      assert (
        Sys.command (Stdcompat.Filename.quote_command file_exe [s]) == 0))
    ~finally:(fun () -> Sys.remove file) in
  check_quote_string "a\\\\";
  check_quote_string "a\\\\b\"\\\"\\\\\"\"\\";
  test_array_for_all2 ();
  test_array_exists2 ();
  test_list_filteri ();
  test_list_fold_left_map ();
  test_seq_cons ();
  test_seq_append ();
  test_seq_unfold ();
  test_set_filter_map ();
  test_map_filter_map ();
  test_mkdir_rmdir ();
  test_set_to_seq_to_rev_seq ();
  test_map_to_seq_to_rev_seq ();
  test_list_partition_map ();
  test_list_compare ();
  test_list_equal ();
  test_hashtbl_rebuild ();
  test_format_pp_print_seq ();
  test_either ();
  ()
