コード例 #1
0
        public static void ValidateStringKeyAndValue(
            string name,
            IDictionary <string, object> dictionary,
            string key,
            object value,
            Action <string, string, string> failedValidationAction)
        {
            var entryExists = dictionary.ContainsKey(key);
            var actualValue = entryExists ? dictionary[key] : null;

            DeepEqualityResult result = null;

            if (!entryExists || Reflection.AreNotDeeplyEqual(value, actualValue, out result))
            {
                failedValidationAction(
                    name,
                    $"to have entry with '{key}' key and the provided value",
                    $"{(entryExists ? $"the value was different. {result}" : "such was not found")}");
            }
        }
コード例 #2
0
        /// <summary>
        /// Test if the all values of objects properties are equals recursively
        /// </summary>
        /// <param name="expected">The expected object</param>
        /// <param name="actual">Actual object</param>
        /// <param name="processedElements">
        ///     Table that binds a managed object, which is represented by a key, to its attached property, which is represented by a value.
        ///     Automatically removes the key/value entry as soon as no other references to a key exist outside the table.
        /// </param>
        /// <param name="result">For which property equality was broken</param>
        /// <returns></returns>
        private static bool AreDeeplyEqual(
            object expected,
            object actual,
            ConditionalWeakTable <object, object> processedElements,
            DeepEqualityResult result)
        {
            result.ApplyValues(expected, actual);

            if (expected == null && actual == null)
            {
                return(result.Success);
            }

            if (expected == null || actual == null)
            {
                return(result.Failure);
            }

            var expectedType = expected.GetType();

            if (expectedType != typeof(string) && !expectedType.GetTypeInfo().IsValueType)
            {
                if (processedElements.TryGetValue(expected, out _))
                {
                    return(result.Success);
                }

                processedElements.Add(expected, expected);
            }

            var actualType = actual.GetType();
            var objectType = typeof(object);

            if ((expectedType == objectType && actualType != objectType) ||
                (actualType == objectType && expectedType != objectType))
            {
                return(result.Failure);
            }

            var stringType = typeof(string);

            if (expected is IEnumerable && expectedType != stringType)
            {
                return(CollectionsAreDeeplyEqual(expected, actual, processedElements, result));
            }

            var expectedTypeIsAnonymous = IsAnonymousType(expectedType);

            if (expectedTypeIsAnonymous)
            {
                var actualIsAnonymous = IsAnonymousType(actualType);
                if (!actualIsAnonymous)
                {
                    return(result.Failure);
                }
            }

            if (!expectedTypeIsAnonymous &&
                expectedType != actualType &&
                !expectedType.IsAssignableFrom(actualType) &&
                !actualType.IsAssignableFrom(expectedType))
            {
                return(result.Failure);
            }

            if (expectedType.GetTypeInfo().IsPrimitive || expectedType.GetTypeInfo().IsEnum)
            {
                return(expected.ToString() == actual.ToString()
                    ? result.Success
                    : result.Failure);
            }

            var equalsOperator = expectedType.GetMethods().FirstOrDefault(m => m.Name == "op_Equality");

            if (equalsOperator != null)
            {
                var equalsOperatorResult = (bool)equalsOperator.Invoke(null, new[] { expected, actual });

                if (!equalsOperatorResult && expectedType != stringType)
                {
                    result.PushPath("== (Equality Operator)");

                    if (!expectedType.IsDateTimeRelated())
                    {
                        result.ClearValues();
                    }
                }

                return(equalsOperatorResult
                    ? result.Success
                    : result.Failure);
            }

            if (expectedType != objectType && !expectedTypeIsAnonymous)
            {
                var equalsMethod = expectedType.GetMethods()
                                   .FirstOrDefault(m => m.Name == "Equals" && m.DeclaringType == expectedType);

                if (equalsMethod != null)
                {
                    var equalsMethodResult = (bool)equalsMethod.Invoke(expected, new[] { actual });

                    if (!equalsMethodResult)
                    {
                        result
                        .PushPath("Equals()")
                        .ClearValues();
                    }

                    return(equalsMethodResult
                        ? result.Success
                        : result.Failure);
                }
            }

            if (ComparablesAreDeeplyEqual(expected, actual, result))
            {
                return(result.Success);
            }

            if (!ObjectPropertiesAreDeeplyEqual(expected, actual, processedElements, result))
            {
                return(false);
            }

            return(true);
        }
コード例 #3
0
        /// <summary>
        /// Checks whether two objects are deeply equal by reflecting all their public properties recursively. Resolves successfully value and reference types, overridden Equals method, custom == operator, IComparable, nested objects and collection properties.
        /// </summary>
        /// <param name="expected">Expected object.</param>
        /// <param name="actual">Actual object.</param>
        /// <param name="result">Result object containing differences between the two objects.</param>
        /// <returns>True or false.</returns>
        public static bool AreDeeplyEqual(object expected, object actual, out DeepEqualityResult result)
        {
            result = new DeepEqualityResult(expected?.GetType(), actual?.GetType());

            return(AreDeeplyEqual(expected, actual, new ConditionalWeakTable <object, object>(), result));
        }
コード例 #4
0
        private static bool ComparablesAreDeeplyEqual(object expected, object actual, DeepEqualityResult result)
        {
            if (expected is IComparable expectedAsComparable)
            {
                if (expectedAsComparable.CompareTo(actual) == 0)
                {
                    return(result.Success);
                }
            }

            if (ObjectImplementsIComparable(expected) && ObjectImplementsIComparable(actual))
            {
                var methodName = "CompareTo";

                var method = expected.GetType().GetMethod(methodName);

                if (method != null)
                {
                    var compareToResult = (int)method.Invoke(expected, new[] { actual }) == 0;

                    if (!compareToResult)
                    {
                        result.PushPath($"{methodName}()");
                    }

                    return(compareToResult);
                }
            }

            return(result.Failure);
        }
コード例 #5
0
 private static bool AreNotDeeplyEqual(
     object expected,
     object actual,
     ConditionalWeakTable <object, object> processedElements,
     DeepEqualityResult result)
 => !AreDeeplyEqual(expected, actual, processedElements, result);
コード例 #6
0
 /// <summary>
 /// Checks whether two objects are not deeply equal by reflecting all their public properties recursively. Resolves successfully value and reference types, overridden Equals method, custom == operator, IComparable, nested objects and collection properties.
 /// </summary>
 /// <param name="expected">Expected object.</param>
 /// <param name="actual">Actual object.</param>
 /// <param name="result">Result object containing differences between the two objects.</param>
 /// <returns>True or false.</returns>
 /// <remarks>This method is used for the route testing. Since the ASP.NET Core MVC model binder creates new instances, circular references are not checked.</remarks>
 public static bool AreNotDeeplyEqual(object expected, object actual, out DeepEqualityResult result)
 => !AreDeeplyEqual(expected, actual, out result);
 public static ResponseModelAssertionException From(string messagePrefix, DeepEqualityResult result)
 => new ResponseModelAssertionException($"{messagePrefix} the response model to be the given model, but in fact it was a different one. {result}.");