Author: vsiveton Date: Fri May 29 13:21:59 2009 New Revision: 779960 URL: http://svn.apache.org/viewvc?rev=779960&view=rev Log: o Modify getAllTestDocuments() to find test resources in an IDE project like eclipse. o filtering error message in test o wrap sax error in a bean
Modified: maven/doxia/doxia/trunk/doxia-core/src/test/java/org/apache/maven/doxia/xsd/AbstractXmlValidatorTest.java Modified: maven/doxia/doxia/trunk/doxia-core/src/test/java/org/apache/maven/doxia/xsd/AbstractXmlValidatorTest.java URL: http://svn.apache.org/viewvc/maven/doxia/doxia/trunk/doxia-core/src/test/java/org/apache/maven/doxia/xsd/AbstractXmlValidatorTest.java?rev=779960&r1=779959&r2=779960&view=diff ============================================================================== --- maven/doxia/doxia/trunk/doxia-core/src/test/java/org/apache/maven/doxia/xsd/AbstractXmlValidatorTest.java (original) +++ maven/doxia/doxia/trunk/doxia-core/src/test/java/org/apache/maven/doxia/xsd/AbstractXmlValidatorTest.java Fri May 29 13:21:59 2009 @@ -19,10 +19,13 @@ * under the License. */ +import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.Reader; import java.io.StringReader; import java.net.JarURLConnection; +import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Collections; @@ -39,8 +42,11 @@ import org.apache.maven.doxia.parser.AbstractXmlParser; import org.codehaus.plexus.PlexusTestCase; +import org.codehaus.plexus.util.FileUtils; import org.codehaus.plexus.util.IOUtil; +import org.codehaus.plexus.util.ReaderFactory; import org.codehaus.plexus.util.SelectorUtils; +import org.codehaus.plexus.util.xml.XmlUtil; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; @@ -51,7 +57,7 @@ import org.xml.sax.helpers.XMLReaderFactory; /** - * Abstract class to validate XML files with Doxia namespaces. + * Abstract class to validate XML files with DTD or XSD mainly for Doxia namespaces. * * @author <a href="mailto:vincent.sive...@gmail.com">Vincent Siveton</a> * @version $Id$ @@ -89,6 +95,50 @@ } /** + * Validate tests documents with DTD or XSD using xerces. + * + * @throws Exception if any + * @see #addNamespaces(String) + * @see #getTestDocuments() + */ + public void testValidateFiles() + throws Exception + { + for ( Iterator it = getTestDocuments().entrySet().iterator(); it.hasNext(); ) + { + Map.Entry entry = (Map.Entry) it.next(); + + if ( getContainer().getLogger().isDebugEnabled() ) + { + getContainer().getLogger().debug( "Validate '" + entry.getKey() + "'" ); + } + + List errors = parseXML( entry.getValue().toString() ); + + for ( Iterator it2 = errors.iterator(); it2.hasNext(); ) + { + ErrorMessage error = (ErrorMessage) it2.next(); + + if ( isFailErrorMessage( error.getMessage() ) ) + { + fail( entry.getKey() + EOL + error.toString() ); + } + else + { + if ( getContainer().getLogger().isDebugEnabled() ) + { + getContainer().getLogger().debug( entry.getKey() + EOL + error.toString() ); + } + } + } + } + } + + // ---------------------------------------------------------------------- + // Protected methods + // ---------------------------------------------------------------------- + + /** * @return a non null patterns to includes specific test files. * @see AbstractXmlValidatorTest#getTestDocuments() */ @@ -101,58 +151,166 @@ protected abstract String addNamespaces( String content ); /** - * Test xml files with namespace. + * @return a map of test resources filtered by patterns from {...@link #getIncludes()}. + * @throws IOException if any + * @see #getIncludes() + * @see #getAllTestDocuments() + */ + protected Map getTestDocuments() + throws IOException + { + if ( getIncludes() == null ) + { + return Collections.EMPTY_MAP; + } + + Map testDocs = getAllTestDocuments(); + Map ret = new Hashtable(); + ret.putAll( testDocs ); + for ( Iterator it = testDocs.keySet().iterator(); it.hasNext(); ) + { + String key = it.next().toString(); + + for ( int i = 0; i < getIncludes().length; i++ ) + { + if ( !SelectorUtils.matchPath( getIncludes()[i], key.toLowerCase( Locale.ENGLISH ) ) ) + { + ret.remove( key ); + } + } + } + + return ret; + } + + /** + * Find test resources in the <code>doxia-test-docs-XXX.jar</code> or in an IDE project. * - * @throws Exception if any + * @return a map of test resources defined as follow: + * <ul> + * <li>key, the full url of test documents, + * i.e. <code>jar:file:/.../doxia-test-docs-XXX.jar!/path/to/resource</code></li> + * <li>value, the content for the resource defined by the key</li> + * </ul> + * @throws IOException if any */ - public void testXmlFilesWithDoxiaNamespaces() - throws Exception + protected static Map getAllTestDocuments() + throws IOException { - for ( Iterator it = getTestDocuments().entrySet().iterator(); it.hasNext(); ) + if ( CACHE_DOXIA_TEST_DOCUMENTS != null && !CACHE_DOXIA_TEST_DOCUMENTS.isEmpty() ) { - Map.Entry entry = (Map.Entry) it.next(); + return CACHE_DOXIA_TEST_DOCUMENTS; + } - if ( getContainer().getLogger().isDebugEnabled() ) + URL testJar = AbstractXmlValidatorTest.class.getClassLoader().getResource( MAVEN_RESOURCE_PATH ); + if ( testJar == null ) + { + // maybe in an IDE project + testJar = AbstractXmlValidatorTest.class.getClassLoader().getResource( "doxia-site" ); + + if ( testJar == null ) { - getContainer().getLogger().debug( "Validate '" + entry.getKey() + "'" ); + throw new RuntimeException( + "Could not find the Doxia test documents artefact i.e. doxia-test-docs-XXX.jar" ); } + } - List errors = parseXML( entry.getValue().toString() ); + if ( testJar.toString().startsWith( "jar" )) + { + JarURLConnection conn = (JarURLConnection) testJar.openConnection(); + JarFile jarFile = conn.getJarFile(); + for ( Enumeration e = jarFile.entries(); e.hasMoreElements(); ) + { + JarEntry entry = (JarEntry) e.nextElement(); - for ( Iterator it2 = errors.iterator(); it2.hasNext(); ) + if ( entry.getName().startsWith( "META-INF" ) ) + { + continue; + } + if ( entry.isDirectory() ) + { + continue; + } + + InputStream in = null; + try + { + in = AbstractXmlValidatorTest.class.getClassLoader().getResource( entry.getName() ).openStream(); + String content = IOUtil.toString( in, "UTF-8" ); + CACHE_DOXIA_TEST_DOCUMENTS.put( "jar:" + conn.getJarFileURL() + "!/" + entry.getName(), content ); + } + finally + { + IOUtil.close( in ); + } + } + } + else + { + // IDE projects + File testDocsDir; + try + { + testDocsDir = new File( testJar.toURI() ).getParentFile(); + } + catch ( URISyntaxException e ) + { + throw new IOException( "URISyntaxException: " + e.getMessage() ); + } + + List files = FileUtils.getFiles( testDocsDir, "**/*.*", FileUtils.getDefaultExcludesAsString(), true ); + for ( Iterator it = files.iterator(); it.hasNext();) { - String message = (String) it2.next(); + File file = new File( it.next().toString() ); - if ( message.length() != 0 ) + if ( file.getAbsolutePath().indexOf( "META-INF" ) != -1 ) { - // Exclude some xhtml errors - if ( message - .indexOf( "schema_reference.4: Failed to read schema document 'http://www.w3.org/2001/xml.xsd'" ) == -1 - && message - .indexOf( "Message: cvc-complex-type.4: Attribute 'alt' must appear on element 'img'." ) == -1 - && message - .indexOf( "Message: cvc-complex-type.2.4.a: Invalid content starting with element" ) == -1 - && message - .indexOf( "Message: cvc-complex-type.2.4.a: Invalid content was found starting with element" ) == -1 - && message.indexOf( "Message: cvc-datatype-valid.1.2.1:" ) == -1 // Doxia allow space - && message.indexOf( "Message: cvc-attribute.3:" ) == -1 ) // Doxia allow space - { - fail( entry.getKey() + EOL + message ); - } - else - { - if ( getContainer().getLogger().isDebugEnabled() ) - { - getContainer().getLogger().debug( entry.getKey() + EOL + message ); - } - } + continue; + } + + Reader reader = null; + if ( XmlUtil.isXml( file )) + { + reader = ReaderFactory.newXmlReader( file ); + } + else + { + reader = ReaderFactory.newReader( file, "UTF-8" ); } + + String content = IOUtil.toString( reader ); + CACHE_DOXIA_TEST_DOCUMENTS.put( file.toURI().toString(), content ); } } + + return CACHE_DOXIA_TEST_DOCUMENTS; + } + + /** + * Filter fail message. + * + * @param message not null + * @return <code>true</code> if the given message will fail the test. + * @since 1.1.1 + */ + protected boolean isFailErrorMessage( String message ) + { + if ( message + .indexOf( "schema_reference.4: Failed to read schema document 'http://www.w3.org/2001/xml.xsd'" ) == -1 + && message.indexOf( "cvc-complex-type.4: Attribute 'alt' must appear on element 'img'." ) == -1 + && message.indexOf( "cvc-complex-type.2.4.a: Invalid content starting with element" ) == -1 + && message.indexOf( "cvc-complex-type.2.4.a: Invalid content was found starting with element" ) == -1 + && message.indexOf( "cvc-datatype-valid.1.2.1:" ) == -1 // Doxia allow space + && message.indexOf( "cvc-attribute.3:" ) == -1 ) // Doxia allow space + { + return true; + } + + return false; } // ---------------------------------------------------------------------- - // Private method + // Private methods // ---------------------------------------------------------------------- private XMLReader getXMLReader() @@ -164,9 +322,7 @@ xmlReader = XMLReaderFactory.createXMLReader( "org.apache.xerces.parsers.SAXParser" ); xmlReader.setFeature( "http://xml.org/sax/features/validation", true ); xmlReader.setFeature( "http://apache.org/xml/features/validation/schema", true ); - MessagesErrorHandler errorHandler = new MessagesErrorHandler(); - xmlReader.setErrorHandler( errorHandler ); - + xmlReader.setErrorHandler( new MessagesErrorHandler() ); xmlReader.setEntityResolver( new AbstractXmlParser.CachedFileEntityResolver() ); } catch ( SAXNotRecognizedException e ) @@ -183,9 +339,17 @@ } } + ( (MessagesErrorHandler) xmlReader.getErrorHandler() ).clearMessages(); + return xmlReader; } + /** + * @param xmlContent + * @return a list of ErrorMessage + * @throws IOException is any + * @throws SAXException if any + */ private List parseXML( String xmlContent ) throws IOException, SAXException { @@ -198,144 +362,195 @@ return errorHandler.getMessages(); } - private static class MessagesErrorHandler + private static class ErrorMessage extends DefaultHandler { - private final List messages; + private final String level; + private final String publicID; + private final String systemID; + private final int lineNumber; + private final int columnNumber; + private final String message; - public MessagesErrorHandler() + public ErrorMessage( String level, String publicID, String systemID, int lineNumber, int columnNumber, + String message ) { - messages = new ArrayList(); + super(); + this.level = level; + this.publicID = publicID; + this.systemID = systemID; + this.lineNumber = lineNumber; + this.columnNumber = columnNumber; + this.message = message; } - /** {...@inheritdoc} */ - public void warning( SAXParseException e ) - throws SAXException + /** + * @return the level + */ + protected String getLevel() { - addMessage( "Warning:", e ); + return level; } - /** {...@inheritdoc} */ - public void error( SAXParseException e ) - throws SAXException + /** + * @return the publicID + */ + protected String getPublicID() { - addMessage( "Error:", e ); + return publicID; } - - /** {...@inheritdoc} */ - public void fatalError( SAXParseException e ) - throws SAXException + /** + * @return the systemID + */ + protected String getSystemID() { - addMessage( "Fatal error:", e ); + return systemID; + } + /** + * @return the lineNumber + */ + protected int getLineNumber() + { + return lineNumber; + } + /** + * @return the columnNumber + */ + protected int getColumnNumber() + { + return columnNumber; + } + /** + * @return the message + */ + protected String getMessage() + { + return message; } - private void addMessage( String pre, SAXParseException e ) + /** {...@inheritdoc} */ + public String toString() { - StringBuffer message = new StringBuffer(); + StringBuffer sb = new StringBuffer(); - message.append( pre ).append( EOL ); - message.append( " Public ID: " + e.getPublicId() ).append( EOL ); - message.append( " System ID: " + e.getSystemId() ).append( EOL ); - message.append( " Line number: " + e.getLineNumber() ).append( EOL ); - message.append( " Column number: " + e.getColumnNumber() ).append( EOL ); - message.append( " Message: " + e.getMessage() ).append( EOL ); + sb.append( level ).append( EOL ); + sb.append( " Public ID: " ).append( publicID ).append( EOL ); + sb.append( " System ID: " ).append( systemID ).append( EOL ); + sb.append( " Line number: " ).append( lineNumber ).append( EOL ); + sb.append( " Column number: " ).append( columnNumber ).append( EOL ); + sb.append( " Message: " ).append( message ).append( EOL ); - messages.add( message.toString() ); + return sb.toString(); } - protected List getMessages() + /** {...@inheritdoc} */ + public int hashCode() { - return messages; + final int prime = 31; + int result = 1; + result = prime * result + columnNumber; + result = prime * result + ( ( level == null ) ? 0 : level.hashCode() ); + result = prime * result + lineNumber; + result = prime * result + ( ( message == null ) ? 0 : message.hashCode() ); + result = prime * result + ( ( publicID == null ) ? 0 : publicID.hashCode() ); + result = prime * result + ( ( systemID == null ) ? 0 : systemID.hashCode() ); + return result; + } + + /** {...@inheritdoc} */ + public boolean equals( Object obj ) + { + if ( this == obj ) + return true; + if ( obj == null ) + return false; + if ( getClass() != obj.getClass() ) + return false; + ErrorMessage other = (ErrorMessage) obj; + if ( columnNumber != other.columnNumber ) + return false; + if ( level == null ) + { + if ( other.level != null ) + return false; + } + else if ( !level.equals( other.level ) ) + return false; + if ( lineNumber != other.lineNumber ) + return false; + if ( message == null ) + { + if ( other.message != null ) + return false; + } + else if ( !message.equals( other.message ) ) + return false; + if ( publicID == null ) + { + if ( other.publicID != null ) + return false; + } + else if ( !publicID.equals( other.publicID ) ) + return false; + if ( systemID == null ) + { + if ( other.systemID != null ) + return false; + } + else if ( !systemID.equals( other.systemID ) ) + return false; + return true; } } - /** - * @return a map of test resources filtered by patterns from {...@link #getIncludes()}. - * @throws IOException if any - * @see #getIncludes() - * @see #getAllTestDocuments() - */ - protected Map getTestDocuments() - throws IOException + private static class MessagesErrorHandler + extends DefaultHandler { - if ( getIncludes() == null ) + private final List messages; + + public MessagesErrorHandler() { - return Collections.EMPTY_MAP; + messages = new ArrayList(); } - Map testDocs = getAllTestDocuments(); - Map ret = new Hashtable(); - ret.putAll( testDocs ); - for ( Iterator it = testDocs.keySet().iterator(); it.hasNext(); ) + /** {...@inheritdoc} */ + public void warning( SAXParseException e ) + throws SAXException { - String key = it.next().toString(); - - for ( int i = 0; i < getIncludes().length; i++ ) - { - if ( !SelectorUtils.matchPath( getIncludes()[i], key.toLowerCase( Locale.ENGLISH ) ) ) - { - ret.remove( key ); - } - } + addMessage( "Warning", e ); } - return ret; - } - - /** - * Find test resources in the <code>doxia-test-docs-XXX.jar</code> - * - * @return a map of test resources defined as follow: - * <ul> - * <li>key, the full url of test documents, - * i.e. <code>jar:file:/.../doxia-test-docs-XXX.jar!/path/to/resource</code></li> - * <li>value, the content for the resource defined by the key</li> - * </ul> - * @throws IOException if any - */ - protected static Map getAllTestDocuments() - throws IOException - { - if ( CACHE_DOXIA_TEST_DOCUMENTS != null && !CACHE_DOXIA_TEST_DOCUMENTS.isEmpty() ) + /** {...@inheritdoc} */ + public void error( SAXParseException e ) + throws SAXException { - return CACHE_DOXIA_TEST_DOCUMENTS; + addMessage( "Error", e ); } - URL testJar = AbstractXmlValidatorTest.class.getClassLoader().getResource( MAVEN_RESOURCE_PATH ); - if ( testJar == null ) + /** {...@inheritdoc} */ + public void fatalError( SAXParseException e ) + throws SAXException { - throw new RuntimeException( - "Could not find the Doxia test documents artefact i.e. doxia-test-docs-XXX.jar" ); + addMessage( "Fatal error", e ); } - JarURLConnection conn = (JarURLConnection) testJar.openConnection(); - JarFile jarFile = conn.getJarFile(); - for ( Enumeration e = jarFile.entries(); e.hasMoreElements(); ) + private void addMessage( String pre, SAXParseException e ) { - JarEntry entry = (JarEntry) e.nextElement(); + ErrorMessage error = + new ErrorMessage( pre, e.getPublicId(), e.getSystemId(), e.getLineNumber(), e.getColumnNumber(), + e.getMessage() ); - if ( entry.getName().startsWith( "META-INF" ) ) - { - continue; - } - if ( entry.isDirectory() ) - { - continue; - } + messages.add( error ); + } - InputStream in = null; - try - { - in = AbstractXmlValidatorTest.class.getClassLoader().getResource( entry.getName() ).openStream(); - String content = IOUtil.toString( in, "UTF-8" ); - CACHE_DOXIA_TEST_DOCUMENTS.put( "jar:" + conn.getJarFileURL() + "!/" + entry.getName(), content ); - } - finally - { - IOUtil.close( in ); - } + protected List getMessages() + { + return messages; } - return CACHE_DOXIA_TEST_DOCUMENTS; + protected void clearMessages() + { + messages.clear(); + } } }