Skip to content

Commit 7f6575e

Browse files
authored
Commonize test codes (#224)
This also fixes some tests to follow the printing style change on v1.6.0-DEV.
1 parent a142308 commit 7f6575e

File tree

3 files changed

+171
-185
lines changed

3 files changed

+171
-185
lines changed

test/common.jl

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ using FixedPointNumbers, Statistics, Random, Test
22
using FixedPointNumbers: bitwidth, rawtype, nbitsfrac
33
using Base.Checked
44

5+
SP = VERSION >= v"1.6.0-DEV.771" ? " " : "" # JuliaLang/julia #37085
6+
57
"""
68
target(X::Type, Ss...; ex = :default)
79
@@ -129,3 +131,127 @@ target_f_series(::Type{Normed}, T::Type{<:Integer}) =
129131
23, 24, 31, 32, 33,
130132
52, 53, 63, 64, 65,
131133
112, 113, 127, 128)
134+
135+
# generator for cartesian product
136+
function xypairs(::Type{X}) where X
137+
xs = typemin(X):eps(X):typemax(X)
138+
((x, y) for x in xs, y in xs)
139+
end
140+
141+
142+
function test_floattype(TX::Type)
143+
@testset "floattype($X)" for X in target(TX, :i8, :i16, :i32, :i64; ex = :heavy)
144+
@test typemax(X) <= maxintfloat(floattype(X))
145+
end
146+
end
147+
148+
function test_convert_from_nan(TX::Type)
149+
@testset "$X(nan)" for X in target(TX; ex = :thin)
150+
@test_throws ArgumentError X(Inf)
151+
@test_throws ArgumentError X(-Inf32)
152+
@test_throws ArgumentError X(NaN)
153+
end
154+
end
155+
156+
function test_rem_type(TX::Type)
157+
@testset "% $X" for X in target(TX, :i8, :i16; ex = :thin)
158+
xs = typemin(X):0.1:typemax(X)
159+
@test all(x -> x % X === X(x), xs)
160+
end
161+
end
162+
163+
function test_rem_nan(TX::Type)
164+
# TODO: avoid undefined behavior
165+
@testset "nan % $X" for X in target(TX, :i8, :i16, :i32, :i64; ex = :thin)
166+
@test NaN % X === NaN32 % X === NaN16 % X === zero(X)
167+
end
168+
end
169+
170+
function test_neg(TX::Type)
171+
for X in target(TX, :i8; ex = :thin)
172+
xs = typemin(X):eps(X):typemax(X)
173+
fneg(x) = -float(x)
174+
@test all(x -> wrapping_neg(wrapping_neg(x)) === x, xs)
175+
@test all(x -> saturating_neg(x) === clamp(fneg(x), X), xs)
176+
@test all(x -> !(typemin(X) <= fneg(x) <= typemax(X)) ||
177+
wrapping_neg(x) === checked_neg(x) === fneg(x) % X, xs)
178+
end
179+
end
180+
181+
function test_abs(TX::Type)
182+
for X in target(TX, :i8; ex = :thin)
183+
xs = typemin(X):eps(X):typemax(X)
184+
fabs(x) = abs(float(x))
185+
@test all(x -> wrapping_abs(x) === (x > 0 ? x : wrapping_neg(x)), xs)
186+
@test all(x -> saturating_abs(x) === clamp(fabs(x), X), xs)
187+
@test all(x -> !(typemin(X) <= fabs(x) <= typemax(X)) ||
188+
wrapping_abs(x) === checked_abs(x) === fabs(x) % X, xs)
189+
end
190+
end
191+
192+
function test_add(TX::Type)
193+
for X in target(TX, :i8; ex = :thin)
194+
xys = xypairs(X)
195+
fadd(x, y) = float(x) + float(y)
196+
@test all(((x, y),) -> wrapping_sub(wrapping_add(x, y), y) === x, xys)
197+
@test all(((x, y),) -> saturating_add(x, y) === clamp(fadd(x, y), X), xys)
198+
@test all(((x, y),) -> !(typemin(X) <= fadd(x, y) <= typemax(X)) ||
199+
wrapping_add(x, y) === checked_add(x, y) === fadd(x, y) % X, xys)
200+
end
201+
end
202+
203+
function test_sub(TX::Type)
204+
for X in target(TX, :i8; ex = :thin)
205+
xys = xypairs(X)
206+
fsub(x, y) = float(x) - float(y)
207+
@test all(((x, y),) -> wrapping_add(wrapping_sub(x, y), y) === x, xys)
208+
@test all(((x, y),) -> saturating_sub(x, y) === clamp(fsub(x, y), X), xys)
209+
@test all(((x, y),) -> !(typemin(X) <= fsub(x, y) <= typemax(X)) ||
210+
wrapping_sub(x, y) === checked_sub(x, y) === fsub(x, y) % X, xys)
211+
end
212+
end
213+
214+
function test_mul(TX::Type)
215+
for X in target(TX, :i8; ex = :thin)
216+
xys = xypairs(X)
217+
fmul(x, y) = float(x) * float(y) # note that precision(Float32) < 32
218+
@test all(((x, y),) -> wrapping_mul(x, y) === fmul(x, y) % X, xys)
219+
@test all(((x, y),) -> saturating_mul(x, y) === clamp(fmul(x, y), X), xys)
220+
@test all(((x, y),) -> !(typemin(X) <= fmul(x, y) <= typemax(X)) ||
221+
wrapping_mul(x, y) === checked_mul(x, y), xys)
222+
end
223+
end
224+
225+
function test_isapprox(TX::Type)
226+
@testset "approx $X" for X in target(TX, :i8, :i16; ex = :light)
227+
xs = typemin(X):eps(X):typemax(X)-eps(X)
228+
@test all(x -> x x + eps(X), xs)
229+
@test all(x -> x + eps(X) x, xs)
230+
@test !any(x -> x - eps(X) x + eps(X), xs)
231+
end
232+
233+
end
234+
235+
function test_clamp_nan(TX::Type)
236+
@testset "clamp(nan, $X)" for X in target(TX; ex = :thin)
237+
@test clamp( Inf, X) === clamp( Inf32, X) === typemax(X)
238+
@test clamp(-Inf, X) === clamp(-Inf32, X) === typemin(X)
239+
@test clamp( NaN, X) === clamp( NaN32, X) === zero(X)
240+
end
241+
end
242+
243+
function test_isinteger(TX::Type)
244+
@testset "isinteger(::$X)" for X in target(TX, :i8, :i16)
245+
xs = typemin(X):eps(X):typemax(X)
246+
@test all(x -> isinteger(x) == isinteger(float(x)), xs)
247+
end
248+
end
249+
250+
function test_rand(TX::Type)
251+
@testset "rand(::$X)" for X in target(TX; ex = :thin)
252+
@test isa(rand(X), X)
253+
a = rand(X, (3, 5))
254+
@test ndims(a) == 2 && eltype(a) === X
255+
@test size(a) == (3, 5)
256+
end
257+
end

test/fixed.jl

Lines changed: 27 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ end
142142
@test occursin("Q0f7 is an 8-bit type representing 256 values from -1.0 to 0.992;", msg)
143143
ret = @test_throws ArgumentError convert(Fixed{Int128,100}, 10.0^9)
144144
msg = ret.value.msg
145-
@test occursin("Fixed{Int128,100} is a 128-bit type representing 2^128 values", msg)
145+
@test occursin("Fixed{Int128,$(SP)100} is a 128-bit type representing 2^128 values", msg)
146146
end
147147

148148
@testset "disambiguation constructors" begin
@@ -214,17 +214,11 @@ end
214214
@test float(0.75Q7f24) === 0.75
215215
@test float(0.75Q10f53)::BigFloat == big"0.75"
216216

217-
@testset "floattype($F)" for F in target(Fixed, :i8, :i16, :i32, :i64; ex = :heavy)
218-
@test typemax(F) <= maxintfloat(floattype(F))
219-
end
217+
test_floattype(Fixed)
220218
end
221219

222220
@testset "conversions from float" begin
223-
@testset "$F(nan)" for F in target(Fixed; ex = :thin)
224-
@test_throws ArgumentError F(Inf)
225-
@test_throws ArgumentError F(-Inf32)
226-
@test_throws ArgumentError F(NaN)
227-
end
221+
test_convert_from_nan(Fixed)
228222
end
229223

230224
@testset "conversions to float" begin
@@ -234,22 +228,22 @@ end
234228

235229
for Tf in (Float16, Float32, Float64)
236230
@testset "$Tf(::$F)" for F in target(Fixed, :i8, :i16)
237-
T, f = rawtype(F), nbitsfrac(F)
238-
float_err = 0.0
231+
T, exp2mf = rawtype(F), big(2.0^-nbitsfrac(F))
232+
float_err = zero(Tf)
239233
for i = typemin(T):typemax(T)
240-
f_expected = Tf(i * BigFloat(2)^-f)
234+
f_expected = Tf(i * exp2mf)
241235
f_actual = Tf(reinterpret(F, i))
242236
float_err += abs(f_actual - f_expected)
243237
end
244-
@test float_err == 0.0
238+
@test float_err == 0
245239
end
246240
@testset "$Tf(::$F)" for F in target(Fixed, :i32, :i64, :i128)
247-
T, f = rawtype(F), nbitsfrac(F)
241+
T, exp2mf = rawtype(F), big(2.0^-nbitsfrac(F))
248242
error_count = 0
249243
for i in vcat(typemin(T):(typemin(T)+0xFF),
250244
-T(0xFF):T(0xFF),
251245
(typemax(T)-0xFF):typemax(T))
252-
f_expected = Tf(i * BigFloat(2)^-f)
246+
f_expected = Tf(i * exp2mf)
253247
isinf(f_expected) && break # for Float16() and Float32()
254248
f_actual = Tf(reinterpret(F, i))
255249
f_actual == f_expected && continue
@@ -271,31 +265,21 @@ end
271265
end
272266

273267
@testset "type modulus" begin
268+
test_rem_type(Fixed)
269+
test_rem_nan(Fixed)
270+
274271
@test Q0f7(0.2) % Q0f7 === Q0f7(0.2)
275272
@test Q1f14(1.2) % Q0f15 === Q0f15(-0.8)
276273
@test Q1f14(1.2) % Q0f7 === Q0f7(-0.8)
277274

278-
T = Fixed{Int8,7}
279-
for i = -1.0:0.1:typemax(T)
280-
@test i % T === T(i)
281-
end
282-
@test ( 1.5 % T).i == round(Int, 1.5*128) % Int8
283-
@test (-0.3 % T).i == round(Int, -0.3*128) % Int8
275+
@test ( 1.5 % Q0f7).i == round(Int, 1.5*128) % Int8
276+
@test (-0.3 % Q0f7).i == round(Int, -0.3*128) % Int8
284277

285-
T = Fixed{Int16,9}
286-
for i = -64.0:0.1:typemax(T)
287-
@test i % T === T(i)
288-
end
289-
@test ( 65.2 % T).i == round(Int, 65.2*512) % Int16
290-
@test (-67.2 % T).i == round(Int, -67.2*512) % Int16
278+
@test ( 65.2 % Q6f9).i == round(Int, 65.2*512) % Int16
279+
@test (-67.2 % Q6f9).i == round(Int, -67.2*512) % Int16
291280

292281
@test -1 % Q0f7 === Q0f7(-1)
293282
@test -2 % Q0f7 === Q0f7(0)
294-
295-
# TODO: avoid undefined behavior
296-
@testset "nan % $F" for F in target(Fixed, :i8, :i16, :i32, :i64; ex = :thin)
297-
@test NaN % F === NaN32 % F === NaN16 % F === zero(F)
298-
end
299283
end
300284

301285
@testset "neg" begin
@@ -312,14 +296,7 @@ end
312296
@test saturating_neg(eps(F)) === zero(F) - eps(F)
313297
@test checked_neg(eps(F)) === zero(F) - eps(F)
314298
end
315-
for F in target(Fixed, :i8; ex = :thin)
316-
xs = typemin(F):eps(F):typemax(F)
317-
fneg(x) = -float(x)
318-
@test all(x -> wrapping_neg(wrapping_neg(x)) === x, xs)
319-
@test all(x -> saturating_neg(x) === clamp(fneg(x), F), xs)
320-
@test all(x -> !(typemin(F) <= fneg(x) <= typemax(F)) ||
321-
wrapping_neg(x) === checked_neg(x) === fneg(x) % F, xs)
322-
end
299+
test_neg(Fixed)
323300
end
324301

325302
@testset "abs" begin
@@ -332,14 +309,7 @@ end
332309
@test saturating_abs(typemin(F)) === typemax(F)
333310
@test_throws OverflowError checked_abs(typemin(F))
334311
end
335-
for F in target(Fixed, :i8; ex = :thin)
336-
xs = typemin(F):eps(F):typemax(F)
337-
fabs(x) = abs(float(x))
338-
@test all(x -> wrapping_abs(x) === (x > 0 ? x : wrapping_neg(x)), xs)
339-
@test all(x -> saturating_abs(x) === clamp(fabs(x), F), xs)
340-
@test all(x -> !(typemin(F) <= fabs(x) <= typemax(F)) ||
341-
wrapping_abs(x) === checked_abs(x) === fabs(x) % F, xs)
342-
end
312+
test_abs(Fixed)
343313
end
344314

345315
@testset "add" begin
@@ -357,15 +327,7 @@ end
357327
@test saturating_add(zero(F), eps(F)) === saturating_add(eps(F), zero(F)) === eps(F)
358328
@test checked_add(zero(F), eps(F)) === checked_add(eps(F), zero(F)) === eps(F)
359329
end
360-
for F in target(Fixed, :i8; ex = :thin)
361-
xs = typemin(F):eps(F):typemax(F)
362-
xys = ((x, y) for x in xs, y in xs)
363-
fadd(x, y) = float(x) + float(y)
364-
@test all(((x, y),) -> wrapping_sub(wrapping_add(x, y), y) === x, xys)
365-
@test all(((x, y),) -> saturating_add(x, y) === clamp(fadd(x, y), F), xys)
366-
@test all(((x, y),) -> !(typemin(F) <= fadd(x, y) <= typemax(F)) ||
367-
wrapping_add(x, y) === checked_add(x, y) === fadd(x, y) % F, xys)
368-
end
330+
test_add(Fixed)
369331
end
370332

371333
@testset "sub" begin
@@ -382,15 +344,7 @@ end
382344
@test saturating_sub(eps(F), zero(F)) === eps(F)
383345
@test checked_sub(eps(F), zero(F)) === eps(F)
384346
end
385-
for F in target(Fixed, :i8; ex = :thin)
386-
xs = typemin(F):eps(F):typemax(F)
387-
xys = ((x, y) for x in xs, y in xs)
388-
fsub(x, y) = float(x) - float(y)
389-
@test all(((x, y),) -> wrapping_add(wrapping_sub(x, y), y) === x, xys)
390-
@test all(((x, y),) -> saturating_sub(x, y) === clamp(fsub(x, y), F), xys)
391-
@test all(((x, y),) -> !(typemin(F) <= fsub(x, y) <= typemax(F)) ||
392-
wrapping_sub(x, y) === checked_sub(x, y) === fsub(x, y) % F, xys)
393-
end
347+
test_sub(Fixed)
394348
end
395349

396350
@testset "mul" begin
@@ -413,15 +367,7 @@ end
413367
@test saturating_mul(typemin(F), typemin(F)) === typemax(F)
414368
@test_throws OverflowError checked_mul(typemin(F), typemin(F))
415369
end
416-
for F in target(Fixed, :i8; ex = :thin)
417-
xs = typemin(F):eps(F):typemax(F)
418-
xys = ((x, y) for x in xs, y in xs)
419-
fmul(x, y) = float(x) * float(y) # note that precision(Float32) < 32
420-
@test all(((x, y),) -> wrapping_mul(x, y) === fmul(x, y) % F, xys)
421-
@test all(((x, y),) -> saturating_mul(x, y) === clamp(fmul(x, y), F), xys)
422-
@test all(((x, y),) -> !(typemin(F) <= fmul(x, y) <= typemax(F)) ||
423-
wrapping_mul(x, y) === checked_mul(x, y), xys)
424-
end
370+
test_mul(Fixed)
425371

426372
FixedPointNumbers.mul_with_rounding(1.5Q6f1, 0.5Q6f1, RoundNearest) === 1.0Q6f1
427373
FixedPointNumbers.mul_with_rounding(1.5Q6f1, -0.5Q6f1, RoundNearest) === -1.0Q6f1
@@ -482,12 +428,7 @@ end
482428
end
483429

484430
@testset "approx" begin
485-
@testset "approx $F" for F in target(Fixed, :i8, :i16; ex = :light)
486-
xs = typemin(F):eps(F):typemax(F)-eps(F)
487-
@test all(x -> x x + eps(F), xs)
488-
@test all(x -> x + eps(F) x, xs)
489-
@test !any(x -> x - eps(F) x + eps(F), xs)
490-
end
431+
test_isapprox(Fixed)
491432

492433
@test isapprox(-0.5Q0f7, -1Q0f7, rtol=0.5, atol=0) # issue 209
493434
@test isapprox(typemin(Q0f7), typemax(Q0f7), rtol=2.0)
@@ -511,11 +452,7 @@ end
511452
@test clamp(-1.5f0, Q0f7) === -1.0Q0f7
512453
@test clamp(1.5Q1f6, Q0f7) === 0.992Q0f7
513454

514-
@testset "clamp(nan, $F)" for F in target(Fixed; ex = :thin)
515-
@test clamp( Inf, F) === clamp( Inf32, F) === typemax(F)
516-
@test clamp(-Inf, F) === clamp(-Inf32, F) === typemin(F)
517-
@test clamp( NaN, F) === clamp( NaN32, F) === zero(F)
518-
end
455+
test_clamp_nan(Fixed)
519456
end
520457

521458
@testset "sign-related functions" begin
@@ -546,10 +483,7 @@ end
546483
@test !isinf(1Q7f8)
547484

548485
@testset "isinteger" begin
549-
@testset "isinteger(::$F)" for F in target(Fixed, :i8, :i16)
550-
xs = typemin(F):eps(F):typemax(F)
551-
@test all(x -> isinteger(x) == isinteger(float(x)), xs)
552-
end
486+
test_isinteger(Fixed)
553487
@testset "isinteger(::$F)" for F in target(Fixed, :i32, :i64, :i128)
554488
fzero, fmax, fmin = zero(F), typemax(F), typemin(F)
555489
if nbitsfrac(F) == 0
@@ -619,12 +553,7 @@ end
619553
end
620554

621555
@testset "rand" begin
622-
@testset "rand(::$F)" for F in target(Fixed; ex = :thin)
623-
@test isa(rand(F), F)
624-
a = rand(F, (3, 5))
625-
@test ndims(a) == 2 && eltype(a) === F
626-
@test size(a) == (3,5)
627-
end
556+
test_rand(Fixed)
628557
@test rand(MersenneTwister(1234), Q0f7) === -0.156Q0f7
629558
end
630559

@@ -695,11 +624,11 @@ end
695624
@test String(take!(iob)) == "-21845.33334Q15f16"
696625

697626
show(iob, Fixed{Int128,64}(-1.2345e6))
698-
@test String(take!(iob)) == "Fixed{Int128,64}(-1.2345e6)"
627+
@test String(take!(iob)) == "Fixed{Int128,$(SP)64}(-1.2345e6)"
699628

700629
# TODO: remove this test
701630
show(iob, reinterpret(Fixed{Int8,8}, signed(0xaa)))
702-
@test String(take!(iob)) == "Fixed{Int8,8}(-0.336)"
631+
@test String(take!(iob)) == "Fixed{Int8,$(SP)8}(-0.336)"
703632
end
704633

705634
@testset "summary" begin

0 commit comments

Comments
 (0)