package org.testng.xml; import org.testng.collections.Lists; import org.testng.internal.AnnotationTypeEnum; import org.testng.log4testng.Logger; import org.testng.reporters.XMLStringBuffer; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Properties; /** * Wrapper for real suites and custom configured suites. * Should only be used for integration purposes; creating a custom testng.xml * * @author <a href='mailto:the_mindstorm@evolva.ro'>Alexandru Popescu</a> */ public abstract class LaunchSuite { /** This class's log4testng Logger. */ private static final Logger LOGGER = Logger.getLogger(LaunchSuite.class); protected boolean m_temporary; /** * Constructs a <code>LaunchSuite</code> * * @param isTemp the temporary status */ protected LaunchSuite(boolean isTemp) { m_temporary = isTemp; } /** * Returns the temporary state. * @return the temporary state. */ public boolean isTemporary() { return m_temporary; } /** * Saves the suite file in the specified directory and returns the file * pathname. * * @param directory the directory where the suite file is to be saved. * @return the file pathname of the saved file. */ public abstract File save(File directory); /** * <code>ExistingSuite</code> is a non-temporary LaunchSuite based on an existing * file. */ public static class ExistingSuite extends LaunchSuite { /** * The existing suite path (either relative to the project root or an absolute path) */ private File m_suitePath; /** * Constructs a <code>ExistingSuite</code> based on an existing file * * @param path the path to the existing Launch suite. */ public ExistingSuite(File path) { super(false); m_suitePath = path; } /** * {@inheritDoc} This implementation saves nothing because the suite file already * exists. */ @Override public File save(File directory) { return m_suitePath; } } /** * <code>CustomizedSuite</code> TODO cquezel JavaDoc. */ private abstract static class CustomizedSuite extends LaunchSuite { protected String m_projectName; protected String m_suiteName; /** The annotation type. May be null. */ protected AnnotationTypeEnum m_annotationType; protected Map<String, String> m_parameters; /** The string buffer used to write the XML file. */ private XMLStringBuffer m_suiteBuffer; /** * Constructs a <code>CustomizedSuite</code> TODO cquezel JavaDoc. * * @param projectName * @param className * @param parameters * @param annotationType */ private CustomizedSuite(final String projectName, final String className, final Map<String, String> parameters, final String annotationType) { super(true); m_projectName = projectName; m_suiteName = className; m_parameters = parameters; m_annotationType = annotationType == null ? null : AnnotationTypeEnum.valueOf(annotationType, false); } /** * TODO cquezel JavaDoc * * @return */ protected XMLStringBuffer createContentBuffer() { XMLStringBuffer suiteBuffer = new XMLStringBuffer(""); //$NON-NLS-1$ suiteBuffer.setDocType("suite SYSTEM \"" + Parser.TESTNG_DTD_URL + "\""); Properties attrs = new Properties(); attrs.setProperty("parallel", XmlSuite.PARALLEL_NONE); attrs.setProperty("name", m_suiteName); suiteBuffer.push("suite", attrs); if (m_parameters != null) { for (Map.Entry<String, String> entry : m_parameters.entrySet()) { Properties paramAttrs = new Properties(); paramAttrs.setProperty("name", entry.getKey()); paramAttrs.setProperty("value", entry.getValue()); suiteBuffer.push("parameter", paramAttrs); suiteBuffer.pop("parameter"); } } initContentBuffer(suiteBuffer); suiteBuffer.pop("suite"); return suiteBuffer; } /** * TODO cquezel JavaDoc * * @return */ private XMLStringBuffer getSuiteBuffer() { if (null == m_suiteBuffer) { m_suiteBuffer = createContentBuffer(); } return m_suiteBuffer; } /** * Initializes the content of the xml string buffer. * * @param suiteBuffer the string buffer to initialize. */ protected abstract void initContentBuffer(XMLStringBuffer suiteBuffer); /** * {@inheritDoc} This implementation saves the suite to the "temp-testng-customsuite.xml" * file in the specified directory. */ @Override public File save(File directory) { final File suiteFile = new File(directory, "temp-testng-customsuite.xml"); saveSuiteContent(suiteFile, getSuiteBuffer()); return suiteFile; } /** * Saves the content of the string buffer to the specified file. * * @param file the file to write to. * @param content the content to write to the file. */ protected void saveSuiteContent(final File file, final XMLStringBuffer content) { try { FileWriter fw = new FileWriter(file); try { fw.write(content.getStringBuffer().toString()); } finally { fw.close(); } } catch (IOException ioe) { // TODO CQ is this normal to swallow exception here LOGGER.error("IO Exception", ioe); } } } /** * A <code>MethodsSuite</code> is a suite made up of methods. */ static class MethodsSuite extends CustomizedSuite { protected Collection<String> m_methodNames; protected String m_className; protected int m_logLevel; /** * Constructs a <code>MethodsSuite</code> TODO cquezel JavaDoc. * * @param projectName * @param className * @param methodNames * @param parameters * @param annotationType (may be null) * @param logLevel */ MethodsSuite(final String projectName, final String className, final Collection<String> methodNames, final Map<String, String> parameters, final String annotationType, final int logLevel) { super(projectName, className, parameters, annotationType); m_className = className; m_methodNames = methodNames; m_logLevel = logLevel; } /** * {@inheritDoc} */ @Override protected void initContentBuffer(XMLStringBuffer suiteBuffer) { Properties testAttrs = new Properties(); testAttrs.setProperty("name", m_className); if (m_annotationType != null) { testAttrs.setProperty("annotations", m_annotationType.getName()); } testAttrs.setProperty("verbose", String.valueOf(m_logLevel)); suiteBuffer.push("test", testAttrs); suiteBuffer.push("classes"); Properties classAttrs = new Properties(); classAttrs.setProperty("name", m_className); if ((null != m_methodNames) && (m_methodNames.size() > 0)) { suiteBuffer.push("class", classAttrs); suiteBuffer.push("methods"); for (Object methodName : m_methodNames) { Properties methodAttrs = new Properties(); methodAttrs.setProperty("name", (String) methodName); suiteBuffer.addEmptyElement("include", methodAttrs); } suiteBuffer.pop("methods"); suiteBuffer.pop("class"); } else { suiteBuffer.addEmptyElement("class", classAttrs); } suiteBuffer.pop("classes"); suiteBuffer.pop("test"); } } static class ClassesAndMethodsSuite extends CustomizedSuite { protected Map<String, Collection<String>> m_classes; protected int m_logLevel; ClassesAndMethodsSuite(final String projectName, final Map<String, Collection<String>> classes, final Map<String, String> parameters, final String annotationType, final int logLevel) { super(projectName, "Custom suite", parameters, annotationType); m_classes = classes; m_logLevel = logLevel; } /** * {@inheritDoc} */ @Override protected void initContentBuffer(XMLStringBuffer suiteBuffer) { Properties testAttrs = new Properties(); testAttrs.setProperty("name", m_projectName); if (m_annotationType != null) { testAttrs.setProperty("annotations", m_annotationType.getName()); } testAttrs.setProperty("verbose", String.valueOf(m_logLevel)); suiteBuffer.push("test", testAttrs); suiteBuffer.push("classes"); for(Map.Entry<String, Collection<String>> entry : m_classes.entrySet()) { Properties classAttrs = new Properties(); classAttrs.setProperty("name", entry.getKey()); Collection<String> methodNames= sanitize(entry.getValue()); if ((null != methodNames) && (methodNames.size() > 0)) { suiteBuffer.push("class", classAttrs); suiteBuffer.push("methods"); for (String methodName : methodNames) { Properties methodAttrs = new Properties(); methodAttrs.setProperty("name", methodName); suiteBuffer.addEmptyElement("include", methodAttrs); } suiteBuffer.pop("methods"); suiteBuffer.pop("class"); } else { suiteBuffer.addEmptyElement("class", classAttrs); } } suiteBuffer.pop("classes"); suiteBuffer.pop("test"); } private Collection<String> sanitize(Collection<String> source) { if(null == source) return null; List<String> result= Lists.newArrayList(); for(String name: source) { if(!"".equals(name)) { result.add(name); } } return result; } } /** * <code>ClassListSuite</code> TODO cquezel JavaDoc. */ static class ClassListSuite extends CustomizedSuite { protected Collection<String> m_packageNames; protected Collection<String> m_classNames; protected Collection<String> m_groupNames; protected int m_logLevel; ClassListSuite(final String projectName, final Collection<String> packageNames, final Collection<String> classNames, final Collection<String> groupNames, final Map<String, String> parameters, final String annotationType, final int logLevel) { super(projectName, "Custom suite", parameters, annotationType); m_packageNames = packageNames; m_classNames = classNames; m_groupNames = groupNames; m_logLevel = logLevel; } /** * {@inheritDoc} */ @Override protected void initContentBuffer(XMLStringBuffer suiteBuffer) { Properties testAttrs = new Properties(); testAttrs.setProperty("name", m_projectName); if (m_annotationType != null) { testAttrs.setProperty("annotations", m_annotationType.getName()); } testAttrs.setProperty("verbose", String.valueOf(m_logLevel)); suiteBuffer.push("test", testAttrs); if (null != m_groupNames) { suiteBuffer.push("groups"); suiteBuffer.push("run"); for (String groupName : m_groupNames) { Properties includeAttrs = new Properties(); includeAttrs.setProperty("name", groupName); suiteBuffer.addEmptyElement("include", includeAttrs); } suiteBuffer.pop("run"); suiteBuffer.pop("groups"); } // packages belongs to suite according to the latest DTD if ((m_packageNames != null) && (m_packageNames.size() > 0)) { suiteBuffer.push("packages"); for (String packageName : m_packageNames) { Properties packageAttrs = new Properties(); packageAttrs.setProperty("name", packageName); suiteBuffer.addEmptyElement("package", packageAttrs); } suiteBuffer.pop("packages"); } if ((m_classNames != null) && (m_classNames.size() > 0)) { suiteBuffer.push("classes"); for (String className : m_classNames) { Properties classAttrs = new Properties(); classAttrs.setProperty("name", className); suiteBuffer.addEmptyElement("class", classAttrs); } suiteBuffer.pop("classes"); } suiteBuffer.pop("test"); } } }