| /******************************************************************************* |
| * Copyright (c) 2000, 2005 Jiva Medical and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Jiva Medical - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.uomo.xml.test; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileNotFoundException; |
| import java.io.FileOutputStream; |
| import java.io.FileWriter; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| |
| import javax.xml.parsers.DocumentBuilder; |
| import javax.xml.parsers.DocumentBuilderFactory; |
| import javax.xml.parsers.ParserConfigurationException; |
| |
| import org.apache.commons.lang.StringUtils; |
| import org.eclipse.uomo.core.UOMoException; |
| import org.eclipse.uomo.xml.impl.XMLReader; |
| import org.eclipse.uomo.xml.impl.XMLWriter; |
| import org.eclipse.uomo.xml.impl.XMLWriterParser; |
| import org.junit.Before; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.NamedNodeMap; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.Text; |
| import org.xml.sax.SAXException; |
| |
| public abstract class XMLTestCase implements |
| XMLTestConfiguration { |
| |
| @Before |
| public void setUp() throws Exception { |
| // super.setUp(); |
| checkOsxXmlHandlers(); |
| } |
| |
| public static void checkOsxXmlHandlers() { |
| // this is a workaround for a weird OSX related issue - something to do |
| // with the way Apple register Crimson. |
| // feel free to disable it if it's not a problem for you |
| if (isOsx()) { |
| System |
| .setProperty("javax.xml.parsers.DocumentBuilderFactory", |
| "com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl"); |
| System |
| .setProperty("javax.xml.parsers.SAXParserFactory", |
| "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl"); |
| System |
| .setProperty("org.w3c.dom.DOMImplementationSourceList", |
| "com.sun.org.apache.xerces.internal.dom.DOMImplementationSourceImpl"); |
| } |
| } |
| |
| private void prettyXML(String source, String dest) throws SAXException, |
| IOException { |
| XMLWriter dst = new XMLWriter(new FileOutputStream(new File(dest)), |
| "UTF-8"); |
| dst.setPretty(true); |
| dst.setSortAttributes(true); |
| XMLReader src = new XMLReader(new XMLWriterParser(dst)); |
| src.parse(new FileInputStream(new File(source))); |
| } |
| |
| private final static int CR = 13; |
| private final static int LF = 10; |
| |
| protected void compareDOMs(String filename1, String filename2, |
| String name1, String name2) throws FileNotFoundException, |
| ParserConfigurationException, SAXException, IOException, |
| InterruptedException, UOMoException { |
| Document one = loadDom(filename1); |
| Document two = loadDom(filename2); |
| |
| String diff = compareElements(one.getDocumentElement(), two |
| .getDocumentElement(), "/"); |
| if (diff != null) { |
| showDiff(filename1, filename2, name1, name2, true, diff); |
| } |
| } |
| |
| private String compareElements(Element e1, Element e2, String p) { |
| if (!e1.getNamespaceURI().equals(e2.getNamespaceURI())) |
| return "element namespaces differ at " + p; |
| if (!e1.getLocalName().equals(e2.getLocalName())) |
| return "element names differ at " + p; |
| |
| String msg = compareAttributes(e1, e2, p); |
| if (msg != null) |
| return msg; |
| |
| p = p + "/" + e1.getNodeName(); |
| |
| int i = 0; |
| Node c1 = getNextRelevantNode(e1.getFirstChild()); |
| Node c2 = getNextRelevantNode(e2.getFirstChild()); |
| while (c1 != null && c2 != null) { |
| if (c1.getNodeType() != c2.getNodeType()) |
| return "Different node types (" |
| + Integer.toString(c1.getNodeType()) + "/" |
| + c2.getNodeType() + ") @ " + p; |
| msg = null; |
| if (c1.getNodeType() == Node.TEXT_NODE) { |
| msg = compareTexts((Text) c1, (Text) c2, p + "[" |
| + Integer.toString(i) + "]"); |
| } else if (c1.getNodeType() == Node.ELEMENT_NODE) { |
| msg = compareElements((Element) c1, (Element) c2, p + "[" |
| + Integer.toString(i) + "]"); |
| } else |
| msg = "unknown node type " + Integer.toString(c1.getNodeType()); |
| if (msg != null) |
| return msg; |
| |
| c1 = getNextRelevantNode(c1.getNextSibling()); |
| c2 = getNextRelevantNode(c2.getNextSibling()); |
| i++; |
| } |
| if (c1 != null && c2 == null) |
| return "node present in one and not in two @ " + p; |
| if (c2 != null && c1 == null) |
| return "node present in two and not in one @ " + p; |
| return null; |
| } |
| |
| private String compareAttributes(Element e1, Element e2, String p) { |
| NamedNodeMap n1 = e1.getAttributes(); |
| NamedNodeMap n2 = e2.getAttributes(); |
| |
| for (int i = 0; i < n1.getLength(); i++) { |
| Node a1 = n1.item(0); |
| Node a2 = n2 |
| .getNamedItemNS(a1.getNamespaceURI(), a1.getLocalName()); |
| if (a2 == null) |
| return "Unable to find attribute " + a1.getNodeName() + " @ " |
| + p; |
| if (a1.getNodeValue() != null || a2.getNodeValue() != null) { |
| if (a1.getNodeValue() == null || a2.getNodeValue() == null |
| || !a1.getNodeValue().equals(a2.getNodeValue())) |
| return "Attribute text differs @ " + p + "/@" |
| + a1.getNodeName() + ": '" + a1.getNodeValue() |
| + "' / '" + a2.getNodeValue() + "'"; |
| } |
| } |
| |
| for (int i = 0; i < n2.getLength(); i++) { |
| Node a2 = n2.item(0); |
| Node a1 = n1 |
| .getNamedItemNS(a2.getNamespaceURI(), a2.getLocalName()); |
| if (a1 == null) |
| return "Unable to find attribute " + a2.getNodeName() + " @ " |
| + p; |
| if (a1.getNodeValue() != null || a2.getNodeValue() != null) { |
| if (a1.getNodeValue() == null || a2.getNodeValue() == null |
| || !a1.getNodeValue().equals(a2.getNodeValue())) |
| return "Attribute text differs @ " + p + "/@" |
| + a1.getNodeName() + ": '" + a1.getNodeValue() |
| + "' / '" + a2.getNodeValue() + "'"; |
| } |
| } |
| |
| return null; |
| } |
| |
| private String compareTexts(Text c1, Text c2, String p) { |
| String s1 = normaliseWhitespace(c1.getNodeValue()); |
| String s2 = normaliseWhitespace(c2.getNodeValue()); |
| if (s1 == null && s2 == null) |
| return null; |
| else if (s1 == null || s2 == null || !s1.equals(s2)) |
| return "Text differs @ " + p + ": '" + s1 + "' / '" + s2 + "'"; |
| else |
| return null; |
| } |
| |
| private String normaliseWhitespace(String s) { |
| StringBuilder bldr = new StringBuilder(); |
| boolean w = false; |
| for (Character ch : s.toCharArray()) { |
| if (!Character.isWhitespace(ch)) { |
| bldr.append(ch); |
| w = false; |
| } else if (!w) { |
| bldr.append(' '); |
| w = true; |
| } else { |
| // nothing |
| } |
| |
| } |
| return bldr.toString(); |
| } |
| |
| private Node getNextRelevantNode(Node node) { |
| while (node != null |
| && node.getNodeType() != Node.ELEMENT_NODE |
| && !(node.getNodeType() == Node.TEXT_NODE && !StringUtils |
| .isWhitespace(node.getNodeValue()))) |
| node = node.getNextSibling(); |
| return node; |
| } |
| |
| private Document loadDom(String filename) |
| throws ParserConfigurationException, FileNotFoundException, |
| SAXException, IOException { |
| |
| DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); |
| factory.setNamespaceAware(true); |
| DocumentBuilder builder = factory.newDocumentBuilder(); |
| File file = new File(filename); |
| return builder.parse(new FileInputStream(file)); |
| |
| } |
| |
| protected void compareXMLs(String filename1, String filename2, |
| String name1, String name2, boolean makePretty) throws IOException, |
| UOMoException, InterruptedException, SAXException { |
| |
| FileInputStream one = new FileInputStream(new File(filename1)); |
| FileInputStream two = new FileInputStream(new File(filename2)); |
| int size1 = one.available(); |
| int size2 = two.available(); |
| |
| boolean same = true; |
| int count = 0; |
| int ia1 = -1; |
| int ia2 = -1; |
| |
| while (same && one.available() > 0 && two.available() > 0) { |
| int i1 = ia1 != -1 ? ia1 : one.read(); |
| ia1 = -1; |
| int i2 = ia2 != -1 ? ia2 : two.read(); |
| ia2 = -1; |
| if (i1 == CR) { |
| i1 = LF; |
| ia1 = one.read(); |
| if (ia1 == LF) |
| ia1 = -1; |
| } |
| if (i2 == CR) { |
| i2 = LF; |
| ia2 = two.read(); |
| if (ia2 == LF) |
| ia2 = -1; |
| } |
| same = i1 == i2; |
| count++; |
| } |
| |
| int left1 = one.available(); |
| int left2 = two.available(); |
| |
| one.close(); |
| two.close(); |
| |
| if (!same || left1 > 0 || left2 > 0) { |
| if (!same) |
| showDiff(filename1, filename2, name1, name2, makePretty, |
| "Content is not as expected @ " |
| + Integer.toString(count) + " of " |
| + Integer.toString(size1) + "/" |
| + Integer.toString(size2)); |
| else |
| showDiff(filename1, filename2, name1, name2, makePretty, |
| "Content is same until end of file @ " |
| + Integer.toString(size1) + "/" |
| + Integer.toString(size2)); |
| } |
| |
| } |
| |
| private void showDiff(String filename1, String filename2, String name1, |
| String name2, boolean makePretty, String msg) throws SAXException, |
| IOException, InterruptedException, UOMoException { |
| if (makePretty) { |
| prettyXML(filename1, TEMP_PATH + name1 + ".xml"); |
| prettyXML(filename2, TEMP_PATH + name2 + ".xml"); |
| |
| } else { |
| copyFile(filename1, TEMP_PATH + name1 + ".xml"); |
| copyFile(filename2, TEMP_PATH + name2 + ".xml"); |
| } |
| if (!SKIP_THIRD_PARTY) { |
| if (isOsx()) |
| Runtime.getRuntime().exec( |
| COMPARE_PATH + " " + TEMP_PATH + name1 + ".xml" + " " |
| + TEMP_PATH + name2 + ".xml"); |
| else |
| Runtime.getRuntime().exec( |
| COMPARE_PATH + " \"" + TEMP_PATH + name1 + ".xml" |
| + "\" \"" + TEMP_PATH + name2 + ".xml" + "\""); |
| } |
| Thread.sleep(1000); |
| throw new UOMoException(msg); |
| |
| } |
| |
| private void copyFile(String source, String dest) throws SAXException, |
| IOException { |
| InputStream in = new FileInputStream(new File(source)); |
| OutputStream out = new FileOutputStream(new File(dest)); |
| |
| // Transfer bytes from in to out |
| byte[] buf = new byte[1024]; |
| int len; |
| while ((len = in.read(buf)) > 0) { |
| out.write(buf, 0, len); |
| } |
| in.close(); |
| out.close(); |
| } |
| |
| protected void compareFiles(String filename1, String filename2) |
| throws IOException, UOMoException, InterruptedException { |
| FileInputStream one = new FileInputStream(new File(filename1)); |
| FileInputStream two = new FileInputStream(new File(filename2)); |
| boolean same = one.available() == two.available(); |
| while (same && one.available() > 0) { |
| same = one.read() == two.read(); |
| } |
| |
| if (!same) { |
| if (!SKIP_THIRD_PARTY) |
| Runtime.getRuntime().exec( |
| COMPARE_PATH + " \"" + filename1 + "\" \"" + filename2 |
| + "\""); |
| Thread.sleep(1000); |
| throw new UOMoException("Content is not as expected @ " |
| + Integer.toString(one.available())); |
| } |
| } |
| |
| protected void compareStrings(String content1, String content2) |
| throws IOException, UOMoException, InterruptedException { |
| String filename1 = TEMP_FILENAME + "1"; |
| String filename2 = TEMP_FILENAME + "2"; |
| stringToFile(content1, filename1); |
| stringToFile(content2, filename2); |
| compareFiles(filename1, filename2); |
| } |
| |
| private void stringToFile(String content, String filename) |
| throws IOException { |
| FileWriter file = new FileWriter(new File(filename)); |
| file.write(content); |
| file.flush(); |
| file.close(); |
| } |
| |
| protected static boolean isOsx() { |
| String lcOSName = System.getProperty("os.name").toLowerCase(); |
| boolean MAC_OS_X = lcOSName.startsWith("mac os x"); |
| return MAC_OS_X; |
| } |
| } |