MathAssertions 0.4.0

Prefix Reserved
dotnet add package MathAssertions --version 0.4.0
                    
NuGet\Install-Package MathAssertions -Version 0.4.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="MathAssertions" Version="0.4.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="MathAssertions" Version="0.4.0" />
                    
Directory.Packages.props
<PackageReference Include="MathAssertions" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add MathAssertions --version 0.4.0
                    
#r "nuget: MathAssertions, 0.4.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package MathAssertions@0.4.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=MathAssertions&version=0.4.0
                    
Install as a Cake Addin
#tool nuget:?package=MathAssertions&version=0.4.0
                    
Install as a Cake Tool

MathAssertions

NuGet License: MIT .NET

Scope: Test projects only. Not intended for production code.

Framework-agnostic core of the MathAssertions package family. Math assertion helpers for .NET tests, spanning tolerance comparisons, sequences, statistics, linear algebra, number theory, and 3D geometry. Test-framework-specific entry points ship in adapter packages (currently MathAssertions.TUnit for TUnit).

Most users want MathAssertions.TUnit, not this package directly. This package ships the framework-agnostic helper classes (MathTolerance, Sequences, Statistics, LinearAlgebra, NumberTheory, plus the Geometry3D namespace); the adapter package adds the fluent Assert.That(value).Method(...) entry points your test framework expects.


What's in this package

Pure, NaN-aware, infinity-aware mathematical-assertion helpers. Six static classes plus the Geometry3D namespace cover ~85 methods:

  • MathTolerance: scalar IsApproximatelyEqual for double/float plus the System.Numerics compounds (Vector2/Vector3/Vector4, Quaternion with IsRotationallyEquivalent and (v0.2.0+) HasAxisAngleApproximately, Matrix4x4, Plane with IsGeometricallyEquivalent, Complex), span / tensor overloads (ReadOnlySpan<double>/<float>, generic ReadOnlyTensorSpan<T>), ULP-distance equality (IsCloseInUlps), combined relative+absolute tolerance, finiteness/probability/percentage predicates, HasRoundtripIdentity for invertible-transformation checks, and (v0.4.0+) the pose primitives RotationAngleDegrees, PositionDistance, and IsPoseApproximatelyEqual.
  • (v0.2.0+) Adapter packages such as MathAssertions.TUnit use an internal per-component / per-cell / first-failing-element failure-message renderer so every compound IsApproximatelyEqualTo failure shows the diverging axis and its delta. The renderer is reachable across the assembly boundary via [InternalsVisibleTo]; consumers do not interact with it directly.
  • Sequences: monotonicity (strict + non-strict), boundedness, arithmetic and geometric progressions, ConvergesTo, single-step IsCauchyConvergent, generic length predicates over ReadOnlySpan<T>.
  • Statistics: Welford's MeanAndVariance, HasMean/Variance/StdDev/Sum/Median/PercentileApproximately, IsWithinSigmasOfMean, AreAllWithinSigmasOfMean. Median and percentile use overflow-safe forms.
  • LinearAlgebra: Matrix4x4 invariants (IsSymmetric, IsOrthogonal, IsIdentity, HasDeterminantApproximately, HasTraceApproximately, IsInvertible) plus Vector3 pair properties (AreOrthogonal, AreParallel, AreLinearlyIndependent).
  • NumberTheory: exact integer predicates over long: IsDivisibleBy, IsPrime, AreCoprime, GreatestCommonDivisor, LeastCommonMultiple, IsPowerOf, IsPerfectSquare, IsCongruent. Overflow-safe and long.MinValue-aware.
  • Geometry3D: eight primitive record struct types (Sphere, AxisAlignedBox, OrientedBox, Ray3D, LineSegment3D, Triangle3D, Capsule, Cylinder) and five static classes: Properties (degeneracy, collinearity, coplanarity), Containment (point/box/sphere/OBB/convex hull), Distance (point-to-plane/segment/triangle), Intersection (sphere-sphere, AABB-AABB, ray-plane/sphere/triangle/AABB with citations to Real-Time Rendering §§22.6, 22.7, 22.8), Pointcloud (boundedness, centroid, on-plane / on-sphere). Algorithm citations preserved per Real-Time Collision Detection and Real-Time Rendering.

All tolerance- and sigma-taking methods validate the bound up front; invalid input throws ArgumentOutOfRangeException even on early-return paths.

Test-framework adapters

Package Test framework Status
MathAssertions.TUnit TUnit Available now
MathAssertions.NUnit NUnit Possible if there is demand
MathAssertions.xUnit xUnit Possible if there is demand
MathAssertions.MSTest MSTest Possible if there is demand

If you'd find a non-TUnit adapter useful, open a feature request. Adapters are not built proactively.

When to install this package directly

Only when authoring a non-TUnit adapter for the assertion family, or when calling MathTolerance from a [GenerateAssertion] extension on a private type. For any TUnit testing use case, install MathAssertions.TUnit.

Installation

dotnet add package MathAssertions.TUnit

MathAssertions comes transitively. You don't need to install it directly unless you're building your own adapter package.

Stability

The public surface above is semver-bound. Breaking changes require a major version bump. The exact text of any future failure-message rendering produced inside MathTolerance is not stable and may gain extra detail or change formatting in any release.

Repository

github.com/JohnVerheij/MathAssertions.TUnit for the full README, design notes, and roadmap.

License

MIT. Copyright (c) 2026 John Verheij.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on MathAssertions:

Package Downloads
MathAssertions.TUnit

TUnit-native math assertions for .NET tests. Fluent .Method(...) entry points (generated via TUnit's [GenerateAssertion]) covering tolerance comparisons (scalar, vector, quaternion, matrix, plane, complex, double[]/float[]), sequences, statistics, Vector3 linear algebra, long-integer number theory, and the Geometry3D primitive surface (containment, distance, intersection, pointcloud aggregates). Extensible: consumers add tolerance assertions for their own domain types via [GenerateAssertion] extensions calling MathTolerance helpers. AOT-compatible, trimmable, no reflection.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.4.0 29 6/2/2026
0.3.0 219 5/14/2026
0.2.0 252 5/12/2026
0.1.0 149 5/9/2026
0.0.1 132 5/8/2026

View the rendered release notes: https://github.com/JohnVerheij/MathAssertions.TUnit/releases/tag/v0.4.0

Feature release. Adds the pose assertion the package's `PoseRenderer` was waiting for: a pose is a position and an orientation together, so `IsPoseApproximatelyEqualTo` compares both halves in one call with separate position (length) and rotation (degrees) tolerances and one combined diagnostic that names which half missed. Also folds in the accumulated CI hardening, the Renovate migration, and the CONVENTIONS v0.7 sync that had collected on the unreleased line.

### Added

- **`Assert.That((position, orientation)).IsPoseApproximatelyEqualTo((expectedPosition, expectedOrientation), positionTolerance, rotationToleranceDegrees)`** (TUnit adapter) compares a `(Vector3, Quaternion)` pose in one call. The two halves use separate tolerances because they carry different units: a Euclidean position distance and a geodesic rotation angle in degrees. On failure the combined message renders both poses and the measured position and rotation deltas, flagging which half exceeded its tolerance. The orientation comparison uses the SO(3) metric, so a quaternion and its negation are the same rotation. Source-generated via `[GenerateAssertion]`.
- **`Assert.That(matrix).IsRigidTransformApproximatelyEqualTo(expectedMatrix, positionTolerance, rotationToleranceDegrees)`** (TUnit adapter) is the `Matrix4x4` overload (a pose is a rigid transform). Translation is read from `Matrix4x4.Translation` and rotation via `Quaternion.CreateFromRotationMatrix`; the overload assumes a rigid transform (orthonormal rotation, unit scale).
- **`MathTolerance.IsPoseApproximatelyEqual(...)`, `RotationAngleDegrees(Quaternion, Quaternion)`, and `PositionDistance(Vector3, Vector3)`** (framework-agnostic core) back the assertions: the geodesic rotation angle in degrees, the double-precision Euclidean position distance, and the combined pose predicate.

### Changed

- Removed `paths-ignore` from `.github/workflows/ci.yml` so the `Build, test & pack` required check always reports a status. Without the fix, docs-only PRs stuck in `Expected - Waiting for status to be reported` and could not satisfy branch protection.
- Dropped drift-prone own-version anchors from the root README and packed adapter README: `## Status: v0.3.0 (pose renderer)` is now `## Status`. Historical "added in vX.Y" markers and the `### Shipped at v0.X.Y` historical sections are unchanged. The CHANGELOG remains the single source of truth for what shipped when.
- Migrated CI dependency automation from Dependabot to Renovate (`.github/renovate.json`), matching `SseAssertions.TUnit` and `TimeAssertions.TUnit`. Daily schedule (before 4am Europe/Amsterdam), `customManagers` keep TUnit version literals in the root README, package README, smoketest csproj, and bug-report Issue Form in lockstep with the central `Directory.Packages.props` pin. `platformAutomerge` replaces the separate `dependabot-auto-merge.yml` workflow. Dependency dashboard issue enabled. Explicit semantic commit scopes: `deps(nuget)`, `ci(github-actions)`, `ci(dotnet-sdk)`. Auto-merge covers `digest`, `pin`, `pinDigest`, and `lockFileMaintenance` updateTypes alongside `minor` and `patch`. The three TUnit packages (`TUnit`, `TUnit.Assertions`, `TUnit.Core`) are grouped into a single PR per release.
- **TUnit dependency bumped `1.44.0` -> `1.44.39`** (and the external-consumer smoke-test pin). 1.44.39 carries the `[GenerateAssertion]` source-generator fix for value-type optional parameters; no behavioural change for this package, taken for family lockstep.
- Updated `CONVENTIONS.md` to v0.7 (cumulative from v0.5).
- Added `JsonAssertions.TUnit` (the fifth family package, JSON path / value / shape assertions) and `SseAssertions.TUnit` (the sixth family package, Server-Sent Events wire-format assertions) to the `CONVENTIONS.md` family roster.
- Added a per-package strict-scope policy section to `CONVENTIONS.md` with explicit scope statements for all six packages.
- Added a core+adapter packaging rule section to `CONVENTIONS.md`: five of six family packages ship core+adapter; `JsonAssertions.TUnit` is the sole single-package member.
- Synchronised `CONVENTIONS.md` across all six family repos (the file is copied identically).
- Expanded the `README.md` Family roster to six packages, adding `JsonAssertions.TUnit` and `SseAssertions.TUnit` to the "Family compatibility" section, the "Pair with" section, and the "shared across" line in Contributing.
- Added GitHub Actions workflow security scanning. `.github/workflows/zizmor.yml` runs `zizmor` (blocking, with findings shown as inline annotations) on every workflow change; `.github/workflows/codeql.yml` now analyzes the `actions` language alongside `csharp`; `.github/workflows/scorecard.yml` (OpenSSF Scorecard) and `.github/workflows/dependency-review.yml` (fails a PR that adds a high-severity-vulnerable dependency) are new. Added the Renovate `helpers:pinGitHubActionDigestsToSemver` preset so any newly-introduced action is auto-pinned to a commit SHA. CI-only; no effect on shipped packages.

### Security

- Hardened GitHub Actions token handling: set `persist-credentials: false` on every `actions/checkout` so the repository token is not written into `.git/config`; moved the inline coverage-report expression in `ci.yml` into an `env:` variable to remove a template-injection vector; and scoped workflow write permissions (`security-events` on `codeql`; `contents`/`id-token`/`packages`/`attestations` on `release`) to the job level with a read-only workflow-level default. CI-only; no released package is affected.