private static AggregatedDifference ValueDifferenceEnumerable(IEnumerable firstItem, string firstName, IEnumerable otherItem, ICollection <object> firstSeen) { if (firstItem.GetType().IsArray&& otherItem.GetType().IsArray) { return(ValueDifferenceArray(firstItem as Array, firstName, otherItem as Array, firstSeen)); } if (firstItem is IDictionary firstDico && otherItem is IDictionary secondDico) { return(ValueDifferenceDictionary(firstDico, firstName, secondDico, firstSeen)); } var valueDifferences = new AggregatedDifference(); var scanner = otherItem.GetEnumerator(); var index = 0; foreach (var item in firstItem) { var firstItemName = $"{firstName}[{index}]"; if (!scanner.MoveNext()) { valueDifferences.Add(DifferenceDetails.WasNotExpected(firstItemName, item, index)); break; } valueDifferences.Merge(ValueDifference(item, firstItemName, scanner.Current, index, firstSeen)); index++; } if (scanner.MoveNext()) { valueDifferences.Add(DifferenceDetails.WasNotFound($"{firstName}[{index}]", scanner.Current, index)); } return(valueDifferences); }
private static AggregatedDifference ValueDifferenceDictionary(IReadOnlyDictionary <object, object> sutDictionary, string sutName, IReadOnlyDictionary <object, object> expectedDictionary, ICollection <object> firstItemsSeen) { var valueDifferences = new AggregatedDifference { IsEquivalent = true }; using var actualKeyIterator = sutDictionary.Keys.GetEnumerator(); using var expectedKeyIterator = expectedDictionary.Keys.GetEnumerator(); var stillExpectedKeys = true; var stillActualKeys = true; var index = 0; for (;;) { stillExpectedKeys = stillExpectedKeys && expectedKeyIterator.MoveNext(); stillActualKeys = stillActualKeys && actualKeyIterator.MoveNext(); if (!stillExpectedKeys) { // no more expected keys if (!stillActualKeys) { // we're done break; } // the sut has extra key(s) valueDifferences.Add(DifferenceDetails.WasNotExpected( $"{sutName}[{actualKeyIterator.Current.ToStringProperlyFormatted()}]", sutDictionary[actualKeyIterator.Current], index)); valueDifferences.IsEquivalent = false; } else if (!stillActualKeys) { // key not found valueDifferences.IsEquivalent = false; valueDifferences.Add(DifferenceDetails.WasNotFound( $"{sutName}[{expectedKeyIterator.Current.ToStringProperlyFormatted()}]", // ReSharper disable once AssignNullToNotNullAttribute new DictionaryEntry(expectedKeyIterator.Current, expectedDictionary[expectedKeyIterator.Current]), 0)); } else { var actualKey = actualKeyIterator.Current; var actualKeyName = $"{sutName} key[{index}]"; var itemDiffs = ValueDifference(actualKey, actualKeyName, expectedKeyIterator.Current, index, firstItemsSeen); if (!expectedDictionary.TryGetValue(actualKey !, out _)) { valueDifferences.Add(DifferenceDetails.WasNotExpected( $"{sutName}'s key {actualKey.ToStringProperlyFormatted()}", sutDictionary[actualKey], index)); valueDifferences.IsEquivalent = false; }
private static AggregatedDifference ScanEnumeration(IEnumerable firstItem, IEnumerable otherItem, Func <int, string> namingCallback, ICollection <object> firstSeen) { var index = 0; var mayBeEquivalent = true; var expected = new List <KeyValuePair <object, int> >(); var unexpected = new List <KeyValuePair <object, int> >(); var aggregatedDifferences = new Dictionary <int, AggregatedDifference>(); var valueDifferences = new AggregatedDifference(); var scanner = otherItem.GetEnumerator(); foreach (var item in firstItem) { var firstItemName = namingCallback(index); if (!scanner.MoveNext()) { valueDifferences.Add(DifferenceDetails.WasNotExpected(firstItemName, item, index)); unexpected.Add(new KeyValuePair <object, int>(item, index)); break; } var aggregatedDifference = ValueDifference(item, firstItemName, scanner.Current, index, firstSeen); if (aggregatedDifference.IsDifferent) { aggregatedDifferences.Add(index, aggregatedDifference); if (!aggregatedDifference.IsEquivalent) { // try to see it was at a different position var indexOrigin = expected.FindIndex(pair => FluentEquivalent(pair.Key, item)); if (indexOrigin >= 0) { // we found the value at another index valueDifferences.Add(DifferenceDetails.WasFoundElseWhere(firstItemName, item, index, expected[indexOrigin].Value)); expected.RemoveAt(indexOrigin); aggregatedDifferences.Remove(indexOrigin); aggregatedDifferences.Remove(index); } else { unexpected.Add(new KeyValuePair <object, int>(item, index)); } // what about the expected value var indexOther = unexpected.FindIndex(pair => FluentEquivalent(pair.Key, scanner.Current)); if (indexOther >= 0) { valueDifferences.Add(DifferenceDetails.WasFoundElseWhere(firstItemName, unexpected[indexOther].Key, unexpected[indexOther].Value, index)); aggregatedDifferences.Remove(unexpected[indexOther].Value); unexpected.RemoveAt(indexOther); } else { expected.Add(new KeyValuePair <object, int>(scanner.Current, index)); } } } index++; } if (scanner.MoveNext()) { valueDifferences.Add(DifferenceDetails.WasNotFound(namingCallback(index), scanner.Current, index)); mayBeEquivalent = false; } foreach (var differencesValue in aggregatedDifferences.Values) { valueDifferences.Merge(differencesValue); } for (var i = 0; i < Math.Min(unexpected.Count, expected.Count); i++) { //aggregatedDifferences.Remove(unexpected[i].Value); valueDifferences.Add(DifferenceDetails.WasFoundInsteadOf(namingCallback(unexpected[i].Value), unexpected[i].Key, expected[i].Key)); } if (mayBeEquivalent && valueDifferences.IsDifferent) { valueDifferences.IsEquivalent = expected.Count == 0 && unexpected.Count == 0; } return(valueDifferences); }
private static AggregatedDifference ValueDifferenceDictionary(IDictionary sutDico, string sutName, IDictionary expectedDico, ICollection <object> firstItemsSeen) { var valueDifferences = new AggregatedDifference { IsEquivalent = true }; var actualKeyIterator = sutDico.Keys.GetEnumerator(); var expectedKeyIterator = expectedDico.Keys.GetEnumerator(); var stillExpectedKeys = true; var stillActualKeys = true; var index = 0; for (;;) { stillExpectedKeys = stillExpectedKeys && expectedKeyIterator.MoveNext(); stillActualKeys = stillActualKeys && actualKeyIterator.MoveNext(); if (!stillExpectedKeys) { // no more expected keys if (!stillActualKeys) { // we're done break; } // the sut has extra key(s) valueDifferences.Add(DifferenceDetails.WasNotExpected($"{sutName}[{actualKeyIterator.Current.ToStringProperlyFormatted()}]", sutDico[actualKeyIterator.Current], index)); valueDifferences.IsEquivalent = false; } else if (!stillActualKeys) { // key not found valueDifferences.IsEquivalent = false; valueDifferences.Add(DifferenceDetails.WasNotFound($"{sutName}[{expectedKeyIterator.Current.ToStringProperlyFormatted()}]", expectedDico[expectedKeyIterator.Current], 0)); } else { var actualKey = actualKeyIterator.Current; var itemDiffs = ValueDifference(actualKey, $"{sutName} key[{index}]", expectedKeyIterator.Current, index, firstItemsSeen); if (!itemDiffs.IsDifferent) { // same key, check the values var keyAsString = actualKey.ToStringProperlyFormatted(); itemDiffs = ValueDifference(sutDico[actualKey], $"{sutName}[{keyAsString}]", expectedDico[actualKey], index, firstItemsSeen); valueDifferences.IsEquivalent &= !itemDiffs.IsDifferent; } else if (valueDifferences.IsEquivalent) { // check if the dictionaries are equivalent anyway valueDifferences.IsEquivalent = expectedDico.Contains(actualKey) && FluentEquals(sutDico[actualKey], expectedDico[actualKey]); } valueDifferences.Merge(itemDiffs); } index++; } return(valueDifferences); }
private static AggregatedDifference ValueDifferenceDictionary(IReadOnlyDictionary <object, object> sutDico, string sutName, IReadOnlyDictionary <object, object> expectedDico, ICollection <object> firstItemsSeen) { // TODO: improve error messages var valueDifferences = new AggregatedDifference { IsEquivalent = true }; var actualKeyIterator = sutDico.Keys.GetEnumerator(); var expectedKeyIterator = expectedDico.Keys.GetEnumerator(); var stillExpectedKeys = true; var stillActualKeys = true; var index = 0; for (; ;) { stillExpectedKeys = stillExpectedKeys && expectedKeyIterator.MoveNext(); stillActualKeys = stillActualKeys && actualKeyIterator.MoveNext(); if (!stillExpectedKeys) { // no more expected keys if (!stillActualKeys) { // we're done break; } // the sut has extra key(s) valueDifferences.Add(DifferenceDetails.WasNotExpected($"{sutName}[{actualKeyIterator.Current.ToStringProperlyFormatted()}]", sutDico[actualKeyIterator.Current], index)); valueDifferences.IsEquivalent = false; } else if (!stillActualKeys) { // key not found valueDifferences.IsEquivalent = false; valueDifferences.Add(DifferenceDetails.WasNotFound($"{sutName}[{expectedKeyIterator.Current.ToStringProperlyFormatted()}]", expectedDico[expectedKeyIterator.Current], 0)); } else { var actualKey = actualKeyIterator.Current; var actualKeyName = $"{sutName} key[{index}]"; var itemDiffs = ValueDifference(actualKey, actualKeyName, expectedKeyIterator.Current, index, firstItemsSeen); if (!itemDiffs.IsDifferent) { // same key, check the values itemDiffs = ValueDifference(sutDico[actualKey], $"{sutName}[{actualKey.ToStringProperlyFormatted()}]", expectedDico[actualKey], index, firstItemsSeen); valueDifferences.IsEquivalent &= (!itemDiffs.IsDifferent || itemDiffs.IsEquivalent); } else //if (valueDifferences.IsEquivalent) { // check if the dictionaries are equivalent anyway var expectedIndex = expectedDico.ContainsKey(actualKey) ? expectedDico.Keys.ToList().FindIndex(x => x == actualKey) : -1; if (expectedIndex >= 0) { itemDiffs = ValueDifference(sutDico[actualKey], $"{sutName}[{actualKey.ToStringProperlyFormatted()}]", expectedDico[actualKey], index, firstItemsSeen); valueDifferences.IsEquivalent &= itemDiffs.IsEquivalent || !itemDiffs.IsDifferent; valueDifferences.Add( DifferenceDetails.WasFoundElseWhere($"{sutName} entry {actualKey.ToStringProperlyFormatted()}", expectedDico[actualKey], index, expectedIndex)); } else { valueDifferences.Add(DifferenceDetails.WasNotExpected($"{sutName}'s key {actualKey.ToStringProperlyFormatted()}", sutDico[actualKey], index)); valueDifferences.IsEquivalent = false; } } valueDifferences.Merge(itemDiffs); } index++; } return(valueDifferences); }