Home | History | Annotate | Download | only in internal
      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