static ExceptionAsserter <TException> ThrowsIfArgumentIs <TArg, TException>(this Asserter assert, Expression <Action <TArg> > testMethod, TArg value, string message, params object[] parameters) where TException : ArgumentException
        {
            Arg.NotNull(assert, nameof(assert));
            Arg.NotNull(assert, nameof(testMethod));
            Contract.Ensures(Contract.Result <ExceptionAsserter <TException> >() != null);

            assert.AssertParameterIsNotNull(testMethod, nameof(testMethod));

            var test          = testMethod.Compile();
            var assertion     = assert.Throws <TException>(() => test(value), message, parameters);
            var expectedParam = testMethod.Parameters.First().Name;
            var actualParam   = assertion.Exception.ParamName;

            assert.AreEqual(expectedParam, actualParam, WrongParameterName, expectedParam, actualParam);

            return(assertion);
        }
        /// <summary>
        /// Asserts that the specified object raises the <see cref="INotifyPropertyChanged.PropertyChanged"/> event for the specified property.
        /// </summary>
        /// <typeparam name="TObject">The <see cref="Type">type</see> of <see cref="INotifyPropertyChanged">object</see> to test.</typeparam>
        /// <typeparam name="TValue">The <see cref="Type">type</see> of value to assign to the property.</typeparam>
        /// <param name="assert">The extended <see cref="Asserter"/>.</param>
        /// <param name="subject">The <see cref="INotifyPropertyChanged">object</see> to test.</param>
        /// <param name="testProperty">The <see cref="Expression{T}"/> representing the test property.</param>
        /// <param name="value">The value to to assign to the tested property.</param>
        /// <param name="otherProperties">A sequence of other property <see cref="Expression{T}">expressions</see> representing the additional properties
        /// that are expected to change and raise the <see cref="INotifyPropertyChanged.PropertyChanged"/> event as a result of changing the
        /// <paramref name="testProperty">tested property</paramref>.</param>
        /// <include file="examples.xml" path="Types/Type[@name='INotifyPropertyChangedExtensions']/Member[@name='PropertyChanged`2']/example" />
        public static void PropertyChanged <TObject, TValue>(
            this Asserter assert,
            TObject subject,
            Expression <Func <TObject, TValue> > testProperty,
            TValue value,
            params Expression <Func <TObject, object> >[] otherProperties) where TObject : INotifyPropertyChanged
        {
            Arg.NotNull(assert, nameof(assert));

            assert.AssertParameterIsNotNull(subject, nameof(subject));
            assert.AssertParameterIsNotNull(testProperty, nameof(testProperty));
            assert.AssertParameterIsNotNull(otherProperties, nameof(otherProperties));

            var test       = subject.GetTestForProperty(assert, testProperty, out var propertyName);
            var unexpected = new HashSet <string>();
            var properties = otherProperties.ToDictionary(assert);

            properties.Add(propertyName, false);

            void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                if (properties.ContainsKey(e.PropertyName))
                {
                    properties[e.PropertyName] = true;
                }
                else
                {
                    unexpected.Add(e.PropertyName);
                }
            }

            subject.PropertyChanged += OnPropertyChanged;

            try
            {
                test(subject, value);
            }
            finally
            {
                subject.PropertyChanged -= OnPropertyChanged;
            }

            assert.AllPropertiesWereChanged(properties);
            assert.UnexpectedPropertiesWereNotChanged(unexpected);
        }
        /// <summary>
        /// Asserts the specified test method throws an exception of any type.
        /// </summary>
        /// <param name="assert">The extended <see cref="Asserter"/>.</param>
        /// <param name="testMethod">The <see cref="Action"/> representing the test method.</param>
        /// <param name="message">A message to display if the assertion fails. This message can be seen in the unit test results.</param>
        /// <param name="parameters">An array of parameters to use when formatting <paramref name="message" />.</param>
        /// <returns>The <see cref="ExceptionAsserter{T}">asserted exception</see>.</returns>
        /// <include file="examples.xml" path="Types/Type[@name='ExceptionExtensions']/Member[@name='Throws']/example[2]" />
        public static ExceptionAsserter <Exception> Throws(this Asserter assert, Action testMethod, string message, params object[] parameters)
        {
            Arg.NotNull(assert, nameof(assert));
            Contract.Ensures(Contract.Result <ExceptionAsserter <Exception> >() != null);

            assert.AssertParameterIsNotNull(testMethod, nameof(testMethod));

            try
            {
                testMethod();
            }
            catch (Exception ex)
            {
                return(new ExceptionAsserter <Exception>(ex));
            }

            assert.Fail(message, parameters);
            return(default(ExceptionAsserter <Exception>));
        }
        /// <summary>
        /// Asserts that the specified object does not raise the <see cref="INotifyPropertyChanged.PropertyChanged"/> event.
        /// </summary>
        /// <typeparam name="TObject">The <see cref="Type">type</see> of <see cref="INotifyPropertyChanged">object</see> to test.</typeparam>
        /// <typeparam name="TValue">The <see cref="Type">type</see> of value to assign to the property.</typeparam>
        /// <param name="assert">The extended <see cref="Asserter"/>.</param>
        /// <param name="subject">The <see cref="INotifyPropertyChanged">object</see> to test.</param>
        /// <param name="testProperty">The <see cref="Expression{T}">expression</see> representing the test property.</param>
        /// <param name="value">The value to to assign to the tested property.</param>
        /// <include file="examples.xml" path="Types/Type[@name='INotifyPropertyChangedExtensions']/Member[@name='PropertyNotChanged`2']/example" />
        public static void PropertyNotChanged <TObject, TValue>(this Asserter assert, TObject subject, Expression <Func <TObject, TValue> > testProperty, TValue value) where TObject : INotifyPropertyChanged
        {
            Arg.NotNull(assert, nameof(assert));

            assert.AssertParameterIsNotNull(subject, nameof(subject));
            assert.AssertParameterIsNotNull(testProperty, nameof(testProperty));

            var changed = false;
            var test    = subject.GetTestForProperty(assert, testProperty, out var propertyName);

            void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                changed      = true;
                propertyName = e.PropertyName;
            }

            subject.PropertyChanged += OnPropertyChanged;

            try
            {
                test(subject, value);
            }
            finally
            {
                subject.PropertyChanged -= OnPropertyChanged;
            }

            if (string.IsNullOrEmpty(propertyName))
            {
                assert.IsFalse(changed, AllPropertiesChangedRaised);
            }
            else
            {
                assert.IsFalse(changed, PropertyChangedRaised, propertyName);
            }
        }
        static Action <TObject, TValue> GetTestForProperty <TObject, TValue>(this TObject subject, Asserter assert, Expression <Func <TObject, TValue> > testProperty, out string propertyName) where TObject : INotifyPropertyChanged
        {
            Contract.Requires(assert != null);
            Contract.Requires(subject != null);
            Contract.Requires(testProperty != null);
            Contract.Ensures(!string.IsNullOrWhiteSpace(Contract.ValueAtReturn(out propertyName)));
            Contract.Ensures(Contract.Result <Action <TObject, TValue> >() != null);

            var property = testProperty.GetPropertyFromExpression(assert);

            propertyName = property.Name;

            // the compiler doesn't support expression assignments. to overcome this, we'll build the appropriate expression here by hand.
            var @this       = testProperty.Parameters[0];
            var value       = Parameter(typeof(TValue), "value");
            var setterBlock = Block(Assign(testProperty.Body, value));
            var setter      = Lambda <Action <TObject, TValue> >(setterBlock, @this, value);
            var test        = setter.Compile();

            return(test);
        }
Exemple #6
0
 /// <summary>
 /// Initializes a new instance of the <see cref="UnitTest"/> class.
 /// </summary>
 /// <param name="assert">The <see cref="Asserter">asserter</see> used for testing.</param>
 public UnitTest(Asserter assert)
 {
     Arg.NotNull(assert, nameof(assert));
     this.assert = assert;
 }
 /// <summary>
 /// Asserts the specified test method throws an exception of the specified type.
 /// </summary>
 /// <typeparam name="TException">The <see cref="Type"/> of <see cref="ArgumentException"/> that should be thrown.</typeparam>
 /// <param name="assert">The extended <see cref="Asserter"/>.</param>
 /// <param name="testMethod">The <see cref="Action"/> representing the test method.</param>
 /// <returns>The <see cref="ExceptionAsserter{T}">asserted exception</see>.</returns>
 /// <include file="examples.xml" path="Types/Type[@name='ExceptionExtensions']/Member[@name='Throws`1']/example[1]" />
 public static ExceptionAsserter <TException> Throws <TException>(this Asserter assert, Action testMethod) where TException : Exception =>
 assert.Throws <TException>(testMethod, ExceptionOfTNotThrown, typeof(TException));
 /// <summary>
 /// Asserts the specified test method throws an exception of any type.
 /// </summary>
 /// <param name="assert">The extended <see cref="Asserter"/>.</param>
 /// <param name="testMethod">The <see cref="Action"/> representing the test method.</param>
 /// <returns>The <see cref="ExceptionAsserter{T}">asserted exception</see>.</returns>
 /// <include file="examples.xml" path="Types/Type[@name='ExceptionExtensions']/Member[@name='Throws']/example[1]" />
 public static ExceptionAsserter <Exception> Throws(this Asserter assert, Action testMethod) => assert.Throws(testMethod, ExceptionNotThrown);
 /// <summary>
 /// Asserts the specified test method throws an <see cref="ArgumentNullException">argument null exception</see> if the supplied parameter is empty.
 /// </summary>
 /// <param name="assert">The extended <see cref="Asserter"/>.</param>
 /// <param name="testMethod">The <see cref="Expression{T}">expression</see> representing the <see cref="Action{T}">test method</see>.</param>
 /// <param name="message">A message to display if the assertion fails. This message can be seen in the unit test results.</param>
 /// <param name="parameters">An array of parameters to use when formatting <paramref name="message" />.</param>
 /// <returns>The <see cref="ExceptionAsserter{T}">asserted exception</see>.</returns>
 /// <include file="examples.xml" path="Types/Type[@name='ExceptionExtensions']/Member[@name='ThrowsIfArgumentIsEmpty']/example[2]" />
 public static ExceptionAsserter <ArgumentNullException> ThrowsIfArgumentIsEmpty(this Asserter assert, Expression <Action <string> > testMethod, string message, params object[] parameters) =>
 assert.ThrowsIfArgumentIs <string, ArgumentNullException>(testMethod, string.Empty, message, parameters);
 /// <summary>
 /// Asserts the specified test method throws an <see cref="ArgumentException">argument exception</see> if the supplied parameter is out of range.
 /// </summary>
 /// <typeparam name="TArg">The <see cref="Type">type</see> of parameter to test.</typeparam>
 /// <typeparam name="TException">The <see cref="Type">type</see> of <see cref="ArgumentException"/> to expect.</typeparam>
 /// <param name="assert">The extended <see cref="Asserter"/>.</param>
 /// <param name="testMethod">The <see cref="Expression{T}">expression</see> representing the <see cref="Action{T}">test method</see>.</param>
 /// <param name="value">The <typeparamref name="TArg">value</typeparamref> that should cause the exception to be thrown.</param>
 /// <returns>The <see cref="ExceptionAsserter{T}">asserted exception</see>.</returns>
 /// <include file="examples.xml" path="Types/Type[@name='ExceptionExtensions']/Member[@name='ThrowsIfArgumentIsOutOfRange`2']/example[1]" />
 public static ExceptionAsserter <TException> ThrowsIfArgumentIsOutOfRange <TArg, TException>(this Asserter assert, Expression <Action <TArg> > testMethod, TArg value) where TException : ArgumentException =>
 assert.ThrowsIfArgumentIs <TArg, TException>(testMethod, value, ExceptionOfTNotThrown, typeof(TException));
 /// <summary>
 /// Asserts the specified test method throws an <see cref="ArgumentException">argument exception</see> if the supplied parameter is null.
 /// </summary>
 /// <typeparam name="TArg">The <see cref="Type">type</see> of parameter to test.</typeparam>
 /// <typeparam name="TException">The <see cref="Type">type</see> of <see cref="ArgumentException"/> to expect.</typeparam>
 /// <param name="assert">The extended <see cref="Asserter"/>.</param>
 /// <param name="testMethod">The <see cref="Expression{T}">expression</see> representing the <see cref="Action{T}">test method</see>.</param>
 /// <param name="message">A message to display if the assertion fails. This message can be seen in the unit test results.</param>
 /// <param name="parameters">An array of parameters to use when formatting <paramref name="message" />.</param>
 /// <returns>The <see cref="ExceptionAsserter{T}">asserted exception</see>.</returns>
 /// <include file="examples.xml" path="Types/Type[@name='ExceptionExtensions']/Member[@name='ThrowsIfArgumentIsNull`2']/example[2]" />
 public static ExceptionAsserter <TException> ThrowsIfArgumentIsNull <TArg, TException>(this Asserter assert, Expression <Action <TArg> > testMethod, string message, params object[] parameters)
     where TArg : class
     where TException : ArgumentException =>
 assert.ThrowsIfArgumentIs <TArg, TException>(testMethod, null, message, parameters);
 /// <summary>
 /// Asserts the specified test method throws an <see cref="ArgumentException">argument exception</see> if the supplied parameter is null.
 /// </summary>
 /// <typeparam name="TArg">The <see cref="Type">type</see> of parameter to test.</typeparam>
 /// <typeparam name="TException">The <see cref="Type">type</see> of <see cref="ArgumentException"/> to expect.</typeparam>
 /// <param name="assert">The extended <see cref="Asserter"/>.</param>
 /// <param name="testMethod">The <see cref="Expression{T}">expression</see> representing the <see cref="Action{T}">test method</see>.</param>
 /// <returns>The <see cref="ExceptionAsserter{T}">asserted exception</see>.</returns>
 /// <include file="examples.xml" path="Types/Type[@name='ExceptionExtensions']/Member[@name='ThrowsIfArgumentIsNull`2']/example[1]" />
 public static ExceptionAsserter <TException> ThrowsIfArgumentIsNull <TArg, TException>(this Asserter assert, Expression <Action <TArg> > testMethod)
     where TArg : class
     where TException : ArgumentException =>
 assert.ThrowsIfArgumentIs <TArg, TException>(testMethod, null, ExceptionOfTNotThrown, typeof(TException));
 /// <summary>
 /// Asserts the specified test method throws an <see cref="ArgumentException">argument exception</see> if the supplied parameter is whitespace.
 /// </summary>
 /// <typeparam name="TException">The <see cref="Type">type</see> of <see cref="ArgumentException"/> to expect.</typeparam>
 /// <param name="assert">The extended <see cref="Asserter"/>.</param>
 /// <param name="testMethod">The <see cref="Expression{T}">expression</see> representing the <see cref="Action{T}">test method</see>.</param>
 /// <param name="message">A message to display if the assertion fails. This message can be seen in the unit test results.</param>
 /// <param name="parameters">An array of parameters to use when formatting <paramref name="message" />.</param>
 /// <returns>The <see cref="ExceptionAsserter{T}">asserted exception</see>.</returns>
 /// <include file="examples.xml" path="Types/Type[@name='ExceptionExtensions']/Member[@name='ThrowsIfArgumentIsWhiteSpace`1']/example[2]" />
 public static ExceptionAsserter <TException> ThrowsIfArgumentIsWhiteSpace <TException>(this Asserter assert, Expression <Action <string> > testMethod, string message, params object[] parameters) where TException : ArgumentException =>
 assert.ThrowsIfArgumentIs <string, TException>(testMethod, " ", message, parameters);
 /// <summary>
 /// Asserts the specified test method throws an <see cref="ArgumentException">argument exception</see> if the supplied parameter is whitespace.
 /// </summary>
 /// <typeparam name="TException">The <see cref="Type">type</see> of <see cref="ArgumentException"/> to expect.</typeparam>
 /// <param name="assert">The extended <see cref="Asserter"/>.</param>
 /// <param name="testMethod">The <see cref="Expression{T}">expression</see> representing the <see cref="Action{T}">test method</see>.</param>
 /// <returns>The <see cref="ExceptionAsserter{T}">asserted exception</see>.</returns>
 /// <include file="examples.xml" path="Types/Type[@name='ExceptionExtensions']/Member[@name='ThrowsIfArgumentIsWhiteSpace`1']/example[1]" />
 public static ExceptionAsserter <TException> ThrowsIfArgumentIsWhiteSpace <TException>(this Asserter assert, Expression <Action <string> > testMethod) where TException : ArgumentException =>
 assert.ThrowsIfArgumentIs <string, TException>(testMethod, " ", ExceptionOfTNotThrown, typeof(TException));
 /// <summary>
 /// Asserts the specified test method throws an <see cref="ArgumentNullException">argument null exception</see> if the supplied parameter is whitespace.
 /// </summary>
 /// <param name="assert">The extended <see cref="Asserter"/>.</param>
 /// <param name="testMethod">The <see cref="Expression{T}">expression</see> representing the <see cref="Action{T}">test method</see>.</param>
 /// <returns>The <see cref="ExceptionAsserter{T}">asserted exception</see>.</returns>
 /// <include file="examples.xml" path="Types/Type[@name='ExceptionExtensions']/Member[@name='ThrowsIfArgumentIsWhiteSpace']/example[1]" />
 public static ExceptionAsserter <ArgumentNullException> ThrowsIfArgumentIsWhiteSpace(this Asserter assert, Expression <Action <string> > testMethod) =>
 assert.ThrowsIfArgumentIs <string, ArgumentNullException>(testMethod, " ", ExceptionOfTNotThrown, typeof(ArgumentNullException));
 /// <summary>
 /// Asserts the specified test method throws an <see cref="ArgumentException">argument exception</see> if the supplied parameter is null.
 /// </summary>
 /// <typeparam name="TArg">The <see cref="Type">type</see> of parameter to test.</typeparam>
 /// <typeparam name="TException">The <see cref="Type">type</see> of <see cref="ArgumentException"/> to expect.</typeparam>
 /// <param name="assert">The extended <see cref="Asserter"/>.</param>
 /// <param name="testMethod">The <see cref="Expression{T}">expression</see> representing the <see cref="Action{T}">test method</see>.</param>
 /// <param name="value">The <typeparamref name="TArg">value</typeparamref> that should cause the exception to be thrown.</param>
 /// <param name="message">A message to display if the assertion fails. This message can be seen in the unit test results.</param>
 /// <param name="parameters">An array of parameters to use when formatting <paramref name="message" />.</param>
 /// <returns>The <see cref="ExceptionAsserter{T}">asserted exception</see>.</returns>
 /// <include file="examples.xml" path="Types/Type[@name='ExceptionExtensions']/Member[@name='ThrowsIfArgumentIsOutOfRange`2']/example[2]" />
 public static ExceptionAsserter <TException> ThrowsIfArgumentIsOutOfRange <TArg, TException>(this Asserter assert, Expression <Action <TArg> > testMethod, TArg value, string message, params object[] parameters) where TException : ArgumentException =>
 assert.ThrowsIfArgumentIs <TArg, TException>(testMethod, value, message, parameters);
 /// <summary>
 /// Asserts the specified test method throws an <see cref="ArgumentException">argument exception</see>.
 /// </summary>
 /// <typeparam name="TException">The <see cref="Type">type</see> of <see cref="ArgumentException"/> to expect.</typeparam>
 /// <param name="assert">The extended <see cref="Asserter"/>.</param>
 /// <param name="testMethod">The <see cref="Action"/> representing the test method.</param>
 /// <param name="paramName">The name of the parameter expected to throw an exception.</param>
 /// <returns>The <see cref="ExceptionAsserter{T}">asserted exception</see>.</returns>
 /// <include file="examples.xml" path="Types/Type[@name='ExceptionExtensions']/Member[@name='ThrowsForArgument`1']/example[1]" />
 public static ExceptionAsserter <TException> ThrowsForArgument <TException>(this Asserter assert, Action testMethod, string paramName) where TException : ArgumentException =>
 assert.ThrowsForArgument <TException>(testMethod, paramName, ExceptionOfTNotThrown, typeof(TException));