/**
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
* <p>
* (C) 2016, Open Source Geospatial Foundation (OSGeo)
* <p>
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
* <p>
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.xml;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
/**
* Test for {@link DocumentFactory}
*
* @author Aaron Waddell
*/
public class DocumentFactoryTest {
private final String DISALLOW_DOCTYPE_DECLAIRATION = "http://apache.org/xml/features/disallow-doctype-decl";
private final String LOAD_EXTERNAL_DTD = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
private final String EXTERNAL_GENERAL_ENTITIES_FEATURE = "http://xml.org/sax/features/external-general-entities";
private final String EXTERNAL_PARAMETER_ENTITIES_FEATURE = "http://xml.org/sax/features/external-parameter-entities";
private URI uri;
private Map<String, Object> hints;
@Mock
private SAXParserFactory mockSaxParserFactory;
@Mock
private SAXParser mockSaxParser;
@Mock
InputStream inputStream;
@Before
public void before() throws Exception {
uri = new URI("http://geotools.org");
hints = new HashMap<String, Object>();
MockitoAnnotations.initMocks(this);
hints.put(XMLHandlerHints.SAX_PARSER_FACTORY, mockSaxParserFactory);
when(mockSaxParserFactory.newSAXParser()).thenReturn(mockSaxParser);
Answer<Void> startDocumentAnswer = new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
XMLSAXHandler xmlSaxHandler = (XMLSAXHandler) invocationOnMock.getArguments()[1];
xmlSaxHandler.startDocument();
return null;
}
};
doAnswer(startDocumentAnswer).when(mockSaxParser).parse(anyString(),
any(XMLSAXHandler.class));
doAnswer(startDocumentAnswer).when(mockSaxParser).parse(any(InputStream.class),
any(XMLSAXHandler.class));
}
@Test
public void testGetInstanceFromURIWithSpecifiedLevelButNoPDisableExternalEntities()
throws Exception {
DocumentFactory.getInstance(uri, hints, Level.WARNING);
verifyDisableExternalEntities(false);
}
@Test
public void testGetInstanceFromURIWithSpecifiedLevelAndDisableExternalEntitiesTrue()
throws Exception {
hints.put(DocumentFactory.DISABLE_EXTERNAL_ENTITIES, Boolean.TRUE);
DocumentFactory.getInstance(uri, hints, Level.WARNING);
verifyDisableExternalEntities(true);
}
@Test
public void testGetInstanceFromURIWithSpecifiedLevelAndDisableExternalEntitiesFalse()
throws Exception {
hints.put(DocumentFactory.DISABLE_EXTERNAL_ENTITIES, Boolean.FALSE);
DocumentFactory.getInstance(uri, hints, Level.WARNING);
verifyDisableExternalEntities(false);
}
@Test(expected = SAXException.class)
public void testGetInstanceFromURIWithSpecifiedLevelParseFailureIOException() throws Exception {
doThrow(new IOException("Failure")).when(mockSaxParser).parse(anyString(),
any(XMLSAXHandler.class));
DocumentFactory.getInstance(uri, hints, Level.WARNING);
}
@Test(expected = SAXException.class)
public void testGetInstanceFromURIWithSpecifiedLevelParseFailureSAXException()
throws Exception {
doThrow(new SAXException("Failure")).when(mockSaxParser).parse(anyString(),
any(XMLSAXHandler.class));
DocumentFactory.getInstance(uri, hints, Level.WARNING);
}
@Test(expected = SAXException.class)
public void testGetInstanceFromURIWithSpecifiedLevelNewSAXParserFailure() throws Exception {
when(mockSaxParserFactory.newSAXParser())
.thenThrow(new ParserConfigurationException("Failure"));
DocumentFactory.getInstance(uri, hints, Level.WARNING);
}
@Test
public void testGetInstanceFromInputStreamWithSpecifiedLevelNoDisableExternalEntities()
throws Exception {
DocumentFactory.getInstance(inputStream, hints, Level.WARNING);
verifyDisableExternalEntities(false);
}
@Test
public void testGetInstanceFromInputStreamWithSpecifiedLevelAndDisableExternalEntitiesTrue()
throws Exception {
hints.put(DocumentFactory.DISABLE_EXTERNAL_ENTITIES, Boolean.TRUE);
DocumentFactory.getInstance(inputStream, hints, Level.WARNING);
verifyDisableExternalEntities(true);
}
@Test
public void testGetInstanceFromInputStreamWithSpecifiedLevelAndPDisableExternalEntitiesFalse()
throws Exception {
hints.put(DocumentFactory.DISABLE_EXTERNAL_ENTITIES, Boolean.FALSE);
DocumentFactory.getInstance(inputStream, hints, Level.WARNING);
verifyDisableExternalEntities(false);
}
@Test(expected = SAXException.class)
public void testGetInstanceFromInputStreamWithSpecifiedLevelParseFailureIOException()
throws Exception {
doThrow(new IOException("Parse failure")).when(mockSaxParser).parse(any(InputStream.class),
any(XMLSAXHandler.class));
DocumentFactory.getInstance(inputStream, hints, Level.WARNING);
}
@Test(expected = SAXException.class)
public void testGetInstanceFromInputStreamWithSpecifiedLevelParseFailureSAXException()
throws Exception {
doThrow(new SAXException("Parse failure")).when(mockSaxParser).parse(any(InputStream.class),
any(XMLSAXHandler.class));
DocumentFactory.getInstance(inputStream, hints, Level.WARNING);
}
void verifyDisableExternalEntities(boolean disabledExternalEntities) throws SAXNotRecognizedException,
SAXNotSupportedException, ParserConfigurationException {
// double check DTD support disabled
// verify(mockSaxParserFactory).setFeature(DISALLOW_DOCTYPE_DECLAIRATION, true);
verify(mockSaxParserFactory).setFeature(LOAD_EXTERNAL_DTD, false);
// check optional eternal entity disabled
if (disabledExternalEntities) {
verify(mockSaxParserFactory).setFeature(EXTERNAL_GENERAL_ENTITIES_FEATURE, false);
verify(mockSaxParserFactory).setFeature(EXTERNAL_PARAMETER_ENTITIES_FEATURE, false);
} else {
verify(mockSaxParserFactory, never()).setFeature(EXTERNAL_GENERAL_ENTITIES_FEATURE,
false);
verify(mockSaxParserFactory, never()).setFeature(EXTERNAL_PARAMETER_ENTITIES_FEATURE,
false);
}
}
}