Skip to main content

entropy/
result.rs

1//! Test result type used by every test in the suite.
2
3use std::fmt;
4
5/// Significance level recommended by NIST SP 800-22 §4.2.1.
6pub const ALPHA: f64 = 0.01;
7
8/// The outcome of a single statistical test run against one RNG.
9#[derive(Debug, Clone)]
10pub struct TestResult {
11    /// Fully-qualified test name, e.g. `"nist::frequency"`.
12    pub name: &'static str,
13    /// Computed p-value.  `NAN` indicates a pre-condition failure
14    /// (sequence too short, etc.).
15    pub p_value: f64,
16    /// Optional human-readable note (e.g. parameter values used).
17    pub note: Option<String>,
18}
19
20impl TestResult {
21    /// Construct a result with the default significance level.
22    pub fn new(name: &'static str, p_value: f64) -> Self {
23        Self {
24            name,
25            p_value,
26            note: None,
27        }
28    }
29
30    /// Construct a result with an explanatory note.
31    pub fn with_note(name: &'static str, p_value: f64, note: impl Into<String>) -> Self {
32        Self {
33            name,
34            p_value,
35            note: Some(note.into()),
36        }
37    }
38
39    /// A result whose preconditions were not met (n too small, etc.).
40    pub fn insufficient(name: &'static str, reason: &str) -> Self {
41        Self {
42            name,
43            p_value: f64::NAN,
44            note: Some(reason.to_owned()),
45        }
46    }
47
48    /// `true` if p_value ≥ alpha (the sequence is not rejected at this level).
49    pub fn passed(&self) -> bool {
50        self.p_value >= ALPHA
51    }
52
53    /// `true` if the preconditions were not met (`p_value` is NaN).
54    pub fn skipped(&self) -> bool {
55        self.p_value.is_nan()
56    }
57}
58
59impl fmt::Display for TestResult {
60    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61        let status = if self.skipped() {
62            "SKIP"
63        } else if self.passed() {
64            "PASS"
65        } else {
66            "FAIL"
67        };
68        if self.skipped() {
69            write!(f, "[{status}] {:<48}  p = N/A", self.name)?;
70        } else {
71            write!(f, "[{status}] {:<48}  p = {:.6}", self.name, self.p_value)?;
72        }
73        if let Some(n) = &self.note {
74            write!(f, "  ({n})")?;
75        }
76        Ok(())
77    }
78}