PageRenderTime 29ms CodeModel.GetById 15ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 1ms

/src/NUnit/framework/Constraints/Tolerance.cs

#
C# | 225 lines | 117 code | 21 blank | 87 comment | 5 complexity | f0c5425961d59d91afe59bd6492a3f68 MD5 | raw file
  1// ****************************************************************
  2// Copyright 2008, Charlie Poole
  3// This is free software licensed under the NUnit license. You may
  4// obtain a copy of the license at http://nunit.org/
  5// ****************************************************************
  6
  7using System;
  8
  9namespace NUnit.Framework.Constraints
 10{
 11    /// <summary>
 12    /// Modes in which the tolerance value for a comparison can
 13    /// be interpreted.
 14    /// </summary>
 15    public enum ToleranceMode
 16    {
 17        /// <summary>
 18        /// The tolerance was created with a value, without specifying 
 19        /// how the value would be used. This is used to prevent setting
 20        /// the mode more than once and is generally changed to Linear
 21        /// upon execution of the test.
 22        /// </summary>
 23        None,
 24        /// <summary>
 25        /// The tolerance is used as a numeric range within which
 26        /// two compared values are considered to be equal.
 27        /// </summary>
 28        Linear,
 29        /// <summary>
 30        /// Interprets the tolerance as the percentage by which
 31        /// the two compared values my deviate from each other.
 32        /// </summary>
 33        Percent,
 34        /// <summary>
 35        /// Compares two values based in their distance in
 36        /// representable numbers.
 37        /// </summary>
 38        Ulps
 39    }
 40
 41    /// <summary>
 42    /// The Tolerance class generalizes the notion of a tolerance
 43    /// within which an equality test succeeds. Normally, it is
 44    /// used with numeric types, but it can be used with any
 45    /// type that supports taking a difference between two 
 46    /// objects and comparing that difference to a value.
 47    /// </summary>
 48    public class Tolerance
 49    {
 50        private ToleranceMode mode;
 51        private object amount;
 52
 53        private static readonly string ModeMustFollowTolerance =
 54            "Tolerance amount must be specified before setting mode";
 55        private static readonly string MultipleToleranceModes =
 56            "Tried to use multiple tolerance modes at the same time";
 57        private static readonly string NumericToleranceRequired =
 58            "A numeric tolerance is required";
 59
 60        /// <summary>
 61        /// Returns an empty Tolerance object, equivalent to 
 62        /// specifying an exact match.
 63        /// </summary>
 64        public static Tolerance Empty
 65        {
 66            get { return new Tolerance(0, ToleranceMode.None); }
 67        }
 68
 69        /// <summary>
 70        /// Constructs a linear tolerance of a specdified amount
 71        /// </summary>
 72        public Tolerance(object amount) : this(amount, ToleranceMode.Linear) { }
 73
 74        /// <summary>
 75        /// Constructs a tolerance given an amount and ToleranceMode
 76        /// </summary>
 77        private Tolerance(object amount, ToleranceMode mode)
 78        {
 79            this.amount = amount;
 80            this.mode = mode;
 81        }
 82
 83        /// <summary>
 84        /// Gets the ToleranceMode for the current Tolerance
 85        /// </summary>
 86        public ToleranceMode Mode
 87        {
 88            get { return this.mode; }
 89        }
 90        
 91
 92        /// <summary>
 93        /// Tests that the current Tolerance is linear with a 
 94        /// numeric value, throwing an exception if it is not.
 95        /// </summary>
 96        private void CheckLinearAndNumeric()
 97        {
 98            if (mode != ToleranceMode.Linear)
 99                throw new InvalidOperationException(mode == ToleranceMode.None
100                    ? ModeMustFollowTolerance
101                    : MultipleToleranceModes);
102
103            if (!Numerics.IsNumericType(amount))
104                throw new InvalidOperationException(NumericToleranceRequired);
105        }
106
107        /// <summary>
108        /// Gets the value of the current Tolerance instance.
109        /// </summary>
110        public object Value
111        {
112            get { return this.amount; }
113        }
114
115        /// <summary>
116        /// Returns a new tolerance, using the current amount as a percentage.
117        /// </summary>
118        public Tolerance Percent
119        {
120            get
121            {
122                CheckLinearAndNumeric();
123                return new Tolerance(this.amount, ToleranceMode.Percent);
124            }
125        }
126
127        /// <summary>
128        /// Returns a new tolerance, using the current amount in Ulps.
129        /// </summary>
130        public Tolerance Ulps
131        {
132            get
133            {
134                CheckLinearAndNumeric();
135                return new Tolerance(this.amount, ToleranceMode.Ulps);
136            }
137        }
138
139        /// <summary>
140        /// Returns a new tolerance with a TimeSpan as the amount, using 
141        /// the current amount as a number of days.
142        /// </summary>
143        public Tolerance Days
144        {
145            get
146            {
147                CheckLinearAndNumeric();
148                return new Tolerance(TimeSpan.FromDays(Convert.ToDouble(amount)));
149            }
150        }
151
152        /// <summary>
153        /// Returns a new tolerance with a TimeSpan as the amount, using 
154        /// the current amount as a number of hours.
155        /// </summary>
156        public Tolerance Hours
157        {
158            get
159            {
160                CheckLinearAndNumeric();
161                return new Tolerance(TimeSpan.FromHours(Convert.ToDouble(amount)));
162            }
163        }
164
165        /// <summary>
166        /// Returns a new tolerance with a TimeSpan as the amount, using 
167        /// the current amount as a number of minutes.
168        /// </summary>
169        public Tolerance Minutes
170        {
171            get
172            {
173                CheckLinearAndNumeric();
174                return new Tolerance(TimeSpan.FromMinutes(Convert.ToDouble(amount)));
175            }
176        }
177
178        /// <summary>
179        /// Returns a new tolerance with a TimeSpan as the amount, using 
180        /// the current amount as a number of seconds.
181        /// </summary>
182        public Tolerance Seconds
183        {
184            get
185            {
186                CheckLinearAndNumeric();
187                return new Tolerance(TimeSpan.FromSeconds(Convert.ToDouble(amount)));
188            }
189        }
190
191        /// <summary>
192        /// Returns a new tolerance with a TimeSpan as the amount, using 
193        /// the current amount as a number of milliseconds.
194        /// </summary>
195        public Tolerance Milliseconds
196        {
197            get
198            {
199                CheckLinearAndNumeric();
200                return new Tolerance(TimeSpan.FromMilliseconds(Convert.ToDouble(amount)));
201            }
202        }
203
204        /// <summary>
205        /// Returns a new tolerance with a TimeSpan as the amount, using 
206        /// the current amount as a number of clock ticks.
207        /// </summary>
208        public Tolerance Ticks
209        {
210            get
211            {
212                CheckLinearAndNumeric();
213                return new Tolerance(TimeSpan.FromTicks(Convert.ToInt64(amount)));
214            }
215        }
216
217        /// <summary>
218        /// Returns true if the current tolerance is empty.
219        /// </summary>
220        public bool IsEmpty
221        {
222            get { return mode == ToleranceMode.None; }
223        }
224    }
225}