From 4db8472ca25cb8e0bfb360354806f02b28174ae8 Mon Sep 17 00:00:00 2001 From: Pass Automated Testing Suite Date: Mon, 29 Apr 2024 15:41:11 +0200 Subject: [PATCH] Make tests more concise and readable. --- test/test_chacha.ml | 11 ++---- test/test_pcg.ml | 10 ++--- test/test_philox.ml | 11 ++---- test/test_xoshiro.ml | 5 +-- test/testconf.ml | 94 ++++++++++++++++++-------------------------- 5 files changed, 52 insertions(+), 79 deletions(-) diff --git a/test/test_chacha.ml b/test/test_chacha.ml index e79282b..320a22d 100644 --- a/test/test_chacha.ml +++ b/test/test_chacha.ml @@ -37,19 +37,16 @@ let test_advance _ = (* manually advance ChaCha n times. Since Chacha generates 32bit ints, we advance manually using next_uint32, else if we used next_uint64 we would need to use n/2 steps.*) - let rec advance_n t = function - | 0 -> t - | i -> advance_n (ChaCha.next_uint32 t |> snd) (i - 1) - in let t = ChaCha.initialize_full (SeedSequence.initialize [Uint128.of_int 12345]) Uint64.(max_int, zero) 4 in + let advance n = Seq.(iterate (fun s -> ChaCha.next_uint32 s |> snd) t |> drop n |> uncons |> Option.get |> fst) in assert_equal - (ChaCha.advance (Uint128.of_int 1000) t |> ChaCha.next_uint32 |> fst |> Uint32.to_string) - (advance_n t 1000 |> ChaCha.next_uint32 |> fst |> Uint32.to_string) + (ChaCha.advance (Uint128.of_int 100) t |> ChaCha.next_uint32 |> fst |> Uint32.to_string) + (advance 100 |> ChaCha.next_uint32 |> fst |> Uint32.to_string) ~printer:(fun x -> x); (* Test zero advancing *) assert_equal (ChaCha.advance Uint128.zero t |> ChaCha.next_uint32 |> fst |> Uint32.to_string) - (advance_n t 0 |> ChaCha.next_uint32 |> fst |> Uint32.to_string) + (advance 0 |> ChaCha.next_uint32 |> fst |> Uint32.to_string) ~printer:(fun x -> x); (* Advancing with the largest 128bit integer should not fail *) ignore (ChaCha.advance Uint128.max_int t) diff --git a/test/test_pcg.ml b/test/test_pcg.ml index 114cb64..2ae8b38 100644 --- a/test/test_pcg.ml +++ b/test/test_pcg.ml @@ -4,15 +4,11 @@ open Bitgen let test_advance _ = let open Stdint in - (* manually advance PCG64 n times and return the (n+1)'th random value. *) - let rec advance_n i t n = match i >= n with - | true -> PCG64.next_uint64 t |> fst |> Uint64.to_string - | false -> advance_n (i + 1) (PCG64.next_uint64 t |> snd) n - in let t = SeedSequence.initialize [Uint128.of_int 12345] |> PCG64.initialize in + let advance n = Seq.(iterate (fun s -> PCG64.next_uint64 s |> snd) t |> drop n |> uncons |> Option.get |> fst) in assert_equal - (PCG64.advance (Int128.of_int 12344) t |> PCG64.next_uint64 |> fst |> Uint64.to_string) - (advance_n 0 t 12344) + (PCG64.advance (Int128.of_int 100) t |> PCG64.next_uint64 |> fst |> Uint64.to_string) + (advance 100 |> PCG64.next_uint64 |> fst |> Uint64.to_string) ~printer:(fun x -> x) diff --git a/test/test_philox.ml b/test/test_philox.ml index 8983483..66fabdf 100644 --- a/test/test_philox.ml +++ b/test/test_philox.ml @@ -19,8 +19,7 @@ let test_counter_init _ = let ss = SeedSequence.initialize [Uint128.of_int 12345] in let next_int init = Philox4x64.initialize_ctr ~counter:init ss - |> Philox4x64.next_uint64 |> fst |> Uint64.to_string - in + |> Philox4x64.next_uint64 |> fst |> Uint64.to_string in let base = next_int Uint64.(max_int, max_int, max_int, max_int) in assert_bool "" (base <> next_int Uint64.(max_int, max_int, max_int, zero)); assert_bool "" (base <> next_int Uint64.(max_int, max_int, zero, zero)); @@ -33,7 +32,7 @@ let test_jump _ = let ss = SeedSequence.initialize [] in let t = Philox4x64.initialize_ctr ~counter:Uint64.(max_int, max_int, max_int, max_int) ss |> Philox4x64.jump in let t' = Philox4x64.initialize_ctr ~counter:Uint64.(max_int, max_int, zero, max_int) ss |> Philox4x64.jump in - assert_bool "" ((Philox4x64.next_double t |> fst) <> (Philox4x64.next_double t' |> fst)) + assert_bool "" ((Philox4x64.next_uint64 t |> fst) <> (Philox4x64.next_uint64 t' |> fst)) let test_advance _ = @@ -41,14 +40,12 @@ let test_advance _ = (* since advance uses a 256-bit integer to advance, the equivalent number of steps if manually calling next_uint64 would be 4 times larger than the steps used to call advance. *) - let rec advance_n t = function - | 0 -> t - | i -> advance_n (Philox4x64.next_uint64 t |> snd) (i - 1) in let t = SeedSequence.initialize [Uint128.of_int 12345] |> Philox4x64.initialize_ctr ~counter:Uint64.(max_int, max_int, zero, zero) in + let advance n = Seq.(iterate (fun s -> Philox4x64.next_uint64 s |> snd) t |> drop n |> uncons |> Option.get |> fst) in assert_equal (Philox4x64.advance Uint64.(of_int 2, zero, zero, zero) t |> Philox4x64.next_uint64 |> fst |> Uint64.to_string) - (advance_n t (4 * 2) |> Philox4x64.next_uint64 |> fst |> Uint64.to_string) + (advance (4 * 2) |> Philox4x64.next_uint64 |> fst |> Uint64.to_string) ~printer:(fun x -> x) diff --git a/test/test_xoshiro.ml b/test/test_xoshiro.ml index 277c7a0..5984c0f 100644 --- a/test/test_xoshiro.ml +++ b/test/test_xoshiro.ml @@ -15,10 +15,9 @@ let test_bounded_u64 _ = Testconf.test_bounded_u64 (module Xoshiro256) let test_jump _ = - let ss = SeedSequence.initialize [] in - let t = Xoshiro256.initialize ss |> Xoshiro256.jump in + let t = SeedSequence.initialize [] |> Xoshiro256.initialize |> Xoshiro256.jump in let t' = Xoshiro256.jump t in - assert_bool "" ((Xoshiro256.next_double t |> fst) <> (Xoshiro256.next_double t' |> fst)) + assert_bool "" ((Xoshiro256.next_uint64 t |> fst) <> (Xoshiro256.next_uint64 t' |> fst)) let tests = [ diff --git a/test/testconf.ml b/test/testconf.ml index 4ffe6bf..76703a1 100644 --- a/test/testconf.ml +++ b/test/testconf.ml @@ -2,75 +2,59 @@ open OUnit2 open Stdint +let maxint32 = Uint64.of_int 0xffffffff let uint32_of_uint64 x = - let upper = Uint64.(shift_right x 32 |> to_uint32) in - let lower = Uint64.(of_int 0xffffffff |> logand x |> to_uint32) in - Uint32.[to_string_hex lower; to_string_hex upper] + let upper = Uint64.(shift_right x 32 |> to_uint32) in + let lower = Uint64.(logand maxint32 x |> to_uint32) in + Uint32.[to_string_hex lower; to_string_hex upper] +let dbl_const = 1.0 /. 9007199254740992.0 let uniform_of_uint64 x = - Uint64.(shift_right x 11 |> to_string |> Float.of_string) *. (1.0 /. 9007199254740992.0) |> Float.to_string + Uint64.(shift_right x 11 |> to_string |> Float.of_string) *. dbl_const |> Float.to_string module type S = sig - type t - val next_uint64 : t -> uint64 * t - val next_uint32 : t -> uint32 * t - val next_double : t -> float * t - val next_bounded_uint64: uint64 -> t -> uint64 * t - val initialize : Bitgen.SeedSequence.t -> t + type t + val next_uint64 : t -> uint64 * t + val next_uint32 : t -> uint32 * t + val next_double : t -> float * t + val next_bounded_uint64: uint64 -> t -> uint64 * t + val initialize : Bitgen.SeedSequence.t -> t end let test_bounded_u64 (module M : S) = - let open Stdint in - let is_less bound t = match M.next_bounded_uint64 bound t with - | u, t' -> Some (u < bound, t') in - let t = Bitgen.SeedSequence.initialize [Uint128.of_int 12345] |> M.initialize in - let all_true b = Seq.(unfold (is_less b) t |> take 100 |> fold_left (&&) true) in - List.iter (fun b -> assert_equal true (all_true b)) Uint64.[of_int 1; of_int 4193609425186963870] + let open Stdint in + let is_less bound t = match M.next_bounded_uint64 bound t with + | u, t' -> Some (u < bound, t') in + let t = Bitgen.SeedSequence.initialize [Uint128.of_int 12345] |> M.initialize in + let all_true b = Seq.(unfold (is_less b) t |> take 100 |> fold_left (&&) true) in + List.iter (fun b -> assert_equal true (all_true b)) Uint64.[of_int 1; of_int 4193609425186963870] (* This tests the correctness of a bitgenerator's implementation against groundtruth data for a given seed. This function takes the module representing the bitgenerator as well as the path to the CSV file containing the groundtruth data. The data is sourced from numpy's random module test suite. *) let bitgen_groundtruth (module M : S) file = - (* Draw a random 64 bit integer n times from Bitgenerator M. *) - let rec loop i t acc n = match i >= n with - | true -> List.rev acc - | false -> - let u, t' = M.next_uint64 t in - loop (i + 1) t' (Uint64.to_string_hex u :: acc) n - in - (* Draw a random 32 bit integer n times from Bitgenerator M. *) - let rec loop_u32 i t acc n = match i >= n with - | true -> List.rev acc - | false -> - let u, t' = M.next_uint32 t in - loop_u32 (i + 1) t' (Uint32.to_string_hex u :: acc) n - in - (* Draw a random 64bit float n times from Bitgenerator M. *) - let rec loopf i t acc n = match i >= n with - | true -> List.rev acc - | false -> - let u, t' = M.next_double t in - loopf (i + 1) t' (Float.to_string u :: acc) n - in - open_in file |> Csv.load_in |> List.(map tl) |> List.flatten |> function - | [] -> - assert_failure "There was an error parsing the CSV file" - | seed :: data -> - let t = Bitgen.SeedSequence.initialize [Uint128.of_string seed] |> M.initialize - in - assert_equal - data - (loop 0 t [] (List.length data)) - ~printer:(List.fold_left (^) ""); - assert_equal - (List.map uint32_of_uint64 (List.map Uint64.of_string data) |> List.concat) - (loop_u32 0 t [] (List.length data * 2)) - ~printer:(List.fold_left (^) ""); - assert_equal - (List.map uniform_of_uint64 (List.map Uint64.of_string data)) - (loopf 0 t [] (List.length data)) - ~printer:(List.fold_left (^) ""); + let u64 t = let u, t' = M.next_uint64 t in Some (Uint64.to_string_hex u, t') + and u32 t = let u, t' = M.next_uint32 t in Some (Uint32.to_string_hex u, t') + and double t = let u, t' = M.next_double t in Some (Float.to_string u, t') + + in open_in file |> Csv.load_in |> List.(map tl) |> List.flatten |> function + | [] -> assert_failure "There was an error parsing the CSV file" + | seed :: data -> + let t = Bitgen.SeedSequence.initialize [Uint128.of_string seed] |> M.initialize in + let n = List.length data in + assert_equal + data Seq.(unfold u64 t |> take n |> List.of_seq) ~printer:(List.fold_left (^) ""); + + assert_equal + List.(map Uint64.of_string data |> map uint32_of_uint64 |> concat) + Seq.(unfold u32 t |> take (n * 2) |> List.of_seq) + ~printer:(List.fold_left (^) ""); + + assert_equal + List.(map Uint64.of_string data |> map uniform_of_uint64) + Seq.(unfold double t |> take n |> List.of_seq) + ~printer:(List.fold_left (^) "");