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.
Example #1
0
        /// <summary>
        /// Test two numeric values for equality, performing the usual numeric 
        /// conversions and using a provided or default tolerance. If the tolerance 
        /// provided is Empty, this method may set it to a default tolerance.
        /// </summary>
        /// <param name="expected">The expected value</param>
        /// <param name="actual">The actual value</param>
        /// <param name="tolerance">A reference to the tolerance in effect</param>
        /// <returns>True if the values are equal</returns>
        public static bool AreEqual( object expected, object actual, ref Tolerance tolerance )
        {
            if ( expected is double || actual is double )
                return AreEqual( Convert.ToDouble(expected), Convert.ToDouble(actual), ref tolerance );

            if ( expected is float || actual is float )
                return AreEqual( Convert.ToSingle(expected), Convert.ToSingle(actual), ref tolerance );

            if (tolerance.Mode == ToleranceMode.Ulps)
                throw new InvalidOperationException("Ulps may only be specified for floating point arguments");

            if ( expected is decimal || actual is decimal )
                return AreEqual( Convert.ToDecimal(expected), Convert.ToDecimal(actual), tolerance );

            if (expected is ulong || actual is ulong)
                return AreEqual(Convert.ToUInt64(expected), Convert.ToUInt64(actual), tolerance );

            if ( expected is long || actual is long )
                return AreEqual( Convert.ToInt64(expected), Convert.ToInt64(actual), tolerance );

            if ( expected is uint || actual is uint )
                return AreEqual( Convert.ToUInt32(expected), Convert.ToUInt32(actual), tolerance );

            return AreEqual( Convert.ToInt32(expected), Convert.ToInt32(actual), tolerance );
        }
Example #2
0
 /// <summary>
 /// Display Expected and Actual lines for given values, including
 /// a tolerance value on the Expected line.
 /// </summary>
 /// <param name="expected">The expected value</param>
 /// <param name="actual">The actual value causing the failure</param>
 /// <param name="tolerance">The tolerance within which the test was made</param>
 public abstract void DisplayDifferences(object expected, object actual, Tolerance tolerance);
Example #3
0
        private bool EnumerablesEqual(IEnumerable x, IEnumerable y, ref Tolerance tolerance)
        {
            IEnumerator expectedEnum = x.GetEnumerator();
            IEnumerator actualEnum = y.GetEnumerator();

            int count;
            for (count = 0; ; count++)
            {
                bool expectedHasData = expectedEnum.MoveNext();
                bool actualHasData = actualEnum.MoveNext();

                if (!expectedHasData && !actualHasData)
                    return true;

                if (expectedHasData != actualHasData ||
                    !AreEqual(expectedEnum.Current, actualEnum.Current, ref tolerance))
                {
                    FailurePoint fp = new FailurePoint();
                    fp.Position = count;
                    fp.ExpectedHasData = expectedHasData;
                    if (expectedHasData)
                            fp.ExpectedValue = expectedEnum.Current;
                    fp.ActualHasData = actualHasData;
                    if (actualHasData)
                        fp.ActualValue = actualEnum.Current;
                    failurePoints.Insert(0, fp);
                    return false;
                }
            }
        }
Example #4
0
        private bool DictionariesEqual(IDictionary x, IDictionary y, ref Tolerance tolerance)
        {
            if (x.Count != y.Count)
                return false;

            CollectionTally tally = new CollectionTally(this, x.Keys);
            if (!tally.TryRemove(y.Keys) || tally.Count > 0)
                return false;

            foreach (object key in x.Keys)
                if (!AreEqual(x[key], y[key], ref tolerance))
                    return false;

            return true;
        }
Example #5
0
        /// <summary>
        /// Helper method to compare two arrays
        /// </summary>
        private bool ArraysEqual(Array x, Array y, ref Tolerance tolerance)
        {
            int rank = x.Rank;

            if (rank != y.Rank)
                return false;

            for (int r = 1; r < rank; r++)
                if (x.GetLength(r) != y.GetLength(r))
                    return false;

            return EnumerablesEqual((IEnumerable)x, (IEnumerable)y, ref tolerance);
        }
Example #6
0
        /// <summary>
        /// Compares two objects for equality within a tolerance.
        /// </summary>
        public bool AreEqual(object x, object y, ref Tolerance tolerance)
        {
            this.failurePoints = new List<object>();

            if (x == null && y == null)
                return true;

            if (x == null || y == null)
                return false;

            if (object.ReferenceEquals(x, y))
                return true;

            Type xType = x.GetType();
            Type yType = y.GetType();

            EqualityAdapter externalComparer = GetExternalComparer(x, y);
            if (externalComparer != null)
                return externalComparer.AreEqual(x, y);

            if (xType.IsArray && yType.IsArray && !compareAsCollection)
                return ArraysEqual((Array)x, (Array)y, ref tolerance);

            if (x is IDictionary && y is IDictionary)
                return DictionariesEqual((IDictionary)x, (IDictionary)y, ref tolerance);

            //if (x is ICollection && y is ICollection)
            //    return CollectionsEqual((ICollection)x, (ICollection)y, ref tolerance);

            if (x is IEnumerable && y is IEnumerable && !(x is string && y is string))
                return EnumerablesEqual((IEnumerable)x, (IEnumerable)y, ref tolerance);

            if (x is string && y is string)
                return StringsEqual((string)x, (string)y);

            if (x is Stream && y is Stream)
                return StreamsEqual((Stream)x, (Stream)y);

            if (Numerics.IsNumericType(x) && Numerics.IsNumericType(y))
                return Numerics.AreEqual(x, y, ref tolerance);

            if (tolerance != null && tolerance.Value is TimeSpan)
            {
                TimeSpan amount = (TimeSpan)tolerance.Value;

                if (x is DateTime && y is DateTime)
                    return ((DateTime)x - (DateTime)y).Duration() <= amount;

                if (x is TimeSpan && y is TimeSpan)
                    return ((TimeSpan)x - (TimeSpan)y).Duration() <= amount;
            }

            if (FirstImplementsIEquatableOfSecond(xType, yType))
                return InvokeFirstIEquatableEqualsSecond(x, y);
            else if (FirstImplementsIEquatableOfSecond(yType, xType))
                return InvokeFirstIEquatableEqualsSecond(y, x);

            return x.Equals(y);
        }
Example #7
0
        /// <summary>
        /// Compares two collection members for equality
        /// </summary>
        protected bool ItemsEqual(object x, object y)
        {
            Tolerance tolerance = Tolerance.Zero;

            return(comparer.AreEqual(x, y, ref tolerance));
        }
Example #8
0
        private bool ItemsEqual(object expected, object actual)
        {
            Tolerance tolerance = Tolerance.Zero;

            return(comparer.AreEqual(expected, actual, ref tolerance));
        }
Example #9
0
        /// <summary>
        /// Write the generic 'Expected' line for a given value
        /// and tolerance.
        /// </summary>
        /// <param name="expected">The expected value</param>
        /// <param name="tolerance">The tolerance within which the test was made</param>
        private void WriteExpectedLine(object expected, Tolerance tolerance)
        {
            Write(Pfx_Expected);
            WriteExpectedValue(expected);

            if (tolerance != null && !tolerance.IsEmpty)
            {
                WriteConnector("+/-");
                WriteExpectedValue(tolerance.Value);
                if (tolerance.Mode != ToleranceMode.Linear)
                    Write(" {0}", tolerance.Mode);
            }

            WriteLine();
        }
Example #10
0
 /// <summary>
 /// Display Expected and Actual lines for given values, including
 /// a tolerance value on the expected line.
 /// </summary>
 /// <param name="expected">The expected value</param>
 /// <param name="actual">The actual value causing the failure</param>
 /// <param name="tolerance">The tolerance within which the test was made</param>
 public override void DisplayDifferences(object expected, object actual, Tolerance tolerance)
 {
     WriteExpectedLine(expected, tolerance);
     WriteActualLine(actual);
 }
Example #11
0
 /// <summary>
 /// Display Expected and Actual lines for given values, including
 /// a tolerance value on the Expected line.
 /// </summary>
 /// <param name="expected">The expected value</param>
 /// <param name="actual">The actual value causing the failure</param>
 /// <param name="tolerance">The tolerance within which the test was made</param>
 public abstract void DisplayDifferences(object expected, object actual, Tolerance tolerance);
Example #12
0
        private static bool AreEqual( int expected, int actual, Tolerance tolerance )
        {
            switch (tolerance.Mode)
            {
                case ToleranceMode.None:
                    return expected.Equals(actual);

                case ToleranceMode.Linear:
                    int intTolerance = Convert.ToInt32(tolerance.Value);
                    if (intTolerance > 0)
                        return Math.Abs(expected - actual) <= intTolerance;

                    return expected.Equals(actual);

                case ToleranceMode.Percent:
                    if (expected == 0)
                        return expected.Equals(actual);

                    double relativeError = Math.Abs(
                        (double)(expected - actual) / (double)expected);
                    return (relativeError <= Convert.ToDouble(tolerance.Value) / 100.0);

                default:
                    throw new ArgumentException("Unknown tolerance mode specified", "mode");
            }
        }
Example #13
0
        private static bool AreEqual( uint expected, uint actual, Tolerance tolerance )
        {
            switch (tolerance.Mode)
            {
                case ToleranceMode.None:
                    return expected.Equals(actual);

                case ToleranceMode.Linear:
                    uint uintTolerance = Convert.ToUInt32(tolerance.Value);
                    if(uintTolerance > 0)
                    {
                        uint diff = expected >= actual ? expected - actual : actual - expected;
                        return diff <= uintTolerance;
                    }

                    return expected.Equals( actual );

                case ToleranceMode.Percent:
                    if(expected == 0u)
                        return expected.Equals(actual);

                    // Can't do a simple Math.Abs() here since it's unsigned
                    uint difference = Math.Max(expected, actual) - Math.Min(expected, actual);
                    double relativeError = Math.Abs((double)difference / (double)expected );
                    return (relativeError <= Convert.ToDouble(tolerance.Value) / 100.0);

                default:
                    throw new ArgumentException("Unknown tolerance mode specified", "mode");
            }
        }
Example #14
0
        private static bool AreEqual( float expected, float actual, ref Tolerance tolerance )
        {
            if ( float.IsNaN(expected) && float.IsNaN(actual) )
                return true;

            // handle infinity specially since subtracting two infinite values gives
            // NaN and the following test fails. mono also needs NaN to be handled
            // specially although ms.net could use either method.
            if (float.IsInfinity(expected) || float.IsNaN(expected) || float.IsNaN(actual))
            {
                return expected.Equals(actual);
            }

            if (tolerance.IsEmpty && GlobalSettings.DefaultFloatingPointTolerance > 0.0d)
                tolerance = new Tolerance(GlobalSettings.DefaultFloatingPointTolerance);

            switch (tolerance.Mode)
            {
                case ToleranceMode.None:
                    return expected.Equals(actual);

                case ToleranceMode.Linear:
                    return Math.Abs(expected - actual) <= Convert.ToDouble(tolerance.Value);

                case ToleranceMode.Percent:
                    if (expected == 0.0f)
                        return expected.Equals(actual);
                    float relativeError = Math.Abs((expected - actual) / expected);
                    return (relativeError <= Convert.ToSingle(tolerance.Value) / 100.0f);
            #if !NETCF_1_0
                case ToleranceMode.Ulps:
                    return FloatingPointNumerics.AreAlmostEqualUlps(
                        expected, actual, Convert.ToInt32(tolerance.Value));
            #endif
                default:
                    throw new ArgumentException("Unknown tolerance mode specified", "mode");
            }
        }