using System; using System.Collections.Generic; namespace Amphora.RandomComparisons { /// /// What one check found: how likely a fair generator is to land this far from the expected result, on either side. /// public sealed class Outcome { public const double FailBelow = 1e-6; public const double SuspectBelow = 1e-3; public readonly double P; public readonly string Detail; /// /// Whether this is a measurement with no expected value, so it has no probability and no verdict. /// public readonly bool IsInformation; public Outcome(double p, string detail, bool isInformation = false) { P = p; Detail = detail; IsInformation = isInformation; } public static Outcome Information(string detail) { return new Outcome(1, detail, isInformation: true); } /// /// Returns the outcome with the smallest probability, which is the one a reader should look at. /// public static Outcome Worst(IReadOnlyList outcomes) { Outcome returnMe = outcomes[0]; foreach (Outcome outcome in outcomes) { if (outcome.P < returnMe.P) { returnMe = outcome; } } return returnMe; } public string Verdict { get { if (IsInformation) { return "info"; } if (P < FailBelow) { return "FAIL"; } return P < SuspectBelow ? "SUSPECT" : "ok"; } } public string PText { get { if (IsInformation) { return ""; } return P < 1e-300 ? "p<1e-300" : "p=" + P.ToString("0.###e+0"); } } } /// /// An outcome with the name of the check that produced it. /// public sealed class NamedOutcome { public readonly string Name; public readonly Outcome Outcome; /// /// Whether this check runs a method known to be wrong, so failing it is the check working. /// public readonly bool ExpectsFailure; public NamedOutcome(string name, Outcome outcome, bool expectsFailure = false) { Name = name; Outcome = outcome; ExpectsFailure = expectsFailure; } } }