Tolerance
The Tolerance class generalizes the notion of a tolerance
within which an equality test succeeds. Normally, it is
used with numeric types, but it can be used with any
type that supports taking a difference between two
objects and comparing that difference to a value.
using System;
namespace NUnit.Framework.Constraints
{
public class Tolerance
{
private readonly ToleranceMode mode;
private readonly object amount;
private const string ModeMustFollowTolerance = "Tolerance amount must be specified before setting mode";
private const string MultipleToleranceModes = "Tried to use multiple tolerance modes at the same time";
private const string NumericToleranceRequired = "A numeric tolerance is required";
public static Tolerance Default => new Tolerance(0, ToleranceMode.Unset);
public static Tolerance Exact => new Tolerance(0, ToleranceMode.Linear);
public ToleranceMode Mode => mode;
public object Value => amount;
public Tolerance Percent {
get {
CheckLinearAndNumeric();
return new Tolerance(amount, ToleranceMode.Percent);
}
}
public Tolerance Ulps {
get {
CheckLinearAndNumeric();
return new Tolerance(amount, ToleranceMode.Ulps);
}
}
public Tolerance Days {
get {
CheckLinearAndNumeric();
return new Tolerance(TimeSpan.FromDays(Convert.ToDouble(amount)));
}
}
public Tolerance Hours {
get {
CheckLinearAndNumeric();
return new Tolerance(TimeSpan.FromHours(Convert.ToDouble(amount)));
}
}
public Tolerance Minutes {
get {
CheckLinearAndNumeric();
return new Tolerance(TimeSpan.FromMinutes(Convert.ToDouble(amount)));
}
}
public Tolerance Seconds {
get {
CheckLinearAndNumeric();
return new Tolerance(TimeSpan.FromSeconds(Convert.ToDouble(amount)));
}
}
public Tolerance Milliseconds {
get {
CheckLinearAndNumeric();
return new Tolerance(TimeSpan.FromMilliseconds(Convert.ToDouble(amount)));
}
}
public Tolerance Ticks {
get {
CheckLinearAndNumeric();
return new Tolerance(TimeSpan.FromTicks(Convert.ToInt64(amount)));
}
}
public bool IsUnsetOrDefault => mode == ToleranceMode.Unset;
public Tolerance(object amount)
: this(amount, ToleranceMode.Linear)
{
}
private Tolerance(object amount, ToleranceMode mode)
{
this.amount = amount;
this.mode = mode;
}
private void CheckLinearAndNumeric()
{
if (mode != ToleranceMode.Linear)
throw new InvalidOperationException((mode == ToleranceMode.Unset) ? "Tolerance amount must be specified before setting mode" : "Tried to use multiple tolerance modes at the same time");
if (!Numerics.IsNumericType(amount))
throw new InvalidOperationException("A numeric tolerance is required");
}
}
}