public bool Compare(ComparisonContext comparisonContext, ValueComparison valueComparison)
        {
            var actual = (IDictionary)valueComparison.ActualValue;
            var expected = (IDictionary)valueComparison.ExpectedValue;

            if (!this.AreKeysEqual(expected, actual, comparisonContext, valueComparison))
            {
                return false;
            }

            foreach (var key in expected.Keys)
            {
                var actualValue = actual[key];
                var expectedValue = expected[key];

                // TODO: Why is this immediately picked up by the recursive comparator
                // TODO: Create a valid use case test for the recursive comparator
                // TODO: Both values null in the dictionary
                // TODO: Comple objects in the dictionary

                var propertyPath = new PropertyPathItem(key.ToString(), valueComparison.PropertyPathItem);
                comparisonContext.CompareItem(expectedValue, actualValue, propertyPath);
            }

            return true;
        }
        public bool Compare(ComparisonContext context, ValueComparison comparison)
        {
            if (comparison.PropertyType == null)
            {
                throw new ArgumentException("Could not determine type to reflect.", "comparison");
            }

            var areEqual = true;
            var properties = comparison.PropertyType
               .GetProperties(BindingFlags.Instance | BindingFlags.Public);

            foreach (var property in properties)
            {
                var propertyPathItem = new PropertyPathItem(property, comparison.PropertyPathItem);

                var expectedPropValue = property.GetValue(comparison.ExpectedValue, null);
                var actualPropValue = property.GetValue(comparison.ActualValue, null);

                if (!context.CompareItem(expectedPropValue, actualPropValue, propertyPathItem))
                {
                    areEqual = false;
                }
            }

            return areEqual;
        }
        private bool CompareArrayItems(ComparisonContext context, ValueComparison comparison, int currentDimension, int[] currentIndices)
        {
            var actual = (Array)comparison.ActualValue;
            var expected = (Array)comparison.ExpectedValue;

            var length = expected.GetLength(currentDimension);

            var areEqual = true;
            for (var i = 0; i < length; i++)
            {
                currentIndices[currentDimension] = i;
                if (currentDimension == currentIndices.Length - 1)
                {
                    // Last dimension, get value and compare
                    var actualValue = actual.GetValue(currentIndices);
                    var expectedValue = expected.GetValue(currentIndices);

                    var indicesString = this.GetArrayIndicesString(currentIndices);
                    var propertyPath = new PropertyPathItem(indicesString, comparison.PropertyPathItem);
                    if (!context.CompareItem(expectedValue, actualValue, propertyPath))
                    {
                        areEqual = false;
                    }
                }
                else
                {
                    if (!this.CompareArrayItems(context, comparison, currentDimension + 1, currentIndices))
                    {
                        areEqual = false;
                    }
                }
            }

            return areEqual;
        }
        public void ThenShouldReturnPropertyNameIfDoesNotHaveParent()
        {
            var stringPropInfo = typeof(SimpleDomain).GetProperties()
                .First(x => x.Name == "StringProp");

            var stringPropPath = new PropertyPathItem(stringPropInfo, PropertyPathItem.Root);

            stringPropPath.GetPathString().Should().Be("StringProp");
        }
        private ValueComparison CreateKeyNamedComparison(ValueComparison comparison, string key, string messageFormat)
        {
            var itemPropPath = new PropertyPathItem(key, comparison.PropertyPathItem);

            var result = new ValueComparison(
                itemPropPath,
                comparison.ExpectedValue,
                comparison.ActualValue);

            result.Message = string.Format(messageFormat, key);
            return result;
        }
        public void ThenShouldReturnDotSeparatedStringIfHasParent()
        {
            var stringPropInfo = typeof(SimpleDomain).GetProperties()
                .First(x => x.Name == "StringProp");

            var intPropInfo = typeof(SimpleDomain).GetProperties()
                .First(x => x.Name == "IntProp");

            var item1 = new PropertyPathItem(stringPropInfo, PropertyPathItem.Root);
            var item2 = new PropertyPathItem(intPropInfo, item1);
            var item3 = new PropertyPathItem(stringPropInfo, item2);

            item2.GetPathString().Should().Be("StringProp.IntProp");
            item3.GetPathString().Should().Be("StringProp.IntProp.StringProp");
        }
        public bool Compare(ComparisonContext context, ValueComparison comparison)
        {
            var areEqual = true;
            var options = context.Rules.GetOptions<CollectionValueComparatorOptions>(comparison);

            var actual = (IEnumerable)comparison.ActualValue;
            var expected = (IEnumerable)comparison.ExpectedValue;

            if (options.OrderFunction != null)
            {
                actual = options.OrderFunction.Invoke(actual);
                expected = options.OrderFunction.Invoke(expected);
            }

            var actualEnumerator = actual.GetEnumerator();
            var expectedEnumerator = expected.GetEnumerator();

            var actualHasNext = actualEnumerator.MoveNext();
            var expectedHasNext = expectedEnumerator.MoveNext();

            var itemCounter = 0;
            while (actualHasNext && expectedHasNext)
            {
                var propertyPath = new PropertyPathItem(itemCounter.ToString(), comparison.PropertyPathItem);
                if (!context.CompareItem(expectedEnumerator.Current, actualEnumerator.Current, propertyPath))
                {
                    areEqual = false;
                }

                expectedHasNext = expectedEnumerator.MoveNext();
                actualHasNext = actualEnumerator.MoveNext();
                itemCounter++;
            }

            if (actualHasNext != expectedHasNext)
            {
                comparison.Message = string.Format(
                    "The collections have a different number of items, expected: {0}, actual: {1}.",
                    expected.Cast<object>().Count(),
                    actual.Cast<object>().Count());

                context.AddDifference(comparison);
                areEqual = false;
            }

            return areEqual;
        }
        public bool IsPropertyPathMatch(PropertyPathItem propertyPath, IEnumerable<string> propertyNames)
        {
            foreach (var propertyName in propertyNames)
            {
                if (propertyPath.IsRoot || propertyPath.PropertyInfo == null || propertyPath.PropertyInfo.Name != propertyName)
                {
                    return false;
                }

                propertyPath = propertyPath.ParentProperty;
            }

            if (!propertyPath.IsRoot)
            {
                return false;
            }

            return true;
        }