public void DiffUnambiguosAddRemoveReplace() { // NOTE (steveb): test unamibiguous addition, deletion, and replacement XDoc a = XDocFactory.From("<p>the quick brown fox jumped over the lazy dog</p>", MimeType.XML); XDoc b = XDocFactory.From("<p>the slow black fox jumped far over the dog</p>", MimeType.XML); var diff = XDocDiff.Diff(a, b, 10000); Match(diff[0], ArrayDiffKind.Same, XmlNodeType.Element, "p"); Match(diff[1], ArrayDiffKind.Same, XmlNodeType.EndElement, string.Empty); Match(diff[2], ArrayDiffKind.Same, XmlNodeType.Text, "the"); Match(diff[3], ArrayDiffKind.Same, XmlNodeType.Text, " "); Match(diff[4], ArrayDiffKind.Removed, XmlNodeType.Text, "quick"); Match(diff[5], ArrayDiffKind.Added, XmlNodeType.Text, "slow"); Match(diff[6], ArrayDiffKind.Same, XmlNodeType.Text, " "); Match(diff[7], ArrayDiffKind.Removed, XmlNodeType.Text, "brown"); Match(diff[8], ArrayDiffKind.Added, XmlNodeType.Text, "black"); Match(diff[9], ArrayDiffKind.Same, XmlNodeType.Text, " "); Match(diff[10], ArrayDiffKind.Same, XmlNodeType.Text, "fox"); Match(diff[11], ArrayDiffKind.Same, XmlNodeType.Text, " "); Match(diff[12], ArrayDiffKind.Same, XmlNodeType.Text, "jumped"); Match(diff[13], ArrayDiffKind.Same, XmlNodeType.Text, " "); Match(diff[14], ArrayDiffKind.Added, XmlNodeType.Text, "far"); Match(diff[15], ArrayDiffKind.Added, XmlNodeType.Text, " "); Match(diff[16], ArrayDiffKind.Same, XmlNodeType.Text, "over"); Match(diff[17], ArrayDiffKind.Same, XmlNodeType.Text, " "); Match(diff[18], ArrayDiffKind.Same, XmlNodeType.Text, "the"); Match(diff[19], ArrayDiffKind.Removed, XmlNodeType.Text, " "); Match(diff[20], ArrayDiffKind.Removed, XmlNodeType.Text, "lazy"); Match(diff[21], ArrayDiffKind.Same, XmlNodeType.Text, " "); Match(diff[22], ArrayDiffKind.Same, XmlNodeType.Text, "dog"); Match(diff[23], ArrayDiffKind.Same, XmlNodeType.None, "p"); }
public void MergeConflicting() { XDoc org = XDocFactory.From("<p>the <span>brown</span> box</p>", MimeType.XML); XDoc left = XDocFactory.From("<p>the <em>brown</em> box</p>", MimeType.XML); XDoc right = XDocFactory.From("<p>the <b>brown</b> fox</p>", MimeType.XML); var conflict = false; var result = XDocDiff.Merge(org, left, right, 10000, ArrayMergeDiffPriority.Left, out conflict); Assert.AreEqual("<p>the <em>brown</em> fox</p>", result.ToString()); }
public void DiffNumbersWithComma() { // NOTE (steveb): test if digits separated by comma are detected as one word XDoc a = XDocFactory.From("<p>1,23</p>", MimeType.XML); XDoc b = XDocFactory.From("<p>4,56</p>", MimeType.XML); var diff = XDocDiff.Diff(a, b, 10000); Match(diff[0], ArrayDiffKind.Same, XmlNodeType.Element, "p"); Match(diff[1], ArrayDiffKind.Same, XmlNodeType.EndElement, string.Empty); Match(diff[2], ArrayDiffKind.Removed, XmlNodeType.Text, "1,23"); Match(diff[3], ArrayDiffKind.Added, XmlNodeType.Text, "4,56"); Match(diff[4], ArrayDiffKind.Same, XmlNodeType.None, "p"); }
public void DiffBasic() { // NOTE (steveb): test a simple diff XDoc a = XDocFactory.From("<p>before</p>", MimeType.XML); XDoc b = XDocFactory.From("<p>after</p>", MimeType.XML); var diff = XDocDiff.Diff(a, b, 10000); Match(diff[0], ArrayDiffKind.Same, XmlNodeType.Element, "p"); Match(diff[1], ArrayDiffKind.Same, XmlNodeType.EndElement, string.Empty); Match(diff[2], ArrayDiffKind.Removed, XmlNodeType.Text, "before"); Match(diff[3], ArrayDiffKind.Added, XmlNodeType.Text, "after"); Match(diff[4], ArrayDiffKind.Same, XmlNodeType.None, "p"); }
public void DiffNumbersWithPeriod() { // NOTE (steveb): test if digits separated by dot/period are detected as one word XDoc a = XDocFactory.From("<p>1.23</p>", MimeType.XML); XDoc b = XDocFactory.From("<p>4.56</p>", MimeType.XML); Tuplet <ArrayDiffKind, XDocDiff.Token>[] diff = XDocDiff.Diff(a, b, 10000); Match(diff[0], ArrayDiffKind.Same, XmlNodeType.Element, "p"); Match(diff[1], ArrayDiffKind.Same, XmlNodeType.EndElement, string.Empty); Match(diff[2], ArrayDiffKind.Removed, XmlNodeType.Text, "1.23"); Match(diff[3], ArrayDiffKind.Added, XmlNodeType.Text, "4.56"); Match(diff[4], ArrayDiffKind.Same, XmlNodeType.None, "p"); }
internal static DekiResource GetPageDiffSummary(PageBE page, string before, string beforeMime, string after, string afterMime, int maxDelta) { ParserResult beforeDoc = DekiXmlParser.Parse(page, beforeMime, page.Language, before, ParserMode.EDIT, false, -1, null, null); ParserResult afterDoc = DekiXmlParser.Parse(page, afterMime, page.Language, after, ParserMode.EDIT, false, -1, null, null); Tuplet <ArrayDiffKind, XDocDiff.Token>[] diff = XDocDiff.Diff(beforeDoc.MainBody, afterDoc.MainBody, maxDelta); if (diff == null) { return(DekiResources.PAGE_DIFF_TOO_LARGE()); } // create change summary int added; int removed; int attributes; int structural; return(GetChangeSummary(diff, out added, out removed, out attributes, out structural)); }
public void HighlightAttributes() { // NOTE (steveb): test unamibiguous addition, deletion, and replacement XDoc a = XDocFactory.From("<p>the <span class=\"red\">brown</span> fox</p>", MimeType.XML); XDoc b = XDocFactory.From("<p>the <span class=\"blue\">brown</span> fox</p>", MimeType.XML); var diff = XDocDiff.Diff(a, b, 10000); List <Tuple <string, string, string> > invisible; XDoc doc; XDoc before; XDoc after; XDocDiff.Highlight(diff, out doc, out invisible, out before, out after); Assert.AreEqual("<p>the <span class=\"blue\">brown</span> fox</p>", doc.ToString()); Assert.AreEqual(1, invisible.Count); Assert.AreEqual(invisible[0].Item1, "/p/span/@class"); Assert.AreEqual(invisible[0].Item2, "red"); Assert.AreEqual(invisible[0].Item3, "blue"); Assert.AreEqual(a.ToString(), before.ToString()); Assert.AreEqual(b.ToString(), after.ToString()); }
public void DiffAttributes() { // NOTE (steveb): test attribute changes XDoc a = XDocFactory.From("<p>the <span class=\"red\">brown</span> fox</p>", MimeType.XML); XDoc b = XDocFactory.From("<p>the <span class=\"blue\">brown</span> fox</p>", MimeType.XML); var diff = XDocDiff.Diff(a, b, 10000); Match(diff[0], ArrayDiffKind.Same, XmlNodeType.Element, "p"); Match(diff[1], ArrayDiffKind.Same, XmlNodeType.EndElement, string.Empty); Match(diff[2], ArrayDiffKind.Same, XmlNodeType.Text, "the"); Match(diff[3], ArrayDiffKind.Same, XmlNodeType.Text, " "); Match(diff[4], ArrayDiffKind.Same, XmlNodeType.Element, "span"); Match(diff[5], ArrayDiffKind.Removed, XmlNodeType.Attribute, "class=red"); Match(diff[6], ArrayDiffKind.Added, XmlNodeType.Attribute, "class=blue"); Match(diff[7], ArrayDiffKind.Same, XmlNodeType.EndElement, ""); Match(diff[8], ArrayDiffKind.Same, XmlNodeType.Text, "brown"); Match(diff[9], ArrayDiffKind.Same, XmlNodeType.None, "span"); Match(diff[10], ArrayDiffKind.Same, XmlNodeType.Text, " "); Match(diff[11], ArrayDiffKind.Same, XmlNodeType.Text, "fox"); Match(diff[12], ArrayDiffKind.Same, XmlNodeType.None, "p"); }
internal static XDoc GetPageDiff(XDoc before, XDoc after, bool compact, int maxDelta, out XDoc invisibleDiff, out DekiResource summary, out XDoc beforeHighlightedChanges, out XDoc afterHighlightedChanges) { var resources = DekiContext.Current.Resources; XDoc result = XDoc.Empty; beforeHighlightedChanges = before; afterHighlightedChanges = after; invisibleDiff = XDoc.Empty; // compute diff between the two documents Tuplet <ArrayDiffKind, XDocDiff.Token>[] diff = XDocDiff.Diff(before, after, maxDelta); if (diff == null) { summary = DekiResources.PAGE_DIFF_TOO_LARGE(); return(result); } // create change summary int added; int removed; int attributes; int structural; summary = GetChangeSummary(diff, out added, out removed, out attributes, out structural); // create document with highlighted changes if ((added > 0) || (removed > 0) || (attributes > 0)) { try { List <Tuplet <string, string, string> > invisibleChanges; XDocDiff.Highlight(diff, out result, out invisibleChanges, out beforeHighlightedChanges, out afterHighlightedChanges); // check if we should only keep top-level elements that contain changes to cut down on the noise if (compact) { if ((added > 0) || (removed > 0)) { CompactDiff(result); CompactDiff(beforeHighlightedChanges); CompactDiff(afterHighlightedChanges); } else { // no changes were made, remove all nodes result = XDoc.Empty; } } // add invisible changes if (invisibleChanges.Count > 0) { invisibleDiff = new XDoc("ol"); foreach (Tuplet <string, string, string> change in invisibleChanges) { invisibleDiff.Start("li"); invisibleDiff.Value(string.Format("{0}: ", change.Item1)); if (change.Item2 != null) { invisibleDiff.Elem("del", change.Item2.QuoteString()); } else { invisibleDiff.Value(resources.Localize(DekiResources.PAGE_DIFF_NOTHING())); } invisibleDiff.Value(" " + DOUBLE_ARROW + " "); if (change.Item3 != null) { invisibleDiff.Elem("ins", change.Item3.QuoteString()); } else { invisibleDiff.Value(resources.Localize(DekiResources.PAGE_DIFF_NOTHING())); } invisibleDiff.End(); } } } catch (Exception e) { summary = DekiResources.PAGE_DIFF_ERROR("MindTouch", e); } } return(result); }