face-core 0.1.0

Core grouping, clustering, and paging primitives for the face CLI.
Documentation
//! Integration tests for [`face_core::detect::preset::invert`] (§4.4).
//!
//! `invert` is the polarity-flip helper used when `--invert` is set
//! (e.g. distance metrics where lower-is-better). The two contract
//! cases: no scale → simple sign flip; with scale → `scale - value`.
//!
//! Public surface under test (locked by the developer brief):
//!
//! ```ignore
//! pub fn invert(value: f64, scale: Option<f64>) -> f64;
//! ```

use face_core::detect::preset::invert;

/// Compare two `f64`s with an absolute tolerance suitable for the
/// rounding error introduced by IEEE 754 subtraction. `1e-12` is
/// generous for the magnitudes used in this file (≤ 60.0).
#[track_caller]
fn assert_close(got: f64, expected: f64) {
    let diff = (got - expected).abs();
    assert!(
        diff < 1e-12,
        "got {got}, expected {expected} (|Δ| = {diff})",
    );
}

mod sign_flip {
    //! No scale → `-value`. Pure unary negation.

    use super::*;

    #[test]
    fn none_scale_negates() {
        assert_eq!(invert(0.5, None), -0.5);
    }

    #[test]
    fn negative_input() {
        // Double-flip: a negative input goes positive.
        assert_eq!(invert(-0.3, None), 0.3);
    }

    #[test]
    fn zero() {
        // `-0.0` and `0.0` compare equal under `==` per IEEE 754, so
        // `0.0 == invert(0.0, None)` works for both. Pin via addition
        // to be defensive about any future signed-zero quirks.
        let got = invert(0.0, None);
        assert_eq!(got + 0.0, 0.0, "invert(0.0, None) ≈ 0.0; got {got}");
    }
}

mod scale_subtraction {
    //! With scale → `scale - value`. Used to flip a [0, 1] confidence
    //! polarity (`scale = 1.0`) or rescale a distance metric.

    use super::*;

    #[test]
    fn confidence_polarity_flip() {
        // 0.7 in a [0, 1] band, flipped about scale=1.0 → 0.3.
        // Tolerance compare: IEEE 754 makes `1.0 - 0.7` round to
        // 0.30000000000000004, which is correct behavior — the
        // contract is `scale - value`, not "the closest representable
        // 0.3".
        assert_close(invert(0.7, Some(1.0)), 0.3);
    }

    #[test]
    fn bm25_distance_flip() {
        // 12.0 against a 50.0 scale → 38.0. Typical bm25-distance flip.
        // Both operands are exactly representable so equality holds,
        // but use the tolerance compare for consistency.
        assert_close(invert(12.0, Some(50.0)), 38.0);
    }

    #[test]
    fn value_above_scale_goes_negative() {
        // The function is `scale - value` with no clamping; values
        // above the chosen scale produce negative outputs by design.
        assert_close(invert(60.0, Some(50.0)), -10.0);
    }
}