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; } } } } }