/Lib/EmitMapper.Sources/Silverlight/NUnit.SL/framework.sl/Constraints/CollectionConstraints.cs
https://github.com/antonsamarsky/emitmapper-tools · C# · 608 lines · 324 code · 69 blank · 215 comment · 36 complexity · c8c06b1b299331e9a45e43c87ccdb5de MD5 · raw file
- // ****************************************************************
- // 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
- // ****************************************************************
-
- using System;
- using System.Collections;
- using System.Reflection;
- using System.Text;
- #if NET_2_0
- using System.Collections.Generic;
- #endif
-
- 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
- {
- /// <summary>
- /// Construct an empty CollectionConstraint
- /// </summary>
- public CollectionConstraint() { }
-
- /// <summary>
- /// Construct a CollectionConstraint
- /// </summary>
- /// <param name="arg"></param>
- public CollectionConstraint(object arg) : base(arg) { }
-
- /// <summary>
- /// Determines whether the specified enumerable is empty.
- /// </summary>
- /// <param name="enumerable">The enumerable.</param>
- /// <returns>
- /// <c>true</c> if the specified enumerable is empty; otherwise, <c>false</c>.
- /// </returns>
- protected static bool IsEmpty( IEnumerable enumerable )
- {
- ICollection collection = enumerable as ICollection;
- if ( collection != null )
- return collection.Count == 0;
- else
- return !enumerable.GetEnumerator().MoveNext();
- }
-
- /// <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 CollectionItemsEqualConstraint
- /// <summary>
- /// CollectionItemsEqualConstraint is the abstract base class for all
- /// collection constraints that apply some notion of item equality
- /// as a part of their operation.
- /// </summary>
- public abstract class CollectionItemsEqualConstraint : CollectionConstraint
- {
- private NUnitEqualityComparer comparer = NUnitEqualityComparer.Default;
-
- /// <summary>
- /// Construct an empty CollectionConstraint
- /// </summary>
- public CollectionItemsEqualConstraint() { }
-
- /// <summary>
- /// Construct a CollectionConstraint
- /// </summary>
- /// <param name="arg"></param>
- public CollectionItemsEqualConstraint(object arg) : base(arg) { }
-
- #region Modifiers
- /// <summary>
- /// Flag the constraint to ignore case and return self.
- /// </summary>
- public CollectionItemsEqualConstraint IgnoreCase
- {
- get
- {
- comparer.IgnoreCase = true;
- 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 CollectionItemsEqualConstraint Using(IComparer comparer)
- {
- this.comparer.ExternalComparer = EqualityAdapter.For(comparer);
- return this;
- }
-
- #if NET_2_0
- /// <summary>
- /// Flag the constraint to use the supplied IComparer object.
- /// </summary>
- /// <param name="comparer">The IComparer object to use.</param>
- /// <returns>Self.</returns>
- public CollectionItemsEqualConstraint Using<T>(IComparer<T> comparer)
- {
- this.comparer.ExternalComparer = EqualityAdapter.For(comparer);
- return this;
- }
-
- /// <summary>
- /// Flag the constraint to use the supplied Comparison object.
- /// </summary>
- /// <param name="comparer">The IComparer object to use.</param>
- /// <returns>Self.</returns>
- public CollectionItemsEqualConstraint Using<T>(Comparison<T> comparer)
- {
- this.comparer.ExternalComparer = EqualityAdapter.For(comparer);
- return this;
- }
-
- /// <summary>
- /// Flag the constraint to use the supplied IEqualityComparer object.
- /// </summary>
- /// <param name="comparer">The IComparer object to use.</param>
- /// <returns>Self.</returns>
- public CollectionItemsEqualConstraint Using(IEqualityComparer comparer)
- {
- this.comparer.ExternalComparer = EqualityAdapter.For(comparer);
- return this;
- }
-
- /// <summary>
- /// Flag the constraint to use the supplied IEqualityComparer object.
- /// </summary>
- /// <param name="comparer">The IComparer object to use.</param>
- /// <returns>Self.</returns>
- public CollectionItemsEqualConstraint Using<T>(IEqualityComparer<T> comparer)
- {
- this.comparer.ExternalComparer = EqualityAdapter.For(comparer);
- return this;
- }
- #endif
- #endregion
-
- /// <summary>
- /// Compares two collection members for equality
- /// </summary>
- protected bool ItemsEqual(object x, object y)
- {
- return comparer.ObjectsEqual(x, y);
- }
-
- /// <summary>
- /// Return a new CollectionTally for use in making tests
- /// </summary>
- /// <param name="c">The collection to be included in the tally</param>
- protected CollectionTally Tally(IEnumerable c)
- {
- return new CollectionTally(comparer, c);
- }
-
- /// <summary>
- /// CollectionTally counts (tallies) the number of
- /// occurences of each object in one or more enumerations.
- /// </summary>
- protected internal class CollectionTally
- {
- // Internal list used to track occurences
- private List<object> list = new List<object>();
-
- private NUnitEqualityComparer comparer;
-
- /// <summary>
- /// Construct a CollectionTally object from a comparer and a collection
- /// </summary>
- public CollectionTally(NUnitEqualityComparer comparer, IEnumerable c)
- {
- this.comparer = comparer;
-
- foreach (object o in c)
- list.Add(o);
- }
-
- /// <summary>
- /// The number of objects remaining in the tally
- /// </summary>
- public int Count
- {
- get { return list.Count; }
- }
-
- private bool ItemsEqual(object expected, object actual)
- {
- return comparer.ObjectsEqual(expected, actual);
- }
-
- /// <summary>
- /// Try to remove an object from the tally
- /// </summary>
- /// <param name="o">The object to remove</param>
- /// <returns>True if successful, false if the object was not found</returns>
- public bool TryRemove(object o)
- {
- for (int index = 0; index < list.Count; index++)
- if (ItemsEqual(list[index], o))
- {
- list.RemoveAt(index);
- return true;
- }
-
- return false;
- }
-
- /// <summary>
- /// Try to remove a set of objects from the tally
- /// </summary>
- /// <param name="c">The objects to remove</param>
- /// <returns>True if successful, false if any object was not found</returns>
- public bool TryRemove(IEnumerable c)
- {
- foreach (object o in c)
- if (!TryRemove(o))
- return false;
-
- return true;
- }
- }
- }
- #endregion
-
- #region EmptyCollectionConstraint
- /// <summary>
- /// EmptyCollectionConstraint tests whether a collection 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 : CollectionItemsEqualConstraint
- {
- /// <summary>
- /// Check that all items are unique.
- /// </summary>
- /// <param name="actual"></param>
- /// <returns></returns>
- protected override bool doMatch(IEnumerable actual)
- {
- List<object> list = new List<object>();
-
- foreach (object o1 in actual)
- {
- foreach( object o2 in list )
- if ( ItemsEqual(o1, o2) )
- return false;
- list.Add(o1);
- }
-
- return true;
- }
-
- /// <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 : CollectionItemsEqualConstraint
- {
- private object expected;
-
- /// <summary>
- /// Construct a CollectionContainsConstraint
- /// </summary>
- /// <param name="expected"></param>
- public CollectionContainsConstraint(object expected)
- : base(expected)
- {
- this.expected = expected;
- this.DisplayName = "contains";
- }
-
- /// <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 (ItemsEqual(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 : CollectionItemsEqualConstraint
- {
- private IEnumerable expected;
-
- /// <summary>
- /// Construct a CollectionEquivalentConstraint
- /// </summary>
- /// <param name="expected"></param>
- public CollectionEquivalentConstraint(IEnumerable expected) : base(expected)
- {
- this.expected = expected;
- this.DisplayName = "equivalent";
- }
-
- /// <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 = Tally(expected);
- return tally.TryRemove(actual) && tally.Count == 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 : CollectionItemsEqualConstraint
- {
- 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) : base(expected)
- {
- this.expected = expected;
- this.DisplayName = "subsetof";
- }
-
- /// <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 Tally(expected).TryRemove( 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
-
- #region CollectionOrderedConstraint
-
- /// <summary>
- /// CollectionOrderedConstraint is used to test whether a collection is ordered.
- /// </summary>
- public class CollectionOrderedConstraint : CollectionConstraint
- {
- private ComparisonAdapter comparer = ComparisonAdapter.Default;
- private string comparerName;
- private string propertyName;
- private bool descending;
-
- /// <summary>
- /// Construct a CollectionOrderedConstraint
- /// </summary>
- public CollectionOrderedConstraint()
- {
- this.DisplayName = "ordered";
- }
-
- ///<summary>
- /// If used performs a reverse comparison
- ///</summary>
- public CollectionOrderedConstraint Descending
- {
- get
- {
- descending = true;
- return this;
- }
- }
-
- /// <summary>
- /// Modifies the constraint to use an IComparer and returns self.
- /// </summary>
- public CollectionOrderedConstraint Using(IComparer comparer)
- {
- this.comparer = ComparisonAdapter.For( comparer );
- this.comparerName = comparer.GetType().FullName;
- return this;
- }
-
- #if NET_2_0
- /// <summary>
- /// Modifies the constraint to use an IComparer<T> and returns self.
- /// </summary>
- public CollectionOrderedConstraint Using<T>(IComparer<T> comparer)
- {
- this.comparer = ComparisonAdapter.For(comparer);
- this.comparerName = comparer.GetType().FullName;
- return this;
- }
-
- /// <summary>
- /// Modifies the constraint to use a Comparison<T> and returns self.
- /// </summary>
- public CollectionOrderedConstraint Using<T>(Comparison<T> comparer)
- {
- this.comparer = ComparisonAdapter.For(comparer);
- this.comparerName = comparer.GetType().FullName;
- return this;
- }
- #endif
-
- /// <summary>
- /// Modifies the constraint to test ordering by the value of
- /// a specified property and returns self.
- /// </summary>
- public CollectionOrderedConstraint By(string propertyName)
- {
- this.propertyName = propertyName;
- return this;
- }
-
- /// <summary>
- /// Test whether the collection is ordered
- /// </summary>
- /// <param name="actual"></param>
- /// <returns></returns>
- protected override bool doMatch(IEnumerable actual)
- {
- object previous = null;
- int index = 0;
- foreach(object obj in actual)
- {
- object objToCompare = obj;
- if (obj == null)
- throw new ArgumentNullException("actual", "Null value at index " + index.ToString());
-
- if (this.propertyName != null)
- {
- PropertyInfo prop = obj.GetType().GetProperty(propertyName);
- objToCompare = prop.GetValue(obj, null);
- if (objToCompare == null)
- throw new ArgumentNullException("actual", "Null property value at index " + index.ToString());
- }
-
- if (previous != null)
- {
- //int comparisonResult = comparer.Compare(al[i], al[i + 1]);
- int comparisonResult = comparer.Compare(previous, objToCompare);
-
- if (descending && comparisonResult < 0)
- return false;
- if (!descending && comparisonResult > 0)
- return false;
- }
-
- previous = objToCompare;
- index++;
- }
-
- return true;
- }
-
- /// <summary>
- /// Write a description of the constraint to a MessageWriter
- /// </summary>
- /// <param name="writer"></param>
- public override void WriteDescriptionTo(MessageWriter writer)
- {
- if (propertyName == null)
- writer.Write("collection ordered");
- else
- {
- writer.WritePredicate("collection ordered by");
- writer.WriteExpectedValue(propertyName);
- }
-
- if (descending)
- writer.WriteModifier("descending");
- }
-
- /// <summary>
- /// Returns the string representation of the constraint.
- /// </summary>
- /// <returns></returns>
- public override string ToString()
- {
- StringBuilder sb = new StringBuilder("<ordered");
-
- if (propertyName != null)
- sb.Append("by " + propertyName);
- if (descending)
- sb.Append(" descending");
- if (comparerName != null)
- sb.Append(" " + comparerName);
-
- sb.Append(">");
-
- return sb.ToString();
- }
- }
- #endregion
- }