This is an automated email from the ASF dual-hosted git repository.

afs pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git


The following commit(s) were added to refs/heads/main by this push:
     new a4ed0f9fb9 Organise GeoSPARQL function tests by function
a4ed0f9fb9 is described below

commit a4ed0f9fb9389e9298d6d131c33bb1c7d21719ef
Author: Edmond Chuc <[email protected]>
AuthorDate: Mon Sep 28 00:41:19 2026 +1000

    Organise GeoSPARQL function tests by function
    
    * Split GeoSPARQL geometry metadata function tests
    
    * Split GeoSPARQL coordinate extrema function tests
    
    * Refine GeoSPARQL centroid function tests
    
    * Move GeometryTransformIndexTest alongside other index tests
---
 .../filter_functions/CentroidFFTest.java           |  25 +-
 .../GeometryCoordinateExtremaFFTest.java           | 284 ---------------------
 .../GeometryMetadataErrorsTest.java                | 147 -----------
 .../geometry_property/GeometryMetadataFFTest.java  | 145 -----------
 .../GeometryPropertyFFTestSupport.java             |  64 +++++
 .../geometry_property/Is3DFFTest.java              | 102 ++++++++
 .../geometry_property/IsEmptyFFTest.java           |  12 +
 .../geometry_property/IsMeasuredFFTest.java        | 102 ++++++++
 .../geometry_property/MaxXFFTest.java              | 136 ++++++++++
 .../geometry_property/MaxYFFTest.java              | 136 ++++++++++
 .../geometry_property/MaxZFFTest.java              | 130 ++++++++++
 .../geometry_property/MinXFFTest.java              | 136 ++++++++++
 .../geometry_property/MinYFFTest.java              | 136 ++++++++++
 .../geometry_property/MinZFFTest.java              | 130 ++++++++++
 .../geometry_property/NumGeometriesFFTest.java     |  86 +++++++
 .../{ => index}/GeometryTransformIndexTest.java    |   4 +-
 16 files changed, 1185 insertions(+), 590 deletions(-)

diff --git 
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/nontopological/filter_functions/CentroidFFTest.java
 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/nontopological/filter_functions/CentroidFFTest.java
index 685bc33cbc..5274baf007 100644
--- 
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/nontopological/filter_functions/CentroidFFTest.java
+++ 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/nontopological/filter_functions/CentroidFFTest.java
@@ -23,7 +23,6 @@ package 
org.apache.jena.geosparql.geof.nontopological.filter_functions;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 
@@ -34,7 +33,6 @@ import 
org.apache.jena.geosparql.implementation.datatype.WKTDatatype;
 import 
org.apache.jena.geosparql.implementation.jts.CoordinateSequenceDimensions;
 import org.apache.jena.graph.Node;
 import org.apache.jena.graph.NodeFactory;
-import org.apache.jena.query.QueryBuildException;
 import org.apache.jena.query.QueryExecution;
 import org.apache.jena.query.QuerySolution;
 import org.apache.jena.query.ResultSet;
@@ -114,6 +112,19 @@ public class CentroidFFTest {
         assertEquals(300, result.getXYGeometry().getCoordinate().getY(), 0);
     }
 
+    @Test
+    public void directExecutionAcceptsExplicitWktCrs() {
+        NodeValue input = NodeValue.makeNode(
+            "<http://www.opengis.net/def/crs/EPSG/0/27700> LINESTRING (100 
200, 300 400)", WKTDatatype.INSTANCE);
+        NodeValue output = new CentroidFF().exec(input);
+        assertEquals(WKTDatatype.URI, output.asNode().getLiteralDatatypeURI());
+        GeometryWrapper result = GeometryWrapper.extract(output.asNode());
+        assertPointMetadata(result);
+        assertEquals("http://www.opengis.net/def/crs/EPSG/0/27700";, 
result.getSrsURI());
+        assertEquals(200, result.getXYGeometry().getCoordinate().getX(), 0);
+        assertEquals(300, result.getXYGeometry().getCoordinate().getY(), 0);
+    }
+
     @Test
     public void geographicCentroidIsPlanar() {
         assertCentroid("MULTIPOINT ((170 10), (-170 10))", 0, 10);
@@ -194,16 +205,6 @@ public class CentroidFFTest {
                 NodeValue.makeNode(NodeFactory.createURI("urn:geometry")), 
NodeValue.makeNode("invalid", WKTDatatype.INSTANCE) }) {
             assertThrows(ExprEvalException.class, () -> function.exec(value));
         }
-        for (String value : new String[] { "42", "'POINT (1 2)'", 
"<urn:geometry>", "'invalid'^^geo:wktLiteral", "?missing" }) {
-            assertNull(evaluate("geof:centroid(" + value + ")"));
-        }
-    }
-
-    @Test
-    public void wrongArityIsRejectedAtQueryBuild() {
-        assertThrows(QueryBuildException.class, () -> 
evaluate("geof:centroid()"));
-        assertThrows(QueryBuildException.class,
-                     () -> evaluate("geof:centroid('POINT 
EMPTY'^^geo:wktLiteral, 1)"));
     }
 
     private static void assertCentroid(String wkt, double x, double y) {
diff --git 
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/GeometryCoordinateExtremaFFTest.java
 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/GeometryCoordinateExtremaFFTest.java
deleted file mode 100644
index 418893b171..0000000000
--- 
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/GeometryCoordinateExtremaFFTest.java
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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
- *
- *   https://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.
- *
- *   SPDX-License-Identifier: Apache-2.0
- */
-package 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.assertThrows;
-import static org.junit.Assume.assumeFalse;
-
-import java.util.List;
-
-import org.apache.jena.geosparql.configuration.GeoSPARQLConfig;
-import org.apache.jena.geosparql.implementation.datatype.WKTDatatype;
-import org.apache.jena.graph.Node;
-import org.apache.jena.graph.NodeFactory;
-import org.apache.jena.query.QueryBuildException;
-import org.apache.jena.query.QueryExecution;
-import org.apache.jena.query.QuerySolution;
-import org.apache.jena.query.ResultSet;
-import org.apache.jena.rdf.model.ModelFactory;
-import org.apache.jena.sparql.expr.ExprEvalException;
-import org.apache.jena.sparql.expr.NodeValue;
-import org.apache.jena.sparql.function.FunctionBase1;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-@RunWith(Parameterized.class)
-public class GeometryCoordinateExtremaFFTest {
-    @Parameterized.Parameters(name = "function: {0}")
-    public static List<Object[]> functions() {
-        return List.of(
-            new Object[] { "minX", new MinXFF() },
-            new Object[] { "minY", new MinYFF() },
-            new Object[] { "minZ", new MinZFF() },
-            new Object[] { "maxX", new MaxXFF() },
-            new Object[] { "maxY", new MaxYFF() },
-            new Object[] { "maxZ", new MaxZFF() }
-        );
-    }
-
-    private final String name;
-    private final FunctionBase1 function;
-
-    public GeometryCoordinateExtremaFFTest(String name, FunctionBase1 
function) {
-        this.name = name;
-        this.function = function;
-    }
-
-    @BeforeClass
-    public static void setup() {
-        GeoSPARQLConfig.setupNoIndex();
-    }
-
-    @Test
-    public void iriArgumentRaisesExpressionError() {
-        assertThrows(ExprEvalException.class, () -> 
function.exec(NodeValue.makeNode(NodeFactory.createURI("urn:not-a-literal"))));
-    }
-
-    @Test
-    public void numericArgumentRaisesExpressionError() {
-        assertThrows(ExprEvalException.class, () -> 
function.exec(NodeValue.makeInteger(42)));
-    }
-
-    @Test
-    public void stringWithoutGeometryDatatypeRaisesExpressionError() {
-        assertThrows(ExprEvalException.class, () -> 
function.exec(NodeValue.makeString("POINT (1 2)")));
-    }
-
-    @Test
-    public void malformedWktRaisesExpressionError() {
-        NodeValue malformed = NodeValue.makeNode("invalid", 
WKTDatatype.INSTANCE);
-        assertThrows(ExprEvalException.class, () -> function.exec(malformed));
-    }
-
-    @Test
-    public void iriArgumentLeavesBindUnbound() {
-        assertUnbound("<urn:not-a-literal>");
-    }
-
-    @Test
-    public void numericArgumentLeavesBindUnbound() {
-        assertUnbound("42");
-    }
-
-    @Test
-    public void stringWithoutGeometryDatatypeLeavesBindUnbound() {
-        assertUnbound("'POINT (1 2)'");
-    }
-
-    @Test
-    public void malformedWktLeavesBindUnbound() {
-        assertUnbound("'invalid'^^geo:wktLiteral");
-    }
-
-    @Test
-    public void unboundArgumentLeavesBindUnbound() {
-        assertUnbound("?missing");
-    }
-
-    @Test
-    public void missingArgumentIsRejectedAtQueryBuild() {
-        assertThrows(QueryBuildException.class, () -> evaluate("geof:" + name 
+ "()"));
-    }
-
-    @Test
-    public void extraArgumentIsRejectedAtQueryBuild() {
-        assertThrows(QueryBuildException.class,
-                     () -> evaluate("geof:" + name + "('POINT 
EMPTY'^^geo:wktLiteral, 1)"));
-    }
-
-    @Test
-    public void extremaReturnDoubleLiterals() {
-        double expected = switch (name) {
-            case "minX" -> -9;
-            case "maxX" -> -2;
-            case "minY" -> 3;
-            case "maxY" -> 8;
-            case "minZ" -> -7;
-            case "maxZ" -> -1;
-            default -> throw new AssertionError(name);
-        };
-        assertEquals(NodeValue.makeDouble(expected).asNode(),
-                     evaluate("geof:" + name + "('LINESTRING ZM (-9 8 -7 100, 
-2 3 -1 -100)'^^geo:wktLiteral)"));
-    }
-
-    @Test
-    public void epsg4326LineStringExtremaFollowSrsDimensionOrder() {
-        String argument = "'<http://www.opengis.net/def/crs/EPSG/0/4326> "
-                        + "LINESTRING (10 100, 20 120)'^^geo:wktLiteral";
-        if (name.endsWith("Z")) {
-            assertUnbound(argument);
-        } else {
-            double expected = switch (name) {
-                case "minX" -> 10;
-                case "maxX" -> 20;
-                case "minY" -> 100;
-                case "maxY" -> 120;
-                default -> throw new AssertionError(name);
-            };
-            assertEquals(NodeValue.makeDouble(expected).asNode(),
-                         evaluate("geof:" + name + "(" + argument + ")"));
-        }
-    }
-
-    @Test
-    public void infiniteOrdinateRaisesExpressionErrorAndLeavesBindUnbound() {
-        for (String infinity : new String[] { "Infinity", "-Infinity" }) {
-            String coordinate = switch (name.charAt(name.length() - 1)) {
-                case 'X' -> infinity + " 1 1";
-                case 'Y' -> "1 " + infinity + " 1";
-                case 'Z' -> "1 1 " + infinity;
-                default -> throw new AssertionError(name);
-            };
-            String wkt = "LINESTRING Z (-4 -4 -4, " + coordinate + ", 9 9 9)";
-            assertThrows(wkt, ExprEvalException.class,
-                         () -> function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
-            assertUnbound("'" + wkt + "'^^geo:wktLiteral");
-        }
-    }
-
-    @Test
-    public void nanXYOrdinateRaisesExpressionErrorAndLeavesBindUnbound() {
-        assumeFalse("Only X/Y extrema are covered by this test", 
name.endsWith("Z"));
-        String coordinate = name.endsWith("Y") ? "2 NaN" : "NaN 2";
-        String wkt = "LINESTRING (1 1, " + coordinate + ", 3 3)";
-        assertThrows(wkt, ExprEvalException.class,
-                     () -> function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
-        assertUnbound("'" + wkt + "'^^geo:wktLiteral");
-    }
-
-    @Test
-    public void emptyGeometryRaisesExpressionErrorAndLeavesBindUnbound() {
-        assertThrows(ExprEvalException.class,
-                     () -> function.exec(NodeValue.makeNode("POINT Z EMPTY", 
WKTDatatype.INSTANCE)));
-        assertUnbound("'POINT Z EMPTY'^^geo:wktLiteral");
-    }
-
-    @Test
-    public void layoutsWithoutZStillHaveXYExtrema() {
-        for (String wkt : new String[] { "POINT (1 2)", "POINT M (1 2 99)" }) {
-            if (name.endsWith("Z")) {
-                assertThrows(wkt, ExprEvalException.class,
-                             () -> function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
-                assertUnbound("'" + wkt + "'^^geo:wktLiteral");
-            } else {
-                double expected = name.endsWith("X") ? 1 : 2;
-                assertEquals(wkt, NodeValue.makeDouble(expected).asNode(),
-                             evaluate("geof:" + name + "('" + wkt + 
"'^^geo:wktLiteral)"));
-            }
-        }
-    }
-
-    @Test
-    public void multiPointExtremaDistinguishZFromMeasures() {
-        for (boolean hasZ : new boolean[] { false, true }) {
-            String wkt = hasZ ? "MULTIPOINT ZM ((1 2 -4 10), (3 4 9 20))"
-                              : "MULTIPOINT M ((1 2 10), (3 4 20))";
-            if (name.endsWith("Z") && !hasZ) {
-                assertThrows(ExprEvalException.class,
-                             () -> function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
-                assertUnbound("'" + wkt + "'^^geo:wktLiteral");
-            } else {
-                double value = switch (name) {
-                    case "minX" -> 1;
-                    case "maxX" -> 3;
-                    case "minY" -> 2;
-                    case "maxY" -> 4;
-                    case "minZ" -> -4;
-                    case "maxZ" -> 9;
-                    default -> throw new AssertionError(name);
-                };
-                NodeValue expected = NodeValue.makeDouble(value);
-                assertEquals(expected, function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
-                assertEquals(expected.asNode(), evaluate("geof:" + name + "('" 
+ wkt + "'^^geo:wktLiteral)"));
-            }
-        }
-    }
-
-    @Test
-    public void mixedCollectionExtremaDoNotDependOnMemberOrder() {
-        for (String wkt : new String[] {
-                "GEOMETRYCOLLECTION (POINT Z (1 2 3))",
-                "GEOMETRYCOLLECTION (POINT (1 2), POINT M (1 2 999), POINT Z 
(1 2 3))",
-                "GEOMETRYCOLLECTION (POINT Z (1 2 3), POINT M (1 2 999), POINT 
(1 2))" }) {
-            NodeValue expected = NodeValue.makeDouble(name.endsWith("X") ? 1 : 
name.endsWith("Y") ? 2 : 3);
-            assertEquals(expected, function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
-            assertEquals(expected.asNode(), evaluate("geof:" + name + "('" + 
wkt + "'^^geo:wktLiteral)"));
-        }
-    }
-
-    @Test
-    public void gmlExtremaFollowSrsDimensionOrder() {
-        String point = """
-            '<gml:Point xmlns:gml="http://www.opengis.net/gml/3.2";
-                        srsName="http://www.opengis.net/def/crs/EPSG/0/4979";>
-               <gml:pos srsDimension="3">10 100 -4</gml:pos>
-             </gml:Point>'^^geo:gmlLiteral
-            """.replace("\n", " ");
-        double expected = name.endsWith("X") ? 10 : name.endsWith("Y") ? 100 : 
-4;
-        assertEquals(NodeValue.makeDouble(expected).asNode(), evaluate("geof:" 
+ name + "(" + point + ")"));
-    }
-
-    private static Node evaluate(String expression) {
-        String query = """
-            PREFIX geof: <http://www.opengis.net/def/function/geosparql/>
-            PREFIX geo: <http://www.opengis.net/ont/geosparql#>
-            SELECT ?result WHERE { BIND(%s AS ?result) }
-            """.formatted(expression);
-        try (QueryExecution execution = QueryExecution.create(query, 
ModelFactory.createDefaultModel())) {
-            ResultSet results = execution.execSelect();
-            assertTrue("Expected one solution for " + expression, 
results.hasNext());
-            QuerySolution solution = results.next();
-            assertFalse("Expected only one solution for " + expression, 
results.hasNext());
-            return solution.contains("result") ? 
solution.get("result").asNode() : null;
-        }
-    }
-
-    private void assertUnbound(String argument) {
-        String expression = "geof:" + name + "(" + argument + ")";
-        assertNull(expression, evaluate(expression));
-    }
-}
diff --git 
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/GeometryMetadataErrorsTest.java
 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/GeometryMetadataErrorsTest.java
deleted file mode 100644
index f4f78eb726..0000000000
--- 
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/GeometryMetadataErrorsTest.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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
- *
- *   https://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.
- *
- *   SPDX-License-Identifier: Apache-2.0
- */
-package 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThrows;
-import static org.junit.Assert.assertTrue;
-
-import java.util.List;
-
-import org.apache.jena.geosparql.configuration.GeoSPARQLConfig;
-import org.apache.jena.geosparql.implementation.datatype.WKTDatatype;
-import org.apache.jena.graph.Node;
-import org.apache.jena.graph.NodeFactory;
-import org.apache.jena.query.QueryBuildException;
-import org.apache.jena.query.QueryExecution;
-import org.apache.jena.query.QuerySolution;
-import org.apache.jena.query.ResultSet;
-import org.apache.jena.rdf.model.ModelFactory;
-import org.apache.jena.sparql.expr.ExprEvalException;
-import org.apache.jena.sparql.expr.NodeValue;
-import org.apache.jena.sparql.function.FunctionBase1;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-@RunWith(Parameterized.class)
-public class GeometryMetadataErrorsTest {
-    @Parameterized.Parameters(name = "function: {0}")
-    public static List<Object[]> functions() {
-        return List.of(
-            new Object[] { "is3D", new Is3DFF() },
-            new Object[] { "isMeasured", new IsMeasuredFF() },
-            new Object[] { "numGeometries", new NumGeometriesFF() }
-        );
-    }
-
-    private final String name;
-    private final FunctionBase1 function;
-
-    public GeometryMetadataErrorsTest(String name, FunctionBase1 function) {
-        this.name = name;
-        this.function = function;
-    }
-
-    @BeforeClass
-    public static void setup() {
-        GeoSPARQLConfig.setupNoIndex();
-    }
-
-    @Test
-    public void iriArgumentRaisesExpressionError() {
-        assertThrows(ExprEvalException.class, () -> 
function.exec(NodeValue.makeNode(NodeFactory.createURI("urn:not-a-literal"))));
-    }
-
-    @Test
-    public void numericArgumentRaisesExpressionError() {
-        assertThrows(ExprEvalException.class, () -> 
function.exec(NodeValue.makeInteger(42)));
-    }
-
-    @Test
-    public void stringWithoutGeometryDatatypeRaisesExpressionError() {
-        assertThrows(ExprEvalException.class, () -> 
function.exec(NodeValue.makeString("POINT (1 2)")));
-    }
-
-    @Test
-    public void malformedWktRaisesExpressionError() {
-        NodeValue malformed = NodeValue.makeNode("invalid", 
WKTDatatype.INSTANCE);
-        assertThrows(ExprEvalException.class, () -> function.exec(malformed));
-    }
-
-    @Test
-    public void iriArgumentLeavesBindUnbound() {
-        assertUnbound("<urn:not-a-literal>");
-    }
-
-    @Test
-    public void numericArgumentLeavesBindUnbound() {
-        assertUnbound("42");
-    }
-
-    @Test
-    public void stringWithoutGeometryDatatypeLeavesBindUnbound() {
-        assertUnbound("'POINT (1 2)'");
-    }
-
-    @Test
-    public void malformedWktLeavesBindUnbound() {
-        assertUnbound("'invalid'^^geo:wktLiteral");
-    }
-
-    @Test
-    public void unboundArgumentLeavesBindUnbound() {
-        assertUnbound("?missing");
-    }
-
-    @Test
-    public void missingArgumentIsRejectedAtQueryBuild() {
-        assertThrows(QueryBuildException.class, () -> evaluate("geof:" + name 
+ "()"));
-    }
-
-    @Test
-    public void extraArgumentIsRejectedAtQueryBuild() {
-        assertThrows(QueryBuildException.class,
-                     () -> evaluate("geof:" + name + "('POINT 
EMPTY'^^geo:wktLiteral, 1)"));
-    }
-
-    private static Node evaluate(String expression) {
-        String query = """
-            PREFIX geof: <http://www.opengis.net/def/function/geosparql/>
-            PREFIX geo: <http://www.opengis.net/ont/geosparql#>
-            SELECT ?result WHERE { BIND(%s AS ?result) }
-            """.formatted(expression);
-        try (QueryExecution execution = QueryExecution.create(query, 
ModelFactory.createDefaultModel())) {
-            ResultSet results = execution.execSelect();
-            assertTrue("Expected one solution for " + expression, 
results.hasNext());
-            QuerySolution solution = results.next();
-            assertFalse("Expected only one solution for " + expression, 
results.hasNext());
-            return solution.contains("result") ? 
solution.get("result").asNode() : null;
-        }
-    }
-
-    private void assertUnbound(String argument) {
-        String expression = "geof:" + name + "(" + argument + ")";
-        assertNull(expression, evaluate(expression));
-    }
-}
diff --git 
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/GeometryMetadataFFTest.java
 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/GeometryMetadataFFTest.java
deleted file mode 100644
index e5c3b7d548..0000000000
--- 
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/GeometryMetadataFFTest.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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
- *
- *   https://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.
- *
- *   SPDX-License-Identifier: Apache-2.0
- */
-package 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import org.apache.jena.datatypes.xsd.XSDDatatype;
-import org.apache.jena.geosparql.configuration.GeoSPARQLConfig;
-import org.apache.jena.graph.Node;
-import org.apache.jena.graph.NodeFactory;
-import org.apache.jena.query.QueryExecution;
-import org.apache.jena.query.QuerySolution;
-import org.apache.jena.query.ResultSet;
-import org.apache.jena.rdf.model.ModelFactory;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-public class GeometryMetadataFFTest {
-    private static final String PREFIXES = """
-        PREFIX geof: <http://www.opengis.net/def/function/geosparql/>
-        PREFIX geo: <http://www.opengis.net/ont/geosparql#>
-        """;
-
-    @BeforeClass
-    public static void setup() {
-        GeoSPARQLConfig.setupNoIndex();
-    }
-
-    @Test
-    public void is3DDistinguishesZFromM() {
-        assertResult("geof:is3D('POINT Z (1 2 3)'^^geo:wktLiteral)", "true", 
XSDDatatype.XSDboolean);
-        assertResult("geof:is3D('POINT M (1 2 3)'^^geo:wktLiteral)", "false", 
XSDDatatype.XSDboolean);
-    }
-
-    @Test
-    public void isMeasuredDistinguishesMFromZ() {
-        assertResult("geof:isMeasured('POINT M (1 2 3)'^^geo:wktLiteral)", 
"true", XSDDatatype.XSDboolean);
-        assertResult("geof:isMeasured('POINT Z (1 2 3)'^^geo:wktLiteral)", 
"false", XSDDatatype.XSDboolean);
-    }
-
-    @Test
-    public void emptyPointsRetainZAndMFlags() {
-        assertFlags("POINT EMPTY", false, false);
-        assertFlags("POINT Z EMPTY", true, false);
-        assertFlags("POINT M EMPTY", false, true);
-        assertFlags("POINT ZM EMPTY", true, true);
-    }
-
-    @Test
-    public void emptyCollectionsRetainDeclaredZAndMFlags() {
-        assertFlags("GEOMETRYCOLLECTION EMPTY", false, false);
-        assertFlags("GEOMETRYCOLLECTION Z EMPTY", true, false);
-        assertFlags("GEOMETRYCOLLECTION M EMPTY", false, true);
-        assertFlags("GEOMETRYCOLLECTION ZM EMPTY", true, true);
-    }
-
-    @Test
-    public void permissiveWktCollectionLayoutDoesNotAggregateMemberLayouts() {
-        // Mixed member layouts are a Jena WKT extension, not an SFA 
conformance case.
-        assertFlags("GEOMETRYCOLLECTION (POINT Z (1 2 3), POINT M (4 5 6))", 
false, false);
-    }
-
-    @Test
-    public void numGeometriesCountsMembersAsAnInteger() {
-        assertResult("geof:numGeometries('MULTIPOINT ((1 2), (3 
4))'^^geo:wktLiteral)",
-                     "2", XSDDatatype.XSDinteger);
-    }
-
-    @Test
-    public void numGeometriesDistinguishesEmptyAtomsFromCollections() {
-        assertResult("geof:numGeometries('POINT EMPTY'^^geo:wktLiteral)", "1", 
XSDDatatype.XSDinteger);
-        assertResult("geof:numGeometries('GEOMETRYCOLLECTION 
EMPTY'^^geo:wktLiteral)", "0", XSDDatatype.XSDinteger);
-        assertResult("geof:numGeometries('MULTIPOINT EMPTY'^^geo:wktLiteral)", 
"0", XSDDatatype.XSDinteger);
-        assertResult("geof:numGeometries('GEOMETRYCOLLECTION (POINT 
EMPTY)'^^geo:wktLiteral)",
-                     "1", XSDDatatype.XSDinteger);
-    }
-
-    @Test
-    public void gmlPointUsesMetadataFunctions() {
-        String point = """
-            '<gml:Point xmlns:gml="http://www.opengis.net/gml/3.2";
-                        srsName="http://www.opengis.net/def/crs/OGC/1.3/CRS84";>
-               <gml:pos>1 2</gml:pos>
-             </gml:Point>'^^geo:gmlLiteral
-            """.replace("\n", " ");
-        assertResult("geof:numGeometries(" + point + ")", "1", 
XSDDatatype.XSDinteger);
-        assertResult("geof:is3D(" + point + ")", "false", 
XSDDatatype.XSDboolean);
-        assertResult("geof:isMeasured(" + point + ")", "false", 
XSDDatatype.XSDboolean);
-        assertResult("geof:isEmpty(" + point + ")", "false", 
XSDDatatype.XSDboolean);
-    }
-
-    @Test
-    public void threeDimensionalGmlPointHasZButNoMeasure() {
-        String point = """
-            '<gml:Point xmlns:gml="http://www.opengis.net/gml/3.2";
-                        srsName="http://www.opengis.net/def/crs/EPSG/0/4979";>
-               <gml:pos srsDimension="3">2 1 3</gml:pos>
-             </gml:Point>'^^geo:gmlLiteral
-            """.replace("\n", " ");
-        assertResult("geof:is3D(" + point + ")", "true", 
XSDDatatype.XSDboolean);
-        assertResult("geof:isMeasured(" + point + ")", "false", 
XSDDatatype.XSDboolean);
-        assertResult("geof:isEmpty(" + point + ")", "false", 
XSDDatatype.XSDboolean);
-    }
-
-    private static void assertFlags(String wkt, boolean hasZ, boolean hasM) {
-        assertResult("geof:is3D('" + wkt + "'^^geo:wktLiteral)", 
Boolean.toString(hasZ), XSDDatatype.XSDboolean);
-        assertResult("geof:isMeasured('" + wkt + "'^^geo:wktLiteral)", 
Boolean.toString(hasM), XSDDatatype.XSDboolean);
-    }
-
-    private static void assertResult(String expression, String lexicalForm, 
XSDDatatype datatype) {
-        Node expected = NodeFactory.createLiteralDT(lexicalForm, datatype);
-        assertEquals(expression, expected, evaluate(expression));
-    }
-
-    private static Node evaluate(String expression) {
-        String query = PREFIXES + "SELECT ?result WHERE { BIND(" + expression 
+ " AS ?result) }";
-        try (QueryExecution execution = QueryExecution.create(query, 
ModelFactory.createDefaultModel())) {
-            ResultSet results = execution.execSelect();
-            assertTrue("Expected one solution for " + expression, 
results.hasNext());
-            QuerySolution solution = results.next();
-            assertFalse("Expected only one solution for " + expression, 
results.hasNext());
-            return solution.contains("result") ? 
solution.get("result").asNode() : null;
-        }
-    }
-}
diff --git 
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/GeometryPropertyFFTestSupport.java
 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/GeometryPropertyFFTestSupport.java
new file mode 100644
index 0000000000..e8346cb140
--- /dev/null
+++ 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/GeometryPropertyFFTestSupport.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ *
+ *   https://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.
+ *
+ *   SPDX-License-Identifier: Apache-2.0
+ */
+package 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property;
+
+import org.apache.jena.graph.Node;
+import org.apache.jena.query.QueryExecution;
+import org.apache.jena.query.QuerySolution;
+import org.apache.jena.query.ResultSet;
+import org.apache.jena.rdf.model.ModelFactory;
+
+final class GeometryPropertyFFTestSupport {
+    static final String GML_2D_POINT = """
+        '<gml:Point xmlns:gml="http://www.opengis.net/gml/3.2";
+                    srsName="http://www.opengis.net/def/crs/OGC/1.3/CRS84";>
+           <gml:pos>1 2</gml:pos>
+         </gml:Point>'^^geo:gmlLiteral
+        """.replace("\n", " ");
+
+    static final String GML_3D_POINT = """
+        '<gml:Point xmlns:gml="http://www.opengis.net/gml/3.2";
+                    srsName="http://www.opengis.net/def/crs/EPSG/0/4979";>
+           <gml:pos srsDimension="3">2 1 3</gml:pos>
+         </gml:Point>'^^geo:gmlLiteral
+        """.replace("\n", " ");
+
+    private GeometryPropertyFFTestSupport() {}
+
+    static String wktArgument(String wkt) {
+        return "'" + wkt + "'^^geo:wktLiteral";
+    }
+
+    static Node evaluate(String expression) {
+        String query = """
+            PREFIX geof: <http://www.opengis.net/def/function/geosparql/>
+            PREFIX geo: <http://www.opengis.net/ont/geosparql#>
+            SELECT ?result WHERE { BIND(%s AS ?result) }
+            """.formatted(expression);
+        try (QueryExecution execution = QueryExecution.create(query, 
ModelFactory.createDefaultModel())) {
+            ResultSet results = execution.execSelect();
+            QuerySolution solution = results.next();
+            if (results.hasNext())
+                throw new IllegalStateException("Expected one solution for " + 
expression);
+            return solution.contains("result") ? 
solution.get("result").asNode() : null;
+        }
+    }
+}
diff --git 
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/Is3DFFTest.java
 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/Is3DFFTest.java
new file mode 100644
index 0000000000..b4f302f83d
--- /dev/null
+++ 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/Is3DFFTest.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ *
+ *   https://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.
+ *
+ *   SPDX-License-Identifier: Apache-2.0
+ */
+package 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property;
+
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.GML_2D_POINT;
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.GML_3D_POINT;
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.evaluate;
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.wktArgument;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import org.apache.jena.geosparql.configuration.GeoSPARQLConfig;
+import org.apache.jena.geosparql.implementation.datatype.WKTDatatype;
+import org.apache.jena.graph.NodeFactory;
+import org.apache.jena.sparql.expr.ExprEvalException;
+import org.apache.jena.sparql.expr.NodeValue;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class Is3DFFTest {
+    private final Is3DFF function = new Is3DFF();
+
+    @BeforeClass
+    public static void setup() {
+        GeoSPARQLConfig.setupNoIndex();
+    }
+
+    @Test
+    public void directExecutionAcceptsExplicitWktCrs() {
+        NodeValue geometry = NodeValue.makeNode(
+            "<http://www.opengis.net/def/crs/EPSG/0/27700> POINT Z (1 2 3)", 
WKTDatatype.INSTANCE);
+        assertEquals(NodeValue.makeBoolean(true), function.exec(geometry));
+    }
+
+    @Test
+    public void distinguishesZFromM() {
+        assertResult("POINT Z (1 2 3)", true);
+        assertResult("POINT M (1 2 3)", false);
+    }
+
+    @Test
+    public void emptyPointsRetainDeclaredLayout() {
+        assertResult("POINT EMPTY", false);
+        assertResult("POINT Z EMPTY", true);
+        assertResult("POINT M EMPTY", false);
+        assertResult("POINT ZM EMPTY", true);
+    }
+
+    @Test
+    public void emptyCollectionsRetainDeclaredLayout() {
+        assertResult("GEOMETRYCOLLECTION EMPTY", false);
+        assertResult("GEOMETRYCOLLECTION Z EMPTY", true);
+        assertResult("GEOMETRYCOLLECTION M EMPTY", false);
+        assertResult("GEOMETRYCOLLECTION ZM EMPTY", true);
+    }
+
+    @Test
+    public void permissiveWktCollectionDoesNotAggregateMemberLayouts() {
+        // Mixed member layouts are a Jena WKT extension, not an SFA 
conformance case.
+        assertResult("GEOMETRYCOLLECTION (POINT Z (1 2 3), POINT M (4 5 6))", 
false);
+    }
+
+    @Test
+    public void gmlPointsReportTheirZLayout() {
+        assertEquals(NodeValue.makeBoolean(false).asNode(), 
evaluate("geof:is3D(" + GML_2D_POINT + ")"));
+        assertEquals(NodeValue.makeBoolean(true).asNode(), 
evaluate("geof:is3D(" + GML_3D_POINT + ")"));
+    }
+
+    @Test
+    public void invalidArgumentsRaiseExpressionErrors() {
+        for (NodeValue value : new NodeValue[] {
+                NodeValue.makeNode(NodeFactory.createURI("urn:not-a-literal")),
+                NodeValue.makeInteger(42),
+                NodeValue.makeString("POINT (1 2)"),
+                NodeValue.makeNode("invalid", WKTDatatype.INSTANCE) }) {
+            assertThrows(ExprEvalException.class, () -> function.exec(value));
+        }
+    }
+
+    private static void assertResult(String wkt, boolean expected) {
+        assertEquals(wkt, NodeValue.makeBoolean(expected).asNode(),
+                     evaluate("geof:is3D(" + wktArgument(wkt) + ")"));
+    }
+}
diff --git 
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/IsEmptyFFTest.java
 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/IsEmptyFFTest.java
index fbd7e715f5..817129e8b4 100644
--- 
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/IsEmptyFFTest.java
+++ 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/IsEmptyFFTest.java
@@ -20,6 +20,11 @@
  */
 package 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property;
 
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.GML_2D_POINT;
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.GML_3D_POINT;
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.evaluate;
+
+import org.apache.jena.geosparql.configuration.GeoSPARQLConfig;
 import org.apache.jena.geosparql.implementation.datatype.WKTDatatype;
 import org.apache.jena.sparql.expr.NodeValue;
 import org.junit.After;
@@ -40,6 +45,7 @@ public class IsEmptyFFTest {
 
     @BeforeClass
     public static void setUpClass() {
+        GeoSPARQLConfig.setupNoIndex();
     }
 
     @AfterClass
@@ -80,4 +86,10 @@ public class IsEmptyFFTest {
         assertEquals(expResult, result);
     }
 
+    @Test
+    public void gmlPointsAreNotEmpty() {
+        assertEquals(NodeValue.makeBoolean(false).asNode(), 
evaluate("geof:isEmpty(" + GML_2D_POINT + ")"));
+        assertEquals(NodeValue.makeBoolean(false).asNode(), 
evaluate("geof:isEmpty(" + GML_3D_POINT + ")"));
+    }
+
 }
diff --git 
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/IsMeasuredFFTest.java
 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/IsMeasuredFFTest.java
new file mode 100644
index 0000000000..fe776c0c4c
--- /dev/null
+++ 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/IsMeasuredFFTest.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ *
+ *   https://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.
+ *
+ *   SPDX-License-Identifier: Apache-2.0
+ */
+package 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property;
+
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.GML_2D_POINT;
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.GML_3D_POINT;
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.evaluate;
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.wktArgument;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import org.apache.jena.geosparql.configuration.GeoSPARQLConfig;
+import org.apache.jena.geosparql.implementation.datatype.WKTDatatype;
+import org.apache.jena.graph.NodeFactory;
+import org.apache.jena.sparql.expr.ExprEvalException;
+import org.apache.jena.sparql.expr.NodeValue;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class IsMeasuredFFTest {
+    private final IsMeasuredFF function = new IsMeasuredFF();
+
+    @BeforeClass
+    public static void setup() {
+        GeoSPARQLConfig.setupNoIndex();
+    }
+
+    @Test
+    public void directExecutionAcceptsExplicitWktCrs() {
+        NodeValue geometry = NodeValue.makeNode(
+            "<http://www.opengis.net/def/crs/EPSG/0/27700> POINT M (1 2 3)", 
WKTDatatype.INSTANCE);
+        assertEquals(NodeValue.makeBoolean(true), function.exec(geometry));
+    }
+
+    @Test
+    public void distinguishesMFromZ() {
+        assertResult("POINT M (1 2 3)", true);
+        assertResult("POINT Z (1 2 3)", false);
+    }
+
+    @Test
+    public void emptyPointsRetainDeclaredLayout() {
+        assertResult("POINT EMPTY", false);
+        assertResult("POINT Z EMPTY", false);
+        assertResult("POINT M EMPTY", true);
+        assertResult("POINT ZM EMPTY", true);
+    }
+
+    @Test
+    public void emptyCollectionsRetainDeclaredLayout() {
+        assertResult("GEOMETRYCOLLECTION EMPTY", false);
+        assertResult("GEOMETRYCOLLECTION Z EMPTY", false);
+        assertResult("GEOMETRYCOLLECTION M EMPTY", true);
+        assertResult("GEOMETRYCOLLECTION ZM EMPTY", true);
+    }
+
+    @Test
+    public void permissiveWktCollectionDoesNotAggregateMemberLayouts() {
+        // Mixed member layouts are a Jena WKT extension, not an SFA 
conformance case.
+        assertResult("GEOMETRYCOLLECTION (POINT Z (1 2 3), POINT M (4 5 6))", 
false);
+    }
+
+    @Test
+    public void gmlPointsAreNotMeasured() {
+        assertEquals(NodeValue.makeBoolean(false).asNode(), 
evaluate("geof:isMeasured(" + GML_2D_POINT + ")"));
+        assertEquals(NodeValue.makeBoolean(false).asNode(), 
evaluate("geof:isMeasured(" + GML_3D_POINT + ")"));
+    }
+
+    @Test
+    public void invalidArgumentsRaiseExpressionErrors() {
+        for (NodeValue value : new NodeValue[] {
+                NodeValue.makeNode(NodeFactory.createURI("urn:not-a-literal")),
+                NodeValue.makeInteger(42),
+                NodeValue.makeString("POINT (1 2)"),
+                NodeValue.makeNode("invalid", WKTDatatype.INSTANCE) }) {
+            assertThrows(ExprEvalException.class, () -> function.exec(value));
+        }
+    }
+
+    private static void assertResult(String wkt, boolean expected) {
+        assertEquals(wkt, NodeValue.makeBoolean(expected).asNode(),
+                     evaluate("geof:isMeasured(" + wktArgument(wkt) + ")"));
+    }
+}
diff --git 
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/MaxXFFTest.java
 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/MaxXFFTest.java
new file mode 100644
index 0000000000..2596d771a4
--- /dev/null
+++ 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/MaxXFFTest.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ *
+ *   https://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.
+ *
+ *   SPDX-License-Identifier: Apache-2.0
+ */
+package 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property;
+
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.GML_3D_POINT;
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.evaluate;
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.wktArgument;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import org.apache.jena.geosparql.configuration.GeoSPARQLConfig;
+import org.apache.jena.geosparql.implementation.datatype.WKTDatatype;
+import org.apache.jena.graph.NodeFactory;
+import org.apache.jena.sparql.expr.ExprEvalException;
+import org.apache.jena.sparql.expr.NodeValue;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class MaxXFFTest {
+    private final MaxXFF function = new MaxXFF();
+
+    @BeforeClass
+    public static void setup() {
+        GeoSPARQLConfig.setupNoIndex();
+    }
+
+    @Test
+    public void directExecutionAcceptsExplicitWktCrs() {
+        NodeValue geometry = NodeValue.makeNode(
+            "<http://www.opengis.net/def/crs/EPSG/0/27700> LINESTRING ZM (-9 8 
-7 100, -2 3 -1 -100)",
+            WKTDatatype.INSTANCE);
+        assertEquals(NodeValue.makeDouble(-2), function.exec(geometry));
+    }
+
+    @Test
+    public void returnsDoubleLiteralThroughSparql() {
+        String wkt = "LINESTRING ZM (-9 8 -7 100, -2 3 -1 -100)";
+        assertEquals(NodeValue.makeDouble(-2).asNode(),
+                     evaluate("geof:maxX(" + wktArgument(wkt) + ")"));
+    }
+
+    @Test
+    public void followsSrsDimensionOrder() {
+        String wkt = "<http://www.opengis.net/def/crs/EPSG/0/4326> LINESTRING 
(10 100, 20 120)";
+        assertEquals(NodeValue.makeDouble(20).asNode(),
+                     evaluate("geof:maxX(" + wktArgument(wkt) + ")"));
+    }
+
+    @Test
+    public void infiniteOrdinateRaisesExpressionError() {
+        for (String infinity : new String[] { "Infinity", "-Infinity" }) {
+            String wkt = "LINESTRING Z (-4 -4 -4, " + infinity + " 1 1, 9 9 
9)";
+            assertThrows(wkt, ExprEvalException.class,
+                         () -> function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+        }
+    }
+
+    @Test
+    public void nanOrdinateRaisesExpressionError() {
+        String wkt = "LINESTRING (1 1, NaN 2, 3 3)";
+        assertThrows(ExprEvalException.class,
+                     () -> function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+    }
+
+    @Test
+    public void emptyGeometryRaisesExpressionError() {
+        assertThrows(ExprEvalException.class,
+                     () -> function.exec(NodeValue.makeNode("POINT Z EMPTY", 
WKTDatatype.INSTANCE)));
+    }
+
+    @Test
+    public void layoutsWithoutZHaveTheExpectedResult() {
+        for (String wkt : new String[] { "POINT (1 2)", "POINT M (1 2 99)" }) {
+            assertEquals(wkt, NodeValue.makeDouble(1),
+                         function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+        }
+    }
+
+    @Test
+    public void multiPointExtremaDistinguishZFromMeasures() {
+        for (String wkt : new String[] {
+                "MULTIPOINT M ((1 2 10), (3 4 20))",
+                "MULTIPOINT ZM ((1 2 -4 10), (3 4 9 20))" }) {
+            NodeValue expected = NodeValue.makeDouble(3);
+            assertEquals(wkt, expected, function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+            assertEquals(wkt, expected.asNode(), evaluate("geof:maxX(" + 
wktArgument(wkt) + ")"));
+        }
+    }
+
+    @Test
+    public void mixedCollectionExtremaDoNotDependOnMemberOrder() {
+        for (String wkt : new String[] {
+                "GEOMETRYCOLLECTION (POINT Z (1 2 3))",
+                "GEOMETRYCOLLECTION (POINT (1 2), POINT M (1 2 999), POINT Z 
(1 2 3))",
+                "GEOMETRYCOLLECTION (POINT Z (1 2 3), POINT M (1 2 999), POINT 
(1 2))" }) {
+            NodeValue expected = NodeValue.makeDouble(1);
+            assertEquals(wkt, expected, function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+            assertEquals(wkt, expected.asNode(), evaluate("geof:maxX(" + 
wktArgument(wkt) + ")"));
+        }
+    }
+
+    @Test
+    public void gmlExtremaFollowSrsDimensionOrder() {
+        assertEquals(NodeValue.makeDouble(2).asNode(),
+                     evaluate("geof:maxX(" + GML_3D_POINT + ")"));
+    }
+
+    @Test
+    public void invalidArgumentsRaiseExpressionErrors() {
+        for (NodeValue value : new NodeValue[] {
+                NodeValue.makeNode(NodeFactory.createURI("urn:not-a-literal")),
+                NodeValue.makeInteger(42),
+                NodeValue.makeString("POINT (1 2)"),
+                NodeValue.makeNode("invalid", WKTDatatype.INSTANCE) }) {
+            assertThrows(ExprEvalException.class, () -> function.exec(value));
+        }
+    }
+}
diff --git 
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/MaxYFFTest.java
 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/MaxYFFTest.java
new file mode 100644
index 0000000000..dc7f204efd
--- /dev/null
+++ 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/MaxYFFTest.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ *
+ *   https://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.
+ *
+ *   SPDX-License-Identifier: Apache-2.0
+ */
+package 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property;
+
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.GML_3D_POINT;
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.evaluate;
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.wktArgument;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import org.apache.jena.geosparql.configuration.GeoSPARQLConfig;
+import org.apache.jena.geosparql.implementation.datatype.WKTDatatype;
+import org.apache.jena.graph.NodeFactory;
+import org.apache.jena.sparql.expr.ExprEvalException;
+import org.apache.jena.sparql.expr.NodeValue;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class MaxYFFTest {
+    private final MaxYFF function = new MaxYFF();
+
+    @BeforeClass
+    public static void setup() {
+        GeoSPARQLConfig.setupNoIndex();
+    }
+
+    @Test
+    public void directExecutionAcceptsExplicitWktCrs() {
+        NodeValue geometry = NodeValue.makeNode(
+            "<http://www.opengis.net/def/crs/EPSG/0/27700> LINESTRING ZM (-9 8 
-7 100, -2 3 -1 -100)",
+            WKTDatatype.INSTANCE);
+        assertEquals(NodeValue.makeDouble(8), function.exec(geometry));
+    }
+
+    @Test
+    public void returnsDoubleLiteralThroughSparql() {
+        String wkt = "LINESTRING ZM (-9 8 -7 100, -2 3 -1 -100)";
+        assertEquals(NodeValue.makeDouble(8).asNode(),
+                     evaluate("geof:maxY(" + wktArgument(wkt) + ")"));
+    }
+
+    @Test
+    public void followsSrsDimensionOrder() {
+        String wkt = "<http://www.opengis.net/def/crs/EPSG/0/4326> LINESTRING 
(10 100, 20 120)";
+        assertEquals(NodeValue.makeDouble(120).asNode(),
+                     evaluate("geof:maxY(" + wktArgument(wkt) + ")"));
+    }
+
+    @Test
+    public void infiniteOrdinateRaisesExpressionError() {
+        for (String infinity : new String[] { "Infinity", "-Infinity" }) {
+            String wkt = "LINESTRING Z (-4 -4 -4, " + "1 " + infinity + " 1, 9 
9 9)";
+            assertThrows(wkt, ExprEvalException.class,
+                         () -> function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+        }
+    }
+
+    @Test
+    public void nanOrdinateRaisesExpressionError() {
+        String wkt = "LINESTRING (1 1, 2 NaN, 3 3)";
+        assertThrows(ExprEvalException.class,
+                     () -> function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+    }
+
+    @Test
+    public void emptyGeometryRaisesExpressionError() {
+        assertThrows(ExprEvalException.class,
+                     () -> function.exec(NodeValue.makeNode("POINT Z EMPTY", 
WKTDatatype.INSTANCE)));
+    }
+
+    @Test
+    public void layoutsWithoutZHaveTheExpectedResult() {
+        for (String wkt : new String[] { "POINT (1 2)", "POINT M (1 2 99)" }) {
+            assertEquals(wkt, NodeValue.makeDouble(2),
+                         function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+        }
+    }
+
+    @Test
+    public void multiPointExtremaDistinguishZFromMeasures() {
+        for (String wkt : new String[] {
+                "MULTIPOINT M ((1 2 10), (3 4 20))",
+                "MULTIPOINT ZM ((1 2 -4 10), (3 4 9 20))" }) {
+            NodeValue expected = NodeValue.makeDouble(4);
+            assertEquals(wkt, expected, function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+            assertEquals(wkt, expected.asNode(), evaluate("geof:maxY(" + 
wktArgument(wkt) + ")"));
+        }
+    }
+
+    @Test
+    public void mixedCollectionExtremaDoNotDependOnMemberOrder() {
+        for (String wkt : new String[] {
+                "GEOMETRYCOLLECTION (POINT Z (1 2 3))",
+                "GEOMETRYCOLLECTION (POINT (1 2), POINT M (1 2 999), POINT Z 
(1 2 3))",
+                "GEOMETRYCOLLECTION (POINT Z (1 2 3), POINT M (1 2 999), POINT 
(1 2))" }) {
+            NodeValue expected = NodeValue.makeDouble(2);
+            assertEquals(wkt, expected, function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+            assertEquals(wkt, expected.asNode(), evaluate("geof:maxY(" + 
wktArgument(wkt) + ")"));
+        }
+    }
+
+    @Test
+    public void gmlExtremaFollowSrsDimensionOrder() {
+        assertEquals(NodeValue.makeDouble(1).asNode(),
+                     evaluate("geof:maxY(" + GML_3D_POINT + ")"));
+    }
+
+    @Test
+    public void invalidArgumentsRaiseExpressionErrors() {
+        for (NodeValue value : new NodeValue[] {
+                NodeValue.makeNode(NodeFactory.createURI("urn:not-a-literal")),
+                NodeValue.makeInteger(42),
+                NodeValue.makeString("POINT (1 2)"),
+                NodeValue.makeNode("invalid", WKTDatatype.INSTANCE) }) {
+            assertThrows(ExprEvalException.class, () -> function.exec(value));
+        }
+    }
+}
diff --git 
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/MaxZFFTest.java
 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/MaxZFFTest.java
new file mode 100644
index 0000000000..8a8162726b
--- /dev/null
+++ 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/MaxZFFTest.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ *
+ *   https://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.
+ *
+ *   SPDX-License-Identifier: Apache-2.0
+ */
+package 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property;
+
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.GML_3D_POINT;
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.evaluate;
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.wktArgument;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import org.apache.jena.geosparql.configuration.GeoSPARQLConfig;
+import org.apache.jena.geosparql.implementation.datatype.WKTDatatype;
+import org.apache.jena.graph.NodeFactory;
+import org.apache.jena.sparql.expr.ExprEvalException;
+import org.apache.jena.sparql.expr.NodeValue;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class MaxZFFTest {
+    private final MaxZFF function = new MaxZFF();
+
+    @BeforeClass
+    public static void setup() {
+        GeoSPARQLConfig.setupNoIndex();
+    }
+
+    @Test
+    public void directExecutionAcceptsExplicitWktCrs() {
+        NodeValue geometry = NodeValue.makeNode(
+            "<http://www.opengis.net/def/crs/EPSG/0/27700> LINESTRING ZM (-9 8 
-7 100, -2 3 -1 -100)",
+            WKTDatatype.INSTANCE);
+        assertEquals(NodeValue.makeDouble(-1), function.exec(geometry));
+    }
+
+    @Test
+    public void returnsDoubleLiteralThroughSparql() {
+        String wkt = "LINESTRING ZM (-9 8 -7 100, -2 3 -1 -100)";
+        assertEquals(NodeValue.makeDouble(-1).asNode(),
+                     evaluate("geof:maxZ(" + wktArgument(wkt) + ")"));
+    }
+
+    @Test
+    public void followsSrsDimensionOrder() {
+        String wkt = "<http://www.opengis.net/def/crs/EPSG/0/4979> LINESTRING 
Z (10 100 -4, 20 120 9)";
+        assertEquals(NodeValue.makeDouble(9).asNode(),
+                     evaluate("geof:maxZ(" + wktArgument(wkt) + ")"));
+        assertThrows(ExprEvalException.class, () -> 
function.exec(NodeValue.makeNode(
+            "<http://www.opengis.net/def/crs/EPSG/0/4326> LINESTRING (10 100, 
20 120)", WKTDatatype.INSTANCE)));
+    }
+
+    @Test
+    public void infiniteOrdinateRaisesExpressionError() {
+        for (String infinity : new String[] { "Infinity", "-Infinity" }) {
+            String wkt = "LINESTRING Z (-4 -4 -4, " + "1 1 " + infinity + ", 9 
9 9)";
+            assertThrows(wkt, ExprEvalException.class,
+                         () -> function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+        }
+    }
+
+    @Test
+    public void emptyGeometryRaisesExpressionError() {
+        assertThrows(ExprEvalException.class,
+                     () -> function.exec(NodeValue.makeNode("POINT Z EMPTY", 
WKTDatatype.INSTANCE)));
+    }
+
+    @Test
+    public void layoutsWithoutZHaveTheExpectedResult() {
+        for (String wkt : new String[] { "POINT (1 2)", "POINT M (1 2 99)" }) {
+            assertThrows(wkt, ExprEvalException.class,
+                         () -> function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+        }
+    }
+
+    @Test
+    public void multiPointExtremaDistinguishZFromMeasures() {
+        assertThrows(ExprEvalException.class,
+                     () -> function.exec(NodeValue.makeNode("MULTIPOINT M ((1 
2 10), (3 4 20))", WKTDatatype.INSTANCE)));
+        String wkt = "MULTIPOINT ZM ((1 2 -4 10), (3 4 9 20))";
+        NodeValue expected = NodeValue.makeDouble(9);
+        assertEquals(expected, function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+        assertEquals(expected.asNode(), evaluate("geof:maxZ(" + 
wktArgument(wkt) + ")"));
+    }
+
+    @Test
+    public void mixedCollectionExtremaDoNotDependOnMemberOrder() {
+        for (String wkt : new String[] {
+                "GEOMETRYCOLLECTION (POINT Z (1 2 3))",
+                "GEOMETRYCOLLECTION (POINT (1 2), POINT M (1 2 999), POINT Z 
(1 2 3))",
+                "GEOMETRYCOLLECTION (POINT Z (1 2 3), POINT M (1 2 999), POINT 
(1 2))" }) {
+            NodeValue expected = NodeValue.makeDouble(3);
+            assertEquals(wkt, expected, function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+            assertEquals(wkt, expected.asNode(), evaluate("geof:maxZ(" + 
wktArgument(wkt) + ")"));
+        }
+    }
+
+    @Test
+    public void gmlExtremaFollowSrsDimensionOrder() {
+        assertEquals(NodeValue.makeDouble(3).asNode(),
+                     evaluate("geof:maxZ(" + GML_3D_POINT + ")"));
+    }
+
+    @Test
+    public void invalidArgumentsRaiseExpressionErrors() {
+        for (NodeValue value : new NodeValue[] {
+                NodeValue.makeNode(NodeFactory.createURI("urn:not-a-literal")),
+                NodeValue.makeInteger(42),
+                NodeValue.makeString("POINT (1 2)"),
+                NodeValue.makeNode("invalid", WKTDatatype.INSTANCE) }) {
+            assertThrows(ExprEvalException.class, () -> function.exec(value));
+        }
+    }
+}
diff --git 
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/MinXFFTest.java
 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/MinXFFTest.java
new file mode 100644
index 0000000000..1ee4ce8481
--- /dev/null
+++ 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/MinXFFTest.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ *
+ *   https://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.
+ *
+ *   SPDX-License-Identifier: Apache-2.0
+ */
+package 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property;
+
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.GML_3D_POINT;
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.evaluate;
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.wktArgument;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import org.apache.jena.geosparql.configuration.GeoSPARQLConfig;
+import org.apache.jena.geosparql.implementation.datatype.WKTDatatype;
+import org.apache.jena.graph.NodeFactory;
+import org.apache.jena.sparql.expr.ExprEvalException;
+import org.apache.jena.sparql.expr.NodeValue;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class MinXFFTest {
+    private final MinXFF function = new MinXFF();
+
+    @BeforeClass
+    public static void setup() {
+        GeoSPARQLConfig.setupNoIndex();
+    }
+
+    @Test
+    public void directExecutionAcceptsExplicitWktCrs() {
+        NodeValue geometry = NodeValue.makeNode(
+            "<http://www.opengis.net/def/crs/EPSG/0/27700> LINESTRING ZM (-9 8 
-7 100, -2 3 -1 -100)",
+            WKTDatatype.INSTANCE);
+        assertEquals(NodeValue.makeDouble(-9), function.exec(geometry));
+    }
+
+    @Test
+    public void returnsDoubleLiteralThroughSparql() {
+        String wkt = "LINESTRING ZM (-9 8 -7 100, -2 3 -1 -100)";
+        assertEquals(NodeValue.makeDouble(-9).asNode(),
+                     evaluate("geof:minX(" + wktArgument(wkt) + ")"));
+    }
+
+    @Test
+    public void followsSrsDimensionOrder() {
+        String wkt = "<http://www.opengis.net/def/crs/EPSG/0/4326> LINESTRING 
(10 100, 20 120)";
+        assertEquals(NodeValue.makeDouble(10).asNode(),
+                     evaluate("geof:minX(" + wktArgument(wkt) + ")"));
+    }
+
+    @Test
+    public void infiniteOrdinateRaisesExpressionError() {
+        for (String infinity : new String[] { "Infinity", "-Infinity" }) {
+            String wkt = "LINESTRING Z (-4 -4 -4, " + infinity + " 1 1, 9 9 
9)";
+            assertThrows(wkt, ExprEvalException.class,
+                         () -> function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+        }
+    }
+
+    @Test
+    public void nanOrdinateRaisesExpressionError() {
+        String wkt = "LINESTRING (1 1, NaN 2, 3 3)";
+        assertThrows(ExprEvalException.class,
+                     () -> function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+    }
+
+    @Test
+    public void emptyGeometryRaisesExpressionError() {
+        assertThrows(ExprEvalException.class,
+                     () -> function.exec(NodeValue.makeNode("POINT Z EMPTY", 
WKTDatatype.INSTANCE)));
+    }
+
+    @Test
+    public void layoutsWithoutZHaveTheExpectedResult() {
+        for (String wkt : new String[] { "POINT (1 2)", "POINT M (1 2 99)" }) {
+            assertEquals(wkt, NodeValue.makeDouble(1),
+                         function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+        }
+    }
+
+    @Test
+    public void multiPointExtremaDistinguishZFromMeasures() {
+        for (String wkt : new String[] {
+                "MULTIPOINT M ((1 2 10), (3 4 20))",
+                "MULTIPOINT ZM ((1 2 -4 10), (3 4 9 20))" }) {
+            NodeValue expected = NodeValue.makeDouble(1);
+            assertEquals(wkt, expected, function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+            assertEquals(wkt, expected.asNode(), evaluate("geof:minX(" + 
wktArgument(wkt) + ")"));
+        }
+    }
+
+    @Test
+    public void mixedCollectionExtremaDoNotDependOnMemberOrder() {
+        for (String wkt : new String[] {
+                "GEOMETRYCOLLECTION (POINT Z (1 2 3))",
+                "GEOMETRYCOLLECTION (POINT (1 2), POINT M (1 2 999), POINT Z 
(1 2 3))",
+                "GEOMETRYCOLLECTION (POINT Z (1 2 3), POINT M (1 2 999), POINT 
(1 2))" }) {
+            NodeValue expected = NodeValue.makeDouble(1);
+            assertEquals(wkt, expected, function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+            assertEquals(wkt, expected.asNode(), evaluate("geof:minX(" + 
wktArgument(wkt) + ")"));
+        }
+    }
+
+    @Test
+    public void gmlExtremaFollowSrsDimensionOrder() {
+        assertEquals(NodeValue.makeDouble(2).asNode(),
+                     evaluate("geof:minX(" + GML_3D_POINT + ")"));
+    }
+
+    @Test
+    public void invalidArgumentsRaiseExpressionErrors() {
+        for (NodeValue value : new NodeValue[] {
+                NodeValue.makeNode(NodeFactory.createURI("urn:not-a-literal")),
+                NodeValue.makeInteger(42),
+                NodeValue.makeString("POINT (1 2)"),
+                NodeValue.makeNode("invalid", WKTDatatype.INSTANCE) }) {
+            assertThrows(ExprEvalException.class, () -> function.exec(value));
+        }
+    }
+}
diff --git 
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/MinYFFTest.java
 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/MinYFFTest.java
new file mode 100644
index 0000000000..1842420c7c
--- /dev/null
+++ 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/MinYFFTest.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ *
+ *   https://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.
+ *
+ *   SPDX-License-Identifier: Apache-2.0
+ */
+package 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property;
+
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.GML_3D_POINT;
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.evaluate;
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.wktArgument;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import org.apache.jena.geosparql.configuration.GeoSPARQLConfig;
+import org.apache.jena.geosparql.implementation.datatype.WKTDatatype;
+import org.apache.jena.graph.NodeFactory;
+import org.apache.jena.sparql.expr.ExprEvalException;
+import org.apache.jena.sparql.expr.NodeValue;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class MinYFFTest {
+    private final MinYFF function = new MinYFF();
+
+    @BeforeClass
+    public static void setup() {
+        GeoSPARQLConfig.setupNoIndex();
+    }
+
+    @Test
+    public void directExecutionAcceptsExplicitWktCrs() {
+        NodeValue geometry = NodeValue.makeNode(
+            "<http://www.opengis.net/def/crs/EPSG/0/27700> LINESTRING ZM (-9 8 
-7 100, -2 3 -1 -100)",
+            WKTDatatype.INSTANCE);
+        assertEquals(NodeValue.makeDouble(3), function.exec(geometry));
+    }
+
+    @Test
+    public void returnsDoubleLiteralThroughSparql() {
+        String wkt = "LINESTRING ZM (-9 8 -7 100, -2 3 -1 -100)";
+        assertEquals(NodeValue.makeDouble(3).asNode(),
+                     evaluate("geof:minY(" + wktArgument(wkt) + ")"));
+    }
+
+    @Test
+    public void followsSrsDimensionOrder() {
+        String wkt = "<http://www.opengis.net/def/crs/EPSG/0/4326> LINESTRING 
(10 100, 20 120)";
+        assertEquals(NodeValue.makeDouble(100).asNode(),
+                     evaluate("geof:minY(" + wktArgument(wkt) + ")"));
+    }
+
+    @Test
+    public void infiniteOrdinateRaisesExpressionError() {
+        for (String infinity : new String[] { "Infinity", "-Infinity" }) {
+            String wkt = "LINESTRING Z (-4 -4 -4, " + "1 " + infinity + " 1, 9 
9 9)";
+            assertThrows(wkt, ExprEvalException.class,
+                         () -> function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+        }
+    }
+
+    @Test
+    public void nanOrdinateRaisesExpressionError() {
+        String wkt = "LINESTRING (1 1, 2 NaN, 3 3)";
+        assertThrows(ExprEvalException.class,
+                     () -> function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+    }
+
+    @Test
+    public void emptyGeometryRaisesExpressionError() {
+        assertThrows(ExprEvalException.class,
+                     () -> function.exec(NodeValue.makeNode("POINT Z EMPTY", 
WKTDatatype.INSTANCE)));
+    }
+
+    @Test
+    public void layoutsWithoutZHaveTheExpectedResult() {
+        for (String wkt : new String[] { "POINT (1 2)", "POINT M (1 2 99)" }) {
+            assertEquals(wkt, NodeValue.makeDouble(2),
+                         function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+        }
+    }
+
+    @Test
+    public void multiPointExtremaDistinguishZFromMeasures() {
+        for (String wkt : new String[] {
+                "MULTIPOINT M ((1 2 10), (3 4 20))",
+                "MULTIPOINT ZM ((1 2 -4 10), (3 4 9 20))" }) {
+            NodeValue expected = NodeValue.makeDouble(2);
+            assertEquals(wkt, expected, function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+            assertEquals(wkt, expected.asNode(), evaluate("geof:minY(" + 
wktArgument(wkt) + ")"));
+        }
+    }
+
+    @Test
+    public void mixedCollectionExtremaDoNotDependOnMemberOrder() {
+        for (String wkt : new String[] {
+                "GEOMETRYCOLLECTION (POINT Z (1 2 3))",
+                "GEOMETRYCOLLECTION (POINT (1 2), POINT M (1 2 999), POINT Z 
(1 2 3))",
+                "GEOMETRYCOLLECTION (POINT Z (1 2 3), POINT M (1 2 999), POINT 
(1 2))" }) {
+            NodeValue expected = NodeValue.makeDouble(2);
+            assertEquals(wkt, expected, function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+            assertEquals(wkt, expected.asNode(), evaluate("geof:minY(" + 
wktArgument(wkt) + ")"));
+        }
+    }
+
+    @Test
+    public void gmlExtremaFollowSrsDimensionOrder() {
+        assertEquals(NodeValue.makeDouble(1).asNode(),
+                     evaluate("geof:minY(" + GML_3D_POINT + ")"));
+    }
+
+    @Test
+    public void invalidArgumentsRaiseExpressionErrors() {
+        for (NodeValue value : new NodeValue[] {
+                NodeValue.makeNode(NodeFactory.createURI("urn:not-a-literal")),
+                NodeValue.makeInteger(42),
+                NodeValue.makeString("POINT (1 2)"),
+                NodeValue.makeNode("invalid", WKTDatatype.INSTANCE) }) {
+            assertThrows(ExprEvalException.class, () -> function.exec(value));
+        }
+    }
+}
diff --git 
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/MinZFFTest.java
 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/MinZFFTest.java
new file mode 100644
index 0000000000..600a86bf31
--- /dev/null
+++ 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/MinZFFTest.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ *
+ *   https://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.
+ *
+ *   SPDX-License-Identifier: Apache-2.0
+ */
+package 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property;
+
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.GML_3D_POINT;
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.evaluate;
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.wktArgument;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import org.apache.jena.geosparql.configuration.GeoSPARQLConfig;
+import org.apache.jena.geosparql.implementation.datatype.WKTDatatype;
+import org.apache.jena.graph.NodeFactory;
+import org.apache.jena.sparql.expr.ExprEvalException;
+import org.apache.jena.sparql.expr.NodeValue;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class MinZFFTest {
+    private final MinZFF function = new MinZFF();
+
+    @BeforeClass
+    public static void setup() {
+        GeoSPARQLConfig.setupNoIndex();
+    }
+
+    @Test
+    public void directExecutionAcceptsExplicitWktCrs() {
+        NodeValue geometry = NodeValue.makeNode(
+            "<http://www.opengis.net/def/crs/EPSG/0/27700> LINESTRING ZM (-9 8 
-7 100, -2 3 -1 -100)",
+            WKTDatatype.INSTANCE);
+        assertEquals(NodeValue.makeDouble(-7), function.exec(geometry));
+    }
+
+    @Test
+    public void returnsDoubleLiteralThroughSparql() {
+        String wkt = "LINESTRING ZM (-9 8 -7 100, -2 3 -1 -100)";
+        assertEquals(NodeValue.makeDouble(-7).asNode(),
+                     evaluate("geof:minZ(" + wktArgument(wkt) + ")"));
+    }
+
+    @Test
+    public void followsSrsDimensionOrder() {
+        String wkt = "<http://www.opengis.net/def/crs/EPSG/0/4979> LINESTRING 
Z (10 100 -4, 20 120 9)";
+        assertEquals(NodeValue.makeDouble(-4).asNode(),
+                     evaluate("geof:minZ(" + wktArgument(wkt) + ")"));
+        assertThrows(ExprEvalException.class, () -> 
function.exec(NodeValue.makeNode(
+            "<http://www.opengis.net/def/crs/EPSG/0/4326> LINESTRING (10 100, 
20 120)", WKTDatatype.INSTANCE)));
+    }
+
+    @Test
+    public void infiniteOrdinateRaisesExpressionError() {
+        for (String infinity : new String[] { "Infinity", "-Infinity" }) {
+            String wkt = "LINESTRING Z (-4 -4 -4, " + "1 1 " + infinity + ", 9 
9 9)";
+            assertThrows(wkt, ExprEvalException.class,
+                         () -> function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+        }
+    }
+
+    @Test
+    public void emptyGeometryRaisesExpressionError() {
+        assertThrows(ExprEvalException.class,
+                     () -> function.exec(NodeValue.makeNode("POINT Z EMPTY", 
WKTDatatype.INSTANCE)));
+    }
+
+    @Test
+    public void layoutsWithoutZHaveTheExpectedResult() {
+        for (String wkt : new String[] { "POINT (1 2)", "POINT M (1 2 99)" }) {
+            assertThrows(wkt, ExprEvalException.class,
+                         () -> function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+        }
+    }
+
+    @Test
+    public void multiPointExtremaDistinguishZFromMeasures() {
+        assertThrows(ExprEvalException.class,
+                     () -> function.exec(NodeValue.makeNode("MULTIPOINT M ((1 
2 10), (3 4 20))", WKTDatatype.INSTANCE)));
+        String wkt = "MULTIPOINT ZM ((1 2 -4 10), (3 4 9 20))";
+        NodeValue expected = NodeValue.makeDouble(-4);
+        assertEquals(expected, function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+        assertEquals(expected.asNode(), evaluate("geof:minZ(" + 
wktArgument(wkt) + ")"));
+    }
+
+    @Test
+    public void mixedCollectionExtremaDoNotDependOnMemberOrder() {
+        for (String wkt : new String[] {
+                "GEOMETRYCOLLECTION (POINT Z (1 2 3))",
+                "GEOMETRYCOLLECTION (POINT (1 2), POINT M (1 2 999), POINT Z 
(1 2 3))",
+                "GEOMETRYCOLLECTION (POINT Z (1 2 3), POINT M (1 2 999), POINT 
(1 2))" }) {
+            NodeValue expected = NodeValue.makeDouble(3);
+            assertEquals(wkt, expected, function.exec(NodeValue.makeNode(wkt, 
WKTDatatype.INSTANCE)));
+            assertEquals(wkt, expected.asNode(), evaluate("geof:minZ(" + 
wktArgument(wkt) + ")"));
+        }
+    }
+
+    @Test
+    public void gmlExtremaFollowSrsDimensionOrder() {
+        assertEquals(NodeValue.makeDouble(3).asNode(),
+                     evaluate("geof:minZ(" + GML_3D_POINT + ")"));
+    }
+
+    @Test
+    public void invalidArgumentsRaiseExpressionErrors() {
+        for (NodeValue value : new NodeValue[] {
+                NodeValue.makeNode(NodeFactory.createURI("urn:not-a-literal")),
+                NodeValue.makeInteger(42),
+                NodeValue.makeString("POINT (1 2)"),
+                NodeValue.makeNode("invalid", WKTDatatype.INSTANCE) }) {
+            assertThrows(ExprEvalException.class, () -> function.exec(value));
+        }
+    }
+}
diff --git 
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/NumGeometriesFFTest.java
 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/NumGeometriesFFTest.java
new file mode 100644
index 0000000000..1d20c45714
--- /dev/null
+++ 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/geof/topological/filter_functions/geometry_property/NumGeometriesFFTest.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ *
+ *   https://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.
+ *
+ *   SPDX-License-Identifier: Apache-2.0
+ */
+package 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property;
+
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.GML_2D_POINT;
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.evaluate;
+import static 
org.apache.jena.geosparql.geof.topological.filter_functions.geometry_property.GeometryPropertyFFTestSupport.wktArgument;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import org.apache.jena.geosparql.configuration.GeoSPARQLConfig;
+import org.apache.jena.geosparql.implementation.datatype.WKTDatatype;
+import org.apache.jena.graph.NodeFactory;
+import org.apache.jena.sparql.expr.ExprEvalException;
+import org.apache.jena.sparql.expr.NodeValue;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class NumGeometriesFFTest {
+    private final NumGeometriesFF function = new NumGeometriesFF();
+
+    @BeforeClass
+    public static void setup() {
+        GeoSPARQLConfig.setupNoIndex();
+    }
+
+    @Test
+    public void directExecutionAcceptsExplicitWktCrs() {
+        NodeValue geometry = NodeValue.makeNode(
+            "<http://www.opengis.net/def/crs/EPSG/0/27700> POINT (1 2)", 
WKTDatatype.INSTANCE);
+        assertEquals(NodeValue.makeInteger(1), function.exec(geometry));
+    }
+
+    @Test
+    public void countsMembersAsAnInteger() {
+        assertResult("MULTIPOINT ((1 2), (3 4))", 2);
+    }
+
+    @Test
+    public void distinguishesAtomsFromCollections() {
+        assertResult("POINT (1 2)", 1);
+        assertResult("POINT EMPTY", 1);
+        assertResult("GEOMETRYCOLLECTION EMPTY", 0);
+        assertResult("MULTIPOINT EMPTY", 0);
+        assertResult("GEOMETRYCOLLECTION (POINT EMPTY)", 1);
+    }
+
+    @Test
+    public void gmlPointCountsAsOne() {
+        assertEquals(NodeValue.makeInteger(1).asNode(), 
evaluate("geof:numGeometries(" + GML_2D_POINT + ")"));
+    }
+
+    @Test
+    public void invalidArgumentsRaiseExpressionErrors() {
+        for (NodeValue value : new NodeValue[] {
+                NodeValue.makeNode(NodeFactory.createURI("urn:not-a-literal")),
+                NodeValue.makeInteger(42),
+                NodeValue.makeString("POINT (1 2)"),
+                NodeValue.makeNode("invalid", WKTDatatype.INSTANCE) }) {
+            assertThrows(ExprEvalException.class, () -> function.exec(value));
+        }
+    }
+
+    private static void assertResult(String wkt, int expected) {
+        assertEquals(wkt, NodeValue.makeInteger(expected).asNode(),
+                     evaluate("geof:numGeometries(" + wktArgument(wkt) + ")"));
+    }
+}
diff --git 
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/GeometryTransformIndexTest.java
 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/index/GeometryTransformIndexTest.java
similarity index 95%
rename from 
jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/GeometryTransformIndexTest.java
rename to 
jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/index/GeometryTransformIndexTest.java
index 434f2711dc..6ff237bd42 100644
--- 
a/jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/GeometryTransformIndexTest.java
+++ 
b/jena-geosparql/src/test/java/org/apache/jena/geosparql/implementation/index/GeometryTransformIndexTest.java
@@ -18,14 +18,14 @@
  *
  *   SPDX-License-Identifier: Apache-2.0
  */
-package org.apache.jena.geosparql.implementation;
+package org.apache.jena.geosparql.implementation.index;
 
 import static org.junit.Assert.assertEquals;
 
 import org.apache.jena.geosparql.configuration.GeoSPARQLConfig;
+import org.apache.jena.geosparql.implementation.GeometryWrapper;
 import org.apache.jena.geosparql.implementation.datatype.GMLDatatype;
 import org.apache.jena.geosparql.implementation.datatype.WKTDatatype;
-import org.apache.jena.geosparql.implementation.index.GeometryTransformIndex;
 import org.junit.Test;
 
 public class GeometryTransformIndexTest {

Reply via email to