package org.testng.eclipse.util;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.testng.collections.Maps;
import org.testng.eclipse.TestNGPlugin;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.regex.Pattern;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.testng.xml.Parser;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class SuiteFileValidator {
private static final SAXParserFactory SAX_FACTORY = SAXParserFactory.newInstance();
private static SAXParser SAXPARSER;
private static final Pattern SUITE_REGEXP = Pattern.compile("<suite.*");
private static final Pattern TAG_REGEXP = Pattern.compile("<[^>?!]+>");
private static Map<IFile,Boolean> s_cache = Maps.newHashMap();
public static boolean isSuiteDefinition(IFile file) throws CoreException {
return isSuiteDefinition(file, false /* both xml and yaml */);
}
public static boolean isSuiteDefinition(IFile file, boolean xmlOnly) throws CoreException {
if (s_cache.containsKey(file)) return true;
boolean result = false;
if (! xmlOnly && file.getName().endsWith("yaml")) {
result = true;
}
if (! result) {
result = isSuiteDefinition(file.getContents());
}
if (result) {
s_cache.put(file, Boolean.TRUE);
}
return result;
}
/**
* @return true if the InputStream represents a TestNG definition file.
* For speed reasons, we stop the search as soon as we find an XML tag.
* If it's <suite>, return true, otherwise, return false (we also dodge
* DOCTYPES and other XML niceties with the TAG_REGEXP regular
* expression defined above.
*/
private static boolean isSuiteDefinition(InputStream is) {
BufferedReader br = new BufferedReader(new InputStreamReader(is));
try {
String line = br.readLine();
while (null != line) {
if (SUITE_REGEXP.matcher(line).matches()) {
return true;
}
else if (TAG_REGEXP.matcher(line).matches()) {
return false;
}
else line = br.readLine();
}
}
catch (IOException e) {
TestNGPlugin.log(e);
}
finally {
try {
br.close();
} catch (IOException exc) {
// swallow exception
}
}
return false;
}
public static void ppp(String s) {
System.out.println("[SuiteFileValidator] " + s);
}
private static SAXParser getParser() {
if(null == SAXPARSER) {
try {
SAX_FACTORY.setValidating(false);
SAXPARSER = SAX_FACTORY.newSAXParser();
}
catch(ParserConfigurationException pce) {
TestNGPlugin.log(pce);
}
catch(SAXException saxe) {
TestNGPlugin.log(saxe);
}
}
return SAXPARSER;
}
private static class SuiteHandler extends DefaultHandler {
protected boolean m_isValid = false;
protected int m_elementCount = 0;
public boolean isValid() {
return m_isValid;
}
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException
{
InputSource result = null;
if(Parser.TESTNG_DTD_URL.equals(publicId)) {
InputStream is = getClass().getClassLoader().getResourceAsStream(Parser.TESTNG_DTD);
if(null == is) {
is = Thread.currentThread().getContextClassLoader()
.getResourceAsStream(Parser.TESTNG_DTD);
if(null == is) {
System.out.println("WARNING: couldn't find in classpath " + Parser.TESTNG_DTD_URL
+ "\n" + "Fetching it from the Web site.");
try {
result = super.resolveEntity(systemId, publicId);
}
catch (Exception e) {
throw new SAXException(e);
}
}
else {
result = new InputSource(is);
}
}
else {
result = new InputSource(is);
}
}
else {
try {
result = super.resolveEntity(systemId, publicId);
}
catch (Exception e) {
throw new SAXException(e);
}
}
return result;
}
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if(m_elementCount++ == 0) {
if ("suite".equals(qName)) {
m_isValid = true;
}
}
}
}
}