package org.testng.xml; import org.testng.TestNG; import org.testng.collections.Lists; import org.testng.collections.Maps; import org.testng.internal.AnnotationTypeEnum; import org.testng.reporters.XMLStringBuffer; import java.io.Serializable; import java.util.List; import java.util.Map; import java.util.Properties; /** * This class describes the tag <test> in testng.xml. * * @author <a href = "mailto:cedric@beust.com">Cedric Beust</a> * @author <a href = 'mailto:the_mindstorm[at]evolva[dot]ro'>Alexandru Popescu</a> */ public class XmlTest implements Serializable, Cloneable { public static int DEFAULT_TIMEOUT_MS = Integer.MAX_VALUE; private XmlSuite m_suite; private String m_name = TestNG.DEFAULT_COMMAND_LINE_SUITE_NAME; private Integer m_verbose = XmlSuite.DEFAULT_VERBOSE; private Boolean m_isJUnit = null; private int m_threadCount= -1; private List<XmlClass> m_xmlClasses = Lists.newArrayList(); private List<String> m_includedGroups = Lists.newArrayList(); private List<String> m_excludedGroups = Lists.newArrayList(); private final Map<String, List<String>> m_metaGroups = Maps.newHashMap(); private Map<String, String> m_parameters = Maps.newHashMap(); private String m_parallel; /** */ private AnnotationTypeEnum m_annotations; // BeanShell expression private String m_expression; private List<XmlMethodSelector> m_methodSelectors = Lists.newArrayList(); // test level packages private List<XmlPackage> m_xmlPackages = Lists.newArrayList(); private String m_timeOut; private Boolean m_skipFailedInvocationCounts = XmlSuite.DEFAULT_SKIP_FAILED_INVOCATION_COUNTS; private Map<String, List<Integer>> m_failedInvocationNumbers = null; // lazily initialized private String m_preserveOrder; /** * Constructs a <code>XmlTest</code> and adds it to suite's list of tests. * * @param suite the parent suite. */ public XmlTest(XmlSuite suite) { m_suite = suite; m_suite.getTests().add(this); } public void setXmlPackages(List<XmlPackage> packages) { m_xmlPackages = packages; } public List<XmlPackage> getXmlPackages() { return m_xmlPackages; } public List<XmlMethodSelector> getMethodSelectors() { return m_methodSelectors; } public void setMethodSelectors(List<XmlMethodSelector> methodSelectors) { m_methodSelectors = methodSelectors; } /** * Returns the suite this test is part of. * @return the suite this test is part of. */ public XmlSuite getSuite() { return m_suite; } /** * @return Returns the includedGroups. */ public List<String> getIncludedGroups() { return m_includedGroups; } /** * Sets the XML Classes. * @param classes The classes to set. * @deprecated use setXmlClasses */ @Deprecated public void setClassNames(List<XmlClass> classes) { m_xmlClasses = classes; } /** * @return Returns the classes. */ public List<XmlClass> getXmlClasses() { return m_xmlClasses; } /** * Sets the XML Classes. * @param classes The classes to set. */ public void setXmlClasses(List<XmlClass> classes) { m_xmlClasses = classes; } /** * @return Returns the name. */ public String getName() { return m_name; } /** * @param name The name to set. */ public void setName(String name) { m_name = name; } /** * @param v */ public void setVerbose(int v) { m_verbose = new Integer( v); } public int getThreadCount() { return m_threadCount > 0 ? m_threadCount : getSuite().getThreadCount(); } public void setThreadCount(int threadCount) { m_threadCount = threadCount; } /** * @param g */ public void setIncludedGroups(List<String> g) { m_includedGroups = g; } /** * @param g The excludedGrousps to set. */ public void setExcludedGroups(List<String> g) { m_excludedGroups = g; } /** * @return Returns the excludedGroups. */ public List<String> getExcludedGroups() { return m_excludedGroups; } /** * @return Returns the verbose. */ public int getVerbose() { Integer result = m_verbose; if (null == result || XmlSuite.DEFAULT_VERBOSE.equals(m_verbose)) { result = m_suite.getVerbose(); } if (null != result) { return result.intValue(); } else { return 1; } } /** * @return Returns the isJUnit. */ public boolean isJUnit() { Boolean result = m_isJUnit; if (null == result || XmlSuite.DEFAULT_JUNIT.equals(result)) { result = m_suite.isJUnit(); } return result; } /** * @param isJUnit The isJUnit to set. */ public void setJUnit(boolean isJUnit) { m_isJUnit = isJUnit; } public void setSkipFailedInvocationCounts(boolean skip) { m_skipFailedInvocationCounts = skip; } /** * @return Returns the isJUnit. */ public boolean skipFailedInvocationCounts() { Boolean result = m_skipFailedInvocationCounts; if (null == result) { result = m_suite.skipFailedInvocationCounts(); } return result; } public void addMetaGroup(String name, List<String> metaGroup) { m_metaGroups.put(name, metaGroup); } /** * @return Returns the metaGroups. */ public Map<String, List<String>> getMetaGroups() { return m_metaGroups; } /** * @param parameters */ public void setParameters(Map<String, String> parameters) { m_parameters = parameters; } public void addParameter(String key, String value) { m_parameters.put(key, value); } public String getParameter(String name) { String result = m_parameters.get(name); if (null == result) { result = m_suite.getParameter(name); } return result; } /** * Returns a merge of the the test parameters and its parent suite parameters. Test parameters * have precedence over suite parameters. * * @return a merge of the the test parameters and its parent suite parameters. */ public Map<String, String> getParameters() { Map<String, String> result = Maps.newHashMap(); Map<String, String> parameters = getSuite().getParameters(); for (Map.Entry<String, String> parameter : parameters.entrySet()) { result.put(parameter.getKey(), parameter.getValue()); } for (String key : m_parameters.keySet()) { result.put(key, m_parameters.get(key)); } return result; } public void setParallel(String parallel) { m_parallel = parallel; } public String getParallel() { String result = null; if (null != m_parallel || XmlSuite.DEFAULT_PARALLEL.equals(m_parallel)) { result = m_parallel; } else { result = m_suite.getParallel(); } return result; } public String getTimeOut() { String result = null; if (null != m_timeOut) { result = m_timeOut; } else { result = m_suite.getTimeOut(); } return result; } public long getTimeOut(long def) { long result = def; if (getTimeOut() != null) { result = new Long(getTimeOut()).longValue(); } return result; } public void setTimeOut(long timeOut) { m_timeOut = new Long(timeOut).toString(); } public String getAnnotations() { return null != m_annotations ? m_annotations.toString() : m_suite.getAnnotations(); } public void setAnnotations(String annotations) { m_annotations = AnnotationTypeEnum.valueOf(annotations); } public void setBeanShellExpression(String expression) { m_expression = expression; } public String getExpression() { return m_expression; } public String toXml(String indent) { XMLStringBuffer xsb = new XMLStringBuffer(indent); Properties p = new Properties(); p.setProperty("name", getName()); p.setProperty("junit", m_isJUnit != null ? m_isJUnit.toString() : "false"); if (null != m_parallel && !"".equals(m_parallel)) { p.setProperty("parallel", m_parallel); } if (null != m_verbose) { p.setProperty("verbose", m_verbose.toString()); } if (null != m_annotations) { p.setProperty("annotations", m_annotations.toString()); } if (null != m_timeOut) { p.setProperty("time-out", m_timeOut.toString()); } if (m_preserveOrder != null) { p.setProperty("preserve-order", m_preserveOrder.toString()); } xsb.push("test", p); if (null != getMethodSelectors() && !getMethodSelectors().isEmpty()) { xsb.push("method-selectors"); for (XmlMethodSelector selector: getMethodSelectors()) { xsb.getStringBuffer().append(selector.toXml(indent + " ")); } xsb.pop("method-selectors"); } // parameters if (!m_parameters.isEmpty()) { for(Map.Entry<String, String> para: m_parameters.entrySet()) { Properties paramProps= new Properties(); paramProps.setProperty("name", para.getKey()); paramProps.setProperty("value", para.getValue()); xsb.addEmptyElement("parameter", paramProps); // BUGFIX: TESTNG-27 } } // groups if (!m_metaGroups.isEmpty() || !m_includedGroups.isEmpty() || !m_excludedGroups.isEmpty()) { xsb.push("groups"); // define for (String metaGroupName: m_metaGroups.keySet()) { Properties metaGroupProp= new Properties(); metaGroupProp.setProperty("name", metaGroupName); xsb.push("define", metaGroupProp); for (String groupName: m_metaGroups.get(metaGroupName)) { Properties includeProps = new Properties(); includeProps.setProperty("name", groupName); xsb.addEmptyElement("include", includeProps); } xsb.pop("define"); } if (!m_includedGroups.isEmpty() || !m_excludedGroups.isEmpty()) { xsb.push("run"); for (String includeGroupName: m_includedGroups) { Properties includeProps = new Properties(); includeProps.setProperty("name", includeGroupName); xsb.addEmptyElement("include", includeProps); } for (String excludeGroupName: m_excludedGroups) { Properties excludeProps = new Properties(); excludeProps.setProperty("name", excludeGroupName); xsb.addEmptyElement("exclude", excludeProps); } xsb.pop("run"); } xsb.pop("groups"); } // HINT: don't call getXmlPackages() cause you will retrieve the suite packages too if (null != m_xmlPackages && !m_xmlPackages.isEmpty()) { xsb.push("packages"); for (XmlPackage pack: m_xmlPackages) { xsb.getStringBuffer().append(pack.toXml(" ")); } xsb.pop("packages"); } // classes if (null != getXmlClasses() && !getXmlClasses().isEmpty()) { xsb.push("classes"); for (XmlClass cls : getXmlClasses()) { xsb.getStringBuffer().append(cls.toXml(indent + " ")); } xsb.pop("classes"); } xsb.pop("test"); return xsb.toXML(); } @Override public String toString() { // return toXml(""); StringBuffer result = new StringBuffer("[Test: \"" + m_name + "\"") .append(" verbose:" + m_verbose); result.append("[parameters:"); for (String k : m_parameters.keySet()) { String v = m_parameters.get(k); result.append(k + "=>" + v); } result.append("]"); result.append("[metagroups:"); for (String g : m_metaGroups.keySet()) { List<String> mg = m_metaGroups.get(g); result.append(g).append("="); for (String n : mg) { result.append(n).append(","); } } result.append("] "); result.append("[included: "); for (String g : m_includedGroups) { result.append(g).append(" "); } result.append("]"); result.append("[excluded: "); for (String g : m_excludedGroups) { result.append(g).append(""); } result.append("] "); result.append(" classes:"); for (XmlClass cl : m_xmlClasses) { result.append(cl).append(" "); } result.append("] "); return result.toString(); } static void ppp(String s) { System.out.println("[XmlTest] " + s); } /** * Clone the <TT>source</TT> <CODE>XmlTest</CODE> by including: * - test attributes * - groups definitions * - parameters * * The <classes> sub element is ignored for the moment. * * @return a clone of the current XmlTest */ @Override public Object clone() { XmlTest result = new XmlTest(getSuite()); result.setName(getName()); result.setAnnotations(getAnnotations()); result.setIncludedGroups(getIncludedGroups()); result.setExcludedGroups(getExcludedGroups()); result.setJUnit(isJUnit()); result.setParallel(getParallel()); result.setVerbose(getVerbose()); result.setParameters(getParameters()); result.setXmlPackages(getXmlPackages()); Map<String, List<String>> metagroups = getMetaGroups(); for (Map.Entry<String, List<String>> group: metagroups.entrySet()) { result.addMetaGroup(group.getKey(), group.getValue()); } return result; } /** * Convenience method to cache the ordering numbers for methods. */ public List<Integer> getInvocationNumbers(String method) { if (m_failedInvocationNumbers == null) { m_failedInvocationNumbers = Maps.newHashMap(); for (XmlClass c : getXmlClasses()) { for (XmlInclude xi : c.getIncludedMethods()) { List<Integer> invocationNumbers = xi.getInvocationNumbers(); if (invocationNumbers.size() > 0) { String methodName = c.getName() + "." + xi.getName(); m_failedInvocationNumbers.put(methodName, invocationNumbers); } } } } List<Integer> result = m_failedInvocationNumbers.get(method); if (result == null) { // Don't use emptyList here since this list might end up receiving values if // the test run fails. return Lists.newArrayList(); } else { return result; } } public void setPreserveOrder(String preserveOrder) { m_preserveOrder = preserveOrder; } public String getPreserveOrder() { return m_preserveOrder; } public void setSuite(XmlSuite result) { m_suite = result; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((m_excludedGroups == null) ? 0 : m_excludedGroups.hashCode()); result = prime * result + ((m_expression == null) ? 0 : m_expression.hashCode()); result = prime * result + ((m_failedInvocationNumbers == null) ? 0 : m_failedInvocationNumbers .hashCode()); result = prime * result + ((m_includedGroups == null) ? 0 : m_includedGroups.hashCode()); result = prime * result + ((m_isJUnit == null) ? 0 : m_isJUnit.hashCode()); result = prime * result + ((m_metaGroups == null) ? 0 : m_metaGroups.hashCode()); result = prime * result + ((m_methodSelectors == null) ? 0 : m_methodSelectors.hashCode()); result = prime * result + ((m_name == null) ? 0 : m_name.hashCode()); result = prime * result + ((m_parallel == null) ? 0 : m_parallel.hashCode()); result = prime * result + ((m_parameters == null) ? 0 : m_parameters.hashCode()); result = prime * result + ((m_preserveOrder == null) ? 0 : m_preserveOrder.hashCode()); result = prime * result + ((m_skipFailedInvocationCounts == null) ? 0 : m_skipFailedInvocationCounts.hashCode()); result = prime * result + m_threadCount; result = prime * result + ((m_timeOut == null) ? 0 : m_timeOut.hashCode()); result = prime * result + ((m_verbose == null) ? 0 : m_verbose.hashCode()); result = prime * result + ((m_xmlClasses == null) ? 0 : m_xmlClasses.hashCode()); result = prime * result + ((m_xmlPackages == null) ? 0 : m_xmlPackages.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; XmlTest other = (XmlTest) obj; if (m_excludedGroups == null) { if (other.m_excludedGroups != null) return false; } else if (!m_excludedGroups.equals(other.m_excludedGroups)) return false; if (m_expression == null) { if (other.m_expression != null) return false; } else if (!m_expression.equals(other.m_expression)) return false; if (m_failedInvocationNumbers == null) { if (other.m_failedInvocationNumbers != null) return false; } else if (!m_failedInvocationNumbers .equals(other.m_failedInvocationNumbers)) return false; if (m_includedGroups == null) { if (other.m_includedGroups != null) return false; } else if (!m_includedGroups.equals(other.m_includedGroups)) return false; if (m_isJUnit == null) { if (other.m_isJUnit != null && ! other.m_isJUnit.equals(XmlSuite.DEFAULT_JUNIT)) return false; } else if (!m_isJUnit.equals(other.m_isJUnit)) return false; if (m_metaGroups == null) { if (other.m_metaGroups != null) return false; } else if (!m_metaGroups.equals(other.m_metaGroups)) return false; if (m_methodSelectors == null) { if (other.m_methodSelectors != null) return false; } else if (!m_methodSelectors.equals(other.m_methodSelectors)) return false; if (m_name == null) { if (other.m_name != null) return false; } else if (!m_name.equals(other.m_name)) return false; if (m_parallel == null) { if (other.m_parallel != null) return false; } else if (!m_parallel.equals(other.m_parallel)) return false; if (m_parameters == null) { if (other.m_parameters != null) return false; } else if (!m_parameters.equals(other.m_parameters)) return false; if (m_preserveOrder == null) { if (other.m_preserveOrder != null) return false; } else if (!m_preserveOrder.equals(other.m_preserveOrder)) return false; if (m_skipFailedInvocationCounts == null) { if (other.m_skipFailedInvocationCounts != null) return false; } else if (!m_skipFailedInvocationCounts .equals(other.m_skipFailedInvocationCounts)) return false; if (m_threadCount != other.m_threadCount) return false; if (m_timeOut == null) { if (other.m_timeOut != null) return false; } else if (!m_timeOut.equals(other.m_timeOut)) return false; if (m_verbose == null) { if (other.m_verbose != null) return false; } else if (!m_verbose.equals(other.m_verbose)) return false; if (m_xmlClasses == null) { if (other.m_xmlClasses != null) return false; } else if (!m_xmlClasses.equals(other.m_xmlClasses)) return false; if (m_xmlPackages == null) { if (other.m_xmlPackages != null) return false; } else if (!m_xmlPackages.equals(other.m_xmlPackages)) return false; return true; } }