Skip to content

Commit abb8540

Browse files
committed
Add Int31 tests
1 parent 191b917 commit abb8540

File tree

4 files changed

+205
-0
lines changed

4 files changed

+205
-0
lines changed

compiler/tests-num/dune

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
11
(executable
22
(name main)
3+
(modules main test_nats test test_big_ints test_ratios test_nums test_io)
34
(libraries num)
45
(modes
56
js
67
(best exe))
78
(flags
89
(:standard -linkall -w -3-7-33-35-37 -safe-string -no-strict-sequence)))
910

11+
(library
12+
(name test_int31)
13+
(modules test_int31)
14+
(inline_tests)
15+
(preprocess
16+
(pps ppx_expect))
17+
(libraries js_of_ocaml-compiler qcheck))
18+
1019
(rule
1120
(target main.referencejs)
1221
(deps main.bc.js)

compiler/tests-num/test_int31.ml

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
open! Js_of_ocaml_compiler.Stdlib
2+
open QCheck2
3+
4+
let () = Printexc.record_backtrace false
5+
6+
let min_int31 = Int32.(neg (shift_left 1l 30))
7+
let max_int31 = Int32.(sub (shift_left 1l 30) 1l)
8+
9+
let in_range i =
10+
Int32.(min_int31 <= i && i <= max_int31)
11+
12+
let in_range_i32 =
13+
Gen.(Int32.of_int <$> int_range (- (1 lsl 30)) (1 lsl 30 - 1))
14+
15+
let out_of_range_int =
16+
let open Gen in
17+
oneof [ int_range (- (1 lsl 31)) (- (1 lsl 30) - 1);
18+
int_range (1 lsl 30) (1 lsl 31 - 1) ]
19+
20+
let out_of_range_i32 =
21+
out_of_range_int |> Gen.map Int32.of_int
22+
23+
let t_corner =
24+
let open Gen in
25+
graft_corners in_range_i32 [min_int31; max_int31] ()
26+
|> map Int31.of_int32_warning_on_overflow
27+
28+
let print_t t =
29+
Format.sprintf "%ld" (Int31.to_int32 t)
30+
31+
let%expect_test _ =
32+
Test.check_exn @@ Test.make ~count:1000 ~name:"Int31.of_int32_warning_on_overflow: normal"
33+
in_range_i32
34+
(fun i ->
35+
Int32.equal Int31.(to_int32 (of_int32_warning_on_overflow i)) i);
36+
[%expect ""]
37+
38+
let%expect_test _ =
39+
Test.check_exn @@ Test.make ~count:1000 ~name:"Int31.of_int_warning_on_overflow: normal"
40+
(Gen.map Int32.to_int in_range_i32)
41+
(fun i ->
42+
Int.equal (Int31.(to_int32 (of_int_warning_on_overflow i)) |> Int32.to_int) i);
43+
[%expect ""]
44+
45+
let%expect_test _ =
46+
Test.check_exn @@ Test.make ~count:1000 ~name:"Int31.of_nativeint_warning_on_overflow: normal"
47+
(Gen.map Nativeint.of_int32 in_range_i32)
48+
(fun i ->
49+
Nativeint.equal
50+
(Int31.(to_int32 (of_nativeint_warning_on_overflow i)) |> Nativeint.of_int32)
51+
i);
52+
[%expect ""]
53+
54+
let%expect_test _ =
55+
let i = Gen.(generate1 (no_shrink out_of_range_i32)) in
56+
let i_trunc = Int32.(shift_right (shift_left i 1) 1) in
57+
ignore (Int31.of_int32_warning_on_overflow i);
58+
let output = [%expect.output] in
59+
let expected =
60+
Format.sprintf "Warning: integer overflow: integer 0x%lx (%ld) truncated to 0x%lx (%ld); the generated code might be incorrect.@." i i i_trunc i_trunc
61+
in
62+
if not (String.equal output expected) then
63+
Format.printf "Unexpected output string@.%[email protected]:@.%s@." output expected;
64+
[%expect ""]
65+
66+
let%expect_test _ =
67+
let i = Gen.(generate1 (no_shrink out_of_range_int)) in
68+
let i_trunc = Int32.(shift_right (shift_left (of_int i) 1) 1) in
69+
ignore (Int31.of_int_warning_on_overflow i);
70+
let output = [%expect.output] in
71+
let expected =
72+
Format.sprintf "Warning: integer overflow: integer 0x%x (%d) truncated to 0x%lx (%ld); the generated code might be incorrect.@." i i i_trunc i_trunc
73+
in
74+
if not (String.equal output expected) then
75+
Format.printf "Unexpected output string@.%[email protected]:@.%s@." output expected;
76+
[%expect ""]
77+
78+
let%expect_test _ =
79+
let i = Gen.(generate1 (no_shrink (Nativeint.of_int <$> out_of_range_int))) in
80+
let i_trunc = Int32.(shift_right (shift_left (Nativeint.to_int32 i) 1) 1) in
81+
ignore (Int31.of_nativeint_warning_on_overflow i);
82+
let output = [%expect.output] in
83+
let expected =
84+
Format.sprintf "Warning: integer overflow: integer 0x%nx (%nd) truncated to 0x%lx (%ld); the generated code might be incorrect.@." i i i_trunc i_trunc
85+
in
86+
if not (String.equal output expected) then
87+
Format.printf "Unexpected output string@.%[email protected]:@.%s@." output expected;
88+
[%expect ""]
89+
90+
let modulus = Int32.(shift_left 1l 31)
91+
92+
let canonicalize x =
93+
if in_range x then x else Int32.(sub x modulus)
94+
95+
let canon_equal x y =
96+
Int32.(=) (canonicalize x) (canonicalize y)
97+
98+
let%expect_test _ =
99+
Test.check_exn @@ Test.make ~count:1000 ~name:"Int31.neg"
100+
t_corner
101+
~print:print_t
102+
(fun i ->
103+
let r_int31 = Int31.(neg i |> to_int32) in
104+
let r_int32 = Int32.neg (Int31.to_int32 i) in
105+
in_range r_int31 && canon_equal r_int31 r_int32);
106+
[%expect ""]
107+
108+
let binop_prop op_i31 op_i32 i j =
109+
let r_int31 = op_i31 i j |> Int31.to_int32 in
110+
let r_int32 = op_i32 (Int31.to_int32 i) (Int31.to_int32 j) in
111+
in_range r_int31 && canon_equal r_int31 r_int32
112+
113+
let binop_check ~count ~name op_i31 op_i32 =
114+
Test.check_exn @@ Test.make ~count ~name
115+
Gen.(tup2 t_corner t_corner)
116+
~print:(Print.tup2 print_t print_t)
117+
(fun (i, j) -> binop_prop op_i31 op_i32 i j)
118+
119+
let%expect_test _ =
120+
binop_check ~count:1000 ~name:"Int31.add" Int31.add Int32.add;
121+
[%expect ""]
122+
123+
let%expect_test _ =
124+
binop_check ~count:1000 ~name:"Int31.sub" Int31.sub Int32.sub;
125+
[%expect ""]
126+
127+
let%expect_test _ =
128+
binop_check ~count:1000 ~name:"Int31.mul" Int31.mul Int32.mul;
129+
[%expect ""]
130+
131+
let%expect_test _ =
132+
Test.check_exn @@ Test.make ~count:1000 ~name:"Int31.div"
133+
Gen.(tup2 t_corner t_corner)
134+
~print:(Print.tup2 print_t print_t)
135+
(fun (i, j) ->
136+
try binop_prop Int31.div Int32.div i j
137+
with Division_by_zero -> Int32.equal (Int31.to_int32 j) 0l)
138+
139+
let%expect_test _ =
140+
Test.check_exn @@ Test.make ~count:1000 ~name:"Int31.rem"
141+
Gen.(tup2 t_corner t_corner)
142+
~print:(Print.tup2 print_t print_t)
143+
(fun (i, j) ->
144+
try binop_prop Int31.rem Int32.rem i j
145+
with Division_by_zero -> Int32.equal (Int31.to_int32 j) 0l)
146+
147+
let%expect_test _ =
148+
binop_check ~count:1000 ~name:"Int31.logand" Int31.logand Int32.logand;
149+
[%expect ""]
150+
151+
let%expect_test _ =
152+
binop_check ~count:1000 ~name:"Int31.logor" Int31.logor Int32.logor;
153+
[%expect ""]
154+
155+
let%expect_test _ =
156+
binop_check ~count:1000 ~name:"Int31.logxor" Int31.logxor Int32.logxor;
157+
[%expect ""]
158+
159+
let shift_op_prop op_i31 op_i32 x i =
160+
let r_int31 = op_i31 x i |> Int31.to_int32 in
161+
let r_int32 = op_i32 (Int31.to_int32 x) i in
162+
in_range r_int31 && canon_equal r_int31 r_int32
163+
164+
let%expect_test _ =
165+
Test.check_exn @@ Test.make ~count:1000 ~name:"Int31.shift_left"
166+
Gen.(tup2 t_corner (int_bound 31))
167+
~print:Print.(tup2 print_t int)
168+
(fun (x, i) -> shift_op_prop Int31.shift_left Int32.shift_left x i)
169+
170+
let%expect_test _ =
171+
Test.check_exn @@ Test.make ~count:1000 ~name:"Int31.shift_right"
172+
Gen.(tup2 t_corner (int_bound 31))
173+
~print:Print.(tup2 print_t int)
174+
(fun (x, i) -> shift_op_prop Int31.shift_right Int32.shift_right x i)
175+
176+
(* Logical implication *)
177+
let (-->) p q = not p || q
178+
179+
let%expect_test _ =
180+
Test.check_exn @@ Test.make ~count:10_000 ~name:"Int31.shift_right_logical"
181+
Gen.(tup2 t_corner (int_bound 31))
182+
~print:Print.(tup2 print_t int)
183+
(fun (x, i) ->
184+
let r_int31 = Int31.shift_right_logical x i |> Int31.to_int32 in
185+
let x_int32 = Int31.to_int32 x in
186+
let r_int32 =
187+
if Int_replace_polymorphic_compare.( i = 0 ) then x_int32
188+
else Int32.(shift_right_logical (logand 0x7fffffffl x_int32) i)
189+
in
190+
(* The bits should be unchanged if the shift amount is zero, otherwise they should
191+
match the result of shifting the 31 lower bits of the canonical representation *)
192+
in_range r_int31 && Int32.equal r_int31 r_int32
193+
&& (Int.equal i 0 --> Int32.(r_int31 = r_int32)));
194+
[%expect ""]

dune-project

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
(re :with-test)
2626
(cmdliner (>= 1.1.0))
2727
(sedlex (>= 2.3))
28+
(qcheck :with-test)
2829
menhir
2930
menhirLib
3031
menhirSdk

js_of_ocaml-compiler.opam

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ depends: [
2020
"re" {with-test}
2121
"cmdliner" {>= "1.1.0"}
2222
"sedlex" {>= "2.3"}
23+
"qcheck" {with-test}
2324
"menhir"
2425
"menhirLib"
2526
"menhirSdk"

0 commit comments

Comments
 (0)