Skip to content

Commit

Permalink
* Improve the selection of an attribute for the xdt:Locator attribute.
Browse files Browse the repository at this point in the history
XdtWriter now tries to choose a unique attribute that also hasn't changed between the two trees.
  • Loading branch information
Cameron Wills committed Nov 17, 2015
1 parent 6a34a9e commit 135c293
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 10 deletions.
88 changes: 80 additions & 8 deletions FatAntelope.Tests/XdtDiffWriterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,76 @@ namespace FatAntelope.Tests
public class XdtWriterTests
{
[TestMethod]
public void SetAttribute()
public void NoLocatorAndSetAttributes()
{
var doc1 = @"
var source = @"
<root>
<child1 name1='child1' type1='elem1'>child1</child1>
<child2 name1='child2' type1='elem2'>child2</child2>
<child1 name='child1' type='elem1'>child1</child1>
<child2 name='child2' type='elem2'>child2</child2>
</root>";

var doc2 = @"
var target = @"
<root>
<child1 type1='DIFFERENT' name1='DIFFERENT'>child1</child1>
<child2 name1='child2' type1='elem2'>child2</child2>
<child1 type='DIFFERENT' name='DIFFERENT'>child1</child1>
<child2 name='child2' type='elem2'>child2</child2>
</root>";

AssertCanTransform(doc1, doc2);
var patch = GetPatch(source, target);

// Locator = none
AssertNoLocator(patch.SelectSingleNode("/root/child1"));

// Transform = SetAttributes
AssertTransform(patch.SelectSingleNode("/root/child1"), "SetAttributes(type,name)");

AssertCanTransform(source, target);
}

[TestMethod]
public void MatchAndSetAttribute()
{
var source = @"
<root>
<child name='child1' type='elem1'>child1</child>
<child name='child2' type='elem2'>child2</child>
</root>";

var target = @"
<root>
<child name='DIFFERENT' type='elem1'>child1</child>
<child name='child2' type='elem2'>child2</child>
</root>";

var patch = GetPatch(source, target);

// Locator = Match(type)
AssertLocator(patch.SelectSingleNode("/root/child"), "Match(type)");

// Transform = SetAttribute(type)
AssertTransform(patch.SelectSingleNode("/root/child"), "SetAttributes(name)");

AssertCanTransform(source, target);
}

private void AssertTransform(XmlNode node, string expected)
{
Assert.IsNotNull(node);
var value = node.SelectSingleNode("@*[local-name() = 'Transform']").Value;
Assert.AreEqual(expected, value);
}

private void AssertLocator(XmlNode node, string expected)
{
Assert.IsNotNull(node);
var value = node.SelectSingleNode("@*[local-name() = 'Locator']").Value;
Assert.AreEqual(expected, value);
}

private void AssertNoLocator(XmlNode node)
{
Assert.IsNotNull(node);
var attribute = node.SelectSingleNode("@*[local-name() = 'Locator']");
Assert.IsNull(attribute);
}

private void AssertCanTransform(string sourceXml, string targetXml)
Expand All @@ -52,6 +107,23 @@ private void AssertCanTransform(string sourceXml, string targetXml)
Assert.IsTrue(Enumerable.SequenceEqual(transformedTree.Root.Hash, tree2.Root.Hash));
}

private XmlDocument GetPatch(string sourceXml, string targetXml)
{
var doc1 = new XmlDocument();
doc1.LoadXml(sourceXml);

// reordered xml but same values
var doc2 = new XmlDocument();
doc2.LoadXml(targetXml);

var tree1 = new XTree(doc1);
var tree2 = new XTree(doc2);
XDiff.Diff(tree1, tree2);

var writer = new XdtDiffWriter();
return writer.GetDiff(tree2);
}

private XmlDocument Transform(XmlDocument sourceXml, XmlDocument patchXml)
{
var source = new XmlTransformableDocument();
Expand Down
11 changes: 9 additions & 2 deletions FatAntelope/Writers/XdtDiffWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,8 @@ private Trait GetUniqueTrait(XNode element)
// Mulitple elements with the same name
if (duplicates.Count > 1)
{
XNode poorAttribute = null;

// try and find unique attribute
foreach (var attribute in element.Attributes)
{
Expand All @@ -408,11 +410,16 @@ private Trait GetUniqueTrait(XNode element)
}

if (unique)
return new Trait() { Attribute = attribute, Index = index };
{
if (attribute.Match != MatchType.Match)
poorAttribute = poorAttribute ?? attribute;
else
return new Trait() { Attribute = attribute, Index = index };
}
}

// No unique attributes, so use index
return new Trait() { Index = index };
return new Trait() { Attribute = poorAttribute, Index = index };
}
}

Expand Down

0 comments on commit 135c293

Please sign in to comment.