Commit c164d769 authored by Pakulin's avatar Pakulin
Browse files

Added comparison between different representations of float values.

NB: it does not work with complex types containing simple content of type float, like this:
	<complexType name="item_t">
		<simpleContent>
			<extension base="float">
				<attribute name="foo" type="float"/>
				<attribute name="bar" type="integer"/>
			</extension>
		</simpleContent>
	</complexType>
parent becdb6e7
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -6,6 +6,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.List;


import org.custommonkey.xmlunit.Difference;
import org.custommonkey.xmlunit.Difference;
import org.w3c.dom.Document;
import org.xml.sax.ErrorHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.SAXParseException;
+176 −0
Original line number Original line Diff line number Diff line
package org.etsi.mts.ttcn.part9.xmldiff;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.custommonkey.xmlunit.Difference;
import org.custommonkey.xmlunit.DifferenceEngine;
import org.custommonkey.xmlunit.DifferenceListener;
import org.custommonkey.xmlunit.NodeDetail;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.TypeInfo;

public class DifferenceHandler implements DifferenceListener {
	private Document originalReference;
	private Document originalTest;
	private XPathFactory xpathFactory;

	public DifferenceHandler(Document originalReference, Document originalTest) {
		super();
		this.originalReference = originalReference;
		this.originalTest = originalTest;
		xpathFactory = XPathFactory.newInstance();
	}


	@Override
    public int differenceFound(Difference difference) {
    	int id = difference.getId();
		if (id == DifferenceEngine.NAMESPACE_PREFIX_ID) {
			return handlePrefixDiff(difference);
    	}
		if (id == DifferenceEngine.TEXT_VALUE_ID) {
			return handleValueDiff(difference);
		}
		if (id == DifferenceEngine.ATTR_VALUE_ID) {
			return handleValueDiff(difference);			
		}
		XmlDiff.logger.debug2("Difference accepted: Namespace prefix ID", 
				difference.getDescription());
    	return RETURN_ACCEPT_DIFFERENCE;
    }


	private int handleValueDiff(Difference difference) {
		
		NodeDetail controlNodeDetail = difference.getControlNodeDetail();
		NodeDetail testNodeDetail = difference.getTestNodeDetail();
		
		// XmlDiff clones DOM trees and loses information about type of nodes and attributes
		// We need to find corresponding node in the original tree to get information about 
		// schema type
		Node originalNode = findOriginalNode(controlNodeDetail);
		
		if (originalNode == null) {
			return RETURN_ACCEPT_DIFFERENCE;
		}
		
		if (isFloat(originalNode)) {
			return handleFloat(controlNodeDetail, testNodeDetail);
		}
		return RETURN_ACCEPT_DIFFERENCE;
	}

	private int handleFloat(NodeDetail controlNodeDetail,
			NodeDetail testNodeDetail) {
		String controlValue = controlNodeDetail.getValue();
		double controlDouble = 0.0;
		
		try {
			controlDouble = Double.parseDouble(controlValue);
		} catch (NumberFormatException err) {
			XmlDiff.logger.severe("Failed to convert reference value to double {", controlValue, "}: error ",
					err.getMessage());
			return RETURN_ACCEPT_DIFFERENCE;
		}

		String testValue = testNodeDetail.getValue();
		double testDouble = 0.0;
		try {
			testDouble = Double.parseDouble(testValue);
		} catch (NumberFormatException err) {
			XmlDiff.logger.severe("Failed to convert test value to double {", testValue, "}: error ",
					err.getMessage());
			return RETURN_ACCEPT_DIFFERENCE;
		}
		
		if (testDouble == controlDouble) {
			XmlDiff.logger.debug("Compare {", controlValue, "} and {", testValue, "}: identical");
			return RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL;
		} else {
			XmlDiff.logger.debug("Compare {", controlValue, "} and {", testValue, "}: different");
			return RETURN_ACCEPT_DIFFERENCE;
		}
	}


	private Node findOriginalNode(NodeDetail nodeDetail) {
		String controlXpath = fixXpath(nodeDetail.getXpathLocation());
		XPath xpath = xpathFactory.newXPath();
		Node result = null;
		try {
			result = (Node) xpath.evaluate(controlXpath, 
					originalReference, 
					XPathConstants.NODE);
		} catch (XPathExpressionException e) {
			XmlDiff.logger.severe("Failed to process XPATH expression '", 
					controlXpath, "': error " + e.getMessage());
			return null;
		}
		if (result == null) {
			XmlDiff.logger.severe("Nothing found by XPATH expression '", 
					controlXpath, "'");
		}
		return result;
	}


	private boolean isFloat(Node node) {
		boolean isFloat = false;
		if (node.getNodeType() == Node.TEXT_NODE) {
			node  = node.getParentNode();
		}
		TypeInfo typeinfo = guessTypeInfo(node);
		if (typeinfo == null) {
			XmlDiff.logger.info("No type info found: node ", node.getNodeName());
			return false;
		}
		
		isFloat = typeinfo.isDerivedFrom(
							"http://www.w3.org/2001/XMLSchema", 
							"float", 
							TypeInfo.DERIVATION_RESTRICTION);
		XmlDiff.logger.debug2("isFloat == ", isFloat, ": type ", typeinfo.getTypeName(), 
				", node ", node.getNodeName());
		return isFloat;
	}


	private int handlePrefixDiff(Difference difference) {
		XmlDiff.logger.debug3("Difference ignored: Namespace prefix ID", 
				difference.getDescription());
		return RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL;
	}
    

	@Override
	public void skippedComparison(Node control, Node test) {
	}
	
	private static String fixXpath(String orig) {
		String result = orig.replaceAll("/([a-zA-Z0-9_-]+)(\\[[0-9]+\\](/|$))?", "/*[local-name()='$1']$2");
		XmlDiff.logger.debug2("Original xpath: {", orig, "}, modified: {", result, "}");
		return result;
	}
	
	private static TypeInfo guessTypeInfo(Node node) {
		TypeInfo typeinfo = null;
		if (node.getNodeType() == Node.ELEMENT_NODE) {
			Element element = (Element)node;
			
			typeinfo = element.getSchemaTypeInfo();
		}
		if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
			Attr attr = (Attr)node;
			
			typeinfo = attr.getSchemaTypeInfo();
		}
		
		return typeinfo;
	}
}
 No newline at end of file
+34 −0
Original line number Original line Diff line number Diff line
package org.etsi.mts.ttcn.part9.xmldiff;

import org.w3c.dom.Element;
import org.w3c.dom.Node;

/** Internal type for debugging purposes.
 * 
 * Do not use.  
 */
class DomTraversal {
	public void processNode(Node node, String prefix) {
		System.out.println(prefix + "#" + node.hashCode());
		if (node.getNodeType() == Node.DOCUMENT_NODE) {
			System.out.println(prefix + "Document: " + node.getNodeName());
		} else if (node.getNodeType() == Node.ELEMENT_NODE) {
			System.out.println(prefix + "Element: " + node.getNodeName());
			Element element = (Element) node;
			System.out.println(prefix + "--" + element.getSchemaTypeInfo().getTypeName());
		} else if (node.getNodeType() == Node.TEXT_NODE) {
			System.out.println(prefix + "Text: {" + node.getTextContent() + "}");
		} else {
			System.out.println(prefix + "smt else: " + node.getNodeType() 
					+ "{" + node.getClass() + "}: {" + node.getTextContent() + "}");
		}
		Node child = node.getFirstChild();
		while (child != null) {
			processNode(child, prefix+"  ");
			child = child.getNextSibling();
		}
	}
	public void processNode(Node node) {
		processNode(node, "");
	}
}
+10 −35
Original line number Original line Diff line number Diff line
@@ -27,8 +27,6 @@ import javax.xml.validation.SchemaFactory;
import org.custommonkey.xmlunit.DetailedDiff;
import org.custommonkey.xmlunit.DetailedDiff;
import org.custommonkey.xmlunit.Diff;
import org.custommonkey.xmlunit.Diff;
import org.custommonkey.xmlunit.Difference;
import org.custommonkey.xmlunit.Difference;
import org.custommonkey.xmlunit.DifferenceEngine;
import org.custommonkey.xmlunit.DifferenceListener;
import org.custommonkey.xmlunit.XMLUnit;
import org.custommonkey.xmlunit.XMLUnit;
import org.w3c.dom.Document;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.Node;
@@ -55,30 +53,12 @@ public class XmlDiff {
		} catch (IOException e) {
		} catch (IOException e) {
			e.printStackTrace();
			e.printStackTrace();
		}
		}
		System.err.println("XmlDiff class loaded");
		
	}
	
	public static class IgnoreSchemePrefix implements DifferenceListener {
		@Override
	    public int differenceFound(Difference difference) {
	    	int id = difference.getId();
			if (id == DifferenceEngine.NAMESPACE_PREFIX_ID /*||
				id == DifferenceEngine.NAMESPACE_URI_ID */
					) {
				logger.debug3("Difference ignored: Namespace prefix ID", 
						difference.getDescription());
	    		return RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL;
	    	}
			logger.debug3("Difference accepted: Namespace prefix ID", 
					difference.getDescription());
	    	return RETURN_ACCEPT_DIFFERENCE;
	}
	}



	static {
		@Override
		XMLUnit.setIgnoreComments(true);
		public void skippedComparison(Node control, Node test) {
		XMLUnit.setIgnoreWhitespace(true);
		}
		XMLUnit.setIgnoreDiffBetweenTextAndCDATA(true);
	}
	}
	
	
	protected File referenceXmlFile;
	protected File referenceXmlFile;
@@ -86,6 +66,8 @@ public class XmlDiff {
	private Schema schemes = null;
	private Schema schemes = null;
	private DocumentBuilderFactory xmlParserFactory;
	private DocumentBuilderFactory xmlParserFactory;
	private DiffErrorHandler errorHandler = new DiffErrorHandler();
	private DiffErrorHandler errorHandler = new DiffErrorHandler();
	private Document controlDoc;
	private Document testDoc;


	/** Initialize the diff engine.
	/** Initialize the diff engine.
	 * 
	 * 
@@ -116,7 +98,6 @@ public class XmlDiff {
	 * 
	 * 
	 */
	 */
	public XmlDiff(File file, String[] xsdFileNames, String[] xsdSearchPath) {
	public XmlDiff(File file, String[] xsdFileNames, String[] xsdSearchPath) {
		System.err.println("XmlDiff constructor called");
		logger.debug("Reference file: ", file, 
		logger.debug("Reference file: ", file, 
				", xsd file names: ", (xsdFileNames == null)? "null" : Arrays.toString(xsdFileNames),
				", xsd file names: ", (xsdFileNames == null)? "null" : Arrays.toString(xsdFileNames),
				", xsd search path: ", (xsdSearchPath == null)? "null" : Arrays.toString(xsdSearchPath));		
				", xsd search path: ", (xsdSearchPath == null)? "null" : Arrays.toString(xsdSearchPath));		
@@ -151,8 +132,6 @@ public class XmlDiff {
		} catch(Throwable err) {
		} catch(Throwable err) {
			err.printStackTrace();
			err.printStackTrace();
			throw err;
			throw err;
		} finally {
			System.err.println("XmlDiff constructor finished");
		}
		}
	}
	}


@@ -223,10 +202,6 @@ public class XmlDiff {
			return false;
			return false;
		}
		}
		
		
		XMLUnit.setIgnoreComments(true);
		XMLUnit.setIgnoreWhitespace(true);
		XMLUnit.setIgnoreDiffBetweenTextAndCDATA(true);
		
		boolean result = differ.identical() || differ.similar();
		boolean result = differ.identical() || differ.similar();
		
		
		if (!result) {
		if (!result) {
@@ -321,10 +296,10 @@ public class XmlDiff {
	}
	}
	
	
	private Diff createDiffer(Reader control, Reader test) throws SAXException, IOException, XmlDiffError {
	private Diff createDiffer(Reader control, Reader test) throws SAXException, IOException, XmlDiffError {
		Document controlDoc = parseXml(control, "sample XML file");
		controlDoc = parseXml(control, "sample XML file");
		Document testDoc = parseXml(test, "generated XML document");
		testDoc = parseXml(test, "generated XML document");
		Diff result = new Diff(controlDoc, testDoc);
		Diff result = new Diff(controlDoc, testDoc);
		result.overrideDifferenceListener(new IgnoreSchemePrefix());
		result.overrideDifferenceListener(new DifferenceHandler(controlDoc, testDoc));
		return result;
		return result;
	}
	}
}
}
+15 −0
Original line number Original line Diff line number Diff line
package org.etsi.mts.ttcn.part9.xmldiff;

import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;

@RunWith(Suite.class)
@SuiteClasses({ Test_001.class, TestDiff_002.class, TestDiff_003.class,
		TestDiff_004_boolean.class, TestDiff_005_fixed_fraction.class,
		TestDiff_005_fixed_no_fraction.class, TestDiff_005_float.class,
		TestDiff_005_float_attribute.class,
		TestDiff_005_float_complex_content.class })
public class AllTests {

}
Loading