/*
* $Header: /home/cvs/jakarta-slide/testsuite/testsuite/junit/src/org/apache/slide/testsuite/testtools/tprocessor/XMLResponseBodyAssert.java,v 1.25 2003/09/09 07:05:46 juergen Exp $
* $Revision: 1.25 $
* $Date: 2003/09/09 07:05:46 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999-2002 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Slide", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.slide.testsuite.testtools.tprocessor;
//java
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import org.apache.slide.testsuite.testtools.tutil.XConf;
import org.apache.webdav.lib.methods.XMLResponseMethodBase;
import org.jdom.Element;
public abstract class XMLResponseBodyAssert extends ResponseBodyAssert {
// debugging purpose only
private boolean extendedPrintlnRequest = false;
protected XMLResponseMethodBase method;
protected Element expectedXmlTree;
/** constructer
* @param WebdavMethodBase Element
*/
public XMLResponseBodyAssert(XMLResponseMethodBase method, Element expectedXmlTree, XConf xconf, XMLOutput xmlresult, List expectedResponseCodes){
super(xconf, method.getName(), xmlresult, expectedResponseCodes);
this.method = method;
this.expectedXmlTree = expectedXmlTree;
this.expectedXmlTree = expectedXmlTree;
}
//
//
public org.jdom.Document responseDocument(){
org.jdom.Document jdom = null;
try{
org.w3c.dom.Document dDoc = method.getResponseDocument();
if (dDoc == null) return null;
jdom = (new org.jdom.input.DOMBuilder().build(dDoc));
} catch(Exception e){
e.printStackTrace();
}
return jdom;
}
/**
* checks if Expected Response and Response are same
*/
public boolean assertResponseBody(){
// check if both expected and received bodies are not available
if ((expectedXmlTree == null) &&
((responseDocument() == null) || responseDocument().getRootElement() == null) )
return true;
if (extendedPrintlnRequest) {
// some debugging output
// START
System.out.println("#########################");
System.out.println("####### method = " + method.getName() +
" response received = " + method.getStatusCode() +
" expected = " + listToString(expectedResponseCodes));
System.out.println("####### expected ########");
if (expectedXmlTree != null)
System.out.println(TProcessors.getElementString(expectedXmlTree));
else
System.out.println("####### NOT PRESENT");
System.out.println("####### received ########");
if (responseDocument() != null && responseDocument().getRootElement() != null)
System.out.println(TProcessors.getElementString(responseDocument().getRootElement()));
else
System.out.println("####### NOT PRESENT");
System.out.println("#########################");
System.out.println();
// STOP
// some debugging output
}
// check if either expected and received bodies are not available and
// the expected response code list does not contain more than one response code
if ( (expectedXmlTree == null ||
responseDocument() == null ||
responseDocument().getRootElement()== null)) {
if (expectedResponseCodes.size() <= 1) {
xmlresult.writeElementStart("XMLValueError");
xmlresult.writeElement("expectedValue", expectedXmlTree==null?"not present":"present");
xmlresult.writeElement("receivedValue", responseDocument()==null?"not present":"present");
xmlresult.writeElementEnd("XMLValueError");
return false;
}
return true;
}
// both expected and received bodies are now available
return compareTrees(expectedXmlTree, responseDocument().getRootElement());
}
public boolean compareTrees(Element element1, Element element2) {
return compareTrees("", element1, element2);
}
private boolean compareTrees(String pathName, Element element1, Element element2) {
boolean result = true;
//System.out.println("########## comparing now " + element1 + " with " + element2);
// check the name of the element
if (!element1.getName().equals(element2.getName())){
xmlresult.writeElementStart("XMLNameError");
xmlresult.writeElement("path", pathName);
xmlresult.writeElement("expectedName", element1.getName());
xmlresult.writeElement("receivedName", element2.getName());
xmlresult.writeElementEnd("XMLNameError");
result = false;
}
String elementName = element1.getName();
// check the value of the element
if (!compareValues(pathName, elementName, element1.getText(), element2.getText())) {
result = false;
}
// now check the children
List children1 = sort(element1.getChildren(), getPathName(pathName, elementName));
List children2 = sort(element2.getChildren(), getPathName(pathName, elementName));
// check the count of children
if (children1.size() != children2.size()){
if (!element1.getTextTrim().equals("*")) {
if (reportDifferentSizeError(children1, children2, pathName, elementName)) {
result = false;
}
}
List children1Result = repairElementList(children1, children2, getPathName(pathName, elementName));
children2 = repairElementList(children2, children1, getPathName(pathName, elementName));
children1 = children1Result;
}
// check if repair was sucessfull
if (children1.size() != children2.size()){
return false;
}
// if (children1.size() > 3) {
//
// Iterator iter = children1.iterator();
// while (iter.hasNext())
// {
// Element element = (Element)iter.next();
// System.out.println(" element1: " + getDisplayName(element, elementName));
// }
// System.out.println();
// Iterator iter2 = children2.iterator();
// while (iter2.hasNext())
// {
// Element element = (Element)iter2.next();
// System.out.println(" element2: " + getDisplayName(element, elementName));
// }
// }
// finally check all children too via recursion
Iterator iter1 = children1.iterator();
Iterator iter2 = children2.iterator();
while (iter1.hasNext()){
try {
if (!compareTrees(getPathName(pathName, element1), (Element)iter1.next(), (Element)iter2.next()))
result = false;
} catch (Exception e) { e.printStackTrace();
System.out.println("###################");
System.out.println("################### list1 = " + getChildNames(children1, getPathName(pathName, elementName)));
System.out.println("################### list2 = " + getChildNames(children2, getPathName(pathName, elementName)));
System.out.println("###################");
}
}
return result;
}
private boolean reportDifferentSizeError(List expected, List received, String path, String name) {
boolean result = false;
String pathName = getPathName(path, name);
List expectedAndNotReceived = getChildNames(expected, pathName);
List receivedAndNotExpected = getChildNames(received, pathName);
expectedAndNotReceived.removeAll(getChildNames(received, pathName));
receivedAndNotExpected.removeAll(getChildNames(expected, pathName));
List illegalElements = new ArrayList(expectedAndNotReceived);
illegalElements.addAll(receivedAndNotExpected);
illegalElements = removeLegalNamesFromList(pathName, illegalElements);
if (illegalElements.size() > 0 ||
repairElementList(expected, received, pathName).size() !=
repairElementList(received, expected, pathName).size()) {
xmlresult.writeElementStart("XMLSizeError");
xmlresult.writeElement("path", pathName);
xmlresult.writeElement("expectedSize", expected.size());
xmlresult.writeElement("receivedSize", received.size());
xmlresult.writeElement("expectedElements", getChildNames(expected, pathName).toString());
xmlresult.writeElement("receivedElements", getChildNames(received, pathName).toString());
expectedAndNotReceived = removeLegalNamesFromList(pathName, expectedAndNotReceived);
if (expectedAndNotReceived.size() > 0){
xmlresult.writeElement("expectedAndNotReceived", expectedAndNotReceived.toString());
}
receivedAndNotExpected = removeLegalNamesFromList(pathName, receivedAndNotExpected);
if (receivedAndNotExpected.size() > 0){
xmlresult.writeElement("receivedAndNotExpected", receivedAndNotExpected.toString());
}
xmlresult.writeElementEnd("XMLSizeError");
result = true;
}
return result;
}
private List repairElementList(List list1, List list2, String pathName) {
List result = list1;
List elementNamesToBeRemoved = getChildNames(list1, pathName);
elementNamesToBeRemoved.removeAll(getChildNames(list2, pathName));
result = elementsMinusDisplaynames(result, elementNamesToBeRemoved, pathName);
//System.out.println("############# list1 " + list1);
//System.out.println("############# list2 " + list2);
//System.out.println("############# Set1 " + getChildNames(list1, pathName));
//System.out.println("############# Set2 " + getChildNames(list2, pathName));
//System.out.println("############# to remove " + elementNamesToBeRemoved);
//List res = getChildNames(list1, pathName);
//res.removeAll(elementNamesToBeRemoved);
//System.out.println("############# expected " + res);
//System.out.println("############# result " + result);
List onlyLegalNames = removeLegalNamesFromList(pathName, getChildNames(result, pathName));
result = elementsRetainDisplaynames(result, onlyLegalNames, pathName);
result = sort(result, pathName);
//System.out.println("#### repaired list = " + getChildNames(result, pathName));
return result;
}
private boolean existsInConfig(String path, String name) {
return this.configuration.contains(getPathName(path, name)) || this.configuration.contains("//"+name);
}
private List removeLegalNamesFromList(String path, List names) {
List result = new ArrayList(names);
Iterator iter = names.iterator();
while (iter.hasNext()){
String name = (String)iter.next();
if (existsInConfig(path, name)){
result.remove(name);;
}
}
return result;
}
private Integer getSingleResponseCode(List codes) {
Integer result = null;
if (codes.size() == 1) {
Iterator iter = codes.iterator();
result = (Integer)iter.next();
}
return result;
}
public boolean compareValues(String path, String name, String expectedValue, String receivedValue) {
boolean result = true;
// check now if this name is excluded from checking
if (existsInConfig(path, name)) {
return true;
}
if (expectedValue.trim().equals("") && expectedValue.trim().equals(receivedValue.trim())) return true;
// hard coded for now, should be configurable in the config file:
// allow multiple response codes to be checked against
if (getPathName(path, name).equals("/multistatus/response/status")) {
List expectedResponseCodes = TProcessors.responseStatus(expectedValue);
Integer receivedResponseCode = getSingleResponseCode(TProcessors.responseStatus(receivedValue));
// System.out.println("#### " + getPathName(path, name));
// System.out.println("#### " + value1 + " --> " + expectedResponseCodes);
// System.out.println("#### " + value2 + " --> " + receivedResponseCode);
if (receivedResponseCode != null &&
expectedResponseCodes.contains(receivedResponseCode)) return true;
}
// hard coded for now, should be configurable in the config file:
// allow multiple response codes to be checked against
if (getPathName(path, name).equals("/multistatus/response/propstat/status")) {
List expectedResponseCodes = TProcessors.responseStatus(expectedValue);
Integer receivedResponseCode = getSingleResponseCode(TProcessors.responseStatus(receivedValue));
// System.out.println("#### " + getPathName(path, name));
// System.out.println("#### " + value1 + " --> " + expectedResponseCodes);
// System.out.println("#### " + value2 + " --> " + receivedResponseCode);
if (receivedResponseCode != null &&
expectedResponseCodes.contains(receivedResponseCode)) return true;
}
// now perform the check and print out the error message
if (!expectedValue.trim().equals("*") &&
!doCompareValues(getPathName(path, name), expectedValue, receivedValue) ){
xmlresult.writeElementStart("XMLValueError");
xmlresult.writeElement("path", getPathName(path, name));
xmlresult.writeElement("expectedValue", expectedValue);
xmlresult.writeElement("receivedValue", receivedValue);
xmlresult.writeElementEnd("XMLValueError");
return false;
}
return result;
}
public boolean doCompareValues(String path, String received, String expected){
return expected.equals(received);
}
private List getChildNames(Element e, String pathName) {
return getChildNames(e.getChildren(), pathName);
}
private List getChildNames(List l, String pathName) {
List result = new ArrayList();
Iterator iter = l.iterator();
while (iter.hasNext()){
result.add(getDisplayName((Element)iter.next(), pathName));
}
return result;
}
private String getPathName(String path, String element) {
return path + "/" + element;
}
private String getPathName(String path, Element element) {
return getPathName(path, element.getName());
}
private List sort(List l, String pathName) {
List result = new ArrayList(l);
Collections.sort(result, new ElementComparator(pathName));
return result;
}
public boolean sortMultistatusResponseHrefElements() {
return true;
}
private String getDisplayName(Element e, String pathName) {
String result = null;
String fullPathName = getPathName(pathName, e.getName());
if (fullPathName.equals("/multistatus/response/href") && sortMultistatusResponseHrefElements() ) {
result = getPathName("/multistatus/response/href", getHrefNormalised(e.getTextTrim()));
} else if (fullPathName.equals("/multistatus/response") && e.getChild("href", e.getNamespace()) != null && sortMultistatusResponseHrefElements() ) {
result = getHrefNormalised(e.getChild("href", e.getNamespace()).getTextTrim());
} else if (fullPathName.equals("/multistatus/response/propstat/prop/workspace-checkout-set/href")) {
result = getHrefNormalised(e.getTextTrim());
} else if (fullPathName.equals("/multistatus/response/propstat") && e.getChild("status",e.getNamespace()) != null ) {
result = getPathName("/multistatus/response/propstat/status", e.getChildText("status",e.getNamespace()));
} else if (fullPathName.equals("/multistatus/response/propstat/prop/supported-report-set/supported-report") && e.getChild("report",e.getNamespace()) != null && e.getChildren().size() == 1) {
result = getPathName("/multistatus/response/propstat/prop/supported-report-set/supported-report/report",
((Element)e.getChild("report",e.getNamespace()).getChildren().get(0)).getName());
} else if (fullPathName.equals("/multistatus/response/propstat/prop/supported-live-property-set/supported-live-property") && e.getChild("prop",e.getNamespace()) != null && e.getChildren().size() == 1) {
result = getPathName("/multistatus/response/propstat/prop/supported-live-property-set/supported-live-property/prop",
((Element)e.getChild("prop",e.getNamespace()).getChildren().get(0)).getName());
} else if (fullPathName.equals("/multistatus/response/propstat/prop/supported-method-set/supported-method") && e.getAttribute("name") != null) {
result = getPathName(fullPathName, e.getAttributeValue("name"));
} else {
result = e.getName();
}
//System.out.println("##### get display name " + fullPathName + " --> " + result);
return result;
}
private String getHrefNormalised(String pathName) {
String result = pathName;
if (result.endsWith("/")){
result = result.substring(0,result.length()-1);
}
return result;
}
private List elementsMinusDisplaynames(List elementList, List displayNames, String pathName) {
List result = new ArrayList(elementList);
Iterator iter = elementList.iterator();
while (iter.hasNext()){
Element e = (Element)iter.next();
if (displayNames.contains(getDisplayName(e, pathName))) {
result.remove(e);
}
}
return result;
}
private List elementsRetainDisplaynames(List elementList, List displayNames, String pathName) {
List result = new ArrayList();
Iterator iter = elementList.iterator();
while (iter.hasNext()){
Element e = (Element)iter.next();
if (displayNames.contains(getDisplayName(e, pathName))) {
result.add(e);
}
}
return result;
}
private String listToString(List list) {
String result = null;
Iterator iter = list.iterator();
while (iter.hasNext()){
Object o = iter.next();
String s = null;
if (o instanceof String) {
s = (String)o;
}
else if(o instanceof Integer) {
s = ((Integer)o).toString();
}
else {
s = o.toString();
}
if (result != null) {
result += ", " + s;
}
else {
result = s;
}
}
return result;
}
/**************************************************************/
/* Inner class to help to create a suitable comparator */
/**************************************************************/
public class ElementComparator implements Comparator {
String pathName;
public ElementComparator(String pathName) {
this.pathName = pathName;
}
public int compare(Object o1, Object o2){
String s1 = getDisplayName(((Element)o1), pathName);
String s2 = getDisplayName(((Element)o2), pathName);
return (s1.compareTo(s2));
}
}
}