/*
* Copyright (c) 2014 the original author or authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.werval.modules.xml;
import javax.xml.validation.Schema;
import java.io.InputStream;
import org.junit.Ignore;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
/**
* Base XML Test.
*/
// TODO Validate!
public abstract class TestBase
{
protected static final String SIMPLE_DOC_XML = "<foo>bar</foo>";
protected static final String SIMPLE_DOC_XSLT_TEXT = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<xsl:stylesheet \n"
+ " version=\"1.0\"\n"
+ " xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n"
+ " <xsl:output method=\"text\" encoding=\"UTF-8\"/>\n"
+ " \n"
+ " <!-- simply copy the foo text to the result tree -->\n"
+ " <xsl:template match=\"/\">\n"
+ " <xsl:value-of select=\"foo\"/>\n"
+ " </xsl:template>\n"
+ "</xsl:stylesheet> ";
/**
* XML Plugin API lookup.
* <p>
* Each concrete test lookup this in their dedicated Application.
*
* @return XML Plugin API
*/
protected abstract XML xml();
@Test
public void parseThenAsString()
{
Document doc = xml().document( SIMPLE_DOC_XML );
assertThat( xml().asString( doc ), allOf( containsString( SIMPLE_DOC_XML ), startsWith( "<?xml version=\"1" ) ) );
assertThat( xml().asString( (Node) doc ), equalTo( SIMPLE_DOC_XML ) );
}
@Test
public void transformDocumentToString()
{
String result = xml().toText( xml().document( SIMPLE_DOC_XML ), xml().xslt( SIMPLE_DOC_XSLT_TEXT ) );
assertThat( result, equalTo( "bar" ) );
}
@Test
public void booksNoValidation()
{
xml().document( books( "books.xml" ) );
xml().document( books( "books_invalid.xml" ) );
}
@Test
public void booksWithValidation()
throws Exception
{
Schema schema = xml().xsd( books( "books.xsd" ) );
xml().document( books( "books.xml" ), schema );
try
{
xml().document( books( "books_invalid.xml" ), schema );
fail( "Invalid books should not validate!" );
}
catch( UncheckedXMLException expected )
{
}
}
// ----------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------
// Defensive Coding
// ----------------------------------------------------------------------------------------------------------------
@Ignore( "DoS - ~1 second" )
@Test
public void internalEntityExponential_DOM()
{
try
{
xml().document( defensive( "XML-Parser-Internal_Entity_Exponential.xml" ), true );
fail( "XML-Parser-Internal_Entity_Exponential.xml should not parse!" );
}
catch( UncheckedXMLException ex )
{
assertThat( ex.getMessage(), allOf( containsString( "parser" ), containsString( "limit" ) ) );
}
}
@Ignore( "DoS - ~2 seconds" )
@Test
public void internalEntityExponentialAttribute_DOM()
{
try
{
xml().document( defensive( "XML-Parser-Internal_Entity_Exponential_Attribute.xml" ), true );
fail( "XML-Parser-Internal_Entity_Exponential_Attribute.xml should not parse!" );
}
catch( UncheckedXMLException ex )
{
assertThat( ex.getMessage(), allOf( containsString( "parser" ), containsString( "limit" ) ) );
}
}
@Ignore( "DoS - ~500 ms" )
@Test
public void internalEntityPolynomial_DOM()
{
try
{
xml().document( defensive( "XML-Parser-Internal_Entity_Polynomial.xml" ), true );
fail( "XML-Parser-Internal_Entity_Polynomial.xml should not parse!" );
}
catch( UncheckedXMLException ex )
{
assertThat( ex.getMessage(), allOf( containsString( "parser" ), containsString( "limit" ) ) );
}
}
@Ignore( "DoS - ~3 MINUTES !!!" )
@Test
public void internalEntityPolynomialAttribute_DOM()
{
try
{
xml().document( defensive( "XML-Parser-Internal_Entity_Polynomial_Attribute.xml" ), true );
fail( "XML-Parser-Internal_Entity_Polynomial_Attribute.xml should not parse!" );
}
catch( UncheckedXMLException ex )
{
assertThat( ex.getMessage(), allOf( containsString( "parser" ), containsString( "limit" ) ) );
}
}
@Ignore( "DoS - OutOfMemoryError !!!" )
@Test
public void internalRegexp1_DOM()
{
xml().document( defensive( "XML-Parser-Internal_Regexp_1.xml" ), true );
}
@Test
public void internalRegexp2_DOM()
{
xml().document( defensive( "XML-Parser-Internal_Regexp_2.xml" ), true );
}
@Test
public void internalRegexp3_DOM()
{
try
{
xml().document( defensive( "XML-Parser-Internal_Regexp_3.xml" ), true );
fail( "XML-Parser-Internal_Regexp_3.xml should not parse!" );
}
catch( UncheckedXMLException ex )
{
assertThat( ex.getMessage(), containsString( "cannot occur within" ) );
}
}
@Test
public void dtdPublic_DOM()
{
xml().document( defensive( "XML-Parser-DTD_Public.xml" ), true );
}
@Test
public void dtdPublicURL_DOM()
{
xml().document( defensive( "XML-Parser-DTD_Public_URL.xml" ), true );
}
@Test
public void dtdSystem_DOM()
{
xml().document( defensive( "XML-Parser-DTD_System.xml" ), true );
}
@Test
public void dtdSystemURL_DOM()
{
xml().document( defensive( "XML-Parser-DTD_System_URL.xml" ), true );
}
@Test
public void notationPublic_DOM()
{
xml().document( defensive( "XML-Parser-Notation_Public.xml" ), true );
}
@Test
public void notationPublicURL_DOM()
{
xml().document( defensive( "XML-Parser-Notation_Public_URL.xml" ), true );
}
@Test
public void notationSystem_DOM()
{
xml().document( defensive( "XML-Parser-Notation_System.xml" ), true );
}
@Test
public void notationSystemURL_DOM()
{
xml().document( defensive( "XML-Parser-Notation_System_URL.xml" ), true );
}
@Test
public void xsdFile_DOM()
{
xml().document( defensive( "XML-Parser-XSD-File.xml" ) );
}
@Test
public void xsdURL_DOM()
{
xml().document( defensive( "XML-Parser-XSD-URL.xml" ) );
}
@Test
public void xsdIncludeFile_DOM()
{
xml().document( defensive( "XML-Parser-XSD-Include_File.xml" ) );
}
@Test
public void xsdIncludeURL_DOM()
{
xml().document( defensive( "XML-Parser-XSD-Include_URL.xml" ) );
}
@Test
public void xIncludeFile_DOM()
{
xml().document( defensive( "XML-Parser-XInclude-File.xml" ) );
}
@Test
public void xIncludeURL_DOM()
{
xml().document( defensive( "XML-Parser-XInclude-URL.xml" ) );
}
@Test
public void externalEntityPublic_DOM()
{
xml().document( defensive( "XML-Parser-External_Entity_Public.xml" ), true );
}
@Test
public void externalEntityPublicURL_DOM()
{
xml().document( defensive( "XML-Parser-External_Entity_Public_URL.xml" ), true );
}
@Test
public void externalEntitySystem_DOM()
{
xml().document( defensive( "XML-Parser-External_Entity_System.xml" ), true );
}
@Test
public void externalEntitySystemURL_DOM()
{
xml().document( defensive( "XML-Parser-External_Entity_System_URL.xml" ), true );
}
@Test
public void externalEntityRegexp3_DOM()
{
xml().document( defensive( "XML-Parser-External_Regexp_3.xml" ), true );
}
@Test
public void validateRegexp1DTD_DOM()
{
try
{
xml().document( defensive( "XML-Parser-Validate-Regexp_1.xml" ), true );
}
catch( UncheckedXMLException ex )
{
assertThat( ex.getMessage(), containsString( "must match DOCTYPE" ) );
}
}
@Ignore( "DoS - ~1 second" )
@Test
public void validateRegexp1XSD_DOM()
{
try
{
xml().document(
defensive( "XML-Parser-Validate-Regexp_1.xml" ),
xml().xsd( defensive( "XML-Parser-Validate-Regexp_1.xsd" ) )
);
}
catch( UncheckedXMLException ex )
{
assertThat( ex.getMessage(), containsString( "Unique Particle Attribution" ) );
}
}
@Test
public void validateRegexp4XSD_DOM()
{
try
{
xml().document(
defensive( "XML-Parser-Validate-Regexp_1.xml" ),
xml().xsd( defensive( "XML-Parser-Validate-Regexp_4.xsd" ) )
);
}
catch( UncheckedXMLException ex )
{
assertThat( ex.getMessage(), containsString( "expansion" ) );
}
}
@Ignore( "DoS - ~1 second" )
@Test
public void validateRegexp1RelaxNG_DOM()
{
xml().document(
defensive( "XML-Parser-Validate-Regexp_1.xml" ),
xml().relaxNg( defensive( "XML-Parser-Validate-Regexp_1.rng" ) )
);
}
private static InputStream books( String filename )
{
return TestBase.class.getClassLoader().getResourceAsStream( "books/" + filename );
}
private static InputStream defensive( String filename )
{
return TestBase.class.getClassLoader().getResourceAsStream( "defensive/" + filename );
}
}