All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opengis.cite.iso19142.ETSAssert Maven / Gradle / Ivy

There is a newer version: 2.0-r18
Show newest version
package org.opengis.cite.iso19142;

import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.namespace.QName;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Validator;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;

import org.apache.xerces.xs.XSComplexTypeDefinition;
import org.apache.xerces.xs.XSElementDeclaration;
import org.apache.xerces.xs.XSSimpleTypeDefinition;
import org.apache.xerces.xs.XSTypeDefinition;
import org.opengis.cite.iso19142.util.TestSuiteLogger;
import org.opengis.cite.iso19142.util.ValidationUtils;
import org.opengis.cite.iso19142.util.WFSClient;
import org.opengis.cite.iso19142.util.XMLUtils;
import org.opengis.cite.validation.SchematronValidator;
import org.opengis.cite.validation.ValidationErrorHandler;
import org.testng.Assert;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.XdmValue;

/**
 * Provides a set of custom assertion methods.
 */
public class ETSAssert {

    private final static Logger LOGR = Logger.getLogger(ETSAssert.class.getName());

    private ETSAssert() {
    }

    /**
     * Asserts that the qualified name of a DOM Node matches the expected value.
     * 
     * @param node
     *            The Node to check.
     * @param qName
     *            A QName object containing a namespace name (URI) and a local
     *            part.
     */
    public static void assertQualifiedName(Node node, QName qName) {
        Assert.assertEquals(node.getLocalName(), qName.getLocalPart(), ErrorMessage.get(ErrorMessageKeys.LOCAL_NAME));
        Assert.assertEquals(node.getNamespaceURI(), qName.getNamespaceURI(),
                ErrorMessage.get(ErrorMessageKeys.NAMESPACE_NAME));
    }

    /**
     * Asserts that an XPath 1.0 expression holds true for the given evaluation
     * context. The following standard namespace bindings do not need to be
     * explicitly declared:
     * 
     * 
    *
  • wfs: {@value org.opengis.cite.iso19142.Namespaces#WFS}
  • *
  • fes: {@value org.opengis.cite.iso19142.Namespaces#FES}
  • *
  • ows: {@value org.opengis.cite.iso19142.Namespaces#OWS}
  • *
  • xlink: {@value org.opengis.cite.iso19142.Namespaces#XLINK}
  • *
  • gml: {@value org.opengis.cite.iso19142.Namespaces#GML}
  • *
  • soap: {@value org.opengis.cite.iso19142.Namespaces#SOAP_ENV}
  • *
  • xsi: * {@value javax.xml.XMLConstants#W3C_XML_SCHEMA_INSTANCE_NS_URI}
  • *
* * The method arguments will be logged at level FINE or lower. * * @param expr * A valid XPath 1.0 expression. * @param context * The context node. * @param nsBindings * A collection of namespace bindings for the XPath expression, * where each entry maps a namespace URI (key) to a prefix * (value). It may be {@code null}. */ public static void assertXPath(String expr, Node context, Map nsBindings) { boolean result = evaluateXPathToBoolean(expr, context, nsBindings); Assert.assertTrue(result, ErrorMessage.format(ErrorMessageKeys.XPATH_RESULT, context.getNodeName(), expr)); } /** * The XPath is evaluated for given expr and context. * * @param expr * A valid XPath expression. * @param context * A context node. * @param nsBindings * The list of namespace required for the expr. * @return True if XPath is evaluated successfully otherwise false. */ public static boolean evaluateXPathToBoolean(String expr, Node context, Map nsBindings ) { if ( null == context ) { throw new NullPointerException( "Context node is null." ); } LOGR.log( Level.FINE, "Evaluating \"{0}\" against context node:\n{1}", new Object[] { expr, XMLUtils.writeNodeToString( context ) } ); try { boolean result = (boolean) XMLUtils.evaluateXPath( context, expr, nsBindings, XPathConstants.BOOLEAN ); LOGR.log( Level.FINE, "XPath result: " + result ); return result; } catch ( XPathExpressionException e ) { String msg = ErrorMessage.format( ErrorMessageKeys.XPATH_ERROR, expr ); LOGR.log( Level.WARNING, msg, e ); throw new AssertionError( msg ); } } /** * Asserts that an XPath 2.0 expression evaluates to {@code true} for the * given XML source. That is, the result set is not empty. * * @param expr * An XPath 2.0 expression. * @param source * A Source object representing an XML resource. * @param namespaceBindings * A collection of namespace bindings for the XPath expression, * where each entry maps a namespace URI (key) to a prefix * (value). It may be {@code null}. */ public static void assertXPath2(String expr, Source source, Map namespaceBindings) { if (TestSuiteLogger.isLoggable(Level.FINE)) { TestSuiteLogger.log(Level.FINE, "Asserting XPath expression {0} against {1} ({2})", new Object[] { expr, source.getClass().getName(), source.getSystemId() }); } XdmValue result = null; try { result = XMLUtils.evaluateXPath2(source, expr, namespaceBindings); } catch (SaxonApiException e) { throw new AssertionError(ErrorMessage.format(ErrorMessageKeys.XPATH_ERROR, expr + e.getMessage())); } Assert.assertTrue(result.size() > 0, ErrorMessage.format(ErrorMessageKeys.XPATH_RESULT, source.getSystemId(), expr)); } /** * Asserts that an XML resource is schema-valid. * * @param validator * The Validator to use. * @param source * The XML Source to be validated. */ public static void assertSchemaValid(Validator validator, Source source) { ValidationErrorHandler errHandler = new ValidationErrorHandler(); validator.setErrorHandler(errHandler); try { validator.validate(source); } catch (Exception e) { throw new AssertionError(ErrorMessage.format(ErrorMessageKeys.XML_ERROR, e.getMessage())); } Assert.assertFalse(errHandler.errorsDetected(), ErrorMessage.format(ErrorMessageKeys.NOT_SCHEMA_VALID, errHandler.getErrorCount(), errHandler.toString())); } /** * Asserts that an XML resource satisfies all applicable constraints * specified in a Schematron (ISO 19757-3) schema. The "xslt2" query * language binding is supported. All patterns are checked. * * @param schemaRef * A URL that denotes the location of a Schematron schema. * @param xmlSource * The XML Source to be validated. */ public static void assertSchematronValid(URL schemaRef, Source xmlSource) { SchematronValidator validator; try { validator = new SchematronValidator(new StreamSource(schemaRef.toString()), "#ALL"); } catch (Exception e) { StringBuilder msg = new StringBuilder("Failed to process Schematron schema at "); msg.append(schemaRef).append('\n'); msg.append(e.getMessage()); throw new AssertionError(msg); } Result result = validator.validate(xmlSource); Assert.assertFalse(validator.ruleViolationsDetected(), ErrorMessage.format(ErrorMessageKeys.NOT_SCHEMA_VALID, validator.getRuleViolationCount(), XMLUtils.resultToString(result))); } /** * Asserts the availability of a feature having the specified resource * identifier. The following XPath expression is checked against the * GetFeature response entity: * * {@code //wfs:member/*[@gml:id = '$id']} * * @param id * The feature identifier (assigned by the system). * @param isAvailable * A boolean value asserting that the feature either is ( * {@code true}) or is not ({@code false}) available. * @param wfsClient * A WFSClient component that interacts with the SUT. */ public static void assertFeatureAvailability(String id, boolean isAvailable, WFSClient wfsClient) { Map params = new HashMap(); params.put("id", id); Document rsp = wfsClient.invokeStoredQuery(WFS2.QRY_GET_FEATURE_BY_ID, params); String xpath = String.format("/*[@gml:id = '%s']", id); NodeList result; try { result = XMLUtils.evaluateXPath(rsp, xpath, null); } catch (XPathExpressionException e) { throw new RuntimeException(e); } if (isAvailable && result.getLength() == 0) { throw new AssertionError( ErrorMessage.format(ErrorMessageKeys.FEATURE_AVAILABILITY, result.getLength(), id)); } if (!isAvailable && result.getLength() > 0) { throw new AssertionError( ErrorMessage.format(ErrorMessageKeys.FEATURE_AVAILABILITY, result.getLength(), id)); } } /** * Asserts that one or more simple properties of a feature have the expected * values. If a property occurs more than once, only the first occurrence is * checked. * * @param feature * An Element node representing a GML feature. * @param expectedValues * A collection of feature properties containing {prop: value} * entries, where the prop key is an element * declaration (XSElementDeclaration) denoting a property. * @param nsBindings * A collection of namespace bindings for the supplied * properties, where each entry is a {namespace-name: prefix} * pair. A binding is not required for standard GML properties. */ public static void assertSimpleProperties(Element feature, Map expectedValues, Map nsBindings) { for (Map.Entry property : expectedValues.entrySet()) { XSElementDeclaration propDecl = property.getKey(); XSSimpleTypeDefinition propType; if (propDecl.getTypeDefinition().getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) { propType = (XSSimpleTypeDefinition) propDecl.getTypeDefinition(); } else { XSComplexTypeDefinition complexType = (XSComplexTypeDefinition) propDecl.getTypeDefinition(); propType = complexType.getSimpleType(); } String expectedValue = XMLUtils.expandReferencesInText(property.getValue().toString()); String expr = null; String nsPrefix = (propDecl.getNamespace().equals(Namespaces.GML)) ? "gml" : nsBindings.get(propDecl.getNamespace()); if (propType.getNumeric()) { expr = String.format("number(%s:%s[1]) eq %s", nsPrefix, propDecl.getName(), expectedValue); } else { // string comparison expr = String.format("%s:%s[1] eq \"%s\"", nsPrefix, propDecl.getName(), expectedValue); } assertXPath2(expr, new DOMSource(feature), nsBindings); } } /** * Asserts that the given XML entity contains the expected number of * descendant elements having the specified name. * * @param xmlEntity * A Document representing an XML entity. * @param elementName * The qualified name of the element. * @param expectedCount * The expected number of occurrences. */ public static void assertDescendantElementCount(Document xmlEntity, QName elementName, int expectedCount) { NodeList features = xmlEntity.getElementsByTagNameNS(elementName.getNamespaceURI(), elementName.getLocalPart()); Assert.assertEquals(features.getLength(), expectedCount, String.format("Unexpected number of %s descendant elements.", elementName)); } /** * Asserts that the actual HTTP status code matches one of the expected * status codes. * * @param actualCode * The actual status code. * @param expectedCodes * An int[] array containing the expected status codes. */ public static void assertStatusCode(int actualCode, int[] expectedCodes) { Arrays.sort(expectedCodes); // precondition for binary search Assert.assertTrue(Arrays.binarySearch(expectedCodes, actualCode) >= 0, String .format("Expected status code(s) %s but received %d.", Arrays.toString(expectedCodes), actualCode)); } /** * Asserts that the given DOM document contains a description of a "Simple * WFS" implementation. * * @param doc * A Document node representing a WFS capabilities document * (wfs:WFS_Capabilities}. */ public static void assertSimpleWFSCapabilities(Document doc) { SchematronValidator validator = ValidationUtils.buildSchematronValidator("wfs-capabilities-2.0.sch", "SimpleWFSPhase"); Result result = validator.validate(new DOMSource(doc, doc.getDocumentURI()), false); Assert.assertFalse(validator.ruleViolationsDetected(), ErrorMessage.format(ErrorMessageKeys.NOT_SCHEMA_VALID, validator.getRuleViolationCount(), XMLUtils.resultToString(result))); } /** * Asserts that the given GetFeature response entity contains the expected * number of feature instances having the specified type name. * * @param featureCollection * A Document representing a GetFeature response * (wfs:FeatureCollection). * @param featureType * The qualified name of a feature type; this may be null, in * which case the actual type is ignored. * @param expectedCount * The expected number of feature instances. */ public static void assertFeatureCount(Document featureCollection, QName featureType, int expectedCount) { NodeList features; if (null != featureType) { features = featureCollection.getElementsByTagNameNS(featureType.getNamespaceURI(), featureType.getLocalPart()); Assert.assertEquals(features.getLength(), expectedCount, String.format("Unexpected number of %s feature instances in response.", featureType)); } else { features = featureCollection.getElementsByTagNameNS(WFS2.NS_URI, "member"); Assert.assertEquals(features.getLength(), expectedCount, "Unexpected number of feature members in response."); } } /** * Asserts that the given response message contains an OGC exception report. * The message body must contain an XML document that has a document element * with the following properties: * *
    *
  • [local name] = "ExceptionReport"
  • *
  • [namespace name] = "http://www.opengis.net/ows/1.1"
  • *
* * @param rspEntity * A Document node representing an HTTP response entity. * @param exceptionCode * The expected OGC exception code. * @param locator * A case-insensitive string value expected to occur in the * locator attribute (e.g. a parameter name); the attribute value * will be ignored if the argument is null or empty. */ public static void assertExceptionReport(Document rspEntity, String exceptionCode, String locator) { String expr = String.format("//ows11:Exception[@exceptionCode = '%s']", exceptionCode); NodeList nodeList = null; try { nodeList = XMLUtils.evaluateXPath(rspEntity, expr, Collections.singletonMap(Namespaces.OWS, "ows11")); } catch (XPathExpressionException xpe) { // won't happen } Assert.assertTrue(nodeList.getLength() > 0, "Exception not found in response: " + expr); if (null != locator && !locator.isEmpty()) { Element exception = (Element) nodeList.item(0); String locatorValue = exception.getAttribute("locator").toLowerCase(); Assert.assertTrue(locatorValue.contains(locator.toLowerCase()), String.format("Expected locator attribute to contain '%s']", locator)); } } /** * Asserts that the specified spatial reference occurs in the given XML * entity. In general the reference is conveyed by the srsName attribute * that may appear on any geometry element or gml:Envelope. All occurrences * must match. * * @param entity * A Document representing an XML entity such as a GML document * or a WFS GetFeature response. * @param crsId * A CRS identifier (an absolute URI value). */ public static void assertSpatialReference(Document entity, String crsId) { NodeList srsNameNodes = null; try { srsNameNodes = XMLUtils.evaluateXPath(entity, "//*/@srsName", null); } catch (XPathExpressionException e) { throw new AssertionError(e.getMessage()); } for (int i = 0; i < srsNameNodes.getLength(); i++) { Attr attr = (Attr) srsNameNodes.item(i); Assert.assertEquals(attr.getValue(), crsId, String.format("Unexpected @srsName value on element %s", new QName(attr.getNamespaceURI(), attr.getLocalName()))); } } /** * Asserts that the given response entity contains at least one feature * instance of the specified type. * * @param entity * A Document representing a GetFeature response entity * (wfs:FeatureCollection). * @param featureType * A QName that identifies the expected feature type; if null, * any type is acceptable. */ public static void assertResultSetNotEmpty(Document entity, QName featureType) { NodeList features; if (null != featureType) { features = entity.getElementsByTagNameNS(featureType.getNamespaceURI(), featureType.getLocalPart()); } else { features = entity.getElementsByTagNameNS(WFS2.NS_URI, "member"); } Assert.assertTrue(features.getLength() > 0, String.format("Expected one or more feature instances in response (type: %s).", (null != featureType) ? featureType : "any")); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy