package org.test4j.spec.scenario.step;
import static org.test4j.spec.scenario.step.xml.MethodDescription.VAR_START;
import java.util.Iterator;
import java.util.List;
import org.dom4j.CharacterData;
import org.dom4j.Element;
import org.test4j.spec.inner.IScenarioStep;
import org.test4j.spec.inner.StepType;
import org.test4j.spec.scenario.step.xml.MethodDescription;
import org.test4j.tools.commons.StringHelper;
@SuppressWarnings("serial")
public class XmlJSpecStep extends JSpecStep {
/**
* 是否有模板
*/
private boolean hasTemplate;
public XmlJSpecStep(String scenario, Element methodNode, List<IScenarioStep> templates) {
super(scenario);
String methodName = methodNode.attributeValue("name");
if (StringHelper.isBlankOrNull(methodName)) {
throw new RuntimeException("the jspec step method can't be empty.");
}
this.method = StringHelper.camel(methodName);
this.parseStepType(methodNode);
IScenarioStep template = JSpecStep.findTemplate(templates, this.method, this.type);
this.hasTemplate = template != null;
this.parseStep(methodNode, template);
}
@Override
public void parseStep(Object content, IScenarioStep template) {
if (!(content instanceof Element)) {
String error = String.format("the step content of XmlJSpecStep must be a xml element, but actual is %s",
content == null ? "<null>" : content.getClass().getName());
throw new RuntimeException(error);
}
Element element = (Element) content;
this.paras = this.initParameters(template);
this.parseParameter(element);
this.displayText = this.getText(element, template);
}
/**
* 解析设置 场景步骤的类型,以及该步骤是否被执行
*
* @param type
*/
private void parseStepType(Element element) {
String type = element.attributeValue("type");
if (StringHelper.isEmpty(type)) {
this.type = StepType.Step;
} else {
type = type.trim();
if ("given".equalsIgnoreCase(type)) {
this.type = StepType.Given;
} else if ("when".equalsIgnoreCase(type)) {
this.type = StepType.When;
} else if ("then".equalsIgnoreCase(type)) {
this.type = StepType.Then;
} else {
throw new RuntimeException(
"illegal step type, the method type must be one of following values: given, when, then. but actual is "
+ type + ".");
}
}
String skip = element.attributeValue("skip", "false");
this.isSkip = "true".equalsIgnoreCase(skip.trim());
}
/**
* 解析方法的参数列表
*
* @param element
*/
@SuppressWarnings("unchecked")
private void parseParameter(Element element) {
List<Element> paraNodes = element.selectNodes("para");
for (Element paraNode : paraNodes) {
String name = paraNode.attributeValue("name");
if (StringHelper.isEmpty(name)) {
String error = String.format("the parameter name of method[%s.%s] can't be empty!", this.scenario,
this.method);
throw new RuntimeException(error);
}
if (this.hasTemplate && !this.paras.containsKey(name)) {
String error = String.format("the template[%s] doesn't contain parameter[%s].", this.method, name);
throw new RuntimeException(error);
}
if (!this.hasTemplate && this.paras.containsKey(name)) {
String error = String.format("the method[%s] have duplicated parameter[%s].", this.method, name);
throw new RuntimeException(error);
}
String json = paraNode.getText().trim();
this.paras.put(name, json);
}
}
/**
* 获取方法描述信息
*
* @param xml
* @return
*/
protected String getText(Element element, IScenarioStep template) {
String templateText = "";
if (template != null) {
templateText = template.getDisplayText();
} else {
templateText = getTemplateText(this.method, element);
}
String text = new MethodDescription(templateText, this.paras).getMethodDisplayText();
return text;
}
/**
* 场景步骤模板
*
* @author darui.wudr
*/
public static class XmlJSpecStepTemplate extends XmlJSpecStep {
public XmlJSpecStepTemplate(Element methodNode) {
super("step template", methodNode, null);
}
@Override
protected String getText(Element element, IScenarioStep template) {
String text = getTemplateText(this.method, element);
return text;
}
}
/**
* 获取方法描述信息的模板内容,变量用$_#_@{var} 表示
*
* @param element
* @return
*/
public static String getTemplateText(String method, Element element) {
StringBuilder buff = new StringBuilder();
for (Iterator<?> it = element.nodeIterator(); it.hasNext();) {
Object item = it.next();
if (item instanceof CharacterData) {
String text = ((CharacterData) item).getText().trim();
//text = StoryFeature.convetTextToHTML(text);
buff.append(text);
} else if (item instanceof Element) {
Element para = (Element) item;
String tag = para.getName();
if ("para".equalsIgnoreCase(tag.trim())) {
String paraName = para.attributeValue("name");
if (StringHelper.isEmpty(paraName)) {
throw new RuntimeException("the parameter name of method[" + method + "] should be specified.");
}
buff.append(VAR_START + paraName + "}");
} else {
buff.append(para.getTextTrim());
}
}
}
return buff.toString();
}
}