1 // ***********************************************************************
2 // Copyright (c) 2008 Charlie Poole
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 // ***********************************************************************
25 #define NUNIT_FRAMEWORK
31 namespace NUnit.Framework.Constraints
34 /// The Tolerance class generalizes the notion of a tolerance
35 /// within which an equality test succeeds. Normally, it is
36 /// used with numeric types, but it can be used with any
37 /// type that supports taking a difference between two
38 /// objects and comparing that difference to a value.
40 public class Tolerance
42 private readonly ToleranceMode mode;
43 private readonly object amount;
45 private const string ModeMustFollowTolerance = "Tolerance amount must be specified before setting mode";
46 private const string MultipleToleranceModes = "Tried to use multiple tolerance modes at the same time";
47 private const string NumericToleranceRequired = "A numeric tolerance is required";
50 /// Returns a default Tolerance object, equivalent to
51 /// specifying an exact match unless <see cref="GlobalSettings.DefaultFloatingPointTolerance"/>
52 /// is set, in which case, the <see cref="GlobalSettings.DefaultFloatingPointTolerance"/>
55 public static Tolerance Default
57 get { return new Tolerance(0, ToleranceMode.Unset); }
61 /// Returns an empty Tolerance object, equivalent to
62 /// specifying an exact match even if
63 /// <see cref="GlobalSettings.DefaultFloatingPointTolerance"/> is set.
65 public static Tolerance Exact
67 get { return new Tolerance(0, ToleranceMode.Linear); }
71 /// Constructs a linear tolerance of a specified amount
73 public Tolerance(object amount) : this(amount, ToleranceMode.Linear) { }
76 /// Constructs a tolerance given an amount and <see cref="ToleranceMode"/>
78 private Tolerance(object amount, ToleranceMode mode)
85 /// Gets the <see cref="ToleranceMode"/> for the current Tolerance
87 public ToleranceMode Mode
89 get { return this.mode; }
94 /// Tests that the current Tolerance is linear with a
95 /// numeric value, throwing an exception if it is not.
97 private void CheckLinearAndNumeric()
99 if (mode != ToleranceMode.Linear)
100 throw new InvalidOperationException(mode == ToleranceMode.Unset
101 ? ModeMustFollowTolerance
102 : MultipleToleranceModes);
104 if (!Numerics.IsNumericType(amount))
105 throw new InvalidOperationException(NumericToleranceRequired);
109 /// Gets the value of the current Tolerance instance.
113 get { return amount; }
117 /// Returns a new tolerance, using the current amount as a percentage.
119 public Tolerance Percent
123 CheckLinearAndNumeric();
124 return new Tolerance(this.amount, ToleranceMode.Percent);
129 /// Returns a new tolerance, using the current amount in Ulps
131 public Tolerance Ulps
135 CheckLinearAndNumeric();
136 return new Tolerance(this.amount, ToleranceMode.Ulps);
141 /// Returns a new tolerance with a <see cref="TimeSpan"/> as the amount, using
142 /// the current amount as a number of days.
144 public Tolerance Days
148 CheckLinearAndNumeric();
149 return new Tolerance(TimeSpan.FromDays(Convert.ToDouble(amount)));
154 /// Returns a new tolerance with a <see cref="TimeSpan"/> as the amount, using
155 /// the current amount as a number of hours.
157 public Tolerance Hours
161 CheckLinearAndNumeric();
162 return new Tolerance(TimeSpan.FromHours(Convert.ToDouble(amount)));
167 /// Returns a new tolerance with a <see cref="TimeSpan"/> as the amount, using
168 /// the current amount as a number of minutes.
170 public Tolerance Minutes
174 CheckLinearAndNumeric();
175 return new Tolerance(TimeSpan.FromMinutes(Convert.ToDouble(amount)));
180 /// Returns a new tolerance with a <see cref="TimeSpan"/> as the amount, using
181 /// the current amount as a number of seconds.
183 public Tolerance Seconds
187 CheckLinearAndNumeric();
188 return new Tolerance(TimeSpan.FromSeconds(Convert.ToDouble(amount)));
193 /// Returns a new tolerance with a <see cref="TimeSpan"/> as the amount, using
194 /// the current amount as a number of milliseconds.
196 public Tolerance Milliseconds
200 CheckLinearAndNumeric();
201 return new Tolerance(TimeSpan.FromMilliseconds(Convert.ToDouble(amount)));
206 /// Returns a new tolerance with a <see cref="TimeSpan"/> as the amount, using
207 /// the current amount as a number of clock ticks.
209 public Tolerance Ticks
213 CheckLinearAndNumeric();
214 return new Tolerance(TimeSpan.FromTicks(Convert.ToInt64(amount)));
219 /// Returns true if the current tolerance has not been set or is using the .
221 public bool IsUnsetOrDefault
223 get { return mode == ToleranceMode.Unset; }