Imported Upstream version 3.6.0

Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
This commit is contained in:
Jo Shields
2014-08-13 10:39:27 +01:00
commit a575963da9
50588 changed files with 8155799 additions and 0 deletions

View File

@@ -0,0 +1,88 @@
// ****************************************************************
// Copyright 2007, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
using System;
namespace NUnit.Framework
{
/// <summary>
/// NOTE: The use of asserters for extending NUnit has
/// now been replaced by the use of constraints. This
/// class is marked obsolete.
///
/// AbstractAsserter is the base class for all asserters.
/// Asserters encapsulate a condition test and generation
/// of an AssertionException with a tailored message. They
/// are used by the Assert class as helper objects.
///
/// User-defined asserters may be passed to the
/// Assert.DoAssert method in order to implement
/// extended asserts.
/// </summary>
[Obsolete("Use Constraints rather than Asserters for new work")]
public abstract class AbstractAsserter : IAsserter
{
/// <summary>
/// The user-defined message for this asserter.
/// </summary>
protected readonly string userMessage;
/// <summary>
/// Arguments to use in formatting the user-defined message.
/// </summary>
protected readonly object[] args;
/// <summary>
/// Our failure message object, initialized as needed
/// </summary>
private AssertionFailureMessage failureMessage;
/// <summary>
/// Constructs an AbstractAsserter
/// </summary>
/// <param name="message">The message issued upon failure</param>
/// <param name="args">Arguments to be used in formatting the message</param>
public AbstractAsserter( string message, params object[] args )
{
this.userMessage = message;
this.args = args;
}
/// <summary>
/// AssertionFailureMessage object used internally
/// </summary>
protected AssertionFailureMessage FailureMessage
{
get
{
if ( failureMessage == null )
failureMessage = new AssertionFailureMessage( userMessage, args );
return failureMessage;
}
}
#region IAsserter Interface
/// <summary>
/// Test method to be implemented by derived types.
/// Default always succeeds.
/// </summary>
/// <returns>True if the test succeeds</returns>
public abstract bool Test();
/// <summary>
/// Message related to a failure. If no failure has
/// occured, the result is unspecified.
/// </summary>
public virtual string Message
{
get
{
return FailureMessage.ToString();
}
}
#endregion
}
}

View File

@@ -0,0 +1,14 @@
// ****************************************************************
// This is free software licensed under the NUnit license. You
// may obtain a copy of the license as well as information regarding
// copyright ownership at http://nunit.org/?p=license&r=2.4.
// ****************************************************************
using System;
using System.Reflection;
[assembly: CLSCompliant(true)]
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("../../nunit.snk")]
[assembly: AssemblyKeyName("")]

View File

@@ -0,0 +1 @@
f27e6e1eb537c2d272e379b410bc20f39849f5c6

View File

@@ -0,0 +1,169 @@
// ****************************************************************
// This is free software licensed under the NUnit license. You
// may obtain a copy of the license as well as information regarding
// copyright ownership at http://nunit.org/?p=license&r=2.4.
// ****************************************************************
namespace NUnit.Framework
{
using System;
/// <summary>
/// The Assertion class is obsolete and has been
/// replaced by the Assert class.
/// </summary>
[Obsolete("Use Assert class instead")]
public class Assertion
{
/// <summary>
/// Asserts that a condition is true. If it isn't it throws
/// an <see cref="AssertionException"/>.
/// </summary>
/// <param name="message">The message to display is the condition
/// is false</param>
/// <param name="condition">The evaluated condition</param>
static public void Assert(string message, bool condition)
{
NUnit.Framework.Assert.IsTrue(condition, message);
}
/// <summary>
/// Asserts that a condition is true. If it isn't it throws
/// an <see cref="AssertionException"/>.
/// </summary>
/// <param name="condition">The evaluated condition</param>
static public void Assert(bool condition)
{
Assertion.Assert(string.Empty, condition);
}
/// <summary>
/// /// Asserts that two doubles are equal concerning a delta. If the
/// expected value is infinity then the delta value is ignored.
/// </summary>
/// <param name="expected">The expected value</param>
/// <param name="actual">The actual value</param>
/// <param name="delta">The maximum acceptable difference between the
/// the expected and the actual</param>
static public void AssertEquals(double expected, double actual, double delta)
{
Assertion.AssertEquals(string.Empty, expected, actual, delta);
}
/// <summary>
/// /// Asserts that two singles are equal concerning a delta. If the
/// expected value is infinity then the delta value is ignored.
/// </summary>
/// <param name="expected">The expected value</param>
/// <param name="actual">The actual value</param>
/// <param name="delta">The maximum acceptable difference between the
/// the expected and the actual</param>
static public void AssertEquals(float expected, float actual, float delta)
{
Assertion.AssertEquals(string.Empty, expected, actual, delta);
}
/// <summary>Asserts that two objects are equal. If they are not
/// an <see cref="AssertionException"/> is thrown.</summary>
static public void AssertEquals(Object expected, Object actual)
{
Assertion.AssertEquals(string.Empty, expected, actual);
}
/// <summary>Asserts that two ints are equal. If they are not
/// an <see cref="AssertionException"/> is thrown.</summary>
static public void AssertEquals(int expected, int actual)
{
Assertion.AssertEquals(string.Empty, expected, actual);
}
/// <summary>Asserts that two ints are equal. If they are not
/// an <see cref="AssertionException"/> is thrown.</summary>
static public void AssertEquals(string message, int expected, int actual)
{
NUnit.Framework.Assert.AreEqual(expected, actual, message);
}
/// <summary>Asserts that two doubles are equal concerning a delta.
/// If the expected value is infinity then the delta value is ignored.
/// </summary>
static public void AssertEquals(string message, double expected,
double actual, double delta)
{
NUnit.Framework.Assert.AreEqual(expected, actual, delta, message);
}
/// <summary>Asserts that two floats are equal concerning a delta.
/// If the expected value is infinity then the delta value is ignored.
/// </summary>
static public void AssertEquals(string message, float expected,
float actual, float delta)
{
NUnit.Framework.Assert.AreEqual(expected, actual, delta, message);
}
/// <summary>
/// Asserts that two objects are equal. Two objects are considered
/// equal if both are null, or if both have the same value. Numeric
/// types are compared via string comparision on their contents to
/// avoid problems comparing values between different types. All
/// non-numeric types are compared by using the <c>Equals</c> method.
/// If they are not equal an <see cref="AssertionException"/> is thrown.
/// </summary>
static public void AssertEquals(string message, Object expected, Object actual)
{
NUnit.Framework.Assert.AreEqual(expected, actual, message);
}
/// <summary>Asserts that an object isn't null.</summary>
static public void AssertNotNull(Object anObject)
{
NUnit.Framework.Assert.IsNotNull(anObject, string.Empty);
}
/// <summary>Asserts that an object isn't null.</summary>
static public void AssertNotNull(string message, Object anObject)
{
NUnit.Framework.Assert.IsNotNull(anObject, message);
}
/// <summary>Asserts that an object is null.</summary>
static public void AssertNull(Object anObject)
{
NUnit.Framework.Assert.IsNull(anObject, string.Empty);
}
/// <summary>Asserts that an object is null.</summary>
static public void AssertNull(string message, Object anObject)
{
NUnit.Framework.Assert.IsNull(anObject, message);
}
/// <summary>Asserts that two objects refer to the same object. If they
/// are not the same an <see cref="AssertionException"/> is thrown.
/// </summary>
static public void AssertSame(Object expected, Object actual)
{
NUnit.Framework.Assert.AreSame(expected, actual, string.Empty);
}
/// <summary>Asserts that two objects refer to the same object.
/// If they are not an <see cref="AssertionException"/> is thrown.
/// </summary>
static public void AssertSame(string message, Object expected, Object actual)
{
NUnit.Framework.Assert.AreSame(expected, actual, message);
}
/// <summary>Fails a test with no message.</summary>
static public void Fail()
{
NUnit.Framework.Assert.Fail();
}
/// <summary>Fails a test with the given message.</summary>
static public void Fail(string message)
{
NUnit.Framework.Assert.Fail(message);
}
}
}

View File

@@ -0,0 +1,40 @@
// ****************************************************************
// This is free software licensed under the NUnit license. You
// may obtain a copy of the license as well as information regarding
// copyright ownership at http://nunit.org/?p=license&r=2.4.
// ****************************************************************
namespace NUnit.Framework
{
using System;
using System.Runtime.Serialization;
/// <summary>
/// Thrown when an assertion failed.
/// </summary>
///
[Serializable]
public class AssertionException : System.Exception
{
/// <param name="message">The error message that explains
/// the reason for the exception</param>
public AssertionException (string message) : base(message)
{}
/// <param name="message">The error message that explains
/// the reason for the exception</param>
/// <param name="inner">The exception that caused the
/// current exception</param>
public AssertionException(string message, Exception inner) :
base(message, inner)
{}
/// <summary>
/// Serialization Constructor
/// </summary>
protected AssertionException(SerializationInfo info,
StreamingContext context) : base(info,context)
{}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,111 @@
// ****************************************************************
// Copyright 2007, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
using System;
using System.Collections;
using NUnit.Framework.SyntaxHelpers;
using NUnit.Framework.Constraints;
namespace NUnit.Framework
{
/// <summary>
/// AssertionHelper is an optional base class for user tests,
/// allowing the use of shorter names for constraints and
/// asserts and avoiding conflict with the definition of
/// <see cref="Is"/>, from which it inherits much of its
/// behavior, in certain mock object frameworks.
/// </summary>
public class AssertionHelper : ConstraintBuilder
{
#region Expect
/// <summary>
/// Apply a constraint to an actual value, succeeding if the constraint
/// is satisfied and throwing an assertion exception on failure. Works
/// identically to <see cref="NUnit.Framework.Assert.That(object, Constraint)"/>
/// </summary>
/// <param name="constraint">A Constraint to be applied</param>
/// <param name="actual">The actual value to test</param>
static public void Expect( object actual, Constraint constraint )
{
Assert.That( actual, constraint, null, null );
}
/// <summary>
/// Apply a constraint to an actual value, succeeding if the constraint
/// is satisfied and throwing an assertion exception on failure. Works
/// identically to <see cref="NUnit.Framework.Assert.That(object, Constraint, string)"/>
/// </summary>
/// <param name="constraint">A Constraint to be applied</param>
/// <param name="actual">The actual value to test</param>
/// <param name="message">The message that will be displayed on failure</param>
static public void Expect( object actual, Constraint constraint, string message )
{
Assert.That( actual, constraint, message, null );
}
/// <summary>
/// Apply a constraint to an actual value, succeeding if the constraint
/// is satisfied and throwing an assertion exception on failure. Works
/// identically to <see cref="NUnit.Framework.Assert.That(object, Constraint, string, object[])"/>
/// </summary>
/// <param name="constraint">A Constraint to be applied</param>
/// <param name="actual">The actual value to test</param>
/// <param name="message">The message that will be displayed on failure</param>
/// <param name="args">Arguments to be used in formatting the message</param>
static public void Expect( object actual, Constraint constraint, string message, params object[] args )
{
Assert.That( actual, constraint, message, args );
}
/// <summary>
/// Asserts that a condition is true. If the condition is false the method throws
/// an <see cref="AssertionException"/>. Works Identically to
/// <see cref="Assert.That(bool, string, object[])"/>.
/// </summary>
/// <param name="condition">The evaluated condition</param>
/// <param name="message">The message to display if the condition is false</param>
/// <param name="args">Arguments to be used in formatting the message</param>
static public void Expect(bool condition, string message, params object[] args)
{
Assert.That(condition, Is.True, message, args);
}
/// <summary>
/// Asserts that a condition is true. If the condition is false the method throws
/// an <see cref="AssertionException"/>. Works Identically to
/// <see cref="Assert.That(bool, string)"/>.
/// </summary>
/// <param name="condition">The evaluated condition</param>
/// <param name="message">The message to display if the condition is false</param>
static public void Expect(bool condition, string message)
{
Assert.That(condition, Is.True, message, null);
}
/// <summary>
/// Asserts that a condition is true. If the condition is false the method throws
/// an <see cref="AssertionException"/>. Works Identically to <see cref="Assert.That(bool)"/>.
/// </summary>
/// <param name="condition">The evaluated condition</param>
static public void Expect(bool condition)
{
Assert.That(condition, Is.True, null, null);
}
#endregion
#region Map
/// <summary>
/// Returns a ListMapper based on a collection.
/// </summary>
/// <param name="original">The original collection</param>
/// <returns></returns>
public ListMapper Map( ICollection original )
{
return new ListMapper( original );
}
#endregion
}
}

View File

@@ -0,0 +1,50 @@
// ****************************************************************
// This is free software licensed under the NUnit license. You
// may obtain a copy of the license as well as information regarding
// copyright ownership at http://nunit.org/?p=license&r=2.4.
// ****************************************************************
using System;
namespace NUnit.Framework
{
/// <summary>
/// Attribute used to apply a category to a test
/// </summary>
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method|AttributeTargets.Assembly, AllowMultiple=true)]
public class CategoryAttribute : Attribute
{
/// <summary>
/// The name of the category
/// </summary>
protected string categoryName;
/// <summary>
/// Construct attribute for a given category
/// </summary>
/// <param name="name">The name of the category</param>
public CategoryAttribute(string name)
{
this.categoryName = name;
}
/// <summary>
/// Protected constructor uses the Type name as the name
/// of the category.
/// </summary>
protected CategoryAttribute()
{
this.categoryName = this.GetType().Name;
if ( categoryName.EndsWith( "Attribute" ) )
categoryName = categoryName.Substring( 0, categoryName.Length - 9 );
}
/// <summary>
/// The name of the category
/// </summary>
public string Name
{
get { return categoryName; }
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,109 @@
// ****************************************************************
// Copyright 2007, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
using System;
namespace NUnit.Framework.Constraints
{
/// <summary>
/// BinaryOperation is the abstract base of all constraints
/// that combine two other constraints in some fashion.
/// </summary>
public abstract class BinaryOperation : Constraint
{
/// <summary>
/// The first constraint being combined
/// </summary>
protected Constraint left;
/// <summary>
/// The second constraint being combined
/// </summary>
protected Constraint right;
/// <summary>
/// Construct a BinaryOperation from two other constraints
/// </summary>
/// <param name="left">The first constraint</param>
/// <param name="right">The second constraint</param>
public BinaryOperation(Constraint left, Constraint right)
{
this.left = left;
this.right = right;
}
}
/// <summary>
/// AndConstraint succeeds only if both members succeed.
/// </summary>
public class AndConstraint : BinaryOperation
{
/// <summary>
/// Create an AndConstraint from two other constraints
/// </summary>
/// <param name="left">The first constraint</param>
/// <param name="right">The second constraint</param>
public AndConstraint(Constraint left, Constraint right) : base(left, right) { }
/// <summary>
/// Apply both member constraints to an actual value, succeeding
/// succeeding only if both of them succeed.
/// </summary>
/// <param name="actual">The actual value</param>
/// <returns>True if the constraints both succeeded</returns>
public override bool Matches(object actual)
{
this.actual = actual;
return left.Matches(actual) && right.Matches(actual);
}
/// <summary>
/// Write a description for this contraint to a MessageWriter
/// </summary>
/// <param name="writer">The MessageWriter to receive the description</param>
public override void WriteDescriptionTo(MessageWriter writer)
{
left.WriteDescriptionTo(writer);
writer.WriteConnector("and");
right.WriteDescriptionTo(writer);
}
}
/// <summary>
/// OrConstraint succeeds if either member succeeds
/// </summary>
public class OrConstraint : BinaryOperation
{
/// <summary>
/// Create an OrConstraint from two other constraints
/// </summary>
/// <param name="left">The first constraint</param>
/// <param name="right">The second constraint</param>
public OrConstraint(Constraint left, Constraint right) : base(left, right) { }
/// <summary>
/// Apply the member constraints to an actual value, succeeding
/// succeeding as soon as one of them succeeds.
/// </summary>
/// <param name="actual">The actual value</param>
/// <returns>True if either constraint succeeded</returns>
public override bool Matches(object actual)
{
this.actual = actual;
return left.Matches(actual) || right.Matches(actual);
}
/// <summary>
/// Write a description for this contraint to a MessageWriter
/// </summary>
/// <param name="writer">The MessageWriter to receive the description</param>
public override void WriteDescriptionTo(MessageWriter writer)
{
left.WriteDescriptionTo(writer);
writer.WriteConnector("or");
right.WriteDescriptionTo(writer);
}
}
}

View File

@@ -0,0 +1,318 @@
// ****************************************************************
// Copyright 2007, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
using System;
using System.Collections;
namespace NUnit.Framework.Constraints
{
#region CollectionConstraint
/// <summary>
/// CollectionConstraint is the abstract base class for
/// constraints that operate on collections.
/// </summary>
public abstract class CollectionConstraint : Constraint
{
protected static bool IsEmpty( IEnumerable enumerable )
{
ICollection collection = enumerable as ICollection;
if ( collection != null )
return collection.Count == 0;
else
return !enumerable.GetEnumerator().MoveNext();
}
/// <summary>
/// CollectionTally counts (tallies) the number of
/// occurences of each object in one or more enuerations.
/// </summary>
protected internal class CollectionTally
{
// Internal hash used to count occurences
private Hashtable hash = new Hashtable();
// We use this for any null entries found, since
// the key to a hash may not be null.
static object NULL = new object();
private int getTally(object obj)
{
if ( obj == null ) obj = NULL;
object val = hash[obj];
return val == null ? 0 : (int)val;
}
private void setTally(object obj, int tally)
{
if ( obj == null ) obj = NULL;
hash[obj] = tally;
}
/// <summary>
/// Construct a CollectionTally object from a collection
/// </summary>
/// <param name="c"></param>
public CollectionTally( IEnumerable c )
{
foreach( object obj in c )
setTally( obj, getTally( obj ) + 1 );
}
/// <summary>
/// Remove the counts for a collection from the tally,
/// so long as their are sufficient items to remove.
/// The tallies are not permitted to become negative.
/// </summary>
/// <param name="c">The collection to remove</param>
/// <returns>True if there were enough items to remove, otherwise false</returns>
public bool CanRemove( IEnumerable c )
{
foreach( object obj in c )
{
int tally = getTally(obj);
if( tally > 0 )
setTally(obj, tally - 1 );
else
return false;
}
return true;
}
/// <summary>
/// Test whether all the counts are equal to a given value
/// </summary>
/// <param name="count">The value to be looked for</param>
/// <returns>True if all counts are equal to the value, otherwise false</returns>
public bool AllCountsEqualTo( int count )
{
foreach( DictionaryEntry entry in hash )
if ( (int)entry.Value != count )
return false;
return true;
}
/// <summary>
/// Get the count of the number of times an object is present in the tally
/// </summary>
public int this[object obj]
{
get { return getTally(obj); }
}
}
/// <summary>
/// Test whether the constraint is satisfied by a given value
/// </summary>
/// <param name="actual">The value to be tested</param>
/// <returns>True for success, false for failure</returns>
public override bool Matches(object actual)
{
this.actual = actual;
IEnumerable enumerable = actual as IEnumerable;
if ( enumerable == null )
throw new ArgumentException( "The actual value must be an IEnumerable", "actual" );
return doMatch( enumerable );
}
/// <summary>
/// Protected method to be implemented by derived classes
/// </summary>
/// <param name="collection"></param>
/// <returns></returns>
protected abstract bool doMatch(IEnumerable collection);
}
#endregion
#region EmptyCollectionConstraint
/// <summary>
/// EmptyCollectionConstraint tests whether a colletion is empty.
/// </summary>
public class EmptyCollectionConstraint : CollectionConstraint
{
/// <summary>
/// Check that the collection is empty
/// </summary>
/// <param name="collection"></param>
/// <returns></returns>
protected override bool doMatch(IEnumerable collection)
{
return IsEmpty( collection );
}
/// <summary>
/// Write the constraint description to a MessageWriter
/// </summary>
/// <param name="writer"></param>
public override void WriteDescriptionTo(MessageWriter writer)
{
writer.Write( "<empty>" );
}
}
#endregion
#region UniqueItemsConstraint
/// <summary>
/// UniqueItemsConstraint tests whether all the items in a
/// collection are unique.
/// </summary>
public class UniqueItemsConstraint : CollectionConstraint
{
/// <summary>
/// Check that all items are unique.
/// </summary>
/// <param name="actual"></param>
/// <returns></returns>
protected override bool doMatch(IEnumerable actual)
{
return new CollectionTally( actual ).AllCountsEqualTo( 1 );
}
/// <summary>
/// Write a description of this constraint to a MessageWriter
/// </summary>
/// <param name="writer"></param>
public override void WriteDescriptionTo(MessageWriter writer)
{
writer.Write("all items unique");
}
}
#endregion
#region CollectionContainsConstraint
/// <summary>
/// CollectionContainsConstraint is used to test whether a collection
/// contains an expected object as a member.
/// </summary>
public class CollectionContainsConstraint : CollectionConstraint
{
private object expected;
/// <summary>
/// Construct a CollectionContainsConstraint
/// </summary>
/// <param name="expected"></param>
public CollectionContainsConstraint(object expected)
{
this.expected = expected;
}
/// <summary>
/// Test whether the expected item is contained in the collection
/// </summary>
/// <param name="actual"></param>
/// <returns></returns>
protected override bool doMatch(IEnumerable actual)
{
foreach (object obj in actual)
if ( Object.Equals( obj, expected ) )
return true;
return false;
}
/// <summary>
/// Write a descripton of the constraint to a MessageWriter
/// </summary>
/// <param name="writer"></param>
public override void WriteDescriptionTo(MessageWriter writer)
{
writer.WritePredicate( "collection containing" );
writer.WriteExpectedValue(expected);
}
}
#endregion
#region CollectionEquivalentConstraint
/// <summary>
/// CollectionEquivalentCOnstraint is used to determine whether two
/// collections are equivalent.
/// </summary>
public class CollectionEquivalentConstraint : CollectionConstraint
{
private IEnumerable expected;
/// <summary>
/// Construct a CollectionEquivalentConstraint
/// </summary>
/// <param name="expected"></param>
public CollectionEquivalentConstraint(IEnumerable expected)
{
this.expected = expected;
}
/// <summary>
/// Test whether two collections are equivalent
/// </summary>
/// <param name="actual"></param>
/// <returns></returns>
protected override bool doMatch(IEnumerable actual)
{
// This is just an optimization
if( expected is ICollection && actual is ICollection )
if( ((ICollection)actual).Count != ((ICollection)expected).Count )
return false;
CollectionTally tally = new CollectionTally( expected );
return tally.CanRemove( actual ) && tally.AllCountsEqualTo( 0 );
}
/// <summary>
/// Write a description of this constraint to a MessageWriter
/// </summary>
/// <param name="writer"></param>
public override void WriteDescriptionTo(MessageWriter writer)
{
writer.WritePredicate("equivalent to");
writer.WriteExpectedValue(expected);
}
}
#endregion
#region CollectionSubsetConstraint
/// <summary>
/// CollectionSubsetConstraint is used to determine whether
/// one collection is a subset of another
/// </summary>
public class CollectionSubsetConstraint : CollectionConstraint
{
private IEnumerable expected;
/// <summary>
/// Construct a CollectionSubsetConstraint
/// </summary>
/// <param name="expected">The collection that the actual value is expected to be a subset of</param>
public CollectionSubsetConstraint(IEnumerable expected)
{
this.expected = expected;
}
/// <summary>
/// Test whether the actual collection is a subset of
/// the expected collection provided.
/// </summary>
/// <param name="actual"></param>
/// <returns></returns>
protected override bool doMatch(IEnumerable actual)
{
return new CollectionTally( expected ).CanRemove( actual );
}
/// <summary>
/// Write a description of this constraint to a MessageWriter
/// </summary>
/// <param name="writer"></param>
public override void WriteDescriptionTo(MessageWriter writer)
{
writer.WritePredicate( "subset of" );
writer.WriteExpectedValue(expected);
}
}
#endregion
}

View File

@@ -0,0 +1,127 @@
// ****************************************************************
// Copyright 2007, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
using System;
namespace NUnit.Framework.Constraints
{
/// <summary>
/// Abstract base class for constraints that compare values to
/// determine if one is greater than, equal to or less than
/// the other.
/// </summary>
public abstract class ComparisonConstraint : Constraint
{
/// <summary>
/// The value against which a comparison is to be made
/// </summary>
protected IComparable expected;
/// <summary>
/// If true, less than returns success
/// </summary>
protected bool ltOK = false;
/// <summary>
/// if true, equal returns success
/// </summary>
protected bool eqOK = false;
/// <summary>
/// if true, greater than returns success
/// </summary>
protected bool gtOK = false;
/// <summary>
/// The predicate used as a part of the description
/// </summary>
private string predicate;
/// <summary>
/// Initializes a new instance of the <see cref="T:ComparisonConstraint"/> class.
/// </summary>
/// <param name="value">The value against which to make a comparison.</param>
/// <param name="ltOK">if set to <c>true</c> less succeeds.</param>
/// <param name="eqOK">if set to <c>true</c> equal succeeds.</param>
/// <param name="gtOK">if set to <c>true</c> greater succeeds.</param>
/// <param name="predicate">String used in describing the constraint.</param>
public ComparisonConstraint(IComparable value, bool ltOK, bool eqOK, bool gtOK, string predicate)
{
this.expected = value;
this.ltOK = ltOK;
this.eqOK = eqOK;
this.gtOK = gtOK;
this.predicate = predicate;
}
/// <summary>
/// Test whether the constraint is satisfied by a given value
/// </summary>
/// <param name="actual">The value to be tested</param>
/// <returns>True for success, false for failure</returns>
public override bool Matches(object actual)
{
this.actual = actual;
int icomp = Numerics.Compare( expected, actual );
return icomp < 0 && gtOK || icomp == 0 && eqOK || icomp > 0 && ltOK;
}
/// <summary>
/// Write the constraint description to a MessageWriter
/// </summary>
/// <param name="writer">The writer on which the description is displayed</param>
public override void WriteDescriptionTo(MessageWriter writer)
{
writer.WritePredicate(predicate);
writer.WriteExpectedValue(expected);
}
}
/// <summary>
/// Tests whether a value is greater than the value supplied to its constructor
/// </summary>
public class GreaterThanConstraint : ComparisonConstraint
{
/// <summary>
/// Initializes a new instance of the <see cref="T:GreaterThanConstraint"/> class.
/// </summary>
/// <param name="expected">The expected value.</param>
public GreaterThanConstraint(IComparable expected) : base(expected, false, false, true, "greater than") { }
}
/// <summary>
/// Tests whether a value is greater than or equal to the value supplied to its constructor
/// </summary>
public class GreaterThanOrEqualConstraint : ComparisonConstraint
{
/// <summary>
/// Initializes a new instance of the <see cref="T:GreaterThanOrEqualConstraint"/> class.
/// </summary>
/// <param name="expected">The expected value.</param>
public GreaterThanOrEqualConstraint(IComparable expected) : base(expected, false, true, true, "greater than or equal to") { }
}
/// <summary>
/// Tests whether a value is less than the value supplied to its constructor
/// </summary>
public class LessThanConstraint : ComparisonConstraint
{
/// <summary>
/// Initializes a new instance of the <see cref="T:LessThanConstraint"/> class.
/// </summary>
/// <param name="expected">The expected value.</param>
public LessThanConstraint(IComparable expected) : base(expected, true, false, false, "less than") { }
}
/// <summary>
/// Tests whether a value is less than or equal to the value supplied to its constructor
/// </summary>
public class LessThanOrEqualConstraint : ComparisonConstraint
{
/// <summary>
/// Initializes a new instance of the <see cref="T:LessThanOrEqualConstraint"/> class.
/// </summary>
/// <param name="expected">The expected value.</param>
public LessThanOrEqualConstraint(IComparable expected) : base(expected, true, true, false, "less than or equal to") { }
}
}

View File

@@ -0,0 +1,209 @@
// ****************************************************************
// Copyright 2007, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
using System;
using System.IO;
using System.Collections;
namespace NUnit.Framework.Constraints
{
/// <summary>
/// The Constraint class is the base of all built-in or
/// user-defined constraints in NUnit. It provides the operator
/// overloads used to combine constraints.
/// </summary>
public abstract class Constraint
{
#region UnsetObject Class
/// <summary>
/// Class used to detect any derived constraints
/// that fail to set the actual value in their
/// Matches override.
/// </summary>
private class UnsetObject
{
public override string ToString()
{
return "UNSET";
}
}
#endregion
#region Static and Instance Fields
/// <summary>
/// Static UnsetObject used to detect derived constraints
/// failing to set the actual value.
/// </summary>
protected static object UNSET = new UnsetObject();
/// <summary>
/// If true, all string comparisons will ignore case
/// </summary>
protected bool caseInsensitive;
/// <summary>
/// If true, strings in error messages will be clipped
/// </summary>
protected bool clipStrings = true;
/// <summary>
/// If true, arrays will be treated as collections, allowing
/// those of different dimensions to be compared
/// </summary>
protected bool compareAsCollection;
/// <summary>
/// If non-zero, equality comparisons within the specified
/// tolerance will succeed.
/// </summary>
protected object tolerance;
/// <summary>
/// IComparer object used in comparisons for some constraints.
/// </summary>
protected IComparer compareWith;
/// <summary>
/// The actual value being tested against a constraint
/// </summary>
protected object actual = UNSET;
#endregion
#region Properties
/// <summary>
/// Flag the constraint to ignore case and return self.
/// </summary>
public virtual Constraint IgnoreCase
{
get
{
caseInsensitive = true;
return this;
}
}
/// <summary>
/// Flag the constraint to suppress string clipping
/// and return self.
/// </summary>
public Constraint NoClip
{
get
{
clipStrings = false;
return this;
}
}
/// <summary>
/// Flag the constraint to compare arrays as collections
/// and return self.
/// </summary>
public Constraint AsCollection
{
get
{
compareAsCollection = true;
return this;
}
}
/// <summary>
/// Flag the constraint to use a tolerance when determining equality.
/// Currently only used for doubles and floats.
/// </summary>
/// <param name="tolerance">Tolerance to be used</param>
/// <returns>Self.</returns>
public Constraint Within(object tolerance)
{
this.tolerance = tolerance;
return this;
}
/// <summary>
/// Flag the constraint to use the supplied IComparer object.
/// </summary>
/// <param name="comparer">The IComparer object to use.</param>
/// <returns>Self.</returns>
public Constraint Comparer(IComparer comparer)
{
this.compareWith = comparer;
return this;
}
#endregion
#region Public Methods
/// <summary>
/// Write the failure message to the MessageWriter provided
/// as an argument. The default implementation simply passes
/// the constraint and the actual value to the writer, which
/// then displays the constraint description and the value.
///
/// Constraints that need to provide additional details,
/// such as where the error occured can override this.
/// </summary>
/// <param name="writer">The MessageWriter on which to display the message</param>
public virtual void WriteMessageTo(MessageWriter writer)
{
writer.DisplayDifferences(this);
}
/// <summary>
/// Test whether the constraint is satisfied by a given value
/// </summary>
/// <param name="actual">The value to be tested</param>
/// <returns>True for success, false for failure</returns>
public abstract bool Matches(object actual);
/// <summary>
/// Write the constraint description to a MessageWriter
/// </summary>
/// <param name="writer">The writer on which the description is displayed</param>
public abstract void WriteDescriptionTo(MessageWriter writer);
/// <summary>
/// Write the actual value for a failing constraint test to a
/// MessageWriter. The default implementation simply writes
/// the raw value of actual, leaving it to the writer to
/// perform any formatting.
/// </summary>
/// <param name="writer">The writer on which the actual value is displayed</param>
public virtual void WriteActualValueTo(MessageWriter writer)
{
writer.WriteActualValue( actual );
}
#endregion
#region Operator Overloads
/// <summary>
/// This operator creates a constraint that is satisfied only if both
/// argument constraints are satisfied.
/// </summary>
public static Constraint operator &(Constraint left, Constraint right)
{
return new AndConstraint(left, right);
}
/// <summary>
/// This operator creates a constraint that is satisfied if either
/// of the argument constraints is satisfied.
/// </summary>
public static Constraint operator |(Constraint left, Constraint right)
{
return new OrConstraint(left, right);
}
/// <summary>
/// This operator creates a constraint that is satisfied if the
/// argument constraint is not satisfied.
/// </summary>
public static Constraint operator !(Constraint m)
{
return new NotConstraint(m == null ? new EqualConstraint(null) : m);
}
#endregion
}
}

View File

@@ -0,0 +1,436 @@
// ****************************************************************
// Copyright 2007, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
using System;
using System.Collections;
namespace NUnit.Framework.Constraints
{
/// <summary>
/// ConstraintBuilder is used to resolve the Not and All properties,
/// which serve as prefix operators for constraints. With the addition
/// of an operand stack, And and Or could be supported, but we have
/// left them out in favor of a simpler, more type-safe implementation.
/// Use the &amp; and | operator overloads to combine constraints.
/// </summary>
public class ConstraintBuilder
{
private enum Op
{
Not,
All,
Some,
None,
Prop,
}
Stack ops = new Stack();
Stack opnds = new Stack();
/// <summary>
/// Implicitly convert ConstraintBuilder to an actual Constraint
/// at the point where the syntax demands it.
/// </summary>
/// <param name="builder"></param>
/// <returns></returns>
public static implicit operator Constraint( ConstraintBuilder builder )
{
return builder.Resolve();
}
#region Constraints Without Arguments
/// <summary>
/// Resolves the chain of constraints using
/// EqualConstraint(null) as base.
/// </summary>
public Constraint Null
{
get { return Resolve(new EqualConstraint(null)); }
}
/// <summary>
/// Resolves the chain of constraints using
/// EqualConstraint(true) as base.
/// </summary>
public Constraint True
{
get { return Resolve(new EqualConstraint(true)); }
}
/// <summary>
/// Resolves the chain of constraints using
/// EqualConstraint(false) as base.
/// </summary>
public Constraint False
{
get { return Resolve(new EqualConstraint(false)); }
}
/// <summary>
/// Resolves the chain of constraints using
/// Is.NaN as base.
/// </summary>
public Constraint NaN
{
get { return Resolve(new EqualConstraint(double.NaN)); }
}
/// <summary>
/// Resolves the chain of constraints using
/// Is.Empty as base.
/// </summary>
public Constraint Empty
{
get { return Resolve(new EmptyConstraint()); }
}
/// <summary>
/// Resolves the chain of constraints using
/// Is.Unique as base.
/// </summary>
public Constraint Unique
{
get { return Resolve(new UniqueItemsConstraint()); }
}
#endregion
#region Constraints with an expected value
#region Equality and Identity
/// <summary>
/// Resolves the chain of constraints using an
/// EqualConstraint as base.
/// </summary>
public Constraint EqualTo(object expected)
{
return Resolve(new EqualConstraint(expected));
}
/// <summary>
/// Resolves the chain of constraints using a
/// SameAsConstraint as base.
/// </summary>
public Constraint SameAs(object expected)
{
return Resolve(new SameAsConstraint(expected));
}
#endregion
#region Comparison Constraints
/// <summary>
/// Resolves the chain of constraints using a
/// LessThanConstraint as base.
/// </summary>
public Constraint LessThan(IComparable expected)
{
return Resolve(new LessThanConstraint(expected));
}
/// <summary>
/// Resolves the chain of constraints using a
/// GreaterThanConstraint as base.
/// </summary>
public Constraint GreaterThan(IComparable expected)
{
return Resolve(new GreaterThanConstraint(expected));
}
/// <summary>
/// Resolves the chain of constraints using a
/// LessThanOrEqualConstraint as base.
/// </summary>
public Constraint LessThanOrEqualTo(IComparable expected)
{
return Resolve(new LessThanOrEqualConstraint(expected));
}
/// <summary>
/// Resolves the chain of constraints using a
/// LessThanOrEqualConstraint as base.
/// </summary>
public Constraint AtMost(IComparable expected)
{
return Resolve(new LessThanOrEqualConstraint(expected));
}
/// <summary>
/// Resolves the chain of constraints using a
/// GreaterThanOrEqualConstraint as base.
/// </summary>
public Constraint GreaterThanOrEqualTo(IComparable expected)
{
return Resolve(new GreaterThanOrEqualConstraint(expected));
}
/// <summary>
/// Resolves the chain of constraints using a
/// GreaterThanOrEqualConstraint as base.
/// </summary>
public Constraint AtLeast(IComparable expected)
{
return Resolve(new GreaterThanOrEqualConstraint(expected));
}
#endregion
#region Type Constraints
/// <summary>
/// Resolves the chain of constraints using an
/// ExactTypeConstraint as base.
/// </summary>
public Constraint TypeOf(Type expectedType)
{
return Resolve(new ExactTypeConstraint(expectedType));
}
/// <summary>
/// Resolves the chain of constraints using an
/// InstanceOfTypeConstraint as base.
/// </summary>
public Constraint InstanceOfType(Type expectedType)
{
return Resolve(new InstanceOfTypeConstraint(expectedType));
}
/// <summary>
/// Resolves the chain of constraints using an
/// AssignableFromConstraint as base.
/// </summary>
public Constraint AssignableFrom(Type expectedType)
{
return Resolve(new AssignableFromConstraint(expectedType));
}
#endregion
#region Containing Constraint
/// <summary>
/// Resolves the chain of constraints using a
/// ContainsConstraint as base. This constraint
/// will, in turn, make use of the appropriate
/// second-level constraint, depending on the
/// type of the actual argument.
/// </summary>
public Constraint Contains(object expected)
{
return Resolve( new ContainsConstraint(expected) );
}
/// <summary>
/// Resolves the chain of constraints using a
/// CollectionContainsConstraint as base.
/// </summary>
/// <param name="expected">The expected object</param>
public Constraint Member( object expected )
{
return Resolve( new CollectionContainsConstraint( expected ) );
}
#endregion
#region String Constraints
/// <summary>
/// Resolves the chain of constraints using a
/// StartsWithConstraint as base.
/// </summary>
public Constraint StartsWith(string substring)
{
return Resolve( new StartsWithConstraint(substring) );
}
/// <summary>
/// Resolves the chain of constraints using a
/// StringEndingConstraint as base.
/// </summary>
public Constraint EndsWith(string substring)
{
return Resolve( new EndsWithConstraint(substring) );
}
/// <summary>
/// Resolves the chain of constraints using a
/// StringMatchingConstraint as base.
/// </summary>
public Constraint Matches(string pattern)
{
return Resolve(new RegexConstraint(pattern));
}
#endregion
#region Collection Constraints
/// <summary>
/// Resolves the chain of constraints using a
/// CollectionEquivalentConstraint as base.
/// </summary>
public Constraint EquivalentTo(ICollection expected)
{
return Resolve( new CollectionEquivalentConstraint(expected) );
}
/// <summary>
/// Resolves the chain of constraints using a
/// CollectionContainingConstraint as base.
/// </summary>
public Constraint CollectionContaining(object expected)
{
return Resolve( new CollectionContainsConstraint(expected) );
}
/// <summary>
/// Resolves the chain of constraints using a
/// CollectionSubsetConstraint as base.
/// </summary>
public Constraint SubsetOf(ICollection expected)
{
return Resolve(new CollectionSubsetConstraint(expected));
}
#endregion
#region Property Constraints
/// <summary>
/// Resolves the chain of constraints using a
/// PropertyConstraint as base
/// </summary>
public Constraint Property( string name, object expected )
{
return Resolve( new PropertyConstraint( name, new EqualConstraint( expected ) ) );
}
/// <summary>
/// Resolves the chain of constraints using a
/// PropertyCOnstraint on Length as base
/// </summary>
/// <param name="length"></param>
/// <returns></returns>
public Constraint Length(int length)
{
return Property("Length", length);
}
/// <summary>
/// Resolves the chain of constraints using a
/// PropertyCOnstraint on Length as base
/// </summary>
/// <param name="count"></param>
/// <returns></returns>
public Constraint Count(int count)
{
return Property("Count", count);
}
#endregion
#endregion
#region Prefix Operators
/// <summary>
/// Modifies the ConstraintBuilder by pushing a Not operator on the stack.
/// </summary>
public ConstraintBuilder Not
{
get
{
ops.Push(Op.Not);
return this;
}
}
/// <summary>
/// Modifies the ConstraintBuilder by pushing a Not operator on the stack.
/// </summary>
public ConstraintBuilder No
{
get
{
ops.Push(Op.Not);
return this;
}
}
/// <summary>
/// Modifies the ConstraintBuilder by pushing an All operator on the stack.
/// </summary>
public ConstraintBuilder All
{
get
{
ops.Push(Op.All);
return this;
}
}
/// <summary>
/// Modifies the ConstraintBuilder by pushing a Some operator on the stack.
/// </summary>
public ConstraintBuilder Some
{
get
{
ops.Push(Op.Some);
return this;
}
}
/// <summary>
/// Modifies the constraint builder by pushing All and Not operators on the stack
/// </summary>
public ConstraintBuilder None
{
get
{
ops.Push(Op.None);
return this;
}
}
/// <summary>
/// Modifies the ConstraintBuilder by pushing a Prop operator on the
/// ops stack and the name of the property on the opnds stack.
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public ConstraintBuilder Property(string name)
{
ops.Push( Op.Prop );
opnds.Push( name );
return this;
}
#endregion
#region Helper Methods
/// <summary>
/// Resolve a constraint that has been recognized by applying
/// any pending operators and returning the resulting Constraint.
/// </summary>
/// <returns>A constraint that incorporates all pending operators</returns>
private Constraint Resolve(Constraint constraint)
{
while (ops.Count > 0)
switch ((Op)ops.Pop())
{
case Op.Not:
constraint = new NotConstraint(constraint);
break;
case Op.All:
constraint = new AllItemsConstraint(constraint);
break;
case Op.Some:
constraint = new SomeItemsConstraint(constraint);
break;
case Op.None:
constraint = new NoItemConstraint(constraint);
break;
case Op.Prop:
constraint = new PropertyConstraint( (string)opnds.Pop(), constraint );
break;
}
return constraint;
}
private Constraint Resolve()
{
return Resolve(null);
}
#endregion
}
}

View File

@@ -0,0 +1,77 @@
// ****************************************************************
// Copyright 2007, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
using System;
namespace NUnit.Framework.Constraints
{
// TODO Needs tests
/// <summary>
/// ContainsConstraint tests a whether a string contains a substring
/// or a collection contains an object. It postpones the decision of
/// which test to use until the type of the actual argument is known.
/// This allows testing whether a string is contained in a collection
/// or as a substring of another string using the same syntax.
/// </summary>
public class ContainsConstraint : Constraint
{
object expected;
Constraint realConstraint;
private Constraint RealConstraint
{
get
{
if ( realConstraint == null )
{
if ( actual is string )
this.realConstraint = new SubstringConstraint( (string)expected );
else
this.realConstraint = new CollectionContainsConstraint( expected );
}
return realConstraint;
}
set
{
realConstraint = value;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="T:ContainsConstraint"/> class.
/// </summary>
/// <param name="expected">The expected.</param>
public ContainsConstraint( object expected )
{
this.expected = expected;
}
/// <summary>
/// Test whether the constraint is satisfied by a given value
/// </summary>
/// <param name="actual">The value to be tested</param>
/// <returns>True for success, false for failure</returns>
public override bool Matches(object actual)
{
this.actual = actual;
if ( this.caseInsensitive )
this.RealConstraint = RealConstraint.IgnoreCase;
return this.RealConstraint.Matches( actual );
}
/// <summary>
/// Write the constraint description to a MessageWriter
/// </summary>
/// <param name="writer">The writer on which the description is displayed</param>
public override void WriteDescriptionTo(MessageWriter writer)
{
this.RealConstraint.WriteDescriptionTo(writer);
}
}
}

View File

@@ -0,0 +1,51 @@
// ****************************************************************
// Copyright 2007, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
using System;
using System.Collections;
namespace NUnit.Framework.Constraints
{
/// <summary>
/// EmptyConstraint tests a whether a string or collection is empty,
/// postponing the decision about which test is applied until the
/// type of the actual argument is known.
/// </summary>
public class EmptyConstraint : Constraint
{
private Constraint RealConstraint
{
get
{
if ( actual is string )
return new EmptyStringConstraint();
else
return new EmptyCollectionConstraint();
}
}
/// <summary>
/// Test whether the constraint is satisfied by a given value
/// </summary>
/// <param name="actual">The value to be tested</param>
/// <returns>True for success, false for failure</returns>
public override bool Matches(object actual)
{
this.actual = actual;
return this.RealConstraint.Matches( actual );
}
/// <summary>
/// Write the constraint description to a MessageWriter
/// </summary>
/// <param name="writer">The writer on which the description is displayed</param>
public override void WriteDescriptionTo(MessageWriter writer)
{
this.RealConstraint.WriteDescriptionTo( writer );
}
}
}

View File

@@ -0,0 +1,393 @@
// ****************************************************************
// Copyright 2007, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
using System;
using System.IO;
using System.Collections;
namespace NUnit.Framework.Constraints
{
/// <summary>
/// EqualConstraint is able to compare an actual value with the
/// expected value provided in its constructor.
/// </summary>
public class EqualConstraint : Constraint
{
private static IDictionary constraintHelpers = new Hashtable();
private readonly object expected;
private ArrayList failurePoints;
private static readonly string StringsDiffer_1 =
"String lengths are both {0}. Strings differ at index {1}.";
private static readonly string StringsDiffer_2 =
"Expected string length {0} but was {1}. Strings differ at index {2}.";
private static readonly string StreamsDiffer_1 =
"Stream lengths are both {0}. Streams differ at offset {1}.";
private static readonly string StreamsDiffer_2 =
"Expected Stream length {0} but was {1}.";// Streams differ at offset {2}.";
private static readonly string CollectionType_1 =
"Expected and actual are both {0}";
private static readonly string CollectionType_2 =
"Expected is {0}, actual is {1}";
private static readonly string ValuesDiffer_1 =
"Values differ at index {0}";
private static readonly string ValuesDiffer_2 =
"Values differ at expected index {0}, actual index {1}";
private static readonly int BUFFER_SIZE = 4096;
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="EqualConstraint"/> class.
/// </summary>
/// <param name="expected">The expected value.</param>
public EqualConstraint(object expected)
{
this.expected = expected;
}
#endregion
#region Public Methods
/// <summary>
/// Test whether the constraint is satisfied by a given value
/// </summary>
/// <param name="actual">The value to be tested</param>
/// <returns>True for success, false for failure</returns>
public override bool Matches(object actual)
{
this.actual = actual;
this.failurePoints = new ArrayList();
return ObjectsEqual( expected, actual );
}
/// <summary>
/// Write a failure message. Overridden to provide custom
/// failure messages for EqualConstraint.
/// </summary>
/// <param name="writer">The MessageWriter to write to</param>
public override void WriteMessageTo(MessageWriter writer)
{
DisplayDifferences(writer, expected, actual, 0);
}
/// <summary>
/// Write description of this constraint
/// </summary>
/// <param name="writer">The MessageWriter to write to</param>
public override void WriteDescriptionTo(MessageWriter writer)
{
writer.WriteExpectedValue( expected );
if ( tolerance != null )
{
writer.WriteConnector("+/-");
writer.WriteExpectedValue(tolerance);
}
if ( this.caseInsensitive )
writer.WriteModifier("ignoring case");
}
private void DisplayDifferences(MessageWriter writer, object expected, object actual, int depth)
{
if (expected is string && actual is string)
DisplayStringDifferences(writer, (string)expected, (string)actual);
else if (expected is ICollection && actual is ICollection)
DisplayCollectionDifferences(writer, (ICollection)expected, (ICollection)actual, depth);
else if (expected is Stream && actual is Stream)
DisplayStreamDifferences(writer, (Stream)expected, (Stream)actual, depth);
else if ( tolerance != null )
writer.DisplayDifferences( expected, actual, tolerance );
else
writer.DisplayDifferences(expected, actual);
}
#endregion
#region ObjectsEqual
private bool ObjectsEqual(object expected, object actual)
{
if (expected == null && actual == null)
return true;
if (expected == null || actual == null)
return false;
Type expectedType = expected.GetType();
Type actualType = actual.GetType();
if (expectedType.IsArray && actualType.IsArray && !compareAsCollection)
return ArraysEqual((Array)expected, (Array)actual);
if (expected is ICollection && actual is ICollection)
return CollectionsEqual((ICollection)expected, (ICollection)actual);
if (expected is Stream && actual is Stream)
return StreamsEqual((Stream)expected, (Stream)actual);
if (compareWith != null)
return compareWith.Compare( expected, actual ) == 0;
if (expected is DirectoryInfo && actual is DirectoryInfo)
return DirectoriesEqual((DirectoryInfo)expected, (DirectoryInfo)actual);
if (Numerics.IsNumericType(expected) && Numerics.IsNumericType(actual))
{
return Numerics.AreEqual(expected, actual, ref tolerance);
}
if (expected is string && actual is string)
{
return StringsEqual( (string) expected, (string)actual );
}
if (expected is DateTime && actual is DateTime && tolerance is TimeSpan)
{
return ((DateTime)expected - (DateTime)actual).Duration() <= (TimeSpan)tolerance;
}
return expected.Equals(actual);
}
/// <summary>
/// Helper method to compare two arrays
/// </summary>
protected virtual bool ArraysEqual(Array expected, Array actual)
{
int rank = expected.Rank;
if (rank != actual.Rank)
return false;
for (int r = 1; r < rank; r++)
if (expected.GetLength(r) != actual.GetLength(r))
return false;
return CollectionsEqual((ICollection)expected, (ICollection)actual);
}
private bool CollectionsEqual(ICollection expected, ICollection actual)
{
IEnumerator expectedEnum = expected.GetEnumerator();
IEnumerator actualEnum = actual.GetEnumerator();
int count;
for (count = 0; expectedEnum.MoveNext() && actualEnum.MoveNext(); count++)
{
if (!ObjectsEqual(expectedEnum.Current, actualEnum.Current))
break;
}
if (count == expected.Count && count == actual.Count)
return true;
failurePoints.Insert(0, count);
return false;
}
private bool StreamsEqual( Stream expected, Stream actual )
{
if (expected.Length != actual.Length) return false;
byte[] bufferExpected = new byte[BUFFER_SIZE];
byte[] bufferActual = new byte[BUFFER_SIZE];
BinaryReader binaryReaderExpected = new BinaryReader(expected);
BinaryReader binaryReaderActual = new BinaryReader(actual);
binaryReaderExpected.BaseStream.Seek(0, SeekOrigin.Begin);
binaryReaderActual.BaseStream.Seek(0, SeekOrigin.Begin);
for(long readByte = 0; readByte < expected.Length; readByte += BUFFER_SIZE )
{
binaryReaderExpected.Read(bufferExpected, 0, BUFFER_SIZE);
binaryReaderActual.Read(bufferActual, 0, BUFFER_SIZE);
for (int count=0; count < BUFFER_SIZE; ++count)
{
if (bufferExpected[count] != bufferActual[count])
{
failurePoints.Insert( 0, readByte + count );
//FailureMessage.WriteLine("\tIndex : {0}", readByte + count);
return false;
}
}
}
return true;
}
private bool StringsEqual( string expected, string actual )
{
string s1 = caseInsensitive ? expected.ToLower() : expected;
string s2 = caseInsensitive ? actual.ToLower() : actual;
return s1.Equals( s2 );
}
/// <summary>
/// Method to compare two DirectoryInfo objects
/// </summary>
/// <param name="expected">first directory to compare</param>
/// <param name="actual">second directory to compare</param>
/// <returns>true if equivalent, false if not</returns>
private bool DirectoriesEqual(DirectoryInfo expected, DirectoryInfo actual)
{
return expected.Attributes == actual.Attributes
&& expected.CreationTime == actual.CreationTime
&& expected.FullName == actual.FullName
&& expected.LastAccessTime == actual.LastAccessTime;
}
#endregion
#region DisplayStringDifferences
private void DisplayStringDifferences(MessageWriter writer, string expected, string actual)
{
int mismatch = MsgUtils.FindMismatchPosition(expected, actual, 0, this.caseInsensitive);
if (expected.Length == actual.Length)
writer.WriteMessageLine(StringsDiffer_1, expected.Length, mismatch);
else
writer.WriteMessageLine(StringsDiffer_2, expected.Length, actual.Length, mismatch);
writer.DisplayStringDifferences(expected, actual, mismatch, caseInsensitive, clipStrings);
}
#endregion
#region DisplayStreamDifferences
private void DisplayStreamDifferences(MessageWriter writer, Stream expected, Stream actual, int depth)
{
if ( expected.Length == actual.Length )
{
long offset = (long)failurePoints[depth];
writer.WriteMessageLine(StreamsDiffer_1, expected.Length, offset);
}
else
writer.WriteMessageLine(StreamsDiffer_2, expected.Length, actual.Length);
}
#endregion
#region DisplayCollectionDifferences
/// <summary>
/// Display the failure information for two collections that did not match.
/// </summary>
/// <param name="writer">The MessageWriter on which to display</param>
/// <param name="expected">The expected collection.</param>
/// <param name="actual">The actual collection</param>
/// <param name="depth">The depth of this failure in a set of nested collections</param>
private void DisplayCollectionDifferences(MessageWriter writer, ICollection expected, ICollection actual, int depth)
{
int failurePoint = failurePoints.Count > depth ? (int)failurePoints[depth] : -1;
DisplayCollectionTypesAndSizes(writer, expected, actual, depth);
if (failurePoint >= 0)
{
DisplayFailurePoint(writer, expected, actual, failurePoint, depth);
if (failurePoint < expected.Count && failurePoint < actual.Count)
DisplayDifferences(
writer,
GetValueFromCollection(expected, failurePoint),
GetValueFromCollection(actual, failurePoint),
++depth);
else if (expected.Count < actual.Count)
{
writer.Write( " Extra: " );
writer.WriteCollectionElements( actual, failurePoint, 3 );
}
else
{
writer.Write( " Missing: " );
writer.WriteCollectionElements( expected, failurePoint, 3 );
}
}
}
/// <summary>
/// Displays a single line showing the types and sizes of the expected
/// and actual collections or arrays. If both are identical, the value is
/// only shown once.
/// </summary>
/// <param name="writer">The MessageWriter on which to display</param>
/// <param name="expected">The expected collection or array</param>
/// <param name="actual">The actual collection or array</param>
/// <param name="indent">The indentation level for the message line</param>
private void DisplayCollectionTypesAndSizes(MessageWriter writer, ICollection expected, ICollection actual, int indent)
{
string sExpected = MsgUtils.GetTypeRepresentation(expected);
if (!(expected is Array))
sExpected += string.Format(" with {0} elements", expected.Count);
string sActual = MsgUtils.GetTypeRepresentation(actual);
if (!(actual is Array))
sActual += string.Format(" with {0} elements", actual.Count);
if (sExpected == sActual)
writer.WriteMessageLine(indent, CollectionType_1, sExpected);
else
writer.WriteMessageLine(indent, CollectionType_2, sExpected, sActual);
}
/// <summary>
/// Displays a single line showing the point in the expected and actual
/// arrays at which the comparison failed. If the arrays have different
/// structures or dimensions, both values are shown.
/// </summary>
/// <param name="writer">The MessageWriter on which to display</param>
/// <param name="expected">The expected array</param>
/// <param name="actual">The actual array</param>
/// <param name="failurePoint">Index of the failure point in the underlying collections</param>
/// <param name="indent">The indentation level for the message line</param>
private void DisplayFailurePoint(MessageWriter writer, ICollection expected, ICollection actual, int failurePoint, int indent)
{
Array expectedArray = expected as Array;
Array actualArray = actual as Array;
int expectedRank = expectedArray != null ? expectedArray.Rank : 1;
int actualRank = actualArray != null ? actualArray.Rank : 1;
bool useOneIndex = expectedRank == actualRank;
if (expectedArray != null && actualArray != null)
for (int r = 1; r < expectedRank && useOneIndex; r++)
if (expectedArray.GetLength(r) != actualArray.GetLength(r))
useOneIndex = false;
int[] expectedIndices = MsgUtils.GetArrayIndicesFromCollectionIndex(expected, failurePoint);
if (useOneIndex)
{
writer.WriteMessageLine(indent, ValuesDiffer_1, MsgUtils.GetArrayIndicesAsString(expectedIndices));
}
else
{
int[] actualIndices = MsgUtils.GetArrayIndicesFromCollectionIndex(actual, failurePoint);
writer.WriteMessageLine(indent, ValuesDiffer_2,
MsgUtils.GetArrayIndicesAsString(expectedIndices), MsgUtils.GetArrayIndicesAsString(actualIndices));
}
}
private static object GetValueFromCollection(ICollection collection, int index)
{
Array array = collection as Array;
if (array != null && array.Rank > 1)
return array.GetValue(MsgUtils.GetArrayIndicesFromCollectionIndex(array, index));
if (collection is IList)
return ((IList)collection)[index];
foreach (object obj in collection)
if (--index < 0)
return obj;
return null;
}
#endregion
}
}

View File

@@ -0,0 +1,216 @@
using System;
namespace NUnit.Framework.Constraints
{
/// <summary>
/// The Numerics class contains common operations on numeric values.
/// </summary>
public class Numerics
{
#region Numeric Type Recognition
/// <summary>
/// Checks the type of the object, returning true if
/// the object is a numeric type.
/// </summary>
/// <param name="obj">The object to check</param>
/// <returns>true if the object is a numeric type</returns>
public static bool IsNumericType(Object obj)
{
return IsFloatingPointNumeric( obj ) || IsFixedPointNumeric( obj );
}
/// <summary>
/// Checks the type of the object, returning true if
/// the object is a floating point numeric type.
/// </summary>
/// <param name="obj">The object to check</param>
/// <returns>true if the object is a floating point numeric type</returns>
public static bool IsFloatingPointNumeric(Object obj)
{
if (null != obj)
{
if (obj is double) return true;
if (obj is float) return true;
if (obj is System.Double) return true;
if (obj is System.Single) return true;
}
return false;
}
/// <summary>
/// Checks the type of the object, returning true if
/// the object is a fixed point numeric type.
/// </summary>
/// <param name="obj">The object to check</param>
/// <returns>true if the object is a fixed point numeric type</returns>
public static bool IsFixedPointNumeric(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 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.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;
}
#endregion
#region Numeric Equality
/// <summary>
/// Test two numeric values for equality, performing the usual numeric
/// conversions and using a provided or default tolerance. If the value
/// referred to by tolerance is null, this method may set it to a default.
/// </summary>
/// <param name="expected">The expected value</param>
/// <param name="actual">The actual value</param>
/// <param name="tolerance">A reference to the numeric tolerance in effect</param>
/// <returns>True if the values are equal</returns>
public static bool AreEqual( object expected, object actual, ref object tolerance )
{
if (IsFloatingPointNumeric(expected) || IsFloatingPointNumeric(actual))
return AreEqual(Convert.ToDouble(expected), Convert.ToDouble(actual), ref tolerance);
if ( expected is decimal || actual is decimal )
return AreEqual( Convert.ToDecimal(expected), Convert.ToDecimal(actual), Convert.ToDecimal(tolerance) );
if ( expected is ulong || actual is ulong )
return AreEqual( Convert.ToUInt64(expected), Convert.ToUInt64(actual), Convert.ToUInt64(tolerance) );
if ( expected is long || actual is long )
return AreEqual( Convert.ToInt64(expected), Convert.ToInt64(actual), Convert.ToInt64(tolerance) );
if ( expected is uint || actual is uint )
return AreEqual( Convert.ToUInt32(expected), Convert.ToUInt32(actual), Convert.ToUInt32(tolerance) );
return AreEqual( Convert.ToInt32(expected), Convert.ToInt32(actual), Convert.ToInt32(tolerance) );
}
private static bool AreEqual( double expected, double actual, ref object tolerance )
{
if (double.IsNaN(expected) && double.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 (double.IsInfinity(expected) || double.IsNaN(expected) || double.IsNaN(actual))
return expected.Equals(actual);
if (tolerance != null)
return Math.Abs(expected - actual) <= Convert.ToDouble(tolerance);
if (GlobalSettings.DefaultFloatingPointTolerance > 0.0d
&& !double.IsNaN(expected) && !double.IsInfinity(expected))
{
tolerance = GlobalSettings.DefaultFloatingPointTolerance;
return Math.Abs(expected - actual) <= GlobalSettings.DefaultFloatingPointTolerance;
}
return expected.Equals( actual );
}
private static bool AreEqual( decimal expected, decimal actual, decimal tolerance )
{
if ( tolerance > 0m )
return Math.Abs(expected - actual) <= tolerance;
return expected.Equals( actual );
}
private static bool AreEqual( ulong expected, ulong actual, ulong tolerance )
{
if ( tolerance > 0ul )
{
ulong diff = expected >= actual ? expected - actual : actual - expected;
return diff <= tolerance;
}
return expected.Equals( actual );
}
private static bool AreEqual( long expected, long actual, long tolerance )
{
if ( tolerance > 0L )
return Math.Abs(expected - actual) <= tolerance;
return expected.Equals( actual );
}
private static bool AreEqual( uint expected, uint actual, uint tolerance )
{
if ( tolerance > 0 )
{
uint diff = expected >= actual ? expected - actual : actual - expected;
return diff <= tolerance;
}
return expected.Equals( actual );
}
private static bool AreEqual( int expected, int actual, int tolerance )
{
if ( tolerance > 0 )
return Math.Abs(expected - actual) <= tolerance;
return expected.Equals( actual );
}
#endregion
#region Numeric Comparisons
/// <summary>
/// Compare two numeric values, performing the usual numeric conversions.
/// </summary>
/// <param name="expected">The expected value</param>
/// <param name="actual">The actual value</param>
/// <returns></returns>
public static int Compare( IComparable expected, object actual )
{
if ( expected == null )
throw new ArgumentException( "Cannot compare using a null reference", "expected" );
if ( actual == null )
throw new ArgumentException( "Cannot compare to null reference", "actual" );
if( IsNumericType( expected ) && IsNumericType( actual ) )
{
if ( IsFloatingPointNumeric(expected) || IsFloatingPointNumeric(actual) )
return Convert.ToDouble(expected).CompareTo(Convert.ToDouble(actual));
if ( expected is decimal || actual is decimal )
return Convert.ToDecimal(expected).CompareTo(Convert.ToDecimal(actual));
if ( expected is ulong || actual is ulong )
return Convert.ToUInt64(expected).CompareTo(Convert.ToUInt64(actual));
if ( expected is long || actual is long )
return Convert.ToInt64(expected).CompareTo(Convert.ToInt64(actual));
if ( expected is uint || actual is uint )
return Convert.ToUInt32(expected).CompareTo(Convert.ToUInt32(actual));
return Convert.ToInt32(expected).CompareTo(Convert.ToInt32(actual));
}
else
return expected.CompareTo(actual);
}
#endregion
private Numerics()
{
}
}
}

View File

@@ -0,0 +1,241 @@
// ****************************************************************
// Copyright 2007, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
using System;
using System.Collections;
namespace NUnit.Framework.Constraints
{
#region PrefixConstraint
/// <summary>
/// Abstract base class used for prefixes
/// </summary>
public abstract class PrefixConstraint : Constraint
{
/// <summary>
/// The base constraint
/// </summary>
protected Constraint baseConstraint;
/// <summary>
/// Construct given a base constraint
/// </summary>
/// <param name="baseConstraint"></param>
protected PrefixConstraint( Constraint baseConstraint )
{
this.baseConstraint = baseConstraint;
}
/// <summary>
/// Set all modifiers applied to the prefix into
/// the base constraint before matching
/// </summary>
protected void PassModifiersToBase()
{
if ( this.caseInsensitive )
baseConstraint = baseConstraint.IgnoreCase;
if (!this.clipStrings)
baseConstraint = baseConstraint.NoClip;
if ( this.tolerance != null )
baseConstraint = baseConstraint.Within( tolerance );
if ( this.compareAsCollection )
baseConstraint = baseConstraint.AsCollection;
if ( this.compareWith != null )
baseConstraint = baseConstraint.Comparer( compareWith );
}
}
#endregion
#region NotConstraint
/// <summary>
/// NotConstraint negates the effect of some other constraint
/// </summary>
public class NotConstraint : PrefixConstraint
{
/// <summary>
/// Initializes a new instance of the <see cref="T:NotConstraint"/> class.
/// </summary>
/// <param name="baseConstraint">The base constraint to be negated.</param>
public NotConstraint(Constraint baseConstraint)
: base( baseConstraint ) { }
/// <summary>
/// Test whether the constraint is satisfied by a given value
/// </summary>
/// <param name="actual">The value to be tested</param>
/// <returns>True for if the base constraint fails, false if it succeeds</returns>
public override bool Matches(object actual)
{
this.actual = actual;
this.PassModifiersToBase();
return !baseConstraint.Matches(actual);
}
/// <summary>
/// Write the constraint description to a MessageWriter
/// </summary>
/// <param name="writer">The writer on which the description is displayed</param>
public override void WriteDescriptionTo( MessageWriter writer )
{
writer.WritePredicate( "not" );
baseConstraint.WriteDescriptionTo( writer );
}
/// <summary>
/// Write the actual value for a failing constraint test to a MessageWriter.
/// </summary>
/// <param name="writer">The writer on which the actual value is displayed</param>
public override void WriteActualValueTo(MessageWriter writer)
{
baseConstraint.WriteActualValueTo (writer);
}
}
#endregion
#region AllItemsConstraint
/// <summary>
/// AllItemsConstraint applies another constraint to each
/// item in a collection, succeeding if they all succeed.
/// </summary>
public class AllItemsConstraint : PrefixConstraint
{
/// <summary>
/// Construct an AllItemsConstraint on top of an existing constraint
/// </summary>
/// <param name="itemConstraint"></param>
public AllItemsConstraint(Constraint itemConstraint)
: base( itemConstraint ) { }
/// <summary>
/// Apply the item constraint to each item in the collection,
/// failing if any item fails.
/// </summary>
/// <param name="actual"></param>
/// <returns></returns>
public override bool Matches(object actual)
{
this.actual = actual;
PassModifiersToBase();
if ( !(actual is ICollection) )
throw new ArgumentException( "The actual value must be a collection", "actual" );
foreach(object item in (ICollection)actual)
if (!baseConstraint.Matches(item))
return false;
return true;
}
/// <summary>
/// Write a description of this constraint to a MessageWriter
/// </summary>
/// <param name="writer"></param>
public override void WriteDescriptionTo(MessageWriter writer)
{
writer.WritePredicate("all items");
baseConstraint.WriteDescriptionTo(writer);
}
}
#endregion
#region SomeItemsConstraint
/// <summary>
/// SomeItemsConstraint applies another constraint to each
/// item in a collection, succeeding if any of them succeeds.
/// </summary>
public class SomeItemsConstraint : PrefixConstraint
{
/// <summary>
/// Construct a SomeItemsConstraint on top of an existing constraint
/// </summary>
/// <param name="itemConstraint"></param>
public SomeItemsConstraint(Constraint itemConstraint)
: base( itemConstraint ) { }
/// <summary>
/// Apply the item constraint to each item in the collection,
/// failing if any item fails.
/// </summary>
/// <param name="actual"></param>
/// <returns></returns>
public override bool Matches(object actual)
{
this.actual = actual;
PassModifiersToBase();
if ( !(actual is ICollection) )
throw new ArgumentException( "The actual value must be a collection", "actual" );
foreach(object item in (ICollection)actual)
if (baseConstraint.Matches(item))
return true;
return false;
}
/// <summary>
/// Write a description of this constraint to a MessageWriter
/// </summary>
/// <param name="writer"></param>
public override void WriteDescriptionTo(MessageWriter writer)
{
writer.WritePredicate("some item");
baseConstraint.WriteDescriptionTo(writer);
}
}
#endregion
#region NoItemConstraint
/// <summary>
/// SomeItemsConstraint applies another constraint to each
/// item in a collection, succeeding if any of them succeeds.
/// </summary>
public class NoItemConstraint : PrefixConstraint
{
/// <summary>
/// Construct a SomeItemsConstraint on top of an existing constraint
/// </summary>
/// <param name="itemConstraint"></param>
public NoItemConstraint(Constraint itemConstraint)
: base( itemConstraint ) { }
/// <summary>
/// Apply the item constraint to each item in the collection,
/// failing if any item fails.
/// </summary>
/// <param name="actual"></param>
/// <returns></returns>
public override bool Matches(object actual)
{
this.actual = actual;
PassModifiersToBase();
if ( !(actual is ICollection) )
throw new ArgumentException( "The actual value must be a collection", "actual" );
foreach(object item in (ICollection)actual)
if (baseConstraint.Matches(item))
return false;
return true;
}
/// <summary>
/// Write a description of this constraint to a MessageWriter
/// </summary>
/// <param name="writer"></param>
public override void WriteDescriptionTo(MessageWriter writer)
{
writer.WritePredicate("no item");
baseConstraint.WriteDescriptionTo(writer);
}
}
#endregion
}

View File

@@ -0,0 +1,83 @@
// ****************************************************************
// Copyright 2007, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
using System;
using System.Collections;
using System.Reflection;
namespace NUnit.Framework.Constraints
{
/// <summary>
/// Summary description for PropertyConstraint.
/// </summary>
public class PropertyConstraint : PrefixConstraint
{
private string name;
private object propValue;
private bool propertyExists;
/// <summary>
/// Initializes a new instance of the <see cref="T:PropertyConstraint"/> class.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="baseConstraint">The constraint to apply to the property.</param>
public PropertyConstraint( string name, Constraint baseConstraint )
: base( baseConstraint )
{
this.name = name;
}
/// <summary>
/// Test whether the constraint is satisfied by a given value
/// </summary>
/// <param name="actual">The value to be tested</param>
/// <returns>True for success, false for failure</returns>
public override bool Matches(object actual)
{
this.actual = actual;
// TODO: Should be argument exception?
if ( actual == null ) return false;
PropertyInfo property = actual.GetType().GetProperty( name,
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance );
this.propertyExists = property != null;
if ( !propertyExists ) return false;
if ( baseConstraint == null ) return true;
propValue = property.GetValue( actual, null );
return baseConstraint.Matches( propValue );
}
/// <summary>
/// Write the constraint description to a MessageWriter
/// </summary>
/// <param name="writer">The writer on which the description is displayed</param>
public override void WriteDescriptionTo(MessageWriter writer)
{
writer.WritePredicate( "Property \"" + name + "\"" );
if ( baseConstraint != null )
baseConstraint.WriteDescriptionTo( writer );
}
/// <summary>
/// Write the actual value for a failing constraint test to a
/// MessageWriter. The default implementation simply writes
/// the raw value of actual, leaving it to the writer to
/// perform any formatting.
/// </summary>
/// <param name="writer">The writer on which the actual value is displayed</param>
public override void WriteActualValueTo(MessageWriter writer)
{
if ( propertyExists )
writer.WriteActualValue( propValue );
else
writer.WriteActualValue( actual.GetType() );
}
}
}

Some files were not shown because too many files have changed in this diff Show More