public static ComparisonResult IsEqualTo(this IElementNavigator expected, IElementNavigator actual) { if (!namesEqual(expected.Name, actual.Name)) { return(ComparisonResult.Fail(actual.Location, $"name: was '{actual.Name}', expected '{expected.Name}'")); } if (!valuesEqual(expected.Value, actual.Value)) { return(ComparisonResult.Fail(actual.Location, $"value: was '{actual.Value}', expected '{expected.Value}'")); } // Allow the expected navigator to have more type info than the actual navigator if (expected.Type != actual.Type && actual.Type != null) { return(ComparisonResult.Fail(actual.Location, $"type: was '{actual.Type}', expected '{expected.Type}'")); } if (expected.Location != actual.Location) { ComparisonResult.Fail(actual.Location, $"location: was '{actual.Location}', expected '{expected.Location}'"); } // Ignore ordering (only relevant to xml) var childrenExp = expected.Children().OrderBy(e => e.Name); var childrenActual = actual.Children().OrderBy(e => e.Name).GetEnumerator(); // Don't compare lengths, as this would require complete enumeration of both collections // just enumerate through the lists, comparing each item as they go. // first fail (or list end) will drop out. foreach (var exp in childrenExp) { if (!childrenActual.MoveNext()) { ComparisonResult.Fail(actual.Location, $"number of children was different"); } var result = exp.IsEqualTo(childrenActual.Current); if (!result.Success) { return(result); } } if (childrenActual.MoveNext()) { ComparisonResult.Fail(actual.Location, $"number of children was different"); } return(ComparisonResult.OK); bool valuesEqual(object e, object a) { string eVal = e != null?PrimitiveTypeConverter.ConvertTo <string>(e) : null; string aVal = a != null?PrimitiveTypeConverter.ConvertTo <string>(a) : null; return(eVal == aVal); } bool namesEqual(string e, string a) => e == a || (a != null && e != null && (a.StartsWith(e))); }
public static ComparisonResult IsEqualTo(this IElementNavigator expected, IElementNavigator actual) { if (!valuesEqual(expected.Value, actual.Value)) { return(ComparisonResult.Fail(actual.Location, $"value: was '{actual.Value}', expected '{expected.Value}'")); } if (!namesEqual(expected.Name, actual.Name)) { return(ComparisonResult.Fail(actual.Location, $"name: was '{actual.Name}', expected '{expected.Name}'")); } // Allow the expected navigator to have more type info than the actual navigator if (expected.Type != actual.Type && actual.Type != null) { return(ComparisonResult.Fail(actual.Location, $"type: was '{actual.Type}', expected '{expected.Type}'")); } if (expected.Location != actual.Location) { ComparisonResult.Fail(actual.Location, $"location: was '{actual.Location}', expected '{expected.Location}'"); } // Ignore ordering (only relevant to xml) var childrenExp = expected.Children().OrderBy(e => e.Name).ToArray(); var childrenActual = actual.Children().OrderBy(e => e.Name).ToArray(); if (childrenExp.Length != childrenActual.Length) { ComparisonResult.Fail(actual.Location, $"number of children was {childrenActual.Length}, expected {childrenExp.Length}"); } for (var index = 0; index < childrenExp.Length; index++) { var result = childrenExp[index].IsEqualTo(childrenActual[index]); if (!result.Success) { return(result); } } return(ComparisonResult.OK); bool valuesEqual(object e, object a) { string eVal = e != null?PrimitiveTypeConverter.ConvertTo <string>(e) : null; string aVal = a != null?PrimitiveTypeConverter.ConvertTo <string>(a) : null; return(eVal == aVal); } bool namesEqual(string e, string a) => e == a || (a != null && e != null && (a.StartsWith(e))); }