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

com.vividsolutions.jtstest.testrunner.TestReader Maven / Gradle / Ivy

The newest version!


/*
 * The JTS Topology Suite is a collection of Java classes that
 * implement the fundamental operations required to validate a given
 * geo-spatial data set to a known topological specification.
 *
 * Copyright (C) 2001 Vivid Solutions
 *
 * 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; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * For more information, contact:
 *
 *     Vivid Solutions
 *     Suite #1A
 *     2328 Government Street
 *     Victoria BC  V8T 5G5
 *     Canada
 *
 *     (250)385-6040
 *     www.vividsolutions.com
 */
package com.vividsolutions.jtstest.testrunner;

import com.vividsolutions.jts.geom.*;
import com.vividsolutions.jts.io.*;
import com.vividsolutions.jtstest.*;
import java.io.*;
import java.util.*;
import org.jdom.*;
import org.jdom.input.*;

import com.vividsolutions.jtstest.geomop.*;
import com.vividsolutions.jtstest.util.*;
import com.vividsolutions.jtstest.util.StringUtil;

/**
 * @version 1.7
 */
public class TestReader
{
	private static final String TAG_geometryOperation = "geometryOperation"; 
	private static final String TAG_resultMatcher = "resultMatcher"; 
	
    Vector parsingProblems = new Vector();
    private GeometryFactory geometryFactory;
    private WKTOrWKBReader wktorbReader;
    private double tolerance = 0.0;
    private GeometryOperation geomOp = null;
    private ResultMatcher resultMatcher = null;
    
    public TestReader() 
    {
    }

    public GeometryOperation getGeometryOperation()
    {
    	// use the main one if it was user-specified or this run does not have an op specified
    	if (TopologyTestApp.isGeometryOperationSpecified()
    			|| geomOp == null)
    		return TopologyTestApp.getGeometryOperation();
    	
    	return geomOp;
    }

    public boolean isBooleanFunction(String name) {
        return getGeometryOperation().getReturnType(name) == boolean.class;
    }

    public boolean isIntegerFunction(String name) {
        return getGeometryOperation().getReturnType(name) == int.class;
    }

    public boolean isDoubleFunction(String name) {
        return getGeometryOperation().getReturnType(name) == double.class;
    }

    public boolean isGeometryFunction(String name) 
    {
    	Class returnType = getGeometryOperation().getReturnType(name);
    	if (returnType == null)
    		return false;
    	return Geometry.class.isAssignableFrom(returnType);
	}

    public List getParsingProblems() {
        return Collections.unmodifiableList(parsingProblems);
    }

    public void clearParsingProblems() {
        parsingProblems.clear();
    }

    public TestRun createTestRun(File testFile, int runIndex) {
        try {
            SAXBuilder builder = new LineNumberSAXBuilder();
            Document document = builder.build(new FileInputStream(testFile));
            Element runElement = document.getRootElement();
            if (!runElement.getName().equalsIgnoreCase("run")) {
                throw new TestParseException(
                    "Expected  but encountered <" + runElement.getName() + ">");
            }
            return parseTestRun(runElement, testFile, runIndex);
        } catch (Exception e) {
            parsingProblems.add(
                "An exception occurred while parsing " + testFile + ": " + e.toString());
            return null;
        }
    }
    
    /**
     *  Creates a List of Test's from the given  Element's.
     */
    private List parseTests(
        List testElements,
        int caseIndex,
        File testFile,
        TestCase testCase,
        double tolerance)
        throws TestParseException {
        List tests = new ArrayList();
        int testIndex = 0;
        for (Iterator i = testElements.iterator(); i.hasNext();) {
            Element testElement = (Element) i.next();
            testIndex++;
            try {
                Element descElement = testElement.getChild("desc");
                if (testElement.getChildren("op").size() > 1) {
                    throw new TestParseException("Multiple s in ");
                }
                Element opElement = testElement.getChild("op");
                if (opElement == null) {
                    throw new TestParseException("Missing  in ");
                }
                Attribute nameAttribute = opElement.getAttribute("name");
                if (nameAttribute == null) {
                    throw new TestParseException("Missing name attribute in ");
                }
                String arg1 =
                    opElement.getAttribute("arg1") == null
                        ? "A"
                        : opElement.getAttribute("arg1").getValue().trim();
                String arg2 =
                    opElement.getAttribute("arg2") == null
                        ? null
                        : opElement.getAttribute("arg2").getValue().trim();
                String arg3 =
                    opElement.getAttribute("arg3") == null
                        ? null
                        : opElement.getAttribute("arg3").getValue().trim();
                if (arg3 == null && nameAttribute.getValue().trim().equalsIgnoreCase("relate")) {
                    arg3 =
                        opElement.getAttribute("pattern") == null
                            ? null
                            : opElement.getAttribute("pattern").getValue().trim();
                }
                ArrayList arguments = new ArrayList();
                if (arg2 != null) {
                    arguments.add(arg2);
                }
                if (arg3 != null) {
                    arguments.add(arg3);
                }
                Result result = toResult(
                        opElement.getTextTrim(),
                        nameAttribute.getValue().trim(),
                        testCase.getTestRun());
                Test test = new Test(
                		testCase, 
                		testIndex,
                		descElement != null ? descElement.getTextTrim() : "", 
                		nameAttribute.getValue().trim(), 
                		arg1, 
                		arguments, 
                		result, 
                		tolerance);

                tests.add(test);
            } catch (Exception e) {
                parsingProblems.add(
                    "An exception occurred while parsing  "
                        + testIndex
                        + " in  "
                        + caseIndex
                        + " in "
                        + testFile
                        + ": "
                        + e.toString() + "\n" + StringUtil.getStackTrace(e));
            }
        }
        return tests;
    }

    private Result toResult(String value, String name, TestRun testRun)
        throws TestParseException, ParseException {
        if (isBooleanFunction(name)) {
            return toBooleanResult(value);
        }
        if (isIntegerFunction(name)) {
            return toIntegerResult(value);
        }
        if (isDoubleFunction(name)) {
            return toDoubleResult(value);
        }
        if (isGeometryFunction(name)) {
            return toGeometryResult(value, testRun);
        }
        throw new TestParseException(
            "Unknown operation name '" + name + "'");
//        return null;
    }

    private BooleanResult toBooleanResult(String value) throws TestParseException {
        if (value.equalsIgnoreCase("true")) {
            return new BooleanResult(true);
        } else if (value.equalsIgnoreCase("false")) {
            return new BooleanResult(false);
        } else {
            throw new TestParseException(
                "Expected 'true' or 'false' but encountered '" + value + "'");
        }
    }

    private DoubleResult toDoubleResult(String value) throws TestParseException {
        try {
            return new DoubleResult(Double.valueOf(value));
        } catch (NumberFormatException e) {
            throw new TestParseException("Expected double but encountered '" + value + "'");
        }
    }

    private IntegerResult toIntegerResult(String value) throws TestParseException {
        try {
            return new IntegerResult(Integer.valueOf(value));
        } catch (NumberFormatException e) {
            throw new TestParseException("Expected integer but encountered '" + value + "'");
        }
    }

    private GeometryResult toGeometryResult(String value, TestRun testRun) throws ParseException {
        GeometryFactory geometryFactory = new GeometryFactory(testRun.getPrecisionModel(), 0);
        WKTOrWKBReader wktorbReader = new WKTOrWKBReader(geometryFactory);
        return new GeometryResult(wktorbReader.read(value));
    }

    /**
     *  Creates a List of TestCase's from the given  Element's.
     */
    private List parseTestCases(
        List caseElements,
        File testFile,
        TestRun testRun,
        double tolerance)
        throws TestParseException {
        geometryFactory = new GeometryFactory(testRun.getPrecisionModel(), 0, TestCoordinateSequenceFactory.instance());
        wktorbReader = new WKTOrWKBReader(geometryFactory);
        Vector testCases = new Vector();
        int caseIndex = 0;
        for (Iterator i = caseElements.iterator(); i.hasNext();) {
            Element caseElement = (Element) i.next();
            //System.out.println("Line: " + ((LineNumberElement)caseElement).getStartLine());
            caseIndex++;
            try {
                Element descElement = caseElement.getChild("desc");
                Element aElement = caseElement.getChild("a");
                Element bElement = caseElement.getChild("b");
                File aWktFile = wktFile(aElement, testRun);
                File bWktFile = wktFile(bElement, testRun);
                Geometry a = readGeometry(aElement, absoluteWktFile(aWktFile, testRun));
                Geometry b = readGeometry(bElement, absoluteWktFile(bWktFile, testRun));
                TestCase testCase =
                    new TestCase(
                        descElement != null ? descElement.getTextTrim() : "",
                        a,
                        b,
                        aWktFile,
                        bWktFile,
                        testRun,
                        caseIndex,
                        ((LineNumberElement)caseElement).getStartLine());
                List testElements = caseElement.getChildren("test");
                //        if (testElements.size() == 0) {
                //          throw  new TestParseException("Missing  in ");
                //        }
                List tests = parseTests(testElements, caseIndex, testFile, testCase, tolerance);
                for (Iterator j = tests.iterator(); j.hasNext();) {
                    Test test = (Test) j.next();
                    testCase.add(test);
                }
                testCases.add(testCase);
            } catch (Exception e) {
                parsingProblems.add(
                    "An exception occurred while parsing  "
                        + caseIndex
                        + " in "
                        + testFile
                        + ": "
                        + e.toString());
            }
        }
        return testCases;
    }

    /**
     *  Creates a TestRun from the  Element.
     */
    private TestRun parseTestRun(Element runElement, File testFile, int runIndex)
        throws TestParseException 
    {
    	
      //-----------  (optional) ------------------
        File workspace = null;
        if (runElement.getChild("workspace") != null) {
            if (runElement.getChild("workspace").getAttribute("dir") == null) {
                throw new TestParseException("Missing  in ");
            }
            workspace =
                new File(runElement.getChild("workspace").getAttribute("dir").getValue().trim());
            if (!workspace.exists()) {
                throw new TestParseException(" does not exist: " + workspace);
            }
            if (!workspace.isDirectory()) {
                throw new TestParseException(" is not a directory: " + workspace);
            }
        }
        
        //-----------  (optional) ------------------
        tolerance = parseTolerance(runElement);
        
        Element descElement = runElement.getChild("desc");

        //-----------  (optional) ------------------
        geomOp = parseGeometryOperation(runElement);
        
        //-----------  (optional) ------------------
        resultMatcher = parseResultMatcher(runElement);
        
        //-----------   (optional) ----------------
        PrecisionModel precisionModel = parsePrecisionModel(runElement);
        
        //--------------- build TestRun  ---------------------
        TestRun testRun =
            new TestRun(
                descElement != null ? descElement.getTextTrim() : "",
                runIndex,
                precisionModel,
                geomOp,
                resultMatcher,
                testFile);
        testRun.setWorkspace(workspace);
        List caseElements = runElement.getChildren("case");
        if (caseElements.size() == 0) {
            throw new TestParseException("Missing  in ");
        }
        for (Iterator i = parseTestCases(caseElements, testFile, testRun, tolerance).iterator();
            i.hasNext();
            ) {
            TestCase testCase = (TestCase) i.next();
            testRun.addTestCase(testCase);
        }
        return testRun;
    }

    /**
     * Parses an optional precisionModel element.
     * The default is to use a FLOATING model.
     * 
     * @param runElement
     * @return a PrecisionModel instance (default if not specified)
     * @throws TestParseException
     */
    private PrecisionModel parsePrecisionModel(Element runElement)
    	throws TestParseException
    {
      PrecisionModel precisionModel = new PrecisionModel();
      Element precisionModelElement = runElement.getChild("precisionModel");
      if (precisionModelElement == null) {
        return precisionModel;
      }
      Attribute typeAttribute = precisionModelElement.getAttribute("type");
      Attribute scaleAttribute = precisionModelElement.getAttribute("scale");
      if (typeAttribute == null && scaleAttribute == null) {
          throw new TestParseException("Missing type attribute in ");
      }
      if (scaleAttribute != null
          || (typeAttribute != null && typeAttribute.getValue().trim().equalsIgnoreCase("FIXED"))) {
          if (typeAttribute != null
              && typeAttribute.getValue().trim().equalsIgnoreCase("FLOATING")) {
              throw new TestParseException("scale attribute not allowed in floating ");
          }
          precisionModel = createPrecisionModel(precisionModelElement);
      }
      return precisionModel;
    }
    
    private PrecisionModel createPrecisionModel(Element precisionModelElement)
			throws TestParseException {
		Attribute scaleAttribute = precisionModelElement.getAttribute("scale");
		if (scaleAttribute == null) {
			throw new TestParseException(
					"Missing scale attribute in ");
		}
		double scale;
		try {
			scale = scaleAttribute.getDoubleValue();
		} catch (DataConversionException e) {
			throw new TestParseException(
					"Could not convert scale attribute to double: "
							+ scaleAttribute.getValue());
		}
		return new PrecisionModel(scale);
	}


    /**
		 * Parses an optional geometryOperation element. 
		 * The default is to leave this unspecified .
		 * 
		 * @param runElement
		 * @return an instance of the GeometryOperation class, if specified, or
		 * null if no geometry operation was specified
		 * @throws TestParseException if a parsing error was encountered
		 */
    private GeometryOperation parseGeometryOperation(Element runElement)
  	throws TestParseException
  {
    Element goElement = runElement.getChild(TAG_geometryOperation);
    if (goElement == null) {
      return null;
    }
    String goClass = goElement.getTextTrim();
    GeometryOperation geomOp = (GeometryOperation) getInstance(goClass, GeometryOperation.class);
    if (geomOp == null) {
    	throw new TestParseException("Could not create instance of GeometryOperation from class " + goClass);
    }
    return geomOp;
  }
 
    /**
		 * Parses an optional resultMatcher element. 
		 * The default is to leave this unspecified .
		 * 
		 * @param runElement
		 * @return an instance of the ResultMatcher class, if specified, or
		 *  null if no result matcher was specified
		 * @throws TestParseException if a parsing error was encountered
		 */
    private ResultMatcher parseResultMatcher(Element runElement)
  	throws TestParseException
  {
    Element goElement = runElement.getChild(TAG_resultMatcher);
    if (goElement == null) {
      return null;
    }
    String goClass = goElement.getTextTrim();
    ResultMatcher resultMatcher = (ResultMatcher) getInstance(goClass, ResultMatcher.class);
    if (resultMatcher == null) {
    	throw new TestParseException("Could not create instance of ResultMatcher from class " + goClass);
    }
    return resultMatcher;
  }
 
  private double parseTolerance(Element runElement) throws TestParseException 
    {
		double tolerance = 0.0;
		// Note: the tolerance element applies to the coordinate-by-coordinate
		// comparisons of spatial functions. It does not apply to binary predicates.
		// [Jon Aquino]
		Element toleranceElement = runElement.getChild("tolerance");
		if (toleranceElement != null) {
			try {
				tolerance = Double.parseDouble(toleranceElement.getTextTrim());
			} catch (NumberFormatException e) {
				throw new TestParseException("Could not parse tolerance from string: "
						+ toleranceElement.getTextTrim());
			}
		}
		return tolerance;
	}

  /*
	private GeometryOperation getGeometryOperationInstance(String classname) {
		GeometryOperation op = null;
		try {
			Class goClass = Class.forName(classname);
			if (!(GeometryOperation.class.isAssignableFrom(goClass)))
				return null;
			op = (GeometryOperation) goClass.newInstance();
		} catch (Exception ex) {
			return null;
		}
		return op;
	}
    */
  
  /**
   * Gets an instance of a class with the given name, 
   * and ensures that the class is assignable to a specified baseClass.
   * 
   * @return an instance of the class, if it is assignment-compatible, or
   *  null if the requested class is not assigment-compatible
   */
	private Object getInstance(String classname, Class baseClass) {
		Object o = null;
		try {
			Class goClass = Class.forName(classname);
			if (!(baseClass.isAssignableFrom(goClass)))
				return null;
			o = goClass.newInstance();
		} catch (Exception ex) {
			return null;
		}
		return o;
	}
    
    private File wktFile(Element geometryElement, TestRun testRun) throws TestParseException {
        if (geometryElement == null) {
            return null;
        }
        if (geometryElement.getAttribute("file") == null) {
            return null;
        }
        if (!geometryElement.getTextTrim().equals("")) {
            throw new TestParseException("WKT specified both in-line and in external file");
        }

        File wktFile = new File(geometryElement.getAttribute("file").getValue().trim());
        File absoluteWktFile = absoluteWktFile(wktFile, testRun);

        if (!absoluteWktFile.exists()) {
            throw new TestParseException("WKT file does not exist: " + absoluteWktFile);
        }
        if (absoluteWktFile.isDirectory()) {
            throw new TestParseException("WKT file is a directory: " + absoluteWktFile);
        }

        return wktFile;
    }

    private Geometry readGeometry(Element geometryElement, File wktFile)
        throws FileNotFoundException, ParseException, IOException
    {
      String geomText = null;
      if (wktFile != null) {
        List wktList = FileUtil.getContents(wktFile.getPath());
        geomText = toString(wktList);
      }
      else {
        if (geometryElement == null)
          return null;
        geomText = geometryElement.getTextTrim();
      }
      return wktorbReader.read(geomText);
        /*
        if (isHex(geomText, 6))
          return wkbReader.read(WKBReader.hexToBytes(geomText));
        reurn wktReader.read(geomText);
        */
    }

    private String toString(List stringList) {
        String string = "";
        for (Iterator i = stringList.iterator(); i.hasNext();) {
            String line = (String) i.next();
            string += line + "\n";
        }
        return string;
    }

    private File absoluteWktFile(File wktFile, TestRun testRun) {
        if (wktFile == null) {
            return null;
        }
        File absoluteWktFile = wktFile;
        if (!absoluteWktFile.isAbsolute()) {
            File directory =
                testRun.getWorkspace() != null
                    ? testRun.getWorkspace()
                    : testRun.getTestFile().getParentFile();
            absoluteWktFile = new File(directory + File.separator + absoluteWktFile.getName());
        }
        return absoluteWktFile;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy