1 package org.testng.xml.dom;
2 
3 import org.testng.collections.Lists;
4 import org.testng.collections.Maps;
5 import org.testng.xml.XmlClass;
6 import org.testng.xml.XmlSuite;
7 import org.testng.xml.XmlTest;
8 import org.w3c.dom.Document;
9 import org.w3c.dom.Element;
10 import org.w3c.dom.Node;
11 import org.w3c.dom.NodeList;
12 
13 import javax.xml.xpath.XPath;
14 import javax.xml.xpath.XPathExpressionException;
15 import javax.xml.xpath.XPathFactory;
16 
17 import java.lang.reflect.InvocationTargetException;
18 import java.lang.reflect.Method;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.Map;
22 
23 public class DomUtil {
24 
25   private XPath m_xpath;
26   private Document m_document;
27 
DomUtil(Document doc)28   public DomUtil(Document doc) {
29     XPathFactory xpathFactory = XPathFactory.newInstance();
30     m_xpath = xpathFactory.newXPath();
31     m_document = doc;
32   }
33 
populate(final XmlSuite xmlSuite)34   public void populate(final XmlSuite xmlSuite) throws XPathExpressionException {
35     NodeList nodes = m_document.getChildNodes();
36     final Map<String, String> parameters = Maps.newHashMap();
37     for (int i = 0; i < nodes.getLength(); i++) {
38       Node item1 = nodes.item(i);
39 
40       Map<String, NodeProcessor> map = Maps.newHashMap();
41       map.put("parameter", new NodeProcessor() {
42         @Override
43         public void process(Node node) {
44           Element e = (Element) node;
45           parameters.put(e.getAttribute("name"), e.getAttribute("value"));
46         }
47       });
48       map.put("test", new NodeProcessor() {
49         @Override
50         public void process(Node node) {
51           XmlTest xmlTest = new XmlTest(xmlSuite);
52           populateTest(xmlTest, node);
53         }
54       });
55       map.put("suite-files", new NodeProcessor() {
56         @Override
57         public void process(Node node) {
58           NodeList item2Children = node.getChildNodes();
59           List<String> suiteFiles = Lists.newArrayList();
60           for (int k = 0; k < item2Children.getLength(); k++) {
61             Node item3 = item2Children.item(k);
62             if (item3 instanceof Element) {
63               Element e = (Element) item3;
64               if ("suite-file".equals(item3.getNodeName())) {
65                 suiteFiles.add(e.getAttribute("path"));
66               }
67             }
68           }
69           xmlSuite.setSuiteFiles(suiteFiles);
70         }
71       });
72       parseNodeAndChildren("suite", item1, xmlSuite, map);
73 
74 //      if ("suite".equals(item1.getNodeName()) && item1.getAttributes() != null) {
75 //        populateAttributes(item1, xmlSuite);
76 //        NodeList item1Children = item1.getChildNodes();
77 //        for (int j = 0; j < item1Children.getLength(); j++) {
78 //          Node item2 = item1Children.item(j);
79 //          if ("parameter".equals(item2.getNodeName())) {
80 //            Element e = (Element) item2;
81 //            parameters.put(e.getAttribute("name"), e.getAttribute("value"));
82 //          } else if ("test".equals(item2.getNodeName())) {
83 //            XmlTest xmlTest = new XmlTest(xmlSuite);
84 //            populateTest(xmlTest, item2);
85 //          } else if ("suite-files".equals(item2.getNodeName())) {
86 //            NodeList item2Children = item2.getChildNodes();
87 //            List<String> suiteFiles = Lists.newArrayList();
88 //            for (int k = 0; k < item2Children.getLength(); k++) {
89 //              Node item3 = item2Children.item(k);
90 //              if (item3 instanceof Element) {
91 //                Element e = (Element) item3;
92 //                if ("suite-file".equals(item3.getNodeName())) {
93 //                  suiteFiles.add(e.getAttribute("path"));
94 //                }
95 //              }
96 //            }
97 //            xmlSuite.setSuiteFiles(suiteFiles);
98 //          }
99 //        }
100 //      }
101     }
102 
103     xmlSuite.setParameters(parameters);
104 //    XPathExpression expr = m_xpath.compile("//suite/test");
105 //    NodeList tests = (NodeList) expr.evaluate(m_document, XPathConstants.NODESET);
106 //    for (int i = 0; i < tests.getLength(); i++) {
107 //      Node node = tests.item(i);
108 //      System.out.println("<test>:" + node);
109 //    }
110   }
111 
112   public static interface NodeProcessor {
process(Node node)113     void process(Node node);
114   }
115 
parseNodeAndChildren(String name, Node root, Object object, Map<String, NodeProcessor> processors)116   private void parseNodeAndChildren(String name, Node root, Object object,
117       Map<String, NodeProcessor> processors) throws XPathExpressionException {
118     if (name.equals(root.getNodeName()) && root.getAttributes() != null) {
119       populateAttributes(root, object);
120       NodeList children = root.getChildNodes();
121       for (int j = 0; j < children.getLength(); j++) {
122         Node item2 = children.item(j);
123         String nodeName = item2.getNodeName();
124         NodeProcessor proc = processors.get(nodeName);
125         if (proc != null) {
126           proc.process(item2);
127         } else if (! nodeName.startsWith("#")){
128           throw new RuntimeException("No processor found for " + nodeName);
129         }
130 //        if ("parameter".equals(item2.getNodeName())) {
131 //          Element e = (Element) item2;
132 //          parameters.put(e.getAttribute("name"), e.getAttribute("value"));
133 //        }
134       }
135     }
136   }
137 
findChildren(Node node, String name)138     public static Iterator<Node> findChildren(Node node, String name) {
139     List<Node> result = Lists.newArrayList();
140     NodeList children = node.getChildNodes();
141     for (int i = 0; i < children.getLength(); i++) {
142       Node n = children.item(i);
143       if (name.equals(n.getNodeName())) {
144         result.add(n);
145       }
146     }
147     return result.iterator();
148   }
149 
populateTest(XmlTest xmlTest, Node item)150   private void populateTest(XmlTest xmlTest, Node item) {
151     Map<String, String> testParameters = Maps.newHashMap();
152     populateAttributes(item, xmlTest);
153     NodeList itemChildren = item.getChildNodes();
154     for (int k = 0; k < itemChildren.getLength(); k++) {
155       Node item2 = itemChildren.item(k);
156       if ("parameter".equals(item2.getNodeName())) {
157         Element e = (Element) item2;
158         testParameters.put(e.getAttribute("name"), e.getAttribute("value"));
159       } else if ("classes".equals(item2.getNodeName())) {
160         NodeList item2Children = item2.getChildNodes();
161         for (int l = 0; l < item2Children.getLength(); l++) {
162           Node item4 = item2Children.item(l);
163           if ("class".equals(item4.getNodeName())) {
164             XmlClass xmlClass = new XmlClass();
165             populateAttributes(item4, xmlClass);
166             xmlTest.getClasses().add(xmlClass);
167 
168             // TODO: excluded/included methods
169           }
170         }
171       } else if ("groups".equals(item2.getNodeName())) {
172         NodeList item2Children = item2.getChildNodes();
173         List<String> includes = Lists.newArrayList();
174         List<String> excludes = Lists.newArrayList();
175         for (int l = 0; l < item2Children.getLength(); l++) {
176           Node item3 = item2Children.item(l);
177           if ("run".equals(item3.getNodeName())) {
178             NodeList item3Children = item3.getChildNodes();
179             for (int m = 0; m < item3Children.getLength(); m++) {
180               Node item4 = item3Children.item(m);
181               if ("include".equals(item4.getNodeName())) {
182                 includes.add(((Element) item4).getAttribute("name"));
183               } else if ("exclude".equals(item4.getNodeName())) {
184                 excludes.add(((Element) item4).getAttribute("name"));
185               }
186             }
187           } else if ("dependencies".equals(item3.getNodeName())) {
188             NodeList item3Children = item3.getChildNodes();
189             for (int m = 0; m < item3Children.getLength(); m++) {
190               Node item4 = item3Children.item(m);
191               if ("group".equals(item4.getNodeName())) {
192                 Element e = (Element) item4;
193                 xmlTest.addXmlDependencyGroup(e.getAttribute("name"), e.getAttribute("depends-on"));
194               }
195             }
196           } else if ("define".equals(item3.getNodeName())) {
197             xmlDefine(xmlTest, item3);
198           }
199         }
200         xmlTest.setIncludedGroups(includes);
201         xmlTest.setExcludedGroups(excludes);
202       } // TODO: (method-selectors?,packages?) >
203     }
204 
205     xmlTest.setParameters(testParameters);
206   }
207 
208   /**
209    * Parse the <define> tag.
210    */
xmlDefine(XmlTest xmlTest, Node item)211   private void xmlDefine(XmlTest xmlTest, Node item) {
212     NodeList item3Children = item.getChildNodes();
213     List<String> groups = Lists.newArrayList();
214     for (int m = 0; m < item3Children.getLength(); m++) {
215       Node item4 = item3Children.item(m);
216       if ("include".equals(item4.getNodeName())) {
217         Element e = (Element) item4;
218         groups.add(e.getAttribute("name"));
219       }
220     }
221     xmlTest.addMetaGroup(((Element) item).getAttribute("name"), groups);
222   }
223 
populateAttributes(Node node, Object object)224   private void populateAttributes(Node node, Object object) {
225     for (int j = 0; j < node.getAttributes().getLength(); j++) {
226       Node item = node.getAttributes().item(j);
227       p(node.getAttributes().item(j).toString());
228       setProperty(object, item.getLocalName(), item.getNodeValue());
229     }
230   }
231 
setProperty(Object object, String name, Object value)232   private void setProperty(Object object, String name, Object value) {
233     String methodName = toCamelCaseSetter(name);
234     Method foundMethod = null;
235     for (Method m : object.getClass().getDeclaredMethods()) {
236       if (m.getName().equals(methodName)) {
237         foundMethod = m;
238         break;
239       }
240     }
241 
242     if (foundMethod == null) {
243       p("Warning: couldn't find setter method " + methodName);
244     } else {
245       try {
246         p("Invoking " + methodName + " with " + value);
247         Class<?> type = foundMethod.getParameterTypes()[0];
248         if (type == Boolean.class || type == boolean.class) {
249           foundMethod.invoke(object, Boolean.parseBoolean(value.toString()));
250         } else if (type == Integer.class || type == int.class) {
251           foundMethod.invoke(object, Integer.parseInt(value.toString()));
252         } else {
253           foundMethod.invoke(object, value.toString());
254         }
255       } catch (IllegalArgumentException | InvocationTargetException | IllegalAccessException e) {
256         e.printStackTrace();
257       }
258     }
259   }
260 
p(String string)261   private void p(String string) {
262 //    System.out.println("[XPathUtil] " + string);
263   }
264 
toCamelCaseSetter(String name)265   private String toCamelCaseSetter(String name) {
266     StringBuilder result = new StringBuilder("set" + name.substring(0, 1).toUpperCase());
267     for (int i = 1; i < name.length(); i++) {
268       if (name.charAt(i) == '-') {
269         result.append(Character.toUpperCase(name.charAt(i + 1)));
270         i++;
271       } else {
272         result.append(name.charAt(i));
273       }
274     }
275     return result.toString();
276   }
277 }
278