using System; namespace NUnit.Framework { /// /// Abstract base class for EqualsAsserter and NotEqualsAsserter /// public abstract class EqualityAsserter : ComparisonAsserter { private double delta; /// /// Constructor taking expected and actual values and a user message with arguments. /// /// /// /// /// public EqualityAsserter( object expected, object actual, string message, params object[] args ) : base( expected, actual, message, args ) { } /// /// Constructor taking expected and actual values, a tolerance /// and a user message and arguments. /// /// /// /// /// /// public EqualityAsserter( double expected, double actual, double delta, string message, params object[] args ) : base( expected, actual, message, args ) { this.delta = delta; } /// /// Used to compare two objects. Two nulls are equal and null /// is not equal to non-null. Comparisons between the same /// numeric types are fine (Int32 to Int32, or Int64 to Int64), /// but the Equals method fails across different types so we /// use ToString and compare the results. /// /// /// /// protected virtual bool ObjectsEqual( Object expected, Object actual ) { if ( expected == null && actual == null ) return true; if ( expected == null || actual == null ) return false; //if ( expected.GetType().IsArray && actual.GetType().IsArray ) // return ArraysEqual( (System.Array)expected, (System.Array)actual ); if ( expected is double && actual is double ) { if ( double.IsNaN((double)expected) && double.IsNaN((double)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 (double.IsInfinity((double)expected) || double.IsNaN((double)expected) || double.IsNaN((double)actual)) return expected.Equals( actual ); else return Math.Abs((double)expected-(double)actual) <= this.delta; } // if ( expected is float && actual is float ) // { // // 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((float)expected) || float.IsNaN((float)expected) || float.IsNaN((float)actual)) // return (float)expected == (float)actual; // else // return Math.Abs((float)expected-(float)actual) <= (float)this.delta; // } if ( expected.GetType() != actual.GetType() && IsNumericType( expected ) && IsNumericType( actual ) ) { // // Convert to strings and compare result to avoid // issues with different types that have the same // value // string sExpected = expected.ToString(); string sActual = actual.ToString(); return sExpected.Equals( sActual ); } return expected.Equals(actual); } /// /// Checks the type of the object, returning true if /// the object is a numeric type. /// /// The object to check /// true if the object is a numeric type private bool IsNumericType( Object obj ) { if( null != obj ) { if( obj is byte ) return true; if( obj is sbyte ) return true; if( obj is decimal ) return true; if( obj is double ) return true; if( obj is float ) return true; if( obj is int ) return true; if( obj is uint ) return true; if( obj is long ) return true; if( obj is short ) return true; if( obj is ushort ) return true; if( obj is System.Byte ) return true; if( obj is System.SByte ) return true; if( obj is System.Decimal ) return true; if( obj is System.Double ) return true; if( obj is System.Single ) return true; if( obj is System.Int32 ) return true; if( obj is System.UInt32 ) return true; if( obj is System.Int64 ) return true; if( obj is System.UInt64 ) return true; if( obj is System.Int16 ) return true; if( obj is System.UInt16 ) return true; } return false; } /// /// Helper method to compare two arrays /// protected virtual bool ArraysEqual( Array expected, Array actual ) { if ( expected.Rank != actual.Rank ) return false; if ( expected.Rank != 1 ) throw new ArgumentException( "Multi-dimension array comparison is not supported" ); int iLength = Math.Min( expected.Length, actual.Length ); for( int i = 0; i < iLength; i++ ) if ( !ObjectsEqual( expected.GetValue( i ), actual.GetValue( i ) ) ) return false; if ( expected.Length != actual.Length ) return false; return true; } } }