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

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git


The following commit(s) were added to refs/heads/geoapi-4.0 by this push:
     new c9641c4260 Fix some (not all) JUnit test failures observed when using 
version 12 of the EPSG geodetic dataset. The fixes preserve compatibility with 
version 9 of EPSG (for now, we revisit in the future).
c9641c4260 is described below

commit c9641c4260a16fabfa3fc11e7285ffed73c4f8c5
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Sun Aug 31 15:03:55 2025 +0200

    Fix some (not all) JUnit test failures observed when using version 12 of 
the EPSG geodetic dataset.
    The fixes preserve compatibility with version 9 of EPSG (for now, we 
revisit in the future).
---
 .../org/apache/sis/console/CRSCommandTest.java     |  2 +-
 .../sis/openoffice/ReferencingFunctionsTest.java   |  5 +-
 .../main/org/apache/sis/referencing/CommonCRS.java | 26 ++++----
 .../apache/sis/referencing/crs/AbstractCRS.java    | 65 +++++++++++---------
 .../sis/referencing/crs/DefaultCompoundCRS.java    | 44 +++++++-------
 .../org/apache/sis/referencing/cs/AbstractCS.java  | 67 ++++++++++++---------
 .../sis/referencing/cs/DefaultCompoundCS.java      | 36 ++++++-----
 .../org/apache/sis/referencing/Assertions.java     | 69 +++++++++++++++++++++-
 .../org/apache/sis/referencing/CommonCRSTest.java  |  4 +-
 .../factory/CommonAuthorityFactoryTest.java        |  4 +-
 .../referencing/factory/sql/EPSGFactoryTest.java   |  3 +-
 .../integration/CoordinateReferenceSystemTest.java | 33 -----------
 12 files changed, 204 insertions(+), 154 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/CRSCommandTest.java
 
b/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/CRSCommandTest.java
index d052c5c319..fe2460df08 100644
--- 
a/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/CRSCommandTest.java
+++ 
b/endorsed/src/org.apache.sis.console/test/org/apache/sis/console/CRSCommandTest.java
@@ -44,7 +44,7 @@ public final class CRSCommandTest extends TestCase {
         final String name = "\"WGS\\E\\s?(?:19)?\\Q84\"";                      
                 // Accept "WGS 84" or "WGS 1984".
         WGS84 = "(?m)\\Q" +                                                    
                 // Multilines.
             "GeodeticCRS[" + name + ",\n" +
-            "  Datum[\"World Geodetic System 1984\",\n" +
+            "  Datum[\"World Geodetic System 1984\\E\\s?\\w*\\Q\",\n" +        
                 // End with "ensemble" in EPSG 10+.
             "    Ellipsoid[" + name + ", 6378137.0, 298.257223563]],\n" +
             "  CS[ellipsoidal, 2],\n" +
             "    Axis[\"Latitude (B)\", north],\n" +
diff --git 
a/endorsed/src/org.apache.sis.openoffice/test/org/apache/sis/openoffice/ReferencingFunctionsTest.java
 
b/endorsed/src/org.apache.sis.openoffice/test/org/apache/sis/openoffice/ReferencingFunctionsTest.java
index 0e78793851..69a701b16b 100644
--- 
a/endorsed/src/org.apache.sis.openoffice/test/org/apache/sis/openoffice/ReferencingFunctionsTest.java
+++ 
b/endorsed/src/org.apache.sis.openoffice/test/org/apache/sis/openoffice/ReferencingFunctionsTest.java
@@ -26,6 +26,7 @@ import org.junit.jupiter.api.TestInstance;
 import static org.junit.jupiter.api.Assertions.*;
 import static org.junit.jupiter.api.Assumptions.assumeFalse;
 import org.apache.sis.test.TestCase;
+import org.apache.sis.referencing.Assertions;
 
 
 /**
@@ -66,7 +67,7 @@ public final class ReferencingFunctionsTest extends TestCase {
         assertEquals("WGS 84", instance.getName("urn:ogc:def:crs:epsg::4326"));
         assertEquals("WGS 84", 
instance.getName("http://www.opengis.net/gml/srs/epsg.xml#4326";));
         assertEquals("WGS 84", instance.getName("EPSG:4326"));
-        assertEquals("World Geodetic System 1984", 
instance.getName("urn:ogc:def:datum:epsg::6326"));
+        Assertions.assertLegacyEquals("World Geodetic System 1984", 
instance.getName("urn:ogc:def:datum:epsg::6326"));
     }
 
     /**
@@ -88,7 +89,7 @@ public final class ReferencingFunctionsTest extends TestCase {
         assertEquals("Latitude (°)",              
instance.getAxis("EPSG:4326", 1));
         assertEquals("Longitude (°)",             
instance.getAxis("EPSG:4326", 2));
         assertEquals("Index 3 is out of bounds.", 
instance.getAxis("EPSG:4326", 3));
-        assertEquals("Expected “urn:ogc:def:datum:epsg::6326” to reference an 
instance of ‘CoordinateReferenceSystem’, " +
+        Assertions.assertLegacyEquals("Expected “urn:ogc:def:datum:epsg::6326” 
to reference an instance of ‘CoordinateReferenceSystem’, " +
                 "but found an instance of ‘GeodeticDatum’.", 
instance.getAxis("urn:ogc:def:datum:epsg::6326", 1));
     }
 
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java
index 003bce6e6e..e8a9d1db04 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/CommonCRS.java
@@ -366,7 +366,7 @@ public enum CommonCRS {
      *
      * @see #normalizedGeographic()
      */
-    private transient GeographicCRS cachedNormalized;
+    private transient volatile GeographicCRS cachedNormalized;
 
     /**
      * The three-dimensional geographic CRS, created when first needed.
@@ -602,19 +602,19 @@ public enum CommonCRS {
      * @see DefaultGeographicCRS#forConvention(AxesConvention)
      * @see AxesConvention#NORMALIZED
      */
-    public synchronized GeographicCRS normalizedGeographic() {
+    public GeographicCRS normalizedGeographic() {
         /*
-         * Note on synchronization: a previous version of this class was using 
volatile fields for the caches,
-         * and kept the synchronized blocks as small as possible. It has been 
replaced by simpler synchronized
-         * methods in order to avoid race conditions which resulted in 
duplicated and confusing log messages
-         * when the EPSG factory is not available.
+         * Avoid synchronization since we observed that it can be a cause of 
deadlock.
+         * In particular, the call to `forConvention(…)` may require an access 
to the
+         * EPSG geodetic dataset. The methods invoked below are already 
thread-safe.
          */
-        if (cachedNormalized == null) {
-            DefaultGeographicCRS crs = 
DefaultGeographicCRS.castOrCopy(geographic());
-            crs = crs.forConvention(AxesConvention.RIGHT_HANDED);       // 
Equivalent to NORMALIZED in our cases, but faster.
+        GeographicCRS crs = cachedNormalized;
+        if (crs == null) {
+            crs = 
DefaultGeographicCRS.castOrCopy(geographic()).forConvention(AxesConvention.RIGHT_HANDED);
+            // `RIGHT_HANDED` is equivalent to `NORMALIZED` in this case, but 
faster.
             cachedNormalized = crs;
         }
-        return cachedNormalized;
+        return crs;
     }
 
     /**
@@ -643,6 +643,12 @@ public enum CommonCRS {
      * @see DefaultGeographicCRS
      */
     public synchronized GeographicCRS geographic() {
+        /*
+         * Note on synchronization: a previous version of this class was using 
volatile fields for the caches,
+         * and kept the synchronized blocks as small as possible. It has been 
replaced by simpler synchronized
+         * methods in order to avoid race conditions which resulted in 
duplicated and confusing log messages
+         * when the EPSG factory is not available.
+         */
         GeographicCRS object = geographic(cached);
         if (object == null) {
             final GeodeticAuthorityFactory factory = factory();
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/AbstractCRS.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/AbstractCRS.java
index 55593e9fd2..df9ddc56eb 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/AbstractCRS.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/AbstractCRS.java
@@ -19,7 +19,6 @@ package org.apache.sis.referencing.crs;
 import java.util.Map;
 import java.util.EnumMap;
 import java.util.Objects;
-import java.util.ConcurrentModificationException;
 import jakarta.xml.bind.annotation.XmlType;
 import jakarta.xml.bind.annotation.XmlRootElement;
 import jakarta.xml.bind.annotation.XmlSeeAlso;
@@ -121,7 +120,7 @@ public class AbstractCRS extends AbstractReferenceSystem 
implements CoordinateRe
      *
      * @see #forConvention(AxesConvention)
      */
-    final EnumMap<AxesConvention,AbstractCRS> forConvention;
+    private final EnumMap<AxesConvention,AbstractCRS> forConvention;
 
     /**
      * Creates the value to assign to the {@link #forConvention} map by 
constructors.
@@ -337,23 +336,33 @@ public class AbstractCRS extends AbstractReferenceSystem 
implements CoordinateRe
     }
 
     /**
-     * Sets the CRS for the given axes convention.
+     * Returns the cached <abbr>CRS</abbr> for the given axes convention.
      *
-     * @param  crs  the CRS to cache.
+     * @return the cached <abbr>CRS</abbr>, or {@code null} if none.
+     */
+    final AbstractCRS getCached(final AxesConvention convention) {
+        synchronized (forConvention) {
+            return forConvention.get(convention);
+        }
+    }
+
+    /**
+     * Sets the <abbr>CRS</abbr>  for the given axes convention.
+     *
+     * @param  crs  the <abbr>CRS</abbr> to cache.
      * @return the cached CRS. May be different than the given {@code crs} if 
an existing instance has been found.
      */
     final AbstractCRS setCached(final AxesConvention convention, AbstractCRS 
crs) {
-        assert Thread.holdsLock(forConvention);
-        for (final AbstractCRS existing : forConvention.values()) {
-            if (crs.equals(existing, ComparisonMode.IGNORE_METADATA)) {
-                crs = existing;
-                break;
-            }
-        }
-        if (forConvention.put(convention, crs) != null) {
-            throw new ConcurrentModificationException();    // Should never 
happen, unless we have a synchronization bug.
+        synchronized (forConvention) {
+            return forConvention.computeIfAbsent(convention, (c) -> {
+                for (final AbstractCRS existing : forConvention.values()) {
+                    if (crs.equals(existing, ComparisonMode.IGNORE_METADATA)) {
+                        return existing;
+                    }
+                }
+                return crs;
+            });
         }
-        return crs;
     }
 
     /**
@@ -366,23 +375,21 @@ public class AbstractCRS extends AbstractReferenceSystem 
implements CoordinateRe
      * @see AbstractCS#forConvention(AxesConvention)
      */
     public AbstractCRS forConvention(final AxesConvention convention) {
-        synchronized (forConvention) {
-            AbstractCRS crs = 
forConvention.get(Objects.requireNonNull(convention));
-            if (crs == null) {
-                final AbstractCS cs = AbstractCS.castOrCopy(coordinateSystem);
-                final AbstractCS candidate = cs.forConvention(convention);
-                if (candidate.equals(cs, ComparisonMode.IGNORE_METADATA)) {
-                    crs = this;
-                } else try {
-                    crs = createSameType(candidate);
-                    crs.getCoordinateSystem();          // Throws 
ClassCastException if the CS type is invalid.
-                } catch (ClassCastException e) {
-                    throw new 
IllegalArgumentException(Errors.format(Errors.Keys.CanNotCompute_1, 
convention), e);
-                }
-                crs = setCached(convention, crs);
+        AbstractCRS crs = getCached(Objects.requireNonNull(convention));
+        if (crs == null) {
+            final AbstractCS cs = AbstractCS.castOrCopy(coordinateSystem);
+            final AbstractCS candidate = cs.forConvention(convention);
+            if (candidate.equals(cs, ComparisonMode.IGNORE_METADATA)) {
+                crs = this;
+            } else try {
+                crs = createSameType(candidate);
+                crs.getCoordinateSystem();          // Throws 
ClassCastException if the CS type is invalid.
+            } catch (ClassCastException e) {
+                throw new 
IllegalArgumentException(Errors.format(Errors.Keys.CanNotCompute_1, 
convention), e);
             }
-            return crs;
+            crs = setCached(convention, crs);
         }
+        return crs;
     }
 
     /**
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultCompoundCRS.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultCompoundCRS.java
index 7c619b698b..9cd24a1aa5 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultCompoundCRS.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/crs/DefaultCompoundCRS.java
@@ -534,33 +534,31 @@ public class DefaultCompoundCRS extends AbstractCRS 
implements CompoundCRS {
      */
     @Override
     public DefaultCompoundCRS forConvention(final AxesConvention convention) {
-        synchronized (forConvention) {
-            var crs = (DefaultCompoundCRS) 
forConvention.get(Objects.requireNonNull(convention));
-            if (crs == null) {
-                crs = this;
-                boolean changed = false;
-                final boolean reorderCRS = convention.ordinal() >= 
AxesConvention.DISPLAY_ORIENTED.ordinal();
-                final List<? extends CoordinateReferenceSystem> elements = 
reorderCRS ? singles : components;
-                final CoordinateReferenceSystem[] newComponents = new 
CoordinateReferenceSystem[elements.size()];
-                for (int i=0; i<newComponents.length; i++) {
-                    CoordinateReferenceSystem component = elements.get(i);
-                    AbstractCRS m = castOrCopy(component);
-                    if (m != (m = m.forConvention(convention))) {
-                        component = m;
-                        changed = true;
-                    }
-                    newComponents[i] = component;
+        var crs = (DefaultCompoundCRS) 
getCached(Objects.requireNonNull(convention));
+        if (crs == null) {
+            crs = this;
+            boolean changed = false;
+            final boolean reorderCRS = convention.ordinal() >= 
AxesConvention.DISPLAY_ORIENTED.ordinal();
+            final List<? extends CoordinateReferenceSystem> elements = 
reorderCRS ? singles : components;
+            final CoordinateReferenceSystem[] newComponents = new 
CoordinateReferenceSystem[elements.size()];
+            for (int i=0; i<newComponents.length; i++) {
+                CoordinateReferenceSystem component = elements.get(i);
+                AbstractCRS m = castOrCopy(component);
+                if (m != (m = m.forConvention(convention))) {
+                    component = m;
+                    changed = true;
                 }
-                if (changed) {
-                    if (reorderCRS) {
-                        Arrays.sort(newComponents, SubTypes.BY_TYPE);   // 
This array typically has less than 4 elements.
-                    }
-                    crs = new DefaultCompoundCRS(crs, newComponents);
+                newComponents[i] = component;
+            }
+            if (changed) {
+                if (reorderCRS) {
+                    Arrays.sort(newComponents, SubTypes.BY_TYPE);   // This 
array typically has less than 4 elements.
                 }
-                crs = (DefaultCompoundCRS) setCached(convention, crs);
+                crs = new DefaultCompoundCRS(crs, newComponents);
             }
-            return crs;
+            crs = (DefaultCompoundCRS) setCached(convention, crs);
         }
+        return crs;
     }
 
     /**
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/cs/AbstractCS.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/cs/AbstractCS.java
index 08eda817e8..11321ae857 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/cs/AbstractCS.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/cs/AbstractCS.java
@@ -19,7 +19,7 @@ package org.apache.sis.referencing.cs;
 import java.util.Map;
 import java.util.EnumMap;
 import java.util.Arrays;
-import java.util.ConcurrentModificationException;
+import java.util.Objects;
 import java.util.logging.Logger;
 import jakarta.xml.bind.annotation.XmlType;
 import jakarta.xml.bind.annotation.XmlElement;
@@ -135,7 +135,7 @@ public class AbstractCS extends AbstractIdentifiedObject 
implements CoordinateSy
      *
      * @see #forConvention(AxesConvention)
      */
-    final EnumMap<AxesConvention,AbstractCS> forConvention;
+    private final EnumMap<AxesConvention,AbstractCS> forConvention;
 
     /**
      * Creates the value to assign to the {@link #forConvention} map by 
constructors.
@@ -427,27 +427,37 @@ next:   for (final CoordinateSystemAxis axis : axes) {
     }
 
     /**
-     * Sets the CS for the given axes convention.
+     * Returns the cached Coordinate System (<abbr>CS</abbr>) for the given 
axes convention.
      *
-     * @param  cs  the CS to cache.
-     * @return the cached CS. May be different than the given {@code cs} if an 
existing instance has been found.
+     * @return the cached <abbr>CS</abbr>, or {@code null} if none.
      */
-    final AbstractCS setCached(final AxesConvention convention, AbstractCS cs) 
{
-        assert Thread.holdsLock(forConvention);
-        /*
-         * It happens often that the CRS created by RIGHT_HANDED, 
DISPLAY_ORIENTED and NORMALIZED are the same.
-         * Sharing the same instance not only saves memory, but can also makes 
future comparisons faster.
-         */
-        for (final AbstractCS existing : forConvention.values()) {
-            if (cs.equals(existing, ComparisonMode.IGNORE_METADATA)) {
-                cs = existing;
-                break;
-            }
+    final AbstractCS getCached(final AxesConvention convention) {
+        synchronized (forConvention) {
+            return forConvention.get(convention);
         }
-        if (forConvention.put(convention, cs) != null) {
-            throw new ConcurrentModificationException();    // Should never 
happen, unless we have a synchronization bug.
+    }
+
+    /**
+     * Sets the Coordinate System (<abbr>CS</abbr>) for the given axes 
convention.
+     *
+     * @param  cs  the <abbr>CS</abbr> to cache.
+     * @return the cached CS. May be different than the given {@code cs} if an 
existing instance has been found.
+     */
+    final AbstractCS setCached(final AxesConvention convention, final 
AbstractCS cs) {
+        synchronized (forConvention) {
+            /*
+             * It happens often that the CRS created by RIGHT_HANDED, 
DISPLAY_ORIENTED and NORMALIZED are the same.
+             * Sharing the same instance not only saves memory, but can also 
makes future comparisons faster.
+             */
+            return forConvention.computeIfAbsent(convention, (c) -> {
+                for (final AbstractCS existing : forConvention.values()) {
+                    if (cs.equals(existing, ComparisonMode.IGNORE_METADATA)) {
+                        return existing;
+                    }
+                }
+                return cs;
+            });
         }
-        return cs;
     }
 
     /**
@@ -460,19 +470,18 @@ next:   for (final CoordinateSystemAxis axis : axes) {
      * @see 
org.apache.sis.referencing.crs.AbstractCRS#forConvention(AxesConvention)
      */
     public AbstractCS forConvention(final AxesConvention convention) {
-        synchronized (forConvention) {
-            AbstractCS cs = forConvention.get(convention);
+        AbstractCS cs = getCached(Objects.requireNonNull(convention));
+        if (cs == null) {
+            // Need to be outside the synchronized block because it may query 
the EPSG database.
+            cs = Normalizer.forConvention(this, convention);
             if (cs == null) {
-                cs = Normalizer.forConvention(this, convention);
-                if (cs == null) {
-                    cs = this;          // This coordinate system is already 
normalized.
-                } else if (convention != AxesConvention.POSITIVE_RANGE) {
-                    cs = cs.resolveEPSG(this);
-                }
-                cs = setCached(convention, cs);
+                cs = this;          // This coordinate system is already 
normalized.
+            } else if (convention != AxesConvention.POSITIVE_RANGE) {
+                cs = cs.resolveEPSG(this);
             }
-            return cs;
+            cs = setCached(convention, cs);
         }
+        return cs;
     }
 
     /**
diff --git 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/cs/DefaultCompoundCS.java
 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/cs/DefaultCompoundCS.java
index c43920f06f..7d77b4a6fa 100644
--- 
a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/cs/DefaultCompoundCS.java
+++ 
b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/cs/DefaultCompoundCS.java
@@ -189,28 +189,26 @@ public class DefaultCompoundCS extends AbstractCS {
      */
     @Override
     public DefaultCompoundCS forConvention(final AxesConvention convention) {
-        synchronized (forConvention) {
-            var cs = (DefaultCompoundCS) 
forConvention.get(Objects.requireNonNull(convention));
-            if (cs == null) {
-                cs = this;
-                boolean changed = false;
-                final var newComponents = new 
CoordinateSystem[components.size()];
-                for (int i=0; i<newComponents.length; i++) {
-                    CoordinateSystem component = components.get(i);
-                    AbstractCS m = castOrCopy(component);
-                    if (m != (m = m.forConvention(convention))) {
-                        component = m;
-                        changed = true;
-                    }
-                    newComponents[i] = component;
+        DefaultCompoundCS cs = (DefaultCompoundCS) 
getCached(Objects.requireNonNull(convention));
+        if (cs == null) {
+            cs = this;
+            boolean changed = false;
+            final var newComponents = new CoordinateSystem[components.size()];
+            for (int i=0; i<newComponents.length; i++) {
+                CoordinateSystem component = components.get(i);
+                AbstractCS m = castOrCopy(component);
+                if (m != (m = m.forConvention(convention))) {
+                    component = m;
+                    changed = true;
                 }
-                if (changed) {
-                    cs = new DefaultCompoundCS(cs, newComponents);
-                }
-                cs = (DefaultCompoundCS) setCached(convention, cs);
+                newComponents[i] = component;
+            }
+            if (changed) {
+                cs = new DefaultCompoundCS(cs, newComponents);
             }
-            return cs;
+            cs = (DefaultCompoundCS) setCached(convention, cs);
         }
+        return cs;
     }
 
     /*
diff --git 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/Assertions.java
 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/Assertions.java
index d571c2d513..11d2eb31e8 100644
--- 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/Assertions.java
+++ 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/Assertions.java
@@ -74,6 +74,20 @@ public final class Assertions extends Static {
         WKT_FORMAT.setSymbols(s);
     }
 
+    /**
+     * Replacements to perform in <abbr>WKT</abbr> strings for compatibility 
between different versions
+     * of the <abbr>EPSG</abbr> geodetic dataset. Values at even indexes are 
legacy names that may still
+     * be present in the tests. Values at odd indexes are the names as they 
may be formatted when using
+     * newer versions of the <abbr>EPSG</abbr> geodetic dataset.
+     *
+     * <p>We may remove this hack in a future <abbr>SIS</abbr> version if we 
abandon support of version 9
+     * of <abbr>EPSG</abbr> dataset (the current version at the time of 
writing is 12).</p>
+     */
+    private static final String[] REPLACEMENTS = {
+        "“World Geodetic System 1984”", "“World Geodetic System 1984 
ensemble”",
+        "“NGF IGN69 height”",           "“NGF-IGN69 height”"
+    };
+
     /**
      * Do not allow instantiation of this class.
      */
@@ -105,10 +119,10 @@ public final class Assertions extends Static {
      */
     public static void assertEpsgIdentifierEquals(final String expected, final 
Identifier actual) {
         assertNotNull(actual);
-        assertEquals(expected,        actual.getCode(), "code");
+        assertLegacyEquals(expected, actual.getCode(), "code");
         assertEquals(Constants.EPSG,  actual.getCodeSpace(), "codeSpace");
         assertEquals(Constants.EPSG,  
Citations.toCodeSpace(actual.getAuthority()), "authority");
-        assertEquals(Constants.EPSG + Constants.DEFAULT_SEPARATOR + expected, 
IdentifiedObjects.toString(actual), "identifier");
+        assertLegacyEquals(Constants.EPSG + Constants.DEFAULT_SEPARATOR + 
expected, IdentifiedObjects.toString(actual), "identifier");
     }
 
     /**
@@ -468,6 +482,48 @@ public final class Assertions extends Static {
         }
     }
 
+    /**
+     * Asserts that the given string is equal to the expected string,
+     * with a tolerance for name changes in <abbr>EPSG</abbr> database.
+     * If the expected string is a old name while the actual string is a new 
name,
+     * then they are considered equal.
+     *
+     * <p>We may remove this hack in a future <abbr>SIS</abbr> version if we 
abandon support of version 9
+     * of <abbr>EPSG</abbr> dataset (the current version at the time of 
writing is 12). If this method is
+     * removed, it would be replaced by an ordinary {@code assertEquals}.</p>
+     *
+     * @param expected  the expected string.
+     * @param actual    the actual string.
+     */
+    public static void assertLegacyEquals(final String expected, final String 
actual) {
+        assertLegacyEquals(expected, actual, null);
+    }
+
+    private static void assertLegacyEquals(String expected, final String 
actual, final String message) {
+        if (expected != null && actual != null) {
+            for (int i=0; i < REPLACEMENTS.length;) {
+                final String oldName = REPLACEMENTS[i++];
+                final String newName = REPLACEMENTS[i++];
+                final int ol = oldName.length() - 2;    // Omit quotes.
+                final int nl = newName.length() - 2;
+                final int s  = expected.length() - ol;
+                if (expected.regionMatches(s, oldName, 1, ol) &&
+                        actual.regionMatches(actual.length() - nl, newName, 1, 
nl))
+                {
+                    expected = expected.substring(0, s) + newName.substring(1, 
nl + 1);
+                }
+            }
+            if (expected.replace("GeodeticDatum", 
"DatumEnsemble").equals(actual)) {
+                return;
+            }
+        }
+        if (message != null) {
+            assertEquals(expected, actual, message);
+        } else {
+            assertEquals(expected, actual);
+        }
+    }
+
     /**
      * Asserts that the WKT 2 of the given object is equal to the expected one.
      * This method expected the {@code “…”} quotation marks instead of {@code 
"…"}
@@ -489,7 +545,7 @@ public final class Assertions extends Static {
      * @param expected    the expected text, or {@code null} if {@code object} 
is expected to be null.
      * @param object      the object to format in <i>Well Known Text</i> 
format, or {@code null}.
      */
-    public static void assertWktEquals(final Convention convention, final 
String expected, final Object object) {
+    public static void assertWktEquals(final Convention convention, String 
expected, final Object object) {
         if (expected == null) {
             assertNull(object);
         } else {
@@ -499,6 +555,13 @@ public final class Assertions extends Static {
                 WKT_FORMAT.setConvention(convention);
                 wkt = WKT_FORMAT.format(object);
             }
+            for (int i=0; i < REPLACEMENTS.length;) {
+                final String oldName = REPLACEMENTS[i++];
+                final String newName = REPLACEMENTS[i++];
+                if (expected.contains(oldName) && wkt.contains(newName)) {
+                    expected = expected.replace(oldName, newName);
+                }
+            }
             assertMultilinesEquals(expected, wkt, (object instanceof 
IdentifiedObject) ?
                     ((IdentifiedObject) object).getName().getCode() : 
object.getClass().getSimpleName());
         }
diff --git 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/CommonCRSTest.java
 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/CommonCRSTest.java
index f457ff1b51..ce8bf97cb0 100644
--- 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/CommonCRSTest.java
+++ 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/CommonCRSTest.java
@@ -399,8 +399,8 @@ public final class CommonCRSTest extends 
EPSGDependentTestCase {
      */
     @Test
     public void testFormat() {
-        assertEquals("World Geodetic System 1984", String.format("%s", 
CommonCRS.WGS84.datum()));
-        assertEquals("WORLD GEODETIC SYSTEM 1984", String.format("%S", 
CommonCRS.WGS84.datum()));
+        Assertions.assertLegacyEquals("World Geodetic System 1984", 
String.format("%s", CommonCRS.WGS84.datum()));
+        assertTrue(String.format("%S",  
CommonCRS.WGS84.datum()).startsWith("WORLD GEODETIC SYSTEM 1984"));
         assertTrue(String.format("%#s", 
CommonCRS.WGS84.datum()).endsWith(":6326"));
     }
 }
diff --git 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/CommonAuthorityFactoryTest.java
 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/CommonAuthorityFactoryTest.java
index 2a258c95f1..ae0e7d31b5 100644
--- 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/CommonAuthorityFactoryTest.java
+++ 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/CommonAuthorityFactoryTest.java
@@ -383,7 +383,7 @@ public final class CommonAuthorityFactoryTest extends 
TestCase {
         GeographicCRS crs = factory.createGeographicCRS("CRS:84");
         assertWktEqualsRegex(Convention.WKT1, "(?m)\\Q" +               // 
Multilines
                 "GEOGCS[" + WGS84 + ",\n" +
-                "  DATUM[“World Geodetic System 1984”,\n" +
+                "  DATUM[“World Geodetic System 1984\\E\\s?\\w*\\Q”,\n" +
                 "    SPHEROID[" + WGS84 + ", 6378137.0, 298.257223563]],\n" +
                 "    PRIMEM[“Greenwich”, 0.0],\n" +
                 "  UNIT[“degree”, 0.017453292519943295],\n" +
@@ -393,7 +393,7 @@ public final class CommonAuthorityFactoryTest extends 
TestCase {
 
         assertWktEqualsRegex(Convention.WKT2, "(?m)\\Q" +
                 "GEODCRS[" + WGS84 + ",\n" +
-                "  DATUM[“World Geodetic System 1984”,\n" +
+                "  DATUM[“World Geodetic System 1984\\E\\s?\\w*\\Q”,\n" +
                 "    ELLIPSOID[" + WGS84 + ", 6378137.0, 298.257223563, 
LENGTHUNIT[“metre”, 1]]],\n" +
                 "    PRIMEM[“Greenwich”, 0.0, ANGLEUNIT[“degree”, 
0.017453292519943295]],\n" +
                 "  CS[ellipsoidal, 2],\n" +
diff --git 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/EPSGFactoryTest.java
 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/EPSGFactoryTest.java
index 3dcd46f972..985c0fa85b 100644
--- 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/EPSGFactoryTest.java
+++ 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/factory/sql/EPSGFactoryTest.java
@@ -48,6 +48,7 @@ import org.apache.sis.referencing.CRS;
 import org.apache.sis.referencing.IdentifiedObjects;
 import org.apache.sis.referencing.cs.AxesConvention;
 import org.apache.sis.referencing.crs.DefaultGeographicCRS;
+import org.apache.sis.referencing.datum.DatumOrEnsemble;
 import org.apache.sis.referencing.operation.AbstractCoordinateOperation;
 import org.apache.sis.referencing.factory.IdentifiedObjectFinder;
 import org.apache.sis.util.collection.BackingStoreException;
@@ -117,7 +118,7 @@ public final class EPSGFactoryTest extends TestCaseWithLogs 
{
         final EPSGFactory factory = dataEPSG.factory();
         final GeographicCRS crs = factory.createGeographicCRS("EPSG:4326");
         assertEpsgNameAndIdentifierEqual("WGS 84", 4326, crs);
-        assertEpsgNameAndIdentifierEqual("World Geodetic System 1984", 6326, 
crs.getDatum());
+        assertEpsgNameAndIdentifierEqual("World Geodetic System 1984", 6326, 
DatumOrEnsemble.of(crs));
         assertAxisDirectionsEqual(crs.getCoordinateSystem(), 
AxisDirection.NORTH, AxisDirection.EAST);
 
         assertSame(crs, factory.createCoordinateReferenceSystem("4326"), "CRS 
shall be cached.");
diff --git 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/test/integration/CoordinateReferenceSystemTest.java
 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/test/integration/CoordinateReferenceSystemTest.java
index 7ab3a9864d..f8a28d18a3 100644
--- 
a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/test/integration/CoordinateReferenceSystemTest.java
+++ 
b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/test/integration/CoordinateReferenceSystemTest.java
@@ -17,9 +17,6 @@
 package org.apache.sis.test.integration;
 
 import org.opengis.util.FactoryException;
-import org.opengis.referencing.cs.CartesianCS;
-import org.opengis.referencing.cs.EllipsoidalCS;
-import org.opengis.referencing.crs.DerivedCRS;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.apache.sis.referencing.CRS;
 
@@ -29,9 +26,6 @@ import static org.junit.jupiter.api.Assertions.*;
 import org.apache.sis.test.TestCase;
 import org.apache.sis.referencing.factory.TestFactorySource;
 
-// Specific to the geoapi-4.0 branch:
-import org.opengis.referencing.crs.ProjectedCRS;
-
 
 /**
  * Advanced CRS constructions requiring the EPSG geodetic dataset.
@@ -57,31 +51,4 @@ public final class CoordinateReferenceSystemTest extends 
TestCase {
         CoordinateReferenceSystem crs = CRS.forCode("urn:ogc:def:crs, 
crs:EPSG::27700, crs:EPSG::5701");
         assertSame(CRS.forCode("EPSG:7405"), crs, "OSGB 1936 / British 
National Grid + ODN height");
     }
-
-    /**
-     * Tests creation of "EPSG topocentric example A/B". They are derived 
geodetic CRS.
-     *
-     * @throws FactoryException if an authority or a code is not recognized.
-     */
-    @Test
-    public void testDerivedCRS() throws FactoryException {
-        assertTrue(TestFactorySource.getSharedFactory() != null);
-        CoordinateReferenceSystem crs = CRS.forCode("EPSG:5820");
-        assertInstanceOf(DerivedCRS  .class, crs);
-        assertInstanceOf(ProjectedCRS.class, crs);
-        assertInstanceOf(CartesianCS .class, crs.getCoordinateSystem());
-        assertInstanceOf(CartesianCS .class, ((DerivedCRS) 
crs).getBaseCRS().getCoordinateSystem());
-        /*
-         * Some tests are disabled because `EPSGDataAccess` confuses CRS type.
-         * We are waiting for upgrade to EPSG database 10+ before to 
re-evaluate
-         * how to fix this issue.
-         *
-         * https://issues.apache.org/jira/browse/SIS-518
-         */
-        crs = CRS.forCode("EPSG:5819");
-//      assertInstanceOf(DerivedCRS .class, crs);
-//      assertInstanceOf(GeodeticCRS.class, crs);
-        assertInstanceOf(CartesianCS.class, crs.getCoordinateSystem());
-        assertInstanceOf(EllipsoidalCS.class, ((DerivedCRS) 
crs).getBaseCRS().getCoordinateSystem());
-    }
 }


Reply via email to