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

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

commit e96a107208acc904df5b9640cd5a287c8143b325
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Fri Jul 17 16:12:04 2026 +0200

    Resolve remaining logs printed during execution of test.
    This is a continuation of the test logging work which was part of the 
previous commit.
---
 .../sis/storage/geotiff/GeoTiffStoreProvider.java  |   2 +-
 .../org/apache/sis/storage/geotiff/IOBase.java     |  10 ++
 .../sis/storage/geotiff/ImageFileDirectory.java    |   4 +-
 .../apache/sis/storage/geotiff/base/Resources.java |   2 +-
 .../sis/storage/geotiff/base/Resources.properties  |   2 +-
 .../storage/geotiff/base/Resources_fr.properties   |   2 +-
 .../sis/storage/geotiff/reader/CRSBuilder.java     | 109 +++++++++++++++++----
 .../geotiff/reader/GridGeometryBuilder.java        |   7 +-
 .../sis/storage/geotiff/GeoTiffStoreTest.java      |  18 +++-
 .../storage/netcdf/NetcdfStoreProviderTest.java    |  12 +--
 .../apache/sis/storage/netcdf/NetcdfStoreTest.java |   4 +-
 .../apache/sis/storage/netcdf/base/GridTest.java   |  12 ++-
 .../apache/sis/storage/netcdf/base/TestCase.java   |   1 +
 .../org/apache/sis/storage/DataStoreTestCase.java  |  27 +++--
 .../org/apache/sis/storage/FeatureNamingTest.java  |   4 +-
 .../sis/storage/event/StoreListenersTest.java      |   1 +
 .../org/apache/sis/storage/folder/StoreTest.java   |   8 +-
 .../apache/sis/storage/folder/test-data/README.txt |  12 +--
 .../test/org/apache/sis/test/LoggingWatcher.java   |   9 +-
 19 files changed, 171 insertions(+), 75 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTiffStoreProvider.java
 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTiffStoreProvider.java
index 7c87fe709d..49ec1a0e50 100644
--- 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTiffStoreProvider.java
+++ 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/GeoTiffStoreProvider.java
@@ -71,7 +71,7 @@ public class GeoTiffStoreProvider extends DataStoreProvider {
      *
      * @see #getLogger()
      */
-    private static final Logger LOGGER = 
Logger.getLogger("org.apache.sis.storage.geotiff");
+    static final Logger LOGGER = 
Logger.getLogger("org.apache.sis.storage.geotiff");
 
     /**
      * Name of the parameter for specifying the format modifiers (BigTIFF, 
<abbr>COG</abbr>…).
diff --git 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/IOBase.java
 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/IOBase.java
index 8795c3a1a3..5c7e71dffd 100644
--- 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/IOBase.java
+++ 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/IOBase.java
@@ -18,7 +18,9 @@ package org.apache.sis.storage.geotiff;
 
 import java.util.Set;
 import java.io.Closeable;
+import java.util.logging.Logger;
 import org.apache.sis.util.resources.Errors;
+import org.apache.sis.storage.DataStoreProvider;
 import org.apache.sis.storage.geotiff.base.Resources;
 
 
@@ -78,4 +80,12 @@ abstract class IOBase implements Closeable {
     final Resources resources() {
         return Resources.forLocale(store.getLocale());
     }
+
+    /**
+     * Returns the logger.
+     */
+    final Logger getLogger() {
+        final DataStoreProvider provider = store.getProvider();
+        return (provider != null) ? provider.getLogger() : 
GeoTiffStoreProvider.LOGGER;
+    }
 }
diff --git 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java
 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java
index e35b1a01e9..4ffc10c3bd 100644
--- 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java
+++ 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java
@@ -1487,7 +1487,7 @@ final class ImageFileDirectory extends DataCube {
             GridGeometry domain = gridGeometry;
             if (domain == null) {
                 if (referencing != null) try {
-                    domain = referencing.build(reader.store.listeners(), 
imageWidth, imageHeight, imageDate);
+                    domain = referencing.build(reader.store.listeners(), 
reader.getLogger(), imageWidth, imageHeight, imageDate);
                 } catch (FactoryException e) {
                     throw new 
DataStoreContentException(reader.resources().getString(Resources.Keys.CanNotComputeGridGeometry_1,
 filename()), e);
                 } else {
@@ -1961,9 +1961,9 @@ final class ImageFileDirectory extends DataCube {
      */
     private void warning(final Level level, final short key, final Object... 
parameters) {
         final LogRecord record = reader.resources().createLogRecord(level, 
key, parameters);
+        record.setLoggerName(reader.getLogger().getName());
         record.setSourceClassName(GeoTiffStore.class.getName());
         record.setSourceMethodName("components()");
-        // Logger name will be set by listeners.warning(record).
         listeners.warning(record);
     }
 
diff --git 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources.java
 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources.java
index fdd6002468..5f690a4e43 100644
--- 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources.java
+++ 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources.java
@@ -201,7 +201,7 @@ public class Resources extends IndexedResourceBundle {
         /**
          * The “{1}” parameter was not expected for the “{0}” projection 
method.
          */
-        public static final short UnexpectedParameter_2 = 17;
+        public static final short UnexpectedProjectionParameter_2 = 17;
 
         /**
          * Found {2} tiles or strips in the “{0}” file while {1} were expected.
diff --git 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources.properties
 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources.properties
index 2d468741eb..ff5e4899fe 100644
--- 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources.properties
+++ 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources.properties
@@ -44,7 +44,7 @@ RandomizedProcessApplied          = A randomized process such 
as error diffusion
 ReassignedParameter_3             = Interpreted parameter \u201c{0}\u201d as 
\u201c{1}\u201d because the former is invalid for the \u201c{2}\u201d map 
projection.
 UndefinedDataFormat_1             = The \u201c{0}\u201d GeoTIFF file does not 
specify the values format.
 UnexpectedListOfValues_2          = A single value was expected for the 
\u201c{0}\u201d key but {1} values have been found.
-UnexpectedParameter_2             = The \u201c{1}\u201d parameter was not 
expected for the \u201c{0}\u201d projection method.
+UnexpectedProjectionParameter_2   = The \u201c{1}\u201d parameter was not 
expected for the \u201c{0}\u201d projection method.
 UnexpectedTileCount_3             = Found {2} tiles or strips in the 
\u201c{0}\u201d file while {1} were expected.
 UnexpectedTileLength_2            = Tile has an unexpected length: {1} bytes 
while {0} were expected.
 UnknownCRS_1                      = TIFF file \u201c{0}\u201d uses an unknown 
coordinate reference system.
diff --git 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources_fr.properties
 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources_fr.properties
index 54f8030cd0..5560f26933 100644
--- 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources_fr.properties
+++ 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/base/Resources_fr.properties
@@ -49,7 +49,7 @@ RandomizedProcessApplied          = Un processus 
randomis\u00e9 comme la diffusi
 ReassignedParameter_3             = Le param\u00e8tre 
\u00ab\u202f{0}\u202f\u00bb a \u00e9t\u00e9 interpr\u00e9t\u00e9 comme 
\u00ab\u202f{1}\u202f\u00bb parce que le premier est invalide pour la 
projection \u00ab\u202f{2}\u202f\u00bb.
 UndefinedDataFormat_1             = Le fichier GeoTIFF 
\u00ab\u202f{0}\u202f\u00bb ne sp\u00e9cifie pas le format de ses valeurs.
 UnexpectedListOfValues_2          = Une seule valeur \u00e9tait attendue pour 
la cl\u00e9 \u00ab\u202f{0}\u202f\u00bb, mais on en a trouv\u00e9es {1}.
-UnexpectedParameter_2             = Le param\u00e8tre 
\u00ab\u202f{1}\u202f\u00bb est inattendu pour la m\u00e9thode de projection 
\u00ab\u202f{0}\u202f\u00bb.
+UnexpectedProjectionParameter_2   = Le param\u00e8tre 
\u00ab\u202f{1}\u202f\u00bb est inattendu pour la m\u00e9thode de projection 
\u00ab\u202f{0}\u202f\u00bb.
 UnexpectedTileCount_3             = {2} tuiles ont \u00e9t\u00e9 trouv\u00e9es 
dans le fichier \u00ab\u202f{0}\u202f\u00bb alors qu\u2019on en attendait {1}.
 UnexpectedTileLength_2            = Une tuile a une longueur inattendue\u00a0: 
{1} octets alors qu\u2019on en attendait {0}.
 UnknownCRS_1                      = Le fichier TIFF 
\u00ab\u202f{0}\u202f\u00bb utilise un syst\u00e8me de r\u00e9f\u00e9rence des 
coordonn\u00e9es inconnu.
diff --git 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/CRSBuilder.java
 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/CRSBuilder.java
index 6c72ab4a9d..18f595ebd7 100644
--- 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/CRSBuilder.java
+++ 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/CRSBuilder.java
@@ -26,6 +26,7 @@ import java.util.StringJoiner;
 import java.util.NoSuchElementException;
 import java.util.Locale;
 import java.util.logging.Level;
+import java.util.logging.Logger;
 import java.util.logging.LogRecord;
 import java.lang.reflect.Array;
 import java.io.IOException;
@@ -43,6 +44,7 @@ import org.opengis.parameter.ParameterValueGroup;
 import org.opengis.parameter.ParameterNotFoundException;
 import org.opengis.referencing.IdentifiedObject;
 import org.opengis.referencing.NoSuchAuthorityCodeException;
+import org.opengis.referencing.cs.CoordinateSystem;
 import org.opengis.referencing.crs.GeodeticCRS;
 import org.opengis.referencing.crs.GeographicCRS;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
@@ -149,6 +151,12 @@ public final class CRSBuilder extends 
ReferencingFactoryContainer {
      */
     private final StoreListeners listeners;
 
+    /**
+     * The logger where warnings are sent when not consumed by a listener.
+     */
+    @SuppressWarnings("NonConstantLogger")
+    private final Logger logger;
+
     /**
      * Version of the set of keys declared in the {@code GeoKeyDirectory} 
header.
      */
@@ -160,7 +168,7 @@ public final class CRSBuilder extends 
ReferencingFactoryContainer {
      * so we can easily detect at the end of the parsing process which GeoTIFF 
keys were
      * unrecognized or ignored.
      */
-    private final Map<Short,Object> geoKeys;
+    private final Map<Short, Object> geoKeys;
 
     /**
      * Missing GeoKeys, used for avoiding to report the same warning twice.
@@ -200,9 +208,11 @@ public final class CRSBuilder extends 
ReferencingFactoryContainer {
      * Creates a new builder of coordinate reference systems.
      *
      * @param  listeners  the listeners where to report warnings.
+     * @param  logger     the logger where warnings are sent when not consumed 
by a listener.
      */
-    public CRSBuilder(final StoreListeners listeners) {
+    public CRSBuilder(final StoreListeners listeners, final Logger logger) {
         this.listeners = listeners;
+        this.logger = logger;
         geoKeys = new HashMap<>(32);
         missingGeoKeys = new HashSet<>();
     }
@@ -224,8 +234,15 @@ public final class CRSBuilder extends 
ReferencingFactoryContainer {
      * @see GeoKeysLoader#warning(short, Object...)
      */
     final void warning(final short key, final Object... args) {
-        LogRecord record = 
Resources.forLocale(getLocale()).createLogRecord(Level.WARNING, key, args);
-        // Logger name will be set by listeners.warning(record).
+        warning(Level.WARNING, key, args);
+    }
+
+    /**
+     * Same as {@link #warning(short, Object...)} but with the specified 
logging level.
+     */
+    private void warning(final Level level, final short key, final Object... 
args) {
+        LogRecord record = 
Resources.forLocale(getLocale()).createLogRecord(level, key, args);
+        record.setLoggerName(logger.getName());
         record.setSourceClassName(GeoTiffStore.class.getName());
         record.setSourceMethodName("getMetadata");
         listeners.warning(record);
@@ -438,7 +455,7 @@ public final class CRSBuilder extends 
ReferencingFactoryContainer {
      * @param  key       the GeoTIFF key of the user-defined value to compare 
with the expected one.
      * @param  unit      the unit of measurement for {@code expected} and 
{@code actual}, or {@code null} if none.
      */
-    private void verify(final IdentifiedObject epsg, final double expected, 
final short key, final Unit<?> unit) {
+    private void verifyNumber(final IdentifiedObject epsg, final double 
expected, final short key, final Unit<?> unit) {
         final double actual = getAsDouble(key);         // May be NaN.
         if (Math.abs(expected - actual) > expected * 
Numerics.COMPARISON_THRESHOLD) {
             String symbol = "";
@@ -452,16 +469,55 @@ public final class CRSBuilder extends 
ReferencingFactoryContainer {
              * Use Double.toString(…) instead of NumberFormat because the 
latter does not show
              * enough significant digits for parameters like inverse 
flattening.
              */
-            warning(Resources.Keys.NotTheEpsgValue_5, 
IdentifiedObjects.getIdentifierOrName(epsg),
-                    String.valueOf(expected), GeoKeys.name(key), 
String.valueOf(actual), symbol);
+            warning(Resources.Keys.NotTheEpsgValue_5,
+                    IdentifiedObjects.getIdentifierOrName(epsg),
+                    String.valueOf(expected),
+                    GeoKeys.name(key),
+                    String.valueOf(actual),
+                    symbol);
         }
     }
 
     /**
-     * Verifies that the EPSG code found in the GeoTIFF file is equal to the 
expected value.
-     * This method is invoked when a CRS component is defined by an EPSG code, 
in which case
-     * there is no need to specify the EPSG codes of the components, but the 
file still supply
-     * those EPSG codes. If the values do not match, a warning is reported.
+     * Verifies that the coordinate system unit declared in GeoTIFF 
corresponds to the <abbr>EPSG</abbr> unit.
+     * Current implementation checks only the unit of the first axis, but 
future implementation may expand to
+     * more dimensions.
+     */
+    private void verifyUnit(final CoordinateSystem epsg, final Unit<?> actual, 
final short key) {
+        final Unit<?> expected = epsg.getAxis(0).getUnit();
+        if (!actual.equals(expected)) {
+            warning(Resources.Keys.NotTheEpsgValue_5,
+                    IdentifiedObjects.getIdentifierOrName(epsg),
+                    expected,
+                    GeoKeys.name(key),
+                    actual, "");
+        }
+    }
+
+    /**
+     * Verifies that the name declared in GeoTIFF corresponds to the 
<abbr>EPSG</abbr> name.
+     *
+     * @param epsg  the EPSG object with authoritative name.
+     * @param key   the GeoTIFF key from which to get the declared name.
+     */
+    private void verifyName(final IdentifiedObject epsg, final short key) {
+        final String name = getAsString(key);
+        if (name != null && IdentifiedObjects.isHeuristicMatchForName(epsg, 
name)) {
+            warning(Level.INFO,
+                    Resources.Keys.NotTheEpsgValue_5,
+                    IdentifiedObjects.getIdentifierOrName(epsg),
+                    epsg.getName().getCode(),
+                    GeoKeys.name(key),
+                    name, "");
+        }
+    }
+
+    /**
+     * Verifies that the <abbr>EPSG</abbr> code found in the GeoTIFF file is 
equal to the expected value.
+     * This method is invoked when a <abbr>CRS</abbr> component is defined by 
an <abbr>EPSG</abbr> code,
+     * in which case supplying the <abbr>EPSG</abbr> codes of the components 
should not be necessary,
+     * but the GeoTIFF file nevertheless supplies the component codes. This 
method compares the supplied
+     * codes with the authoritative codes and, if they do not match, emits a 
warning.
      *
      * @param  parent  the parent which contains the {@code epsg} object
      * @param  epsg    the object created from the EPSG geodetic dataset.
@@ -775,7 +831,7 @@ public final class CRSBuilder extends 
ReferencingFactoryContainer {
      * @param  unit  the unit of measurement declared in the GeoTIFF file.
      */
     private void verify(final PrimeMeridian pm, final Unit<Angle> unit) {
-        verify(pm, ReferencingUtilities.getGreenwichLongitude(pm, unit), 
GeoKeys.PrimeMeridianLongitude, unit);
+        verifyNumber(pm, ReferencingUtilities.getGreenwichLongitude(pm, unit), 
GeoKeys.PrimeMeridianLongitude, unit);
     }
 
     /**
@@ -853,9 +909,9 @@ public final class CRSBuilder extends 
ReferencingFactoryContainer {
      */
     private void verify(final Ellipsoid ellipsoid, final Unit<Length> unit) {
         final UnitConverter uc = ellipsoid.getAxisUnit().getConverterTo(unit);
-        verify(ellipsoid, uc.convert(ellipsoid.getSemiMajorAxis()), 
GeoKeys.SemiMajorAxis, unit);
-        verify(ellipsoid, uc.convert(ellipsoid.getSemiMinorAxis()), 
GeoKeys.SemiMinorAxis, unit);
-        verify(ellipsoid, ellipsoid.getInverseFlattening(),         
GeoKeys.InvFlattening, null);
+        verifyNumber(ellipsoid, uc.convert(ellipsoid.getSemiMajorAxis()), 
GeoKeys.SemiMajorAxis, unit);
+        verifyNumber(ellipsoid, uc.convert(ellipsoid.getSemiMinorAxis()), 
GeoKeys.SemiMinorAxis, unit);
+        verifyNumber(ellipsoid, ellipsoid.getInverseFlattening(),         
GeoKeys.InvFlattening, null);
     }
 
     /**
@@ -1325,7 +1381,7 @@ public final class CRSBuilder extends 
ReferencingFactoryContainer {
         final Conversion projection = crs.getConversionFromBase();
         verifyIdentifier(crs, projection, GeoKeys.Projection);
         verify(projection, angularUnit, linearUnit);
-        getAsString(GeoKeys.ProjectedCitation);
+        verifyName(crs, GeoKeys.ProjectedCitation);
     }
 
     /**
@@ -1522,10 +1578,10 @@ public final class CRSBuilder extends 
ReferencingFactoryContainer {
                         value = parameters.doubleValue(p, unit);
                     } catch (ClassCastException | ParameterNotFoundException 
e) {
                         if (isSameProjection) {
-                            warning(Resources.Keys.UnexpectedParameter_2, 
code, GeoKeys.name(key));
+                            
warning(Resources.Keys.UnexpectedProjectionParameter_2, code, 
GeoKeys.name(key));
                         }
                     }
-                    verify(projection, value, key, unit);
+                    verifyNumber(projection, value, key, unit);
                 }
             }
         }
@@ -1595,11 +1651,26 @@ public final class CRSBuilder extends 
ReferencingFactoryContainer {
                 return getCRSFactory().createVerticalCRS(properties(name), 
datum, cs);
             }
             default: {
-                return 
getCRSAuthorityFactory().createVerticalCRS(String.valueOf(epsg));
+                VerticalCRS crs = 
getCRSAuthorityFactory().createVerticalCRS(String.valueOf(epsg));
+                verify(crs);
+                return crs;
             }
         }
     }
 
+    /**
+     * Verifies if the user-defined CRS created from GeoTIFF values
+     * matches the given CRS created from the EPSG geodetic dataset.
+     * This method does not verify the EPSG code of the given CRS.
+     *
+     * @param  crs  the CRS created from the EPSG geodetic dataset.
+     */
+    private void verify(final VerticalCRS crs) throws FactoryException {
+        verifyName      (crs, GeoKeys.VerticalCitation);
+        verifyIdentifier(crs, DatumOrEnsemble.asDatum(crs), 
GeoKeys.VerticalDatum);
+        verifyUnit      (crs.getCoordinateSystem(), 
createLinearUnit(UnitKey.VERTICAL), GeoKeys.VerticalUnits);
+    }
+
     /**
      * Returns the locale to use for error messages.
      */
diff --git 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/GridGeometryBuilder.java
 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/GridGeometryBuilder.java
index 35b5c0a569..aa53b7be20 100644
--- 
a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/GridGeometryBuilder.java
+++ 
b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/GridGeometryBuilder.java
@@ -18,6 +18,7 @@ package org.apache.sis.storage.geotiff.reader;
 
 import java.time.Instant;
 import java.util.NoSuchElementException;
+import java.util.logging.Logger;
 import org.opengis.util.FactoryException;
 import org.opengis.util.NoSuchIdentifierException;
 import org.opengis.metadata.spatial.CellGeometry;
@@ -268,6 +269,7 @@ public final class GridGeometryBuilder extends 
GeoKeysLoader {
      * and can be used as a flag for determining that the build has been 
completed.
      *
      * @param  listeners  the listeners where to report warnings.
+     * @param  logger     the logger where warnings are sent when not consumed 
by a listener.
      * @param  width      the image width in pixels.
      * @param  height     the image height in pixels.
      * @param  imageDate  the date/time found in the {@code DATE_TIME} tag, or 
{@code null} if none.
@@ -275,12 +277,13 @@ public final class GridGeometryBuilder extends 
GeoKeysLoader {
      * @throws FactoryException if an error occurred while creating a CRS or a 
transform.
      */
     @SuppressWarnings("fallthrough")
-    public GridGeometry build(final StoreListeners listeners, final long 
width, final long height, final Instant imageDate)
+    public GridGeometry build(final StoreListeners listeners, final Logger 
logger,
+                              final long width, final long height, final 
Instant imageDate)
             throws FactoryException
     {
         CoordinateReferenceSystem crs = null;
         if (keyDirectory != null) {
-            final var helper = new CRSBuilder(listeners);
+            final var helper = new CRSBuilder(listeners, logger);
             try {
                 crs = helper.build(this);
                 description  = helper.description;
diff --git 
a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/GeoTiffStoreTest.java
 
b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/GeoTiffStoreTest.java
index 93be7446d2..12d06fe9ad 100644
--- 
a/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/GeoTiffStoreTest.java
+++ 
b/endorsed/src/org.apache.sis.storage.geotiff/test/org/apache/sis/storage/geotiff/GeoTiffStoreTest.java
@@ -61,8 +61,8 @@ import static org.apache.sis.test.Assertions.assertSingleton;
 import static org.apache.sis.feature.Assertions.assertPixelsEqual;
 import static org.apache.sis.feature.Assertions.assertGridToCornerEquals;
 import org.apache.sis.image.OverviewImageTest;
-import org.apache.sis.test.TestCase;
 import org.apache.sis.test.TestUtilities;
+import org.apache.sis.storage.DataStoreTestCase;
 import org.apache.sis.referencing.crs.HardCodedCRS;
 import org.apache.sis.referencing.operation.HardCodedConversions;
 
@@ -79,7 +79,7 @@ import static 
org.opengis.test.Assertions.assertAxisDirectionsEqual;
  * @author  Alexis Manin (Geomatys)
  */
 @SuppressWarnings("exports")
-public final class GeoTiffStoreTest extends TestCase {
+public final class GeoTiffStoreTest extends DataStoreTestCase {
     /**
      * Name of a test file for an untiled image with a single band in 
gray-scale.
      * The image is uncompressed for avoiding <abbr>JVM</abbr>-dependent 
variations.
@@ -135,6 +135,7 @@ public final class GeoTiffStoreTest extends TestCase {
         final Path file = Files.createTempFile("sis-test-", ".tiff");
         try {
             try (DataStore store = DataStores.openWritable(file, "GeoTIFF")) {
+                listenToWarnings(store);
                 assertInstanceOf(GeoTiffStore.class, store).append(coverage, 
null);
             }
             /*
@@ -142,6 +143,7 @@ public final class GeoTiffStoreTest extends TestCase {
              * and that the result has the expected number of dimensions, axis 
order and scale factors.
              */
             try (DataStore store = DataStores.open(file, "GeoTIFF")) {
+                listenToWarnings(store);
                 GridCoverageResource r = 
assertSingleton(assertInstanceOf(GeoTiffStore.class, store).components());
                 GridGeometry gg = r.getGridGeometry();
                 assertEquals(3, gg.getDimension());
@@ -161,6 +163,7 @@ public final class GeoTiffStoreTest extends TestCase {
         } finally {
             Files.delete(file);
         }
+        loggings.assertNoUnexpectedLog();
     }
 
     /**
@@ -208,7 +211,7 @@ public final class GeoTiffStoreTest extends TestCase {
      * @param  tileSize  size of the tiles, or {@code null} for the image size.
      * @param  length    expected length in bytes.
      */
-    private static void testWriteAndRead(final String filename, final 
Rectangle bounds, final Dimension tileSize, final int length)
+    private void testWriteAndRead(final String filename, final Rectangle 
bounds, final Dimension tileSize, final int length)
             throws TransformException, DataStoreException, IOException
     {
         /*
@@ -228,8 +231,9 @@ public final class GeoTiffStoreTest extends TestCase {
         final var buffer = new ByteArrayOutputStream(length);
         final var source = new StorageConnector(buffer);
         source.setOption(Compression.OPTION_KEY, Compression.NONE);
-        try (DataStore ds = DataStores.openWritable(source, "geotiff")) {
-            assertInstanceOf(GeoTiffStore.class, ds).append(coverage, null);
+        try (DataStore store = DataStores.openWritable(source, "geotiff")) {
+            listenToWarnings(store);
+            assertInstanceOf(GeoTiffStore.class, store).append(coverage, null);
         }
         final byte[] actual = buffer.toByteArray();
         assertEquals(length, actual.length);
@@ -247,6 +251,7 @@ public final class GeoTiffStoreTest extends TestCase {
          * unless we had no file to compare with.
          */
         try (var store = new GeoTiffStore(null, new 
StorageConnector(ByteBuffer.wrap(actual)))) {
+            listenToWarnings(store);
             final var coverageToValidate = 
assertSingleton(store.components()).read(null);
             assertEqualsApproximately(
                     coverage.getGridGeometry(),
@@ -266,6 +271,7 @@ public final class GeoTiffStoreTest extends TestCase {
                 validateTileSize("height", tileSize.height, 
actualRendering.getTileHeight());
             }
         }
+        loggings.assertNoUnexpectedLog();
     }
 
     /**
@@ -330,6 +336,7 @@ public final class GeoTiffStoreTest extends TestCase {
                 StandardOpenOption.WRITE
             });
             try (var store = new GeoTiffStore(null, connector)) {
+                listenToWarnings(store);
                 assertNotNull(store.append(coverage, null));
             }
             /*
@@ -365,5 +372,6 @@ public final class GeoTiffStoreTest extends TestCase {
         } finally {
             Files.delete(path);
         }
+        loggings.assertNoUnexpectedLog();
     }
 }
diff --git 
a/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/NetcdfStoreProviderTest.java
 
b/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/NetcdfStoreProviderTest.java
index 51580075d1..d6f0b5a22e 100644
--- 
a/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/NetcdfStoreProviderTest.java
+++ 
b/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/NetcdfStoreProviderTest.java
@@ -57,8 +57,8 @@ public final class NetcdfStoreProviderTest extends TestCase {
      */
     @Test
     public void testProbeContentFromStream() throws DataStoreException {
-        final StorageConnector c = new 
StorageConnector(TestData.NETCDF_2D_GEOGRAPHIC.location());
-        final NetcdfStoreProvider provider = new NetcdfStoreProvider();
+        final var c = new 
StorageConnector(TestData.NETCDF_2D_GEOGRAPHIC.location());
+        final var provider = new NetcdfStoreProvider();
         final ProbeResult probe = provider.probeContent(c);
         assertTrue  (probe.isSupported());
         assertEquals(NetcdfStoreProvider.MIME_TYPE, probe.getMimeType());
@@ -75,8 +75,8 @@ public final class NetcdfStoreProviderTest extends TestCase {
     @Test
     public void testProbeContentFromUCAR() throws IOException, 
DataStoreException {
         try (NetcdfFile file = createUCAR(TestData.NETCDF_2D_GEOGRAPHIC)) {
-            final StorageConnector c = new StorageConnector(file);
-            final NetcdfStoreProvider provider = new NetcdfStoreProvider();
+            final var c = new StorageConnector(file);
+            final var provider = new NetcdfStoreProvider();
             final ProbeResult probe = provider.probeContent(c);
             assertTrue  (probe.isSupported());
             assertEquals(NetcdfStoreProvider.MIME_TYPE, probe.getMimeType());
@@ -93,7 +93,7 @@ public final class NetcdfStoreProviderTest extends TestCase {
      */
     @Test
     public void testDecoderFromStream() throws IOException, DataStoreException 
{
-        final StorageConnector c = new 
StorageConnector(TestData.NETCDF_2D_GEOGRAPHIC.open());
+        final var c = new 
StorageConnector(TestData.NETCDF_2D_GEOGRAPHIC.open());
         final Decoder decoder = NetcdfStoreProvider.decoder(createListeners(), 
c);
         assertInstanceOf(ChannelDecoder.class, decoder);
         decoder.close(new DataStoreMock("lock"));
@@ -108,7 +108,7 @@ public final class NetcdfStoreProviderTest extends TestCase 
{
      */
     @Test
     public void testDecoderFromUCAR() throws IOException, DataStoreException {
-        final StorageConnector c = new 
StorageConnector(createUCAR(TestData.NETCDF_2D_GEOGRAPHIC));
+        final var c = new 
StorageConnector(createUCAR(TestData.NETCDF_2D_GEOGRAPHIC));
         final Decoder decoder = NetcdfStoreProvider.decoder(createListeners(), 
c);
         assertInstanceOf(DecoderWrapper.class, decoder);
         decoder.close(new DataStoreMock("lock"));
diff --git 
a/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/NetcdfStoreTest.java
 
b/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/NetcdfStoreTest.java
index 01c42e47fe..823b849ebc 100644
--- 
a/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/NetcdfStoreTest.java
+++ 
b/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/NetcdfStoreTest.java
@@ -29,7 +29,6 @@ import org.apache.sis.coverage.grid.PixelInCell;
 import org.apache.sis.storage.StorageConnector;
 import org.apache.sis.storage.DataStoreException;
 import org.apache.sis.storage.GridCoverageResource;
-import org.apache.sis.system.Loggers;
 import org.apache.sis.util.Version;
 
 // Test dependencies
@@ -54,7 +53,6 @@ public final class NetcdfStoreTest extends DataStoreTestCase {
      * Creates a new test case.
      */
     public NetcdfStoreTest() {
-        super(Loggers.CRS_FACTORY);
     }
 
     /**
@@ -89,7 +87,7 @@ public final class NetcdfStoreTest extends DataStoreTestCase {
     private NetcdfStore create(final String name, final URL dataset) throws 
DataStoreException {
         assertNotNull(dataset, name);
         final var store = new NetcdfStore(null, new StorageConnector(dataset));
-        listen(store);
+        listenToWarnings(store);
         return store;
     }
 
diff --git 
a/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/base/GridTest.java
 
b/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/base/GridTest.java
index 0d0f6cbf72..1f3b7a14d2 100644
--- 
a/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/base/GridTest.java
+++ 
b/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/base/GridTest.java
@@ -17,9 +17,12 @@
 package org.apache.sis.storage.netcdf.base;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import org.opengis.referencing.crs.ProjectedCRS;
 import org.opengis.parameter.ParameterValueGroup;
 import org.apache.sis.storage.DataStoreException;
+import org.apache.sis.storage.event.WarningEvent;
+import org.apache.sis.util.ArraysExt;
 
 // Test dependencies
 import org.junit.jupiter.api.Test;
@@ -163,7 +166,10 @@ public class GridTest extends TestCase {
      */
     @Test
     public void testGridMapping() throws IOException, DataStoreException {
-        final Node data = 
selectDataset(TestData.NETCDF_4D_PROJECTED).findNode("CIP");
+        final Decoder decoder = selectDataset(TestData.NETCDF_4D_PROJECTED);
+        final var warnings = new ArrayList<Object[]>();
+        decoder.listeners.addListener(WarningEvent.class, (event) -> 
warnings.add(event.getDescription().getParameters()));
+        final Node data = decoder.findNode("CIP");
         final GridMapping mapping = GridMapping.forVariable((Variable) data);
         assertNotNull(mapping);
         assertInstanceOf(ProjectedCRS.class, mapping.crs());
@@ -172,5 +178,9 @@ public class GridTest extends TestCase {
         assertEquals(-95,    pg.parameter("Longitude of false origin")        
.doubleValue());
         assertEquals( 25,    pg.parameter("Latitude of 1st standard 
parallel").doubleValue());
         assertEquals( 25.05, pg.parameter("Latitude of 2nd standard 
parallel").doubleValue());
+
+        // Verifies warning about missing ellipsoid axis lengths.
+        final Object[] parameters = assertSingleton(warnings);
+        assertTrue(ArraysExt.contains(parameters, "grid_mapping_0"));
     }
 }
diff --git 
a/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/base/TestCase.java
 
b/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/base/TestCase.java
index cf34b35b18..b586c3610f 100644
--- 
a/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/base/TestCase.java
+++ 
b/endorsed/src/org.apache.sis.storage.netcdf/test/org/apache/sis/storage/netcdf/base/TestCase.java
@@ -200,6 +200,7 @@ public abstract class TestCase extends 
org.apache.sis.test.TestCase {
      * @throws IOException if an error occurred while closing a file.
      */
     @AfterAll
+    @SuppressWarnings("UseSpecificCatch")
     public void closeAllDecoders() throws IOException {
         final var ds = new DataStoreMock("lock");
         Throwable failure = null;
diff --git 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/DataStoreTestCase.java
 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/DataStoreTestCase.java
index 277161153c..b6340636f6 100644
--- 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/DataStoreTestCase.java
+++ 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/DataStoreTestCase.java
@@ -16,9 +16,9 @@
  */
 package org.apache.sis.storage;
 
-import java.util.logging.Logger;
 import org.apache.sis.storage.event.StoreListener;
 import org.apache.sis.storage.event.WarningEvent;
+import org.apache.sis.system.Loggers;
 
 // Test dependencies
 import org.apache.sis.test.TestCaseWithLogs;
@@ -26,27 +26,22 @@ import org.apache.sis.test.TestCaseWithLogs;
 
 /**
  * Base class for {@link DataStore} tests which may emit warnings.
+ * This class listens to logs emitted by the referencing modules,
+ * because this is the module which is most likely to emit logs
+ * that are not under control of the data store.
+ *
+ * <p>For listening to logs emitted by the tested data store,
+ * subclasses should invoke {@link #listenToWarnings(DataStore)}.</p>
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
 @SuppressWarnings("exports")
 public abstract class DataStoreTestCase extends TestCaseWithLogs implements 
StoreListener<WarningEvent> {
     /**
-     * Creates a new test case which will listen to logs emitted by the given 
logger.
-     *
-     * @param  logger  the logger to listen to.
-     */
-    protected DataStoreTestCase(Logger logger) {
-        super(logger);
-    }
-
-    /**
-     * Creates a new test case which will listen to logs emitted by the logger 
of the given name.
-     *
-     * @param logger  name of the logger to listen.
+     * Creates a new test case which will listen to logs emitted by the 
referencing modules.
      */
-    protected DataStoreTestCase(String logger) {
-        super(logger);
+    protected DataStoreTestCase() {
+        super(Loggers.CRS_FACTORY);
     }
 
     /**
@@ -55,7 +50,7 @@ public abstract class DataStoreTestCase extends 
TestCaseWithLogs implements Stor
      *
      * @param  store  the data store to listen to.
      */
-    protected final void listen(DataStore store) {
+    protected final void listenToWarnings(DataStore store) {
         store.addListener(WarningEvent.class, this);
     }
 
diff --git 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/FeatureNamingTest.java
 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/FeatureNamingTest.java
index e3d012cf77..e955514065 100644
--- 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/FeatureNamingTest.java
+++ 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/FeatureNamingTest.java
@@ -88,8 +88,8 @@ public final class FeatureNamingTest extends TestCase {
      */
     @Test
     public void testSimple() throws IllegalNameException {
-        final DataStoreMock store = new DataStoreMock("testDataStore");
-        final FeatureNaming<Integer> map = new FeatureNaming<>();
+        final var store = new DataStoreMock("testDataStore");
+        final var map   = new FeatureNaming<Integer>();
         map.add(store, A, 1);
         map.add(store, B, 2);
         assertEquals(Integer.valueOf(1), map.get(store, "myNS:A"));
diff --git 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/event/StoreListenersTest.java
 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/event/StoreListenersTest.java
index c2521dd2fc..cde594da00 100644
--- 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/event/StoreListenersTest.java
+++ 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/event/StoreListenersTest.java
@@ -32,6 +32,7 @@ import org.apache.sis.test.TestCase;
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
+@SuppressWarnings("exports")
 public final class StoreListenersTest extends TestCase implements 
StoreListener<WarningEvent> {
     /**
      * Dummy data store used for firing events.
diff --git 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/folder/StoreTest.java
 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/folder/StoreTest.java
index 73fe86ca53..7f17e9947c 100644
--- 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/folder/StoreTest.java
+++ 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/folder/StoreTest.java
@@ -48,7 +48,7 @@ public final class StoreTest extends TestCaseWithLogs {
      * Creates a new test case.
      */
     public StoreTest() {
-        super("ucar.nc2.NetcdfFile");
+        super("ucar.nc2.NetcdfFiles");
     }
 
     /**
@@ -71,7 +71,7 @@ public final class StoreTest extends TestCaseWithLogs {
      */
     @Test
     public void testComponents() throws URISyntaxException, 
DataStoreException, IOException {
-        final Set<String> identifiers = new HashSet<>(List.of("EPSG:4326", 
"Sample 1", "Sample 2", "Sample 3", "data4"));
+        final var identifiers = new HashSet<String>(List.of("EPSG:4326", 
"Sample 1", "Sample 2", "Sample 3", "data4"));
         final Path path = testDirectory();
         try (Store store = new Store(null, new StorageConnector(path), path, 
null)) {
             assertEquals(4, store.components().size(), "Wrong number of data 
stores.");
@@ -94,8 +94,8 @@ public final class StoreTest extends TestCaseWithLogs {
      */
     @Test
     public void testSearchProviderParameter() throws URISyntaxException, 
DataStoreException, IOException {
-        final StoreProvider provider = new StoreProvider();
-        final Set<String> identifiers = new HashSet<>(List.of("Sample 1", 
"Sample 2", "Sample 3", "data4"));
+        final var provider = new StoreProvider();
+        final var identifiers = new HashSet<String>(List.of("Sample 1", 
"Sample 2", "Sample 3", "data4"));
         final ParameterValueGroup params = 
StoreProvider.provider().getOpenParameters().createValue();
         params.parameter("location").setValue(testDirectory());
         params.parameter("format").setValue("XML");
diff --git 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/folder/test-data/README.txt
 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/folder/test-data/README.txt
index 500353ab80..32c2e1cdac 100644
--- 
a/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/folder/test-data/README.txt
+++ 
b/endorsed/src/org.apache.sis.storage/test/org/apache/sis/storage/folder/test-data/README.txt
@@ -1,6 +1,6 @@
-This directory contains data to be read by the folder data store.
-We need to put those data in a different directory than the Store
-implementation class because otherwise, opening the folder would
-scan all *.class files in addition to test files. Implementation
-should be robust to that, but we nevertheless keep those files
-separated for more predictable tests.
+This directory contains data to be read by the folder data store test.
+It contains:
+
+- 1 CRS definition in Well Known Text (WKT) format,
+- 3 metadata in XML format (including in one sub-directory).
+- 1 dummy XML file.
diff --git 
a/endorsed/src/org.apache.sis.util/test/org/apache/sis/test/LoggingWatcher.java 
b/endorsed/src/org.apache.sis.util/test/org/apache/sis/test/LoggingWatcher.java
index 28c39b2b8b..5b63d8163b 100644
--- 
a/endorsed/src/org.apache.sis.util/test/org/apache/sis/test/LoggingWatcher.java
+++ 
b/endorsed/src/org.apache.sis.util/test/org/apache/sis/test/LoggingWatcher.java
@@ -28,6 +28,7 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.logging.LogRecord;
 import java.util.logging.SimpleFormatter;
+import org.apache.sis.pending.jdk.JDK19;
 
 // Test dependencies
 import static org.junit.jupiter.api.Assertions.*;
@@ -151,7 +152,7 @@ public final class LoggingWatcher implements 
BeforeEachCallback, AfterEachCallba
     /**
      * Identifier of the thread to watch.
      */
-    private final long threadId = Thread.currentThread().getId();
+    private final long threadId = JDK19.threadId(Thread.currentThread());
 
     /**
      * Whether the test will be multi-threaded. If this flag is set to {@code 
true},
@@ -325,12 +326,10 @@ public final class LoggingWatcher implements 
BeforeEachCallback, AfterEachCallba
      * Each call of this method advances to the next log message.
      *
      * @param  keywords  the keywords that are expected to exist in the next 
log message.
-     *         May be an empty array for requesting only the existence of a 
log with any message.
+     *         May be an empty array for requesting the existence of a log 
with any message.
      */
     public synchronized void assertNextLogContains(final String... keywords) {
-        if (messages.isEmpty()) {
-            fail("Expected a logging messages but got no more.");
-        }
+        assertFalse(messages.isEmpty(), "Expected a logging messages but got 
no more.");
         final Message message = messages.remove();
         for (final String word : keywords) {
             if (!message.text.contains(word)) {


Reply via email to