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)) {
