1 package org.testng.internal; 2 3 import org.testng.xml.XmlClass; 4 import org.testng.xml.XmlInclude; 5 import org.testng.xml.XmlPackage; 6 import org.testng.xml.XmlSuite; 7 import org.testng.xml.XmlTest; 8 import org.yaml.snakeyaml.TypeDescription; 9 import org.yaml.snakeyaml.constructor.Constructor; 10 import org.yaml.snakeyaml.nodes.Node; 11 import org.yaml.snakeyaml.nodes.NodeId; 12 import org.yaml.snakeyaml.nodes.ScalarNode; 13 14 import java.io.File; 15 import java.io.FileInputStream; 16 import java.io.FileNotFoundException; 17 import java.io.InputStream; 18 import java.util.List; 19 import java.util.Map; 20 21 /** 22 * YAML support for TestNG. 23 * 24 * @author Cedric Beust <cedric (at) beust.com> 25 */ 26 public class Yaml { 27 28 public static XmlSuite parse(String filePath, InputStream is) 29 throws FileNotFoundException { 30 Constructor constructor = new TestNGConstructor(XmlSuite.class); 31 { 32 TypeDescription suiteDescription = new TypeDescription(XmlSuite.class); 33 suiteDescription.putListPropertyType("packages", XmlPackage.class); 34 suiteDescription.putListPropertyType("listeners", String.class); 35 suiteDescription.putListPropertyType("tests", XmlTest.class); 36 suiteDescription.putListPropertyType("method-selectors", XmlMethodSelector.class); 37 constructor.addTypeDescription(suiteDescription); 38 } 39 40 { 41 TypeDescription testDescription = new TypeDescription(XmlTest.class); 42 testDescription.putListPropertyType("classes", XmlClass.class); 43 testDescription.putMapPropertyType("metaGroups", String.class, List.class); 44 testDescription.putListPropertyType("method-selectors", XmlMethodSelector.class); 45 constructor.addTypeDescription(testDescription); 46 } 47 48 org.yaml.snakeyaml.Yaml y = new org.yaml.snakeyaml.Yaml(constructor); 49 if (is == null) is = new FileInputStream(new File(filePath)); 50 XmlSuite result = (XmlSuite) y.load(is); 51 52 result.setFileName(filePath); 53 // DEBUG 54 // System.out.println("[Yaml] " + result.toXml()); 55 56 // Adjust XmlTest parents and indices 57 for (XmlTest t : result.getTests()) { 58 t.setSuite(result); 59 int index = 0; 60 for (XmlClass c : t.getClasses()) { 61 c.setIndex(index++); 62 } 63 } 64 65 return result; 66 } 67 68 private static void maybeAdd(StringBuilder sb, String key, Object value, Object def) { 69 maybeAdd(sb, "", key, value, def); 70 } 71 72 private static void maybeAdd(StringBuilder sb, String sp, String key, Object value, Object def) { 73 if (value != null && ! value.equals(def)) { 74 sb.append(sp).append(key).append(": ").append(value.toString()).append("\n"); 75 } 76 } 77 78 /** 79 * The main entry point to convert an XmlSuite into YAML. This method is allowed to be used 80 * by external tools (e.g. Eclipse). 81 */ 82 public static StringBuilder toYaml(XmlSuite suite) { 83 StringBuilder result = new StringBuilder(); 84 85 maybeAdd(result, "name", suite.getName(), null); 86 maybeAdd(result, "junit", suite.isJUnit(), XmlSuite.DEFAULT_JUNIT); 87 maybeAdd(result, "verbose", suite.getVerbose(), XmlSuite.DEFAULT_VERBOSE); 88 maybeAdd(result, "threadCount", suite.getThreadCount(), XmlSuite.DEFAULT_THREAD_COUNT); 89 maybeAdd(result, "dataProviderThreadCount", suite.getDataProviderThreadCount(), 90 XmlSuite.DEFAULT_DATA_PROVIDER_THREAD_COUNT); 91 maybeAdd(result, "timeOut", suite.getTimeOut(), null); 92 maybeAdd(result, "parallel", suite.getParallel(), XmlSuite.DEFAULT_PARALLEL); 93 maybeAdd(result, "skipFailedInvocationCounts", suite.skipFailedInvocationCounts(), 94 XmlSuite.DEFAULT_SKIP_FAILED_INVOCATION_COUNTS); 95 96 toYaml(result, "parameters", "", suite.getParameters()); 97 toYaml(result, suite.getPackages()); 98 99 if (suite.getListeners().size() > 0) { 100 result.append("listeners:\n"); 101 toYaml(result, " ", suite.getListeners()); 102 } 103 104 if (suite.getPackages().size() > 0) { 105 result.append("packages:\n"); 106 toYaml(result, suite.getPackages()); 107 } 108 if (suite.getTests().size() > 0) { 109 result.append("tests:\n"); 110 for (XmlTest t : suite.getTests()) { 111 toYaml(result, " ", t); 112 } 113 } 114 115 if (suite.getChildSuites().size() > 0) { 116 result.append("suite-files:\n"); 117 toYaml(result, " ", suite.getSuiteFiles()); 118 } 119 120 return result; 121 } 122 123 private static void toYaml(StringBuilder result, String sp, XmlTest t) { 124 String sp2 = sp + " "; 125 result.append(sp).append("- name: ").append(t.getName()).append("\n"); 126 127 maybeAdd(result, sp2, "junit", t.isJUnit(), XmlSuite.DEFAULT_JUNIT); 128 maybeAdd(result, sp2, "verbose", t.getVerbose(), XmlSuite.DEFAULT_VERBOSE); 129 maybeAdd(result, sp2, "timeOut", t.getTimeOut(), null); 130 maybeAdd(result, sp2, "parallel", t.getParallel(), XmlSuite.DEFAULT_PARALLEL); 131 maybeAdd(result, sp2, "skipFailedInvocationCounts", t.skipFailedInvocationCounts(), 132 XmlSuite.DEFAULT_SKIP_FAILED_INVOCATION_COUNTS); 133 134 maybeAdd(result, "preserveOrder", sp2, t.getPreserveOrder(), XmlSuite.DEFAULT_PRESERVE_ORDER); 135 136 toYaml(result, "parameters", sp2, t.getTestParameters()); 137 138 if (t.getIncludedGroups().size() > 0) { 139 result.append(sp2).append("includedGroups: [ ") 140 .append(Utils.join(t.getIncludedGroups(), ",")) 141 .append(" ]\n"); 142 } 143 144 if (t.getExcludedGroups().size() > 0) { 145 result.append(sp2).append("excludedGroups: [ ") 146 .append(Utils.join(t.getExcludedGroups(), ",")) 147 .append(" ]\n"); 148 } 149 150 Map<String, List<String>> mg = t.getMetaGroups(); 151 if (mg.size() > 0) { 152 result.append(sp2).append("metaGroups: { "); 153 boolean first = true; 154 for (Map.Entry<String, List<String>> entry : mg.entrySet()) { 155 if (! first) result.append(", "); 156 result.append(entry.getKey()).append(": [ ") 157 .append(Utils.join(entry.getValue(), ",")).append(" ] "); 158 first = false; 159 } 160 result.append(" }\n"); 161 } 162 163 if (t.getXmlPackages().size() > 0) { 164 result.append(sp2).append("xmlPackages:\n"); 165 for (XmlPackage xp : t.getXmlPackages()) { 166 toYaml(result, sp2 + " - ", xp); 167 } 168 } 169 170 if (t.getXmlClasses().size() > 0) { 171 result.append(sp2).append("classes:\n"); 172 for (XmlClass xc : t.getXmlClasses()) { 173 toYaml(result, sp2 + " ", xc); 174 } 175 } 176 177 178 result.append("\n"); 179 } 180 181 private static void toYaml(StringBuilder result, String sp2, XmlClass xc) { 182 List<XmlInclude> im = xc.getIncludedMethods(); 183 List<String> em = xc.getExcludedMethods(); 184 String name = im.size() > 0 || em.size() > 0 ? "name: " : ""; 185 186 result.append(sp2).append("- " + name).append(xc.getName()).append("\n"); 187 if (im.size() > 0) { 188 result.append(sp2 + " includedMethods:\n"); 189 for (XmlInclude xi : im) { 190 toYaml(result, sp2 + " ", xi); 191 } 192 } 193 194 if (em.size() > 0) { 195 result.append(sp2 + " excludedMethods:\n"); 196 toYaml(result, sp2 + " ", em); 197 } 198 } 199 200 private static void toYaml(StringBuilder result, String sp2, XmlInclude xi) { 201 result.append(sp2 + "- " + xi.getName()).append("\n"); 202 } 203 204 private static void toYaml(StringBuilder result, String sp, List<String> strings) { 205 for (String l : strings) { 206 result.append(sp).append("- ").append(l).append("\n"); 207 } 208 } 209 210 private static final String SP = " "; 211 212 private static void toYaml(StringBuilder sb, List<XmlPackage> packages) { 213 if (packages.size() > 0) { 214 sb.append("packages:\n"); 215 for (XmlPackage p : packages) { 216 toYaml(sb, " ", p); 217 } 218 } 219 for (XmlPackage p : packages) { 220 toYaml(sb, " ", p); 221 } 222 } 223 224 private static void toYaml(StringBuilder sb, String sp, XmlPackage p) { 225 sb.append(sp).append("name: ").append(p.getName()).append("\n"); 226 227 generateIncludeExclude(sb, sp, "includes", p.getInclude()); 228 generateIncludeExclude(sb, sp, "excludes", p.getExclude()); 229 } 230 231 private static void generateIncludeExclude(StringBuilder sb, String sp, 232 String key, List<String> includes) { 233 if (includes.size() > 0) { 234 sb.append(sp).append(" ").append(key).append("\n"); 235 for (String inc : includes) { 236 sb.append(sp).append(" ").append(inc); 237 } 238 } 239 } 240 241 private static void mapToYaml(Map<String, String> map, StringBuilder out) { 242 if (map.size() > 0) { 243 out.append("{ "); 244 boolean first = true; 245 for (Map.Entry<String, String> e : map.entrySet()) { 246 if (! first) out.append(", "); 247 first = false; 248 out.append(e.getKey() + ": " + e.getValue()); 249 } 250 out.append(" }\n"); 251 } 252 } 253 254 private static void toYaml(StringBuilder sb, String key, String sp, 255 Map<String, String> parameters) { 256 if (parameters.size() > 0) { 257 sb.append(sp).append(key).append(": "); 258 mapToYaml(parameters, sb); 259 } 260 } 261 262 private static class TestNGConstructor extends Constructor { 263 public TestNGConstructor(Class<? extends Object> theRoot) { 264 super(theRoot); 265 yamlClassConstructors.put(NodeId.scalar, new ConstructParallelMode()); 266 } 267 268 private class ConstructParallelMode extends ConstructScalar { 269 public Object construct(Node node) { 270 if (node.getType().equals(XmlSuite.ParallelMode.class)) { 271 String parallel = (String) constructScalar((ScalarNode) node); 272 return XmlSuite.ParallelMode.getValidParallel(parallel); 273 } 274 return super.construct(node); 275 } 276 } 277 } 278 } 279