// **************************************************************** // 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 { /// /// 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 & and | operator overloads to combine constraints. /// public class ConstraintBuilder { private enum Op { Not, All, Some, None, Prop, } Stack ops = new Stack(); Stack opnds = new Stack(); /// /// Implicitly convert ConstraintBuilder to an actual Constraint /// at the point where the syntax demands it. /// /// /// public static implicit operator Constraint( ConstraintBuilder builder ) { return builder.Resolve(); } #region Constraints Without Arguments /// /// Resolves the chain of constraints using /// EqualConstraint(null) as base. /// public Constraint Null { get { return Resolve(new EqualConstraint(null)); } } /// /// Resolves the chain of constraints using /// EqualConstraint(true) as base. /// public Constraint True { get { return Resolve(new EqualConstraint(true)); } } /// /// Resolves the chain of constraints using /// EqualConstraint(false) as base. /// public Constraint False { get { return Resolve(new EqualConstraint(false)); } } /// /// Resolves the chain of constraints using /// Is.NaN as base. /// public Constraint NaN { get { return Resolve(new EqualConstraint(double.NaN)); } } /// /// Resolves the chain of constraints using /// Is.Empty as base. /// public Constraint Empty { get { return Resolve(new EmptyConstraint()); } } /// /// Resolves the chain of constraints using /// Is.Unique as base. /// public Constraint Unique { get { return Resolve(new UniqueItemsConstraint()); } } #endregion #region Constraints with an expected value #region Equality and Identity /// /// Resolves the chain of constraints using an /// EqualConstraint as base. /// public Constraint EqualTo(object expected) { return Resolve(new EqualConstraint(expected)); } /// /// Resolves the chain of constraints using a /// SameAsConstraint as base. /// public Constraint SameAs(object expected) { return Resolve(new SameAsConstraint(expected)); } #endregion #region Comparison Constraints /// /// Resolves the chain of constraints using a /// LessThanConstraint as base. /// public Constraint LessThan(IComparable expected) { return Resolve(new LessThanConstraint(expected)); } /// /// Resolves the chain of constraints using a /// GreaterThanConstraint as base. /// public Constraint GreaterThan(IComparable expected) { return Resolve(new GreaterThanConstraint(expected)); } /// /// Resolves the chain of constraints using a /// LessThanOrEqualConstraint as base. /// public Constraint LessThanOrEqualTo(IComparable expected) { return Resolve(new LessThanOrEqualConstraint(expected)); } /// /// Resolves the chain of constraints using a /// LessThanOrEqualConstraint as base. /// public Constraint AtMost(IComparable expected) { return Resolve(new LessThanOrEqualConstraint(expected)); } /// /// Resolves the chain of constraints using a /// GreaterThanOrEqualConstraint as base. /// public Constraint GreaterThanOrEqualTo(IComparable expected) { return Resolve(new GreaterThanOrEqualConstraint(expected)); } /// /// Resolves the chain of constraints using a /// GreaterThanOrEqualConstraint as base. /// public Constraint AtLeast(IComparable expected) { return Resolve(new GreaterThanOrEqualConstraint(expected)); } #endregion #region Type Constraints /// /// Resolves the chain of constraints using an /// ExactTypeConstraint as base. /// public Constraint TypeOf(Type expectedType) { return Resolve(new ExactTypeConstraint(expectedType)); } /// /// Resolves the chain of constraints using an /// InstanceOfTypeConstraint as base. /// public Constraint InstanceOfType(Type expectedType) { return Resolve(new InstanceOfTypeConstraint(expectedType)); } /// /// Resolves the chain of constraints using an /// AssignableFromConstraint as base. /// public Constraint AssignableFrom(Type expectedType) { return Resolve(new AssignableFromConstraint(expectedType)); } #endregion #region Containing Constraint /// /// 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. /// public Constraint Contains(object expected) { return Resolve( new ContainsConstraint(expected) ); } /// /// Resolves the chain of constraints using a /// CollectionContainsConstraint as base. /// /// The expected object public Constraint Member( object expected ) { return Resolve( new CollectionContainsConstraint( expected ) ); } #endregion #region String Constraints /// /// Resolves the chain of constraints using a /// StartsWithConstraint as base. /// public Constraint StartsWith(string substring) { return Resolve( new StartsWithConstraint(substring) ); } /// /// Resolves the chain of constraints using a /// StringEndingConstraint as base. /// public Constraint EndsWith(string substring) { return Resolve( new EndsWithConstraint(substring) ); } /// /// Resolves the chain of constraints using a /// StringMatchingConstraint as base. /// public Constraint Matches(string pattern) { return Resolve(new RegexConstraint(pattern)); } #endregion #region Collection Constraints /// /// Resolves the chain of constraints using a /// CollectionEquivalentConstraint as base. /// public Constraint EquivalentTo(ICollection expected) { return Resolve( new CollectionEquivalentConstraint(expected) ); } /// /// Resolves the chain of constraints using a /// CollectionContainingConstraint as base. /// public Constraint CollectionContaining(object expected) { return Resolve( new CollectionContainsConstraint(expected) ); } /// /// Resolves the chain of constraints using a /// CollectionSubsetConstraint as base. /// public Constraint SubsetOf(ICollection expected) { return Resolve(new CollectionSubsetConstraint(expected)); } #endregion #region Property Constraints /// /// Resolves the chain of constraints using a /// PropertyConstraint as base /// public Constraint Property( string name, object expected ) { return Resolve( new PropertyConstraint( name, new EqualConstraint( expected ) ) ); } /// /// Resolves the chain of constraints using a /// PropertyCOnstraint on Length as base /// /// /// public Constraint Length(int length) { return Property("Length", length); } /// /// Resolves the chain of constraints using a /// PropertyCOnstraint on Length as base /// /// /// public Constraint Count(int count) { return Property("Count", count); } #endregion #endregion #region Prefix Operators /// /// Modifies the ConstraintBuilder by pushing a Not operator on the stack. /// public ConstraintBuilder Not { get { ops.Push(Op.Not); return this; } } /// /// Modifies the ConstraintBuilder by pushing a Not operator on the stack. /// public ConstraintBuilder No { get { ops.Push(Op.Not); return this; } } /// /// Modifies the ConstraintBuilder by pushing an All operator on the stack. /// public ConstraintBuilder All { get { ops.Push(Op.All); return this; } } /// /// Modifies the ConstraintBuilder by pushing a Some operator on the stack. /// public ConstraintBuilder Some { get { ops.Push(Op.Some); return this; } } /// /// Modifies the constraint builder by pushing All and Not operators on the stack /// public ConstraintBuilder None { get { ops.Push(Op.None); return this; } } /// /// Modifies the ConstraintBuilder by pushing a Prop operator on the /// ops stack and the name of the property on the opnds stack. /// /// /// public ConstraintBuilder Property(string name) { ops.Push( Op.Prop ); opnds.Push( name ); return this; } #endregion #region Helper Methods /// /// Resolve a constraint that has been recognized by applying /// any pending operators and returning the resulting Constraint. /// /// A constraint that incorporates all pending operators 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 } }