public XmlReaderValidator(XmlReader subjectReader, XmlReader expectationReader, string because, object[] reasonArgs) { assertion = Execute.Assertion.BecauseOf(because, reasonArgs); subjectIterator = new XmlIterator(subjectReader); expectationIterator = new XmlIterator(expectationReader); }
private Failure Validate() { if (subjectReader is null && expectationReader is null) { return(null); } Failure failure = ValidateAgainstNulls(); if (failure is not null) { return(failure); } subjectIterator = new XmlIterator(subjectReader); expectationIterator = new XmlIterator(expectationReader); while (!subjectIterator.IsEndOfDocument && !expectationIterator.IsEndOfDocument) { if (subjectIterator.NodeType != expectationIterator.NodeType) { var expectation = expectationIterator.NodeType == XmlNodeType.Text ? $"content \"{expectationIterator.Value}\"" : $"{expectationIterator.NodeType} \"{expectationIterator.LocalName}\""; var subject = subjectIterator.NodeType == XmlNodeType.Text ? $"content \"{subjectIterator.Value}\"" : $"{subjectIterator.NodeType} \"{subjectIterator.LocalName}\""; return(new Failure( $"Expected {expectation} in {{context:subject}} at {{0}}{{reason}}, but found {subject}.", currentNode.GetXPath())); } failure = null; #pragma warning disable IDE0010 // The default case handles the many missing cases switch (expectationIterator.NodeType) #pragma warning restore IDE0010 { case XmlNodeType.Element: failure = ValidateStartElement(); if (failure is not null) { return(failure); } // starting new element, add local name to location stack // to build XPath info currentNode = currentNode.Push(expectationIterator.LocalName); failure = ValidateAttributes(); if (expectationIterator.IsEmptyElement) { // The element is already complete. (We will NOT get an EndElement node.) // Update node information. currentNode = currentNode.Parent; } // check whether empty element and self-closing element needs to be synchronized if (subjectIterator.IsEmptyElement && !expectationIterator.IsEmptyElement) { expectationIterator.MoveToEndElement(); } else if (expectationIterator.IsEmptyElement && !subjectIterator.IsEmptyElement) { subjectIterator.MoveToEndElement(); } break; case XmlNodeType.EndElement: // No need to verify end element, if it doesn't match // the start element it isn't valid XML, so the parser // would handle that. currentNode.Pop(); currentNode = currentNode.Parent; break; case XmlNodeType.Text: failure = ValidateText(); break; default: throw new NotSupportedException( $"{expectationIterator.NodeType} found at {currentNode.GetXPath()} is not supported for equivalency comparison."); } if (failure is not null) { return(failure); } subjectIterator.Read(); expectationIterator.Read(); } if (!expectationIterator.IsEndOfDocument) { return(new Failure( "Expected {0} in {context:subject}{reason}, but found end of document.", expectationIterator.LocalName)); } if (!subjectIterator.IsEndOfDocument) { return(new Failure( "Expected end of document in {context:subject}{reason}, but found {0}.", subjectIterator.LocalName)); } return(null); }