1package org.testng.xml;
2
3import org.testng.TestNGException;
4import org.testng.collections.Lists;
5import org.testng.collections.Maps;
6import org.testng.collections.Objects;
7import org.testng.internal.ClassHelper;
8import org.testng.reporters.XMLStringBuffer;
9
10import java.io.Serializable;
11import java.util.List;
12import java.util.Map;
13import java.util.Properties;
14
15/**
16 * This class describes the tag <class> in testng.xml.
17 *
18 * @author <a href="mailto:cedric@beust.com">Cedric Beust</a>
19 */
20public class XmlClass implements Serializable, Cloneable {
21
22  private static final long serialVersionUID = 8885360896966149897L;
23  private List<XmlInclude> m_includedMethods = Lists.newArrayList();
24  private List<String> m_excludedMethods = Lists.newArrayList();
25  private String m_name = null;
26  private Class m_class = null;
27  /** The index of this class in the <test> tag */
28  private int m_index;
29  /** True if the classes need to be loaded */
30  private boolean m_loadClasses = true;
31  private Map<String, String> m_parameters = Maps.newHashMap();
32  private XmlTest m_xmlTest;
33
34  public XmlClass() {
35    init("", null, 0, false /* load classes */);
36  }
37
38  public XmlClass(String name) {
39    init(name, null, 0);
40  }
41
42  public XmlClass(String name, boolean loadClasses) {
43    init(name, null, 0, loadClasses);
44  }
45
46  public XmlClass(Class cls) {
47    init(cls.getName(), cls, 0, true);
48  }
49
50  public XmlClass(Class cls, boolean loadClasses) {
51    init(cls.getName(), cls, 0, loadClasses);
52  }
53
54  public XmlClass(String className, int index) {
55    init(className, null, index, true /* load classes */);
56  }
57
58  public XmlClass(String className, int index, boolean loadClasses) {
59    init(className, null, index, loadClasses);
60  }
61
62  private void init(String className, Class cls, int index) {
63    init(className, cls, index, true /* load classes */);
64  }
65
66  private void init(String className, Class cls, int index,
67      boolean resolveClass) {
68    m_name = className;
69    m_class = cls;
70    m_index = index;
71
72    if (null == m_class && resolveClass) {
73      loadClass();
74    }
75  }
76
77  private void loadClass() {
78    m_class = ClassHelper.forName(m_name);
79
80    if (null == m_class) {
81      throw new TestNGException("Cannot find class in classpath: " + m_name);
82    }
83  }
84
85  /**
86   * @return Returns the className.
87   */
88  public Class getSupportClass() {
89    if (m_class == null) loadClass();
90    return m_class;
91  }
92
93  /**
94   * @param className The className to set.
95   */
96  public void setClass(Class className) {
97    m_class = className;
98  }
99
100  /**
101   * @return Returns the excludedMethods.
102   */
103  public List<String> getExcludedMethods() {
104    return m_excludedMethods;
105  }
106
107  /**
108   * @param excludedMethods The excludedMethods to set.
109   */
110  public void setExcludedMethods(List<String> excludedMethods) {
111    m_excludedMethods = excludedMethods;
112  }
113
114  /**
115   * @return Returns the includedMethods.
116   */
117  public List<XmlInclude> getIncludedMethods() {
118    return m_includedMethods;
119  }
120
121  /**
122   * @param includedMethods The includedMethods to set.
123   */
124  public void setIncludedMethods(List<XmlInclude> includedMethods) {
125    m_includedMethods = includedMethods;
126  }
127
128  /**
129   * @return Returns the name.
130   */
131  public String getName() {
132    return m_name;
133  }
134
135  /**
136   * @param name The name to set.
137   */
138  public void setName(String name) {
139    m_name = name;
140  }
141
142  /**
143   * @return true if the classes need to be loaded.
144   */
145  public boolean loadClasses() {
146    return m_loadClasses;
147  }
148
149  @Override
150  public String toString() {
151    return Objects.toStringHelper(getClass())
152        .add("class", m_name)
153        .toString();
154  }
155
156  public String toXml(String indent) {
157    XMLStringBuffer xsb = new XMLStringBuffer(indent);
158    Properties prop = new Properties();
159    prop.setProperty("name", getName());
160
161    boolean hasMethods = !m_includedMethods.isEmpty() || !m_excludedMethods.isEmpty();
162    boolean hasParameters = !m_parameters.isEmpty();
163    if (hasParameters || hasMethods) {
164      xsb.push("class", prop);
165      XmlUtils.dumpParameters(xsb, m_parameters);
166
167      if (hasMethods) {
168        xsb.push("methods");
169
170        for (XmlInclude m : getIncludedMethods()) {
171          xsb.getStringBuffer().append(m.toXml(indent + "    "));
172        }
173
174        for (String m: getExcludedMethods()) {
175          Properties p= new Properties();
176          p.setProperty("name", m);
177          xsb.addEmptyElement("exclude", p);
178        }
179
180        xsb.pop("methods");
181      }
182
183      xsb.pop("class");
184    }
185    else {
186      xsb.addEmptyElement("class", prop);
187    }
188
189    return xsb.toXML();
190
191  }
192
193  public static String listToString(List<Integer> invocationNumbers) {
194    StringBuilder result = new StringBuilder();
195    int i = 0;
196    for (Integer n : invocationNumbers) {
197      if (i++ > 0) {
198        result.append(" ");
199      }
200      result.append(n);
201    }
202    return result.toString();
203  }
204
205  /**
206   * Clone an XmlClass by copying all its components.
207   */
208  @Override
209  public Object clone() {
210    XmlClass result = new XmlClass(getName(), getIndex(), loadClasses());
211    result.setExcludedMethods(getExcludedMethods());
212    result.setIncludedMethods(getIncludedMethods());
213
214    return result;
215  }
216
217  /**
218   * Note that this attribute does not come from the XML file, it's calculated
219   * internally and represents the order in which this class was found in its
220   * &lt;test&gt; tag.  It's used to calculate the ordering of the classes
221   * when preserve-order is true.
222   */
223  public int getIndex() {
224    return m_index;
225  }
226
227  public void setIndex(int index) {
228    m_index = index;
229  }
230
231  @Override
232  public int hashCode() {
233    final int prime = 31;
234    int result = 1;
235    result = prime * result + ((m_class == null) ? 0 : m_class.hashCode());
236    result = prime * result + (m_loadClasses ? 1 : 0);
237    result = prime * result
238        + ((m_excludedMethods == null) ? 0 : m_excludedMethods.hashCode());
239    result = prime * result
240        + ((m_includedMethods == null) ? 0 : m_includedMethods.hashCode());
241    result = prime * result + m_index;
242    result = prime * result + ((m_name == null) ? 0 : m_name.hashCode());
243    return result;
244  }
245
246  @Override
247  public boolean equals(Object obj) {
248    if (this == obj) {
249      return true;
250    }
251    if (obj == null)
252      return XmlSuite.f();
253    if (getClass() != obj.getClass())
254      return XmlSuite.f();
255    XmlClass other = (XmlClass) obj;
256    if (other.m_loadClasses != m_loadClasses) {
257      return XmlSuite.f();
258    } else if (!m_excludedMethods.equals(other.m_excludedMethods)) {
259      return XmlSuite.f();
260    }
261    if (m_includedMethods == null) {
262      if (other.m_includedMethods != null)
263        return XmlSuite.f();
264    } else if (!m_includedMethods.equals(other.m_includedMethods))
265      return XmlSuite.f();
266//    if (m_index != other.m_index)
267//      return XmlSuite.f();
268    if (m_name == null) {
269      if (other.m_name != null)
270        return XmlSuite.f();
271    } else if (!m_name.equals(other.m_name))
272      return XmlSuite.f();
273
274    return true;
275  }
276
277  public void setParameters(Map<String, String> parameters) {
278    m_parameters.clear();
279    m_parameters.putAll(parameters);
280  }
281
282  /**
283   * @return The parameters defined in this test tag and the tags above it.
284   */
285  public Map<String, String> getAllParameters() {
286    Map<String, String> result = Maps.newHashMap();
287    Map<String, String> parameters = m_xmlTest.getLocalParameters();
288    result.putAll(parameters);
289    result.putAll(m_parameters);
290    return result;
291  }
292
293  /**
294   * @return The parameters defined in this tag, and only this test tag. To retrieve
295   * the inherited parameters as well, call {@code getAllParameters()}.
296   */
297  public Map<String, String> getLocalParameters() {
298    return m_parameters;
299  }
300
301  /**
302   * @deprecated Use {@code getLocalParameters()} or {@code getAllParameters()}
303   */
304  @Deprecated
305  public Map<String, String> getParameters() {
306    return getAllParameters();
307  }
308
309  public void setXmlTest(XmlTest test) {
310    m_xmlTest = test;
311  }
312}
313