blob: dbf347ceb330a16f92ffa521474a582583150387 [file] [log] [blame]
package org.testng.xml.dom;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathExpressionException;
import org.testng.Assert;
import org.testng.collections.ListMultiMap;
import org.testng.collections.Lists;
import org.testng.internal.collections.Pair;
import org.testng.xml.XmlDefine;
import org.testng.xml.XmlGroups;
import org.testng.xml.XmlMethodSelector;
import org.testng.xml.XmlSuite;
import org.testng.xml.XmlTest;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.SAXException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class XDom {
// private static Map<String, Class<?>> m_map = Maps.newHashMap();
private Document m_document;
private ITagFactory m_tagFactory;
public XDom(ITagFactory tagFactory, Document document)
throws XPathExpressionException,
InstantiationException, IllegalAccessException {
m_tagFactory = tagFactory;
m_document = document;
}
public Object parse() throws XPathExpressionException,
InstantiationException, IllegalAccessException, SecurityException,
IllegalArgumentException, NoSuchMethodException,
InvocationTargetException {
Object result = null;
NodeList nodes = m_document.getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
Node item = nodes.item(i);
if (item.getAttributes() != null) {
String nodeName = item.getNodeName();
System.out.println("Node name:" + nodeName);
Class<?> c = m_tagFactory.getClassForTag(nodeName);
if (c == null) {
throw new RuntimeException("No class found for tag " + nodeName);
}
result = c.newInstance();
populateAttributes(item, result);
if (ITagSetter.class.isAssignableFrom(result.getClass())) {
throw new RuntimeException("TAG SETTER");
}
populateChildren(item, result);
}
}
return result;
}
public void populateChildren(Node root, Object result) throws InstantiationException,
IllegalAccessException, XPathExpressionException, SecurityException, IllegalArgumentException, NoSuchMethodException, InvocationTargetException {
p("populateChildren: " + root.getLocalName());
NodeList childNodes = root.getChildNodes();
ListMultiMap<String, Object> children = ListMultiMap.create();
for (int i = 0; i < childNodes.getLength(); i++) {
Node item = childNodes.item(i);
if (item.getAttributes() != null) {
String nodeName = item.getNodeName();
if ("suite-files".equals(nodeName)) {
System.out.println("BREAK");
}
Class<?> c = m_tagFactory.getClassForTag(nodeName);
if (c == null) {
System.out.println("Warning: No class found for tag " + nodeName);
boolean foundSetter = invokeOnSetter(result, (Element) item, nodeName, null);
System.out.println(" found setter:" + foundSetter);
} else {
Object object = instantiateElement(c, result);
if (ITagSetter.class.isAssignableFrom(object.getClass())) {
System.out.println("Tag setter:" + result);
((ITagSetter) object).setProperty(nodeName, result, item);
} else {
children.put(nodeName, object);
populateAttributes(item, object);
populateContent(item, object);
}
boolean foundSetter = invokeOnSetter(result, (Element) item, nodeName, object);
// setProperty(result, nodeName, object);
populateChildren(item, object);
}
// boolean foundSetter = invokeOnSetter(result, (Element) item, nodeName);
// if (! foundSetter) {
// boolean foundListSetter = invokeOnListSetter(result, nodeName, item);
// if (! foundListSetter) {
// }
// }
}
}
// System.out.println("Found children:" + children);
// for (String s : children.getKeys()) {
// setCollectionProperty(result, s, children.get(s), object);
// }
}
/**
* Try to find a @ParentSetter. If this fails, try to find a constructor that takes the parent as a parameter.
* If this fails, use the default constructor.
*/
private Object instantiateElement(Class<?> c, Object parent)
throws SecurityException, NoSuchMethodException,
IllegalArgumentException, InstantiationException, IllegalAccessException,
InvocationTargetException {
Object result = null;
Method m = findMethodAnnotatedWith(c, ParentSetter.class);
if (m != null) {
result = c.newInstance();
m.invoke(result, parent);
} else {
try {
result = c.getConstructor(parent.getClass()).newInstance(parent);
} catch(NoSuchMethodException ex) {
result = c.newInstance();
}
}
return result;
}
// private List<Pair<Method, ? extends Annotation>>
// findMethodsWithAnnotation(Class<?> c, Class<? extends Annotation> ac) {
// List<Pair<Method, ? extends Annotation>> result = Lists.newArrayList();
// for (Method m : c.getMethods()) {
// Annotation a = m.getAnnotation(ac);
// if (a != null) {
// result.add(Pair.of(m, a));
// }
// }
// return result;
// }
private Method findMethodAnnotatedWith(Class<?> c, Class<? extends Annotation> annotation) {
for (Method m : c.getMethods()) {
if (m.getAnnotation(annotation) != null) {
return m;
}
}
return null;
}
private void populateContent(Node item, Object object) {
for (int i = 0; i < item.getChildNodes().getLength(); i++) {
Node child = item.getChildNodes().item(i);
if (child instanceof Text) {
setText(object, (Text) child);
}
}
}
private void setText(Object bean, Text child) {
List<Pair<Method, Wrapper>> pairs =
Reflect.findMethodsWithAnnotation(bean.getClass(), TagContent.class, bean);
for (Pair<Method, Wrapper> pair : pairs) {
try {
pair.first().invoke(bean, child.getTextContent());
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (DOMException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
private boolean invokeOnSetter(Object object, Element element, String nodeName,
Object bean) {
Pair<Method, Wrapper> pair =
Reflect.findSetterForTag(object.getClass(), nodeName, bean);
List<Object[]> allParameters = null;
if (pair != null) {
Method m = pair.first();
try {
if (pair.second() != null) {
allParameters = pair.second().getParameters(element);
} else {
allParameters = Lists.newArrayList();
allParameters.add(new Object[] { bean });
}
for (Object[] p : allParameters) {
m.invoke(object, p);
}
return true;
} catch (IllegalArgumentException e) {
System.out.println("Parameters: " + allParameters);
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
return false;
}
private void populateAttributes(Node node, Object object) throws XPathExpressionException {
for (int j = 0; j < node.getAttributes().getLength(); j++) {
Node item = node.getAttributes().item(j);
setProperty(object, item.getLocalName(), item.getNodeValue());
}
}
private void setProperty(Object object, String name, Object value) {
Pair<Method, Wrapper> setter = Reflect.findSetterForTag(object.getClass(), name,
value);
if (setter != null) {
Method foundMethod = setter.first();
try {
Class<?> type = foundMethod.getParameterTypes()[0];
if (type == Boolean.class || type == boolean.class) {
foundMethod.invoke(object, Boolean.parseBoolean(value.toString()));
} else if (type == Integer.class || type == int.class) {
foundMethod.invoke(object, Integer.parseInt(value.toString()));
} else {
foundMethod.invoke(object, value);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} else {
e("Couldn't find setter method for property" + name + " on " + object.getClass());
}
}
// private Method findSetter(Object object, String name) {
// String methodName = toCamelCaseSetter(name);
// Method foundMethod = null;
// for (Method m : object.getClass().getDeclaredMethods()) {
// if (m.getName().equals(methodName)) {
// foundMethod = m;
// break;
// }
// }
// return foundMethod;
// }
private void p(String string) {
System.out.println("[XDom] " + string);
}
private void e(String string) {
System.out.println("[XDom] [Error] " + string);
}
public static void main(String[] args) throws SAXException, IOException,
ParserConfigurationException, XPathExpressionException,
InstantiationException, IllegalAccessException, SecurityException,
IllegalArgumentException, NoSuchMethodException,
InvocationTargetException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true); // never forget this!
DocumentBuilder builder = factory.newDocumentBuilder();
FileInputStream inputStream =
new FileInputStream(new File(System.getProperty("user.home")
+ "/java/testng/src/test/resources/testng-all.xml"));
Document doc = builder.parse(inputStream);
XmlSuite result = (XmlSuite) new XDom(new TestNGTagFactory(), doc).parse();
test(result);
System.out.println(result.toXml());
}
private static void test(XmlSuite s) {
Assert.assertEquals("TestNG", s.getName());
Assert.assertEquals(s.getDataProviderThreadCount(), 3);
Assert.assertEquals(s.getThreadCount(), 2);
{
// method-selectors
List<XmlMethodSelector> selectors = s.getMethodSelectors();
Assert.assertEquals(selectors.size(), 2);
XmlMethodSelector s1 = selectors.get(0);
Assert.assertEquals(s1.getLanguage(), "javascript");
Assert.assertEquals(s1.getExpression(), "foo()");
XmlMethodSelector s2 = selectors.get(1);
Assert.assertEquals(s2.getClassName(), "SelectorClass");
Assert.assertEquals(s2.getPriority(), 3);
}
{
// child-suites
List<String> suiteFiles = s.getSuiteFiles();
Assert.assertEquals(suiteFiles, Arrays.asList("./junit-suite.xml"));
}
{
// parameters
Map<String, String> p = s.getParameters();
Assert.assertEquals(p.size(), 2);
Assert.assertEquals(p.get("suiteParameter"), "suiteParameterValue");
Assert.assertEquals(p.get("first-name"), "Cedric");
}
{
// run
Assert.assertEquals(s.getIncludedGroups(), Arrays.asList("includeThisGroup"));
Assert.assertEquals(s.getExcludedGroups(), Arrays.asList("excludeThisGroup"));
XmlGroups groups = s.getGroups();
// define
List<XmlDefine> defines = groups.getDefines();
Assert.assertEquals(defines.size(), 1);
XmlDefine define = defines.get(0);
Assert.assertEquals(define.getName(), "bigSuite");
Assert.assertEquals(define.getIncludes(), Arrays.asList("suite1", "suite2"));
// packages
Assert.assertEquals(s.getPackageNames(), Arrays.asList("com.example1", "com.example2"));
// listeners
Assert.assertEquals(s.getListeners(),
Arrays.asList("com.beust.Listener1", "com.beust.Listener2"));
// dependencies
// only defined on test for now
}
{
// tests
Assert.assertEquals(s.getTests().size(), 3);
for (int i = 0; i < s.getTests().size(); i++) {
if ("Nopackage".equals(s.getTests().get(i).getName())) {
testNoPackage(s.getTests().get(i));
}
}
}
}
private static void testNoPackage(XmlTest t) {
Assert.assertEquals(t.getThreadCount(), 42);
Assert.assertTrue(t.getAllowReturnValues());
Assert.assertEquals(t.getIncludedGroups(), Arrays.asList("nopackage", "includeThisGroup"));
Assert.assertEquals(t.getExcludedGroups(), Arrays.asList("excludeThisGroup"));
}
}