1package org.testng.xml;
2
3import java.io.Serializable;
4import java.util.ArrayList;
5import java.util.List;
6import java.util.Map;
7import java.util.Properties;
8import java.util.UUID;
9
10import org.testng.TestNG;
11import org.testng.TestNGException;
12import org.testng.collections.Lists;
13import org.testng.collections.Maps;
14import org.testng.reporters.XMLStringBuffer;
15import org.testng.xml.dom.ParentSetter;
16
17/**
18 * This class describes the tag <test>  in testng.xml.
19 *
20 * @author <a href = "mailto:cedric&#64;beust.com">Cedric Beust</a>
21 * @author <a href = 'mailto:the_mindstorm[at]evolva[dot]ro'>Alexandru Popescu</a>
22 */
23public class XmlTest implements Serializable, Cloneable {
24  private static final long serialVersionUID = 6533504325942417606L;
25
26  public static final int DEFAULT_TIMEOUT_MS = Integer.MAX_VALUE;
27
28  private XmlSuite m_suite;
29  private String m_name;
30  private Integer m_verbose = XmlSuite.DEFAULT_VERBOSE;
31  private Boolean m_isJUnit = XmlSuite.DEFAULT_JUNIT;
32  private int m_threadCount= -1;
33
34  private List<XmlClass> m_xmlClasses = Lists.newArrayList();
35
36  private List<String> m_includedGroups = Lists.newArrayList();
37  private List<String> m_excludedGroups = Lists.newArrayList();
38
39  private Map<String, List<String>> m_metaGroups = Maps.newHashMap();
40  private Map<String, String> m_parameters = Maps.newHashMap();
41  private XmlSuite.ParallelMode m_parallel;
42
43  private List<XmlMethodSelector> m_methodSelectors = Lists.newArrayList();
44  // test level packages
45  private List<XmlPackage> m_xmlPackages = Lists.newArrayList();
46
47  private String m_timeOut;
48  private Boolean m_skipFailedInvocationCounts = XmlSuite.DEFAULT_SKIP_FAILED_INVOCATION_COUNTS;
49  private Map<String, List<Integer>> m_failedInvocationNumbers = null; // lazily initialized
50
51  private String m_preserveOrder = XmlSuite.DEFAULT_PRESERVE_ORDER;
52
53  private int m_index;
54
55  private Boolean m_groupByInstances;
56
57  private Boolean m_allowReturnValues = null;
58
59  private Map<String, String> m_xmlDependencyGroups = Maps.newHashMap();
60
61  /**
62   * Constructs a <code>XmlTest</code> and adds it to suite's list of tests.
63   *
64   * @param suite the parent suite.
65   * @param index the index of this test tag in testng.xml
66   */
67  public XmlTest(XmlSuite suite, int index) {
68    init(suite, index);
69  }
70
71  public XmlTest(XmlSuite suite) {
72    init(suite, 0);
73  }
74
75  private void init(XmlSuite suite, int index) {
76    m_suite = suite;
77    m_suite.getTests().add(this);
78    m_index = index;
79    //no two tests in the same suite should have the same name.
80    //so, make the default test name unique
81    m_name = TestNG.DEFAULT_COMMAND_LINE_TEST_NAME
82      + " " + UUID.randomUUID().toString();
83  }
84
85  // For YAML
86  public XmlTest() {
87  }
88
89  public void setXmlPackages(List<XmlPackage> packages) {
90    m_xmlPackages = Lists.newArrayList(packages);
91  }
92
93  public List<XmlPackage> getXmlPackages() {
94    return m_xmlPackages;
95  }
96
97  // For YAML
98  public List<XmlPackage> getPackages() {
99    return getXmlPackages();
100  }
101
102  // For YAML
103  public void setPackages(List<XmlPackage> p) {
104    setXmlPackages(p);
105  }
106
107  public List<XmlMethodSelector> getMethodSelectors() {
108    return m_methodSelectors;
109  }
110
111  public void setMethodSelectors(List<XmlMethodSelector> methodSelectors) {
112    m_methodSelectors = Lists.newArrayList(methodSelectors);
113  }
114
115  /**
116   * Returns the suite this test is part of.
117   * @return the suite this test is part of.
118   */
119  public XmlSuite getSuite() {
120    return m_suite;
121  }
122
123  /**
124   * @return the includedGroups.
125   * Note: do not modify the returned value, use {@link #addIncludedGroup(String)}.
126   */
127  public List<String> getIncludedGroups() {
128    List<String> result;
129    if (m_xmlGroups != null) {
130      result = m_xmlGroups.getRun().getIncludes();
131      result.addAll(m_suite.getIncludedGroups());
132    } else {
133      // deprecated
134      result = Lists.newArrayList(m_includedGroups);
135      result.addAll(m_suite.getIncludedGroups());
136    }
137    return result;
138  }
139
140  /**
141   * Sets the XML Classes.
142   * @param classes The classes to set.
143   * @deprecated use setXmlClasses
144   */
145  @Deprecated
146  public void setClassNames(List<XmlClass> classes) {
147    m_xmlClasses = classes;
148  }
149
150  /**
151   * @return Returns the classes.
152   */
153  public List<XmlClass> getXmlClasses() {
154    return m_xmlClasses;
155  }
156
157  // For YAML
158  public List<XmlClass> getClasses() {
159    return getXmlClasses();
160  }
161
162  // For YAML
163  public void setClasses(List<XmlClass> c) {
164    setXmlClasses(c);
165  }
166
167  /**
168   * Sets the XML Classes.
169   * @param classes The classes to set.
170   */
171  public void setXmlClasses(List<XmlClass> classes) {
172    m_xmlClasses = classes;
173  }
174
175  /**
176   * @return Returns the name.
177   */
178  public String getName() {
179    return m_name;
180  }
181
182  /**
183   * @param name The name to set.
184   */
185  public void setName(String name) {
186    m_name = name;
187  }
188
189  /**
190   * @param v
191   */
192  public void setVerbose(int v) {
193    m_verbose = v;
194  }
195
196  public int getThreadCount() {
197    return m_threadCount > 0 ? m_threadCount : getSuite().getThreadCount();
198  }
199
200  public void setThreadCount(int threadCount) {
201    m_threadCount = threadCount;
202  }
203
204  /**
205   * @param g
206   */
207  public void setIncludedGroups(List<String> g) {
208    m_includedGroups = g;
209  }
210
211  /**
212   * @param g The excludedGrousps to set.
213   */
214  public void setExcludedGroups(List<String> g) {
215    m_excludedGroups = g;
216  }
217
218  /**
219   * @return Returns the excludedGroups.
220   * Note: do not modify the returned value, use {@link #addExcludedGroup(String)}.
221   */
222  public List<String> getExcludedGroups() {
223    List<String> result = new ArrayList(m_excludedGroups);
224    result.addAll(m_suite.getExcludedGroups());
225    return result;
226  }
227
228  public void addIncludedGroup(String g) {
229    m_includedGroups.add(g);
230  }
231
232  public void addExcludedGroup(String g) {
233    m_excludedGroups.add(g);
234  }
235
236  /**
237   * @return Returns the verbose.
238   */
239  public int getVerbose() {
240    Integer result = m_verbose;
241    if (null == result || XmlSuite.DEFAULT_VERBOSE.equals(m_verbose)) {
242      result = m_suite.getVerbose();
243    }
244
245    if (null != result) {
246      return result;
247    } else {
248      return 1;
249    }
250  }
251
252  public boolean getGroupByInstances() {
253    Boolean result = m_groupByInstances;
254    if (result == null || XmlSuite.DEFAULT_GROUP_BY_INSTANCES.equals(m_groupByInstances)) {
255      result = m_suite.getGroupByInstances();
256    }
257    if (result != null) {
258      return result;
259    } else {
260      return XmlSuite.DEFAULT_GROUP_BY_INSTANCES;
261    }
262  }
263
264  public void setGroupByInstances(boolean f) {
265    m_groupByInstances = f;
266  }
267
268  /**
269   * @return Returns the isJUnit.
270   */
271  public boolean isJUnit() {
272    Boolean result = m_isJUnit;
273    if (null == result || XmlSuite.DEFAULT_JUNIT.equals(result)) {
274      result = m_suite.isJUnit();
275    }
276
277    return result;
278  }
279
280  /**
281   * @param isJUnit The isJUnit to set.
282   */
283  public void setJUnit(boolean isJUnit) {
284    m_isJUnit = isJUnit;
285  }
286
287  // For YAML
288  public void setJunit(boolean isJUnit) {
289    setJUnit(isJUnit);
290  }
291
292  public void setSkipFailedInvocationCounts(boolean skip) {
293    m_skipFailedInvocationCounts = skip;
294  }
295
296  /**
297   * @return Returns the isJUnit.
298   */
299  public boolean skipFailedInvocationCounts() {
300    Boolean result = m_skipFailedInvocationCounts;
301    if (null == result) {
302      result = m_suite.skipFailedInvocationCounts();
303    }
304
305    return result;
306  }
307
308  public void addMetaGroup(String name, List<String> metaGroup) {
309    m_metaGroups.put(name, metaGroup);
310  }
311
312  // For YAML
313  public void setMetaGroups(Map<String, List<String>> metaGroups) {
314    m_metaGroups = metaGroups;
315  }
316
317  /**
318   * @return Returns the metaGroups.
319   */
320  public Map<String, List<String>> getMetaGroups() {
321    if (m_xmlGroups != null) {
322      Map<String, List<String>> result = Maps.newHashMap();
323      List<XmlDefine> defines = m_xmlGroups.getDefines();
324      for (XmlDefine xd : defines) {
325        result.put(xd.getName(), xd.getIncludes());
326      }
327      return result;
328    } else {
329      // deprecated
330      return m_metaGroups;
331    }
332  }
333
334  /**
335   * @param parameters
336   */
337  public void setParameters(Map<String, String> parameters) {
338    m_parameters = parameters;
339  }
340
341  public void addParameter(String key, String value) {
342    m_parameters.put(key, value);
343  }
344
345  public String getParameter(String name) {
346    String result = m_parameters.get(name);
347    if (null == result) {
348      result = m_suite.getParameter(name);
349    }
350
351    return result;
352  }
353
354  /**
355   * @return the parameters defined in this test tag and the tags above it.
356   */
357  public Map<String, String> getAllParameters() {
358    Map<String, String> result = Maps.newHashMap();
359    result.putAll(getSuite().getParameters());
360    result.putAll(m_parameters);
361    return result;
362  }
363
364  /**
365   * @return the parameters defined in this tag, and only this test tag. To retrieve
366   * the inherited parameters as well, call {@code getAllParameters()}.
367   */
368  public Map<String, String> getLocalParameters() {
369    return m_parameters;
370  }
371
372  /**
373   * @deprecated Use {@code getLocalParameters()} or {@code getAllParameters()}
374   */
375  @Deprecated
376  public Map<String, String> getParameters() {
377    return getAllParameters();
378  }
379
380  /**
381   * @return the parameters defined on this <test> tag only
382   */
383  public Map<String, String> getTestParameters() {
384    return m_parameters;
385  }
386
387  public void setParallel(XmlSuite.ParallelMode parallel) {
388    m_parallel = parallel;
389  }
390
391  public XmlSuite.ParallelMode getParallel() {
392    XmlSuite.ParallelMode result;
393    if (null != m_parallel || XmlSuite.DEFAULT_PARALLEL.equals(m_parallel)) {
394      result = m_parallel;
395    }
396    else {
397      result = m_suite.getParallel();
398    }
399
400    return result;
401  }
402
403  public String getTimeOut() {
404    String result = null;
405    if (null != m_timeOut) {
406      result = m_timeOut;
407    }
408    else {
409      result = m_suite.getTimeOut();
410    }
411
412    return result;
413  }
414
415  public long getTimeOut(long def) {
416    long result = def;
417    if (getTimeOut() != null) {
418        result = Long.parseLong(getTimeOut());
419    }
420
421    return result;
422  }
423
424  public void setTimeOut(long timeOut) {
425      m_timeOut = Long.toString(timeOut);
426  }
427
428  private void setTimeOut(String timeOut) {
429      m_timeOut = timeOut;
430  }
431
432  public void setExpression(String expression) {
433    setBeanShellExpression(expression);
434  }
435
436  public void setBeanShellExpression(String expression) {
437    List<XmlMethodSelector> selectors = getMethodSelectors();
438    if (selectors.size() > 0) {
439      selectors.get(0).setExpression(expression);
440    } else if (expression != null) {
441      XmlMethodSelector xms = new XmlMethodSelector();
442      xms.setExpression(expression);
443      xms.setLanguage("BeanShell");
444      getMethodSelectors().add(xms);
445    }
446  }
447
448  public String getExpression() {
449    List<XmlMethodSelector> selectors = getMethodSelectors();
450    if (selectors.size() > 0) {
451      return selectors.get(0).getExpression();
452    } else {
453      return null;
454    }
455  }
456
457  public String toXml(String indent) {
458    XMLStringBuffer xsb = new XMLStringBuffer(indent);
459    Properties p = new Properties();
460    p.setProperty("name", getName());
461    if (m_isJUnit != null) {
462      XmlUtils.setProperty(p, "junit", m_isJUnit.toString(), XmlSuite.DEFAULT_JUNIT.toString());
463    }
464    if (m_parallel != null) {
465      XmlUtils.setProperty(p, "parallel", m_parallel.toString(), XmlSuite.DEFAULT_PARALLEL.toString());
466    }
467    if (m_verbose != null) {
468      XmlUtils.setProperty(p, "verbose", m_verbose.toString(), XmlSuite.DEFAULT_VERBOSE.toString());
469    }
470    if (null != m_timeOut) {
471      p.setProperty("time-out", m_timeOut.toString());
472    }
473    if (m_preserveOrder != null && ! XmlSuite.DEFAULT_PRESERVE_ORDER.equals(m_preserveOrder)) {
474      p.setProperty("preserve-order", m_preserveOrder.toString());
475    }
476    if (m_threadCount != -1) {
477      p.setProperty("thread-count", Integer.toString(m_threadCount));
478    }
479    if (m_groupByInstances != null) {
480      XmlUtils.setProperty(p, "group-by-instances", String.valueOf(getGroupByInstances()),
481          XmlSuite.DEFAULT_GROUP_BY_INSTANCES.toString());
482    }
483
484    xsb.push("test", p);
485
486
487    if (null != getMethodSelectors() && !getMethodSelectors().isEmpty()) {
488      xsb.push("method-selectors");
489      for (XmlMethodSelector selector: getMethodSelectors()) {
490        xsb.getStringBuffer().append(selector.toXml(indent + "    "));
491      }
492
493      xsb.pop("method-selectors");
494    }
495
496    XmlUtils.dumpParameters(xsb, m_parameters);
497
498    // groups
499    if (!m_metaGroups.isEmpty() || !m_includedGroups.isEmpty() || !m_excludedGroups.isEmpty()
500        || !m_xmlDependencyGroups.isEmpty()) {
501      xsb.push("groups");
502
503      // define
504      for (Map.Entry<String, List<String>> entry: m_metaGroups.entrySet()) {
505        String metaGroupName = entry.getKey();
506        List<String> groupNames = entry.getValue();
507
508        Properties metaGroupProp= new Properties();
509        metaGroupProp.setProperty("name",  metaGroupName);
510
511        xsb.push("define", metaGroupProp);
512
513        for (String groupName: groupNames) {
514          Properties includeProps = new Properties();
515          includeProps.setProperty("name", groupName);
516
517          xsb.addEmptyElement("include", includeProps);
518        }
519
520        xsb.pop("define");
521      }
522
523      // run
524      if (!m_includedGroups.isEmpty() || !m_excludedGroups.isEmpty()) {
525        xsb.push("run");
526
527        for (String includeGroupName: m_includedGroups) {
528          Properties includeProps = new Properties();
529          includeProps.setProperty("name", includeGroupName);
530
531          xsb.addEmptyElement("include", includeProps);
532        }
533
534        for (String excludeGroupName: m_excludedGroups) {
535          Properties excludeProps = new Properties();
536          excludeProps.setProperty("name", excludeGroupName);
537
538          xsb.addEmptyElement("exclude", excludeProps);
539        }
540
541        xsb.pop("run");
542      }
543
544      // group dependencies
545      if (m_xmlDependencyGroups != null && ! m_xmlDependencyGroups.isEmpty()) {
546        xsb.push("dependencies");
547        for (Map.Entry<String, String> entry : m_xmlDependencyGroups.entrySet()) {
548          xsb.addEmptyElement("group", "name", entry.getKey(), "depends-on", entry.getValue());
549        }
550        xsb.pop("dependencies");
551      }
552
553      xsb.pop("groups");
554    }
555
556    if (null != m_xmlPackages && !m_xmlPackages.isEmpty()) {
557      xsb.push("packages");
558
559      for (XmlPackage pack: m_xmlPackages) {
560        xsb.getStringBuffer().append(pack.toXml("      "));
561      }
562
563      xsb.pop("packages");
564    }
565
566    // classes
567    if (null != getXmlClasses() && !getXmlClasses().isEmpty()) {
568      xsb.push("classes");
569      for (XmlClass cls : getXmlClasses()) {
570        xsb.getStringBuffer().append(cls.toXml(indent + "    "));
571      }
572      xsb.pop("classes");
573    }
574
575    xsb.pop("test");
576
577    return xsb.toXML();
578  }
579
580  @Override
581  public String toString() {
582//    return toXml("");
583    StringBuilder result = new StringBuilder("[Test: \"")
584            .append(m_name)
585            .append("\"")
586            .append(" verbose:")
587            .append(m_verbose);
588
589    result.append("[parameters:");
590    for (Map.Entry<String, String> entry : m_parameters.entrySet()) {
591      result.append(entry.getKey()).append("=>").append(entry.getValue());
592    }
593
594    result.append("]");
595    result.append("[metagroups:");
596    for (Map.Entry<String, List<String>> entry : m_metaGroups.entrySet()) {
597      result.append(entry.getKey()).append("=");
598      for (String n : entry.getValue()) {
599        result.append(n).append(",");
600      }
601    }
602    result.append("] ");
603
604    result.append("[included: ");
605    for (String g : m_includedGroups) {
606      result.append(g).append(" ");
607    }
608    result.append("]");
609
610    result.append("[excluded: ");
611    for (String g : m_excludedGroups) {
612      result.append(g).append(" ");
613    }
614    result.append("] ");
615
616    result.append(" classes:");
617    for (XmlClass cl : m_xmlClasses) {
618      result.append(cl).append(" ");
619    }
620
621    result.append(" packages:");
622    for (XmlPackage p : m_xmlPackages) {
623      result.append(p).append(" ");
624    }
625
626    result.append("] ");
627
628    return result.toString();
629  }
630
631  static void ppp(String s) {
632    System.out.println("[XmlTest] " + s);
633  }
634
635  /**
636   * Clone the <TT>source</TT> <CODE>XmlTest</CODE> by including:
637   * - test attributes
638   * - groups definitions
639   * - parameters
640   *
641   * The &lt;classes&gt; sub element is ignored for the moment.
642   *
643   * @return a clone of the current XmlTest
644   */
645  @Override
646  public Object clone() {
647    XmlTest result = new XmlTest(getSuite());
648
649    result.setName(getName());
650    result.setIncludedGroups(getIncludedGroups());
651    result.setExcludedGroups(getExcludedGroups());
652    result.setJUnit(isJUnit());
653    result.setParallel(getParallel());
654    result.setVerbose(getVerbose());
655    result.setParameters(getLocalParameters());
656    result.setXmlPackages(getXmlPackages());
657    result.setTimeOut(getTimeOut());
658
659    Map<String, List<String>> metagroups = getMetaGroups();
660    for (Map.Entry<String, List<String>> group: metagroups.entrySet()) {
661      result.addMetaGroup(group.getKey(), group.getValue());
662    }
663
664    return result;
665  }
666
667  /**
668   * Convenience method to cache the ordering numbers for methods.
669   */
670  public List<Integer> getInvocationNumbers(String method) {
671    if (m_failedInvocationNumbers == null) {
672      m_failedInvocationNumbers = Maps.newHashMap();
673      for (XmlClass c : getXmlClasses()) {
674        for (XmlInclude xi : c.getIncludedMethods()) {
675          List<Integer> invocationNumbers = xi.getInvocationNumbers();
676          if (invocationNumbers.size() > 0) {
677            String methodName = c.getName() + "." + xi.getName();
678            m_failedInvocationNumbers.put(methodName, invocationNumbers);
679          }
680        }
681      }
682    }
683
684    List<Integer> result = m_failedInvocationNumbers.get(method);
685    if (result == null) {
686      // Don't use emptyList here since this list might end up receiving values if
687      // the test run fails.
688      return Lists.newArrayList();
689    } else {
690      return result;
691    }
692  }
693
694  public void setPreserveOrder(String preserveOrder) {
695    m_preserveOrder = preserveOrder;
696  }
697
698  public String getPreserveOrder() {
699    String result = m_preserveOrder;
700    if (result == null || XmlSuite.DEFAULT_PRESERVE_ORDER.equals(m_preserveOrder)) {
701      result = m_suite.getPreserveOrder();
702    }
703
704    return result;
705  }
706
707  public void setSuite(XmlSuite result) {
708    m_suite = result;
709  }
710
711  public Boolean getAllowReturnValues() {
712    if (m_allowReturnValues != null) return m_allowReturnValues;
713    else return getSuite().getAllowReturnValues();
714  }
715
716  public void setAllowReturnValues(Boolean allowReturnValues) {
717    m_allowReturnValues = allowReturnValues;
718  }
719
720  /**
721   * Note that this attribute does not come from the XML file, it's calculated
722   * internally and represents the order in which this test tag was found in its
723   * &lt;suite&gt; tag.  It's used to calculate the ordering of the tests
724   * when preserve-test-order is true.
725   */
726  public int getIndex() {
727    return m_index;
728  }
729
730  @Override
731  public int hashCode() {
732    final int prime = 31;
733    int result = 1;
734    result = prime * result
735        + ((m_excludedGroups == null) ? 0 : m_excludedGroups.hashCode());
736    result = prime
737        * result
738        + ((m_failedInvocationNumbers == null) ? 0 : m_failedInvocationNumbers
739            .hashCode());
740    result = prime * result
741        + ((m_includedGroups == null) ? 0 : m_includedGroups.hashCode());
742    result = prime * result + ((m_isJUnit == null) ? 0 : m_isJUnit.hashCode());
743    result = prime * result
744        + ((m_metaGroups == null) ? 0 : m_metaGroups.hashCode());
745    result = prime * result
746        + ((m_methodSelectors == null) ? 0 : m_methodSelectors.hashCode());
747    result = prime * result + ((m_name == null) ? 0 : m_name.hashCode());
748    result = prime * result
749        + ((m_parallel == null) ? 0 : m_parallel.hashCode());
750    result = prime * result
751        + ((m_parameters == null) ? 0 : m_parameters.hashCode());
752    result = prime * result
753        + ((m_preserveOrder == null) ? 0 : m_preserveOrder.hashCode());
754    result = prime
755        * result
756        + ((m_skipFailedInvocationCounts == null) ? 0
757            : m_skipFailedInvocationCounts.hashCode());
758    result = prime * result + m_threadCount;
759    result = prime * result + ((m_timeOut == null) ? 0 : m_timeOut.hashCode());
760    result = prime * result + ((m_verbose == null) ? 0 : m_verbose.hashCode());
761    result = prime * result
762        + ((m_xmlClasses == null) ? 0 : m_xmlClasses.hashCode());
763    result = prime * result
764        + ((m_xmlPackages == null) ? 0 : m_xmlPackages.hashCode());
765    return result;
766  }
767
768  @Override
769  public boolean equals(Object obj) {
770    if (this == obj) {
771      return true;
772    }
773    if (obj == null)
774      return XmlSuite.f();
775    if (getClass() != obj.getClass())
776      return XmlSuite.f();
777    XmlTest other = (XmlTest) obj;
778    if (m_excludedGroups == null) {
779      if (other.m_excludedGroups != null)
780        return XmlSuite.f();
781    } else if (!m_excludedGroups.equals(other.m_excludedGroups))
782      return XmlSuite.f();
783//    if (m_expression == null) {
784//      if (other.m_expression != null)
785//        return XmlSuite.f();
786//    } else if (!m_expression.equals(other.m_expression))
787//      return XmlSuite.f();
788    if (m_failedInvocationNumbers == null) {
789      if (other.m_failedInvocationNumbers != null)
790        return XmlSuite.f();
791    } else if (!m_failedInvocationNumbers
792        .equals(other.m_failedInvocationNumbers))
793      return XmlSuite.f();
794    if (m_includedGroups == null) {
795      if (other.m_includedGroups != null)
796        return XmlSuite.f();
797    } else if (!m_includedGroups.equals(other.m_includedGroups))
798      return XmlSuite.f();
799    if (m_isJUnit == null) {
800      if (other.m_isJUnit != null && ! other.m_isJUnit.equals(XmlSuite.DEFAULT_JUNIT))
801        return XmlSuite.f();
802    } else if (!m_isJUnit.equals(other.m_isJUnit))
803      return XmlSuite.f();
804    if (m_metaGroups == null) {
805      if (other.m_metaGroups != null)
806        return XmlSuite.f();
807    } else if (!m_metaGroups.equals(other.m_metaGroups))
808      return XmlSuite.f();
809    if (m_methodSelectors == null) {
810      if (other.m_methodSelectors != null)
811        return XmlSuite.f();
812    } else if (!m_methodSelectors.equals(other.m_methodSelectors))
813      return XmlSuite.f();
814    if (m_name == null) {
815      if (other.m_name != null)
816        return XmlSuite.f();
817    } else if (!m_name.equals(other.m_name))
818      return XmlSuite.f();
819    if (m_parallel == null) {
820      if (other.m_parallel != null)
821        return XmlSuite.f();
822    } else if (!m_parallel.equals(other.m_parallel))
823      return XmlSuite.f();
824    if (m_parameters == null) {
825      if (other.m_parameters != null)
826        return XmlSuite.f();
827    } else if (!m_parameters.equals(other.m_parameters))
828      return XmlSuite.f();
829    if (m_preserveOrder == null) {
830      if (other.m_preserveOrder != null)
831        return XmlSuite.f();
832    } else if (!m_preserveOrder.equals(other.m_preserveOrder))
833      return XmlSuite.f();
834    if (m_skipFailedInvocationCounts == null) {
835      if (other.m_skipFailedInvocationCounts != null)
836        return XmlSuite.f();
837    } else if (!m_skipFailedInvocationCounts
838        .equals(other.m_skipFailedInvocationCounts))
839      return XmlSuite.f();
840    if (m_threadCount != other.m_threadCount)
841      return XmlSuite.f();
842    if (m_timeOut == null) {
843      if (other.m_timeOut != null)
844        return XmlSuite.f();
845    } else if (!m_timeOut.equals(other.m_timeOut))
846      return XmlSuite.f();
847    if (m_verbose == null) {
848      if (other.m_verbose != null)
849        return XmlSuite.f();
850    } else if (!m_verbose.equals(other.m_verbose))
851      return XmlSuite.f();
852    if (m_xmlClasses == null) {
853      if (other.m_xmlClasses != null)
854        return XmlSuite.f();
855    } else if (!m_xmlClasses.equals(other.m_xmlClasses))
856      return XmlSuite.f();
857    if (m_xmlPackages == null) {
858      if (other.m_xmlPackages != null)
859        return XmlSuite.f();
860    } else if (!m_xmlPackages.equals(other.m_xmlPackages))
861      return XmlSuite.f();
862
863    return true;
864  }
865
866  public void addXmlDependencyGroup(String group, String dependsOn) {
867    if (! m_xmlDependencyGroups.containsKey(group)) {
868      m_xmlDependencyGroups.put(group, dependsOn);
869    } else {
870      throw new TestNGException("Duplicate group dependency found for group \"" + group + "\""
871          + ", use a space-separated list of groups in the \"depends-on\" attribute");
872    }
873  }
874
875  public Map<String, String> getXmlDependencyGroups() {
876    if (m_xmlGroups != null) {
877      Map<String, String> result = Maps.newHashMap();
878      List<XmlDependencies> deps = m_xmlGroups.getDependencies();
879      for (XmlDependencies d : deps) {
880        result.putAll(d.getDependencies());
881      }
882      return result;
883    } else {
884      // deprecated
885      return m_xmlDependencyGroups;
886    }
887  }
888
889  @ParentSetter
890  public void setXmlSuite(XmlSuite suite) {
891	  m_suite = suite;
892  }
893
894  private XmlGroups m_xmlGroups;
895
896  public void setGroups(XmlGroups xmlGroups) {
897    m_xmlGroups = xmlGroups;
898  }
899}
900