# test_help-rs <!-- omit in toc -->
Test helpers for Rust

[](https://opensource.org/licenses/BSD-3-Clause)
[](https://crates.io/crates/test_help-rs)
[](https://github.com/synesissoftware/test_help-rs/releases/latest)

[](https://github.com/synesissoftware/test_help-rs/actions/workflows/ci.yml)
[](https://docs.rs/test_help-rs)
## Table of Contents <!-- omit in toc -->
- [Introduction](#introduction)
- [Installation](#installation)
- [Components](#components)
- [Constants](#constants)
- [Enumerations](#enumerations)
- [Features](#features)
- [Functions](#functions)
- [Macros](#macros)
- [Structures](#structures)
- [Traits](#traits)
- [Examples](#examples)
- [Project Information](#project-information)
- [Where to get help](#where-to-get-help)
- [Contribution guidelines](#contribution-guidelines)
- [Minimum Supported Rust Version (MSRV)](#minimum-supported-rust-version-msrv)
- [Dependencies](#dependencies)
- [Efferent (fan-out)](#efferent-fan-out)
- [Build Dependencies](#build-dependencies)
- [Development Dependencies](#development-dependencies)
- [Afferent (fan-in)](#afferent-fan-in)
- [Related projects](#related-projects)
- [License](#license)
## Introduction
Rust has powerful and easy-to-use unit-testing mechanisms, but there are some missing elements, particularly around the use of floating-point values - `f32` and `f64` - that are provided by this crate for asserting approximate equality, as in:
```rust
use test_helpers::{
assert_scalar_eq_approx,
assert_vector_eq_approx,
margin,
multiplier,
};
#[test]
fn example_test_of_scalar_evaluation() {
let expected = 3.0;
let actual = 3.0001;
assert_scalar_eq_approx!(expected, actual, margin(0.0001));
}
#[test]
fn example_test_of_vector_evaluation() {
let expected = &[ 3.0, -40404.0, 1.23456 ];
let actual = Vec::from([ 3.0, -40410.0, 1.234567 ]);
assert_vector_eq_approx!(expected, actual, multiplier(0.00015));
}
```
## Installation
Reference in **Cargo.toml** in the usual way:
```toml
test_help-rs = { version = "0.2.1" }
```
## Components
### Constants
The following constants are defined in [`constants`](https://docs.rs/test_help-rs/latest/test_helpers/constants/index.html):
* `DEFAULT_MARGIN` — default absolute margin (`0.0001`, i.e. 1e-4) used by the stock two-argument assertion macros when no custom evaluator is supplied;
* `DEFAULT_MULTIPLIER` — default relative multiplier (`0.000001`, i.e. 1e-6) used together with `DEFAULT_MARGIN` by the stock [`zero_margin_or_multiplier()`](https://docs.rs/test_help-rs/latest/test_helpers/fn.zero_margin_or_multiplier.html) evaluator path;
### Enumerations
The following enumerations are defined:
* [`ComparisonResult`](https://docs.rs/test_help-rs/latest/test_helpers/enum.ComparisonResult.html) — outcome of comparing two scalar `f64` values:
* `ExactlyEqual` — the values are identical (including matching infinities and, when the `"nan-equality"` feature is enabled, both `NaN`);
* `ApproximatelyEqual` — the values differ but are within the margin or multiplier tolerance of the evaluator;
* `Unequal` — the values are not equal under the evaluator;
* [`VectorComparisonResult`](https://docs.rs/test_help-rs/latest/test_helpers/enum.VectorComparisonResult.html) — outcome of comparing two vectors of `f64` values:
* `ExactlyEqual` — same length and every element pair is exactly equal;
* `ApproximatelyEqual` — same length and every element pair is equal within the evaluator tolerance;
* `DifferentLengths { expected_length, actual_length }` — the vectors have different lengths;
* `UnequalElements { index_of_first_unequal_element, expected_value_of_first_unequal_element, actual_value_of_first_unequal_element }` — same length but at least one element pair is unequal under the evaluator;
### Features
The following optional features are defined in **Cargo.toml**:
* **Crate-specific features**:
* `full` — enables all crate-specific features; use a nightly toolchain because it includes `nightly-constants`;
* `nan-equality` — allows two `f64::NAN` values to be treated as equal for stock comparisons (does not affect custom [`ApproximateEqualityEvaluator`](https://docs.rs/test_help-rs/latest/test_helpers/traits/trait.ApproximateEqualityEvaluator.html) implementations);
* `nightly-constants` — enables unit tests for additional `std::f64` constants that require the unstable `more_float_constants` feature; build and test with pinned nightly-2026-09-10 via `./scripts/test-nightly-constants` (this feature is for crate development only and is not required by downstream consumers);
* **General features**:
* `null-feature` — a feature that has no effect (and, thus, is useful for simplifying driver scripts);
### Functions
The following functions are defined:
* `margin() -> impl ApproximateEqualityEvaluator` — creates a margin-based evaluator;
* `multiplier() -> impl ApproximateEqualityEvaluator` — creates a multiplier-based evaluator;
* `zero_margin_or_multiplier() -> impl ApproximateEqualityEvaluator` — applies a margin when either comparand is zero and a multiplier otherwise;
* `evaluate_scalar_eq_approx()` — compares scalar values that are logically `f64` without asserting;
* `evaluate_vector_eq_approx()` — compares vectors of values that are logically `f64` without asserting;
### Macros
The following macros are defined (re-exported at the crate root via [`test_helpers`](https://docs.rs/test_help-rs/latest/test_helpers/index.html)):
* `assert_scalar_eq_approx!(expected, actual)` — asserts approximate equality using the stock [`zero_margin_or_multiplier()`](https://docs.rs/test_help-rs/latest/test_helpers/fn.zero_margin_or_multiplier.html) evaluator (`DEFAULT_MULTIPLIER` / `DEFAULT_MARGIN`);
* `assert_scalar_eq_approx!(expected, actual, evaluator)` — asserts approximate equality using a custom [`ApproximateEqualityEvaluator`](https://docs.rs/test_help-rs/latest/test_helpers/traits/trait.ApproximateEqualityEvaluator.html);
* `assert_scalar_ne_approx!(expected, actual)` — asserts approximate inequality using the stock evaluator;
* `assert_scalar_ne_approx!(expected, actual, evaluator)` — asserts approximate inequality using a custom evaluator;
* `assert_vector_eq_approx!(expected, actual)` — asserts approximate equality of two vectors (slices, arrays, or `Vec`) using the stock evaluator;
* `assert_vector_eq_approx!(expected, actual, evaluator)` — asserts approximate vector equality using a custom evaluator;
* `assert_vector_ne_approx!(expected, actual)` — asserts approximate vector inequality using the stock evaluator;
* `assert_vector_ne_approx!(expected, actual, evaluator)` — asserts approximate vector inequality using a custom evaluator;
### Structures
No public structures are defined at this time.
### Traits
The following traits are defined:
* `ApproximateEqualityEvaluator` — prescribes the non-mutating `evaluate()` method, allowing custom evaluators to be used with the assertion macros;
* `TestableAsF64` — prescribes the non-mutating `testable_as_f64() -> f64` method, with an implementation for any type that implements the `ToF64` trait defined in the [**base-traits**](https://github.com/synesissoftware/base-traits) crate;
## Examples
Example programs are provided in the **examples** directory:
* [**examples/scalars.rs**](./examples/scalars.rs) — scalar approximate equality and inequality:
```sh
cargo run --example scalars
```
* [**examples/strings.rs**](./examples/strings.rs) — string-view equality and inequality using a custom `AsStr` implementation:
```sh
cargo run --example strings
```
* [**examples/vectors.rs**](./examples/vectors.rs) — vector approximate equality and inequality (slice and `Vec`):
```sh
cargo run --example vectors
```
**scalars** exercises `assert_scalar_eq_approx!()` and
`assert_scalar_ne_approx!()` with margin- and multiplier-based evaluators.
**strings** demonstrates custom `AsStr` implementations. **vectors** includes
the README introduction example and similar pass/fail demonstrations for
vector assertions.
## Project Information
### Where to get help
[GitHub Page](https://github.com/synesissoftware/test_help-rs "GitHub Page")
### Contribution guidelines
Defect reports, feature requests, and pull requests are welcome on https://github.com/synesissoftware/test_help-rs.
### Minimum Supported Rust Version (MSRV)
The declared Minimum Supported Rust Version (MSRV) for **test_help-rs** is **1.74**.
This MSRV guarantee applies to the library crate itself, its runtime dependencies (`[dependencies]`), and its build dependencies (`[build-dependencies]`). Downstream consumers compiling this crate as a dependency are guaranteed that it builds cleanly on the declared MSRV toolchain.
Development dependencies (`[dev-dependencies]`, such as benchmarking frameworks like **criterion**) may require newer Rust toolchains for local development or performance testing. These dev-dependencies are never fetched or compiled by downstream consumers and do not affect the library's MSRV guarantee.
### Dependencies
#### Efferent (fan-out)
Libraries upon which **test_help-rs** depends:
* [**base-traits**](https://github.com/synesissoftware/base-traits) — [`ToF64`](https://docs.rs/base-traits/latest/base_traits/trait.ToF64.html) trait used by [`TestableAsF64`](https://docs.rs/test_help-rs/latest/test_helpers/traits/trait.TestableAsF64.html);
The committed **Cargo.lock** is retained for reproducible development and CI
builds; locked Cargo commands are used throughout the workflow.
#### Build Dependencies
Libraries used only when building **test_help-rs** (not required by downstream consumers):
* [**bt-rs**](https://github.com/synesissoftware/bt-rs) — [`rustc::compiler_version()`](https://docs.rs/bt-rs/latest/bt_rs/rustc/fn.compiler_version.html) in **build.rs** to detect Rust 1.94+ and set the `rustc_1_94_or_newer` cfg for unit tests of stable `std::f64::consts` added in that release;
#### Development Dependencies
None currently.
#### Afferent (fan-in)
Projects that depend on **test_help-rs** (typically as a **dev-dependency** for unit tests):
* [**auto_buffer.Rust**](https://github.com/synesissoftware/auto_buffer.Rust);
* [**collect-rs**](https://github.com/synesissoftware/collect-rs);
* [**libpath.Rust**](https://github.com/synesissoftware/libpath.Rust);
* [**p99.Rust**](https://github.com/synesissoftware/p99.Rust);
* [**shwild.Rust**](https://github.com/synesissoftware/shwild.Rust);
### Related projects
* [**shwild.Rust**](https://github.com/synesissoftware/shwild.Rust) defines functionality for matching strings against **SH**ell-compatible **WILD**card patterns, including matching assertion macros that are useful in unit-testing;
### License
**test_help-rs** is released under the 3-clause BSD license. See [LICENSE](./LICENSE) for details.