/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.test.remote;
import gw.lang.reflect.IType;
import gw.lang.reflect.TypeSystem;
import gw.xml.simple.SimpleXmlNode;
import junit.framework.AssertionFailedError;
import java.util.ArrayList;
import java.util.List;
public class RemoteTestResult {
public static final String SUCCESS_ATTRIBUTE = "success";
public static final String ROOT_ELEMENT = "RemoteTestResult";
private boolean _success = true;
private ExceptionInfo _exceptionInfo;
public static class ExceptionInfo {
private String _className;
private String _message;
private StackTraceElement[] _stackTrace;
private ExceptionInfo _cause;
public static final String ELEMENT_NAME = "ExceptionInfo";
public static final String CLASS_NAME_ATTRIBUTE = "className";
public static final String MESSAGE_ATTRIBUTE = "message";
public static final String STACK_TRACE_ELEMENT_NAME = "StackTrace";
public static final String STACK_TRACE_ELEMENT_ELEMENT_NAME = "StackTraceElement";
public static final String STACK_TRACE_ELEMENT_DECLARING_CLASS_ATTRIBUTE = "declaringClass";
public static final String STACK_TRACE_ELEMENT_METHOD_NAME_ATTRIBUTE = "methodName";
public static final String STACK_TRACE_ELEMENT_FILE_NAME_ATTRIBUTE = "fileName";
public static final String STACK_TRACE_ELEMENT_LINE_NUMBER_ATTRIBUTE = "lineNumber";
public static final String CAUSE_ELEMENT_NAME = "Cause";
public static ExceptionInfo fromXml(SimpleXmlNode xmlNode) {
String className = xmlNode.getAttributes().get(CLASS_NAME_ATTRIBUTE);
String message = xmlNode.getAttributes().get(MESSAGE_ATTRIBUTE);
SimpleXmlNode stackNode = xmlNode.getChildren().get(0);
// TODO - Assert it's the right thing
List<StackTraceElement> stes = new ArrayList<StackTraceElement>();
for (SimpleXmlNode steNode : stackNode.getChildren()) {
stes.add(new StackTraceElement(
steNode.getAttributes().get(STACK_TRACE_ELEMENT_DECLARING_CLASS_ATTRIBUTE),
steNode.getAttributes().get(STACK_TRACE_ELEMENT_METHOD_NAME_ATTRIBUTE),
steNode.getAttributes().get(STACK_TRACE_ELEMENT_FILE_NAME_ATTRIBUTE),
Integer.valueOf(steNode.getAttributes().get(STACK_TRACE_ELEMENT_LINE_NUMBER_ATTRIBUTE))
));
}
ExceptionInfo cause = null;
if (xmlNode.getChildren().size() > 1) {
SimpleXmlNode causeNode = xmlNode.getChildren().get(1);
cause = fromXml(causeNode.getChildren().get(0));
}
return new ExceptionInfo(className, message, stes.toArray(new StackTraceElement[stes.size()]), cause);
}
public static ExceptionInfo fromThrowable(Throwable t) {
ExceptionInfo causeExceptionInfo = null;
Throwable cause = t.getCause();
if (cause != null && cause != t) {
causeExceptionInfo = fromThrowable(cause);
}
IType type = TypeSystem.getFromObject( t );
if ( type == null ) {
t.printStackTrace();
throw new IllegalStateException( "Unable to determine type from throwable: " + t );
}
return new ExceptionInfo( type.getName(), t.getMessage(), t.getStackTrace(), causeExceptionInfo);
}
private ExceptionInfo(String className, String message, StackTraceElement[] stackTrace, ExceptionInfo cause) {
_className = className;
_message = message;
_stackTrace = stackTrace;
_cause = cause;
}
public String getClassName() {
return _className;
}
public String getMessage() {
return _message;
}
public StackTraceElement[] getStackTrace() {
return _stackTrace;
}
public ExceptionInfo getCause() {
return _cause;
}
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
public Throwable toThrowable() {
if (_className.equals(AssertionFailedError.class.getName())) {
return new RemoteAssertionFailedError(_message, _className, _stackTrace);
} else {
return new RemoteTestException(_message, _cause == null ? null : _cause.toThrowable(), _className, _stackTrace);
}
}
public SimpleXmlNode toXml() {
SimpleXmlNode root = new SimpleXmlNode(ELEMENT_NAME);
root.getAttributes().put(CLASS_NAME_ATTRIBUTE, _className);
root.getAttributes().put(MESSAGE_ATTRIBUTE, _message);
SimpleXmlNode stack = new SimpleXmlNode(STACK_TRACE_ELEMENT_NAME);
root.getChildren().add(stack);
for (StackTraceElement ste : _stackTrace) {
SimpleXmlNode stackTraceElement = new SimpleXmlNode(STACK_TRACE_ELEMENT_ELEMENT_NAME);
stackTraceElement.getAttributes().put(STACK_TRACE_ELEMENT_DECLARING_CLASS_ATTRIBUTE, ste.getClassName());
stackTraceElement.getAttributes().put(STACK_TRACE_ELEMENT_METHOD_NAME_ATTRIBUTE, ste.getMethodName());
stackTraceElement.getAttributes().put(STACK_TRACE_ELEMENT_FILE_NAME_ATTRIBUTE, ste.getFileName());
stackTraceElement.getAttributes().put(STACK_TRACE_ELEMENT_LINE_NUMBER_ATTRIBUTE, "" + ste.getLineNumber());
stack.getChildren().add(stackTraceElement);
}
if (_cause != null) {
SimpleXmlNode cause = new SimpleXmlNode(CAUSE_ELEMENT_NAME);
cause.getChildren().add(_cause.toXml());
root.getChildren().add(cause);
}
return root;
}
}
public String toXML() {
SimpleXmlNode root = new SimpleXmlNode(ROOT_ELEMENT);
root.getAttributes().put(SUCCESS_ATTRIBUTE, Boolean.toString(_success));
if (_exceptionInfo != null) {
root.getChildren().add(_exceptionInfo.toXml());
}
return root.toXmlString();
}
public boolean successful() {
return _success;
}
public void setException(Throwable t) {
_success = false;
_exceptionInfo = ExceptionInfo.fromThrowable(t);
}
// Exposed for testing purposes only
ExceptionInfo getExceptionInfo() {
return _exceptionInfo;
}
public Throwable recreateException() {
return _exceptionInfo.toThrowable();
}
public static RemoteTestResult fromXML(String xml) {
RemoteTestResult result = new RemoteTestResult();
// TODO - Assert that the root has the right name
// TODO - Assert that if it's not successful, there must be a stack trace
SimpleXmlNode resultNode = SimpleXmlNode.parse(xml);
result._success = Boolean.valueOf(resultNode.getAttributes().get(SUCCESS_ATTRIBUTE));
if (resultNode.getChildren().size() > 0) {
// TODO - AHK - Assert it's the right node
result._exceptionInfo = ExceptionInfo.fromXml(resultNode.getChildren().get(0));
}
return result;
}
}