Add domain and edge case tests to musl

This provides an increase in test coverage on platforms that cannot test
against MPFR.
This commit is contained in:
Trevor Gross 2024-12-28 09:52:19 +00:00
parent d9aee94763
commit a3363785ea
3 changed files with 101 additions and 2 deletions

View file

@ -23,7 +23,9 @@ use std::time::SystemTime;
pub use f8_impl::f8;
pub use libm::support::{Float, Int, IntTy, MinInt};
pub use num::{FloatExt, logspace};
pub use op::{BaseName, FloatTy, Identifier, MathOp, OpCFn, OpFTy, OpRustFn, OpRustRet, Ty};
pub use op::{
BaseName, FloatTy, Identifier, MathOp, OpCFn, OpCRet, OpFTy, OpRustFn, OpRustRet, Ty,
};
pub use precision::{MaybeOverride, SpecialCase, default_ulp};
use run_cfg::EXTENSIVE_MAX_ITERATIONS;
pub use run_cfg::{CheckBasis, CheckCtx, EXTENSIVE_ENV, GeneratorKind, skip_extensive_test};

View file

@ -96,6 +96,8 @@ pub type OpFTy<Op> = <Op as MathOp>::FTy;
pub type OpITy<Op> = <<Op as MathOp>::FTy as Float>::Int;
/// Access the associated `CFn` type from an op (helper to avoid ambiguous associated types).
pub type OpCFn<Op> = <Op as MathOp>::CFn;
/// Access the associated `CRet` type from an op (helper to avoid ambiguous associated types).
pub type OpCRet<Op> = <Op as MathOp>::CRet;
/// Access the associated `RustFn` type from an op (helper to avoid ambiguous associated types).
pub type OpRustFn<Op> = <Op as MathOp>::RustFn;
/// Access the associated `RustRet` type from an op (helper to avoid ambiguous associated types).

View file

@ -9,8 +9,9 @@
// There are some targets we can't build musl for
#![cfg(feature = "build-musl")]
use libm_test::gen::random;
use libm_test::domain::HasDomain;
use libm_test::gen::random::RandomInput;
use libm_test::gen::{domain_logspace, edge_cases, random};
use libm_test::{CheckBasis, CheckCtx, CheckOutput, MathOp, TupleCall};
macro_rules! musl_rand_tests {
@ -53,3 +54,97 @@ libm_macros::for_each_function! {
[exp10, exp10f, exp2, exp2f, rint]
],
}
/// Test against musl with generators from a domain.
macro_rules! musl_domain_tests {
(
fn_name: $fn_name:ident,
attrs: [$($attr:meta),*],
) => {
paste::paste! {
#[test]
$(#[$attr])*
fn [< musl_edge_case_ $fn_name >]() {
type Op = libm_test::op::$fn_name::Routine;
domain_test_runner::<Op, _>(
edge_cases::get_test_cases::<Op, _>,
musl_math_sys::$fn_name,
);
}
#[test]
$(#[$attr])*
fn [< musl_logspace_ $fn_name >]() {
type Op = libm_test::op::$fn_name::Routine;
domain_test_runner::<Op, _>(
domain_logspace::get_test_cases::<Op>,
musl_math_sys::$fn_name,
);
}
}
};
}
/// Test a single routine against domaine-aware inputs.
fn domain_test_runner<Op, I>(gen: impl FnOnce(&CheckCtx) -> I, musl_fn: Op::CFn)
where
Op: MathOp,
Op: HasDomain<Op::FTy>,
I: Iterator<Item = Op::RustArgs>,
{
let ctx = CheckCtx::new(Op::IDENTIFIER, CheckBasis::Musl);
let cases = gen(&ctx);
for input in cases {
let musl_res = input.call(musl_fn);
let crate_res = input.call(Op::ROUTINE);
crate_res.validate(musl_res, input, &ctx).unwrap();
}
}
libm_macros::for_each_function! {
callback: musl_domain_tests,
attributes: [],
skip: [
// Functions with multiple inputs
atan2,
atan2f,
copysign,
copysignf,
copysignf16,
copysignf128,
fdim,
fdimf,
fma,
fmaf,
fmax,
fmaxf,
fmin,
fminf,
fmod,
fmodf,
hypot,
hypotf,
jn,
jnf,
ldexp,
ldexpf,
nextafter,
nextafterf,
pow,
powf,
remainder,
remainderf,
remquo,
remquof,
scalbn,
scalbnf,
yn,
ynf,
// Not provided by musl
fabsf16,
fabsf128,
],
}