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
commit d5834c52c3c0ccf30fb4a01a492b1687b53af5d6 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Tue Feb 20 16:14:35 2024 +0100 Handle a log record about a deprecated EPSG code. That record may or may not be emitted depending on execution order. --- .../referencing/factory/sql/EPSGDataAccess.java | 18 +++++--- .../test/org/apache/sis/referencing/CRSTest.java | 3 +- .../transform/EllipsoidToCentricTransformTest.java | 28 +++++++++++- .../test/org/apache/sis/test/LoggingWatcher.java | 51 ++++++++++++++++++---- .../sis/util/logging/PerformanceLevelTest.java | 3 +- 5 files changed, 87 insertions(+), 16 deletions(-) diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java index 45749cd97c..abcd65befc 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java @@ -1209,6 +1209,7 @@ codes: for (int i=0; i<codes.length; i++) { if ("?".equals(scope)) { // EPSG sometimes uses this value for unspecified scope. scope = null; } + @SuppressWarnings("LocalVariableHidesMemberVariable") final Map<String,Object> properties = createProperties(table, name, code, remarks, deprecated); if (domainCode != null) { properties.put(Datum.DOMAIN_OF_VALIDITY_KEY, owner.createExtent(domainCode)); @@ -1487,7 +1488,8 @@ codes: for (int i=0; i<codes.length; i++) { * We need to check if EPSG database 10+ has more specific information. * See https://issues.apache.org/jira/browse/SIS-518 */ - final Map<String, Object> properties = createProperties("Coordinate Reference System", + @SuppressWarnings("LocalVariableHidesMemberVariable") + final Map<String,Object> properties = createProperties("Coordinate Reference System", name, epsg, area, scope, remarks, deprecated); if (baseCRS instanceof GeographicCRS) { crs = crsFactory.createProjectedCRS(properties, (GeographicCRS) baseCRS, op, cs); @@ -1555,8 +1557,9 @@ codes: for (int i=0; i<codes.length; i++) { case "geocentric": { final CoordinateSystem cs = owner.createCoordinateSystem(getString(code, result, 8)); final GeodeticDatum datum = owner.createGeodeticDatum (getString(code, result, 9)); + @SuppressWarnings("LocalVariableHidesMemberVariable") final Map<String,Object> properties = createProperties("Coordinate Reference System", - name, epsg, area, scope, remarks, deprecated); + name, epsg, area, scope, remarks, deprecated); if (cs instanceof CartesianCS) { crs = crsFactory.createGeocentricCRS(properties, datum, (CartesianCS) cs); } else if (cs instanceof SphericalCS) { @@ -1659,8 +1662,8 @@ codes: for (int i=0; i<codes.length; i++) { final String scope = getOptionalString (result, 7); final String remarks = getOptionalString (result, 8); final boolean deprecated = getOptionalBoolean(result, 9); - Map<String,Object> properties = createProperties("Datum", - name, epsg, area, scope, remarks, deprecated); + @SuppressWarnings("LocalVariableHidesMemberVariable") + Map<String,Object> properties = createProperties("Datum", name, epsg, area, scope, remarks, deprecated); if (anchor != null) { properties.put(Datum.ANCHOR_POINT_KEY, anchor); } @@ -1683,6 +1686,7 @@ codes: for (int i=0; i<codes.length; i++) { } } if (year != 0) { + @SuppressWarnings("LocalVariableHidesMemberVariable") final Calendar calendar = getCalendar(); calendar.set(year, month, day); properties.put(Datum.REALIZATION_EPOCH_KEY, calendar.getTime()); @@ -1945,6 +1949,7 @@ codes: for (int i=0; i<codes.length; i++) { final String remarks = getOptionalString (result, 7); final boolean deprecated = getOptionalBoolean(result, 8); final Unit<Length> unit = owner.createUnit(unitCode).asType(Length.class); + @SuppressWarnings("LocalVariableHidesMemberVariable") final Map<String,Object> properties = createProperties("Ellipsoid", name, epsg, remarks, deprecated); final Ellipsoid ellipsoid; if (Double.isNaN(inverseFlattening)) { @@ -2164,6 +2169,7 @@ codes: for (int i=0; i<codes.length; i++) { final String remarks = getOptionalString (result, 5); final boolean deprecated = getOptionalBoolean(result, 6); final CoordinateSystemAxis[] axes = createCoordinateSystemAxes(epsg, dimension); + @SuppressWarnings("LocalVariableHidesMemberVariable") final Map<String,Object> properties = createProperties("Coordinate System", name, epsg, remarks, deprecated); // Must be after axes. /* * The following switch statement should have a case for all "epsg_cs_kind" values enumerated @@ -2607,7 +2613,8 @@ next: while (r.next()) { case 1: valueDomain = MeasurementRange.create(Double.NEGATIVE_INFINITY, false, Double.POSITIVE_INFINITY, false, CollectionsExt.first(units)); break; } - final Map<String, Object> properties = + @SuppressWarnings("LocalVariableHidesMemberVariable") + final Map<String,Object> properties = createProperties("Coordinate_Operation Parameter", name, epsg, isReversible, deprecated); properties.put(Identifier.DESCRIPTION_KEY, description); final ParameterDescriptor<?> descriptor = new DefaultParameterDescriptor<>(properties, @@ -2771,6 +2778,7 @@ next: while (r.next()) { final String remarks = getOptionalString (result, 3); final boolean deprecated = getOptionalBoolean(result, 4); final ParameterDescriptor<?>[] descriptors = createParameterDescriptors(epsg); + @SuppressWarnings("LocalVariableHidesMemberVariable") Map<String,Object> properties = createProperties("Coordinate_Operation Method", name, epsg, remarks, deprecated); /* * Note: we do not store the formula at this time, because the text is very verbose and rarely used. diff --git a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/CRSTest.java b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/CRSTest.java index 65f91dabba..a347e64488 100644 --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/CRSTest.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/CRSTest.java @@ -247,6 +247,7 @@ public final class CRSTest extends TestCaseWithLogs { null, new DefaultGeographicBoundingBox(-1, +1, ymin, ymax), null, null)); crs[i] = new DefaultProjectedCRS(properties, baseCRS.geographic(), HardCodedConversions.MERCATOR, cs); } + loggings.skipNextLogIfContains("EPSG:4047"); // No longer supported by EPSG. final ProjectedCRS[] overlappingCRS = Arrays.copyOf(crs, 3); // Exclude the last CRS only. /* * Test between the 3 overlapping CRS without region of interest. We expect the CRS having a domain @@ -257,7 +258,7 @@ public final class CRSTest extends TestCaseWithLogs { * If we specify a smaller region of interest, we should get the CRS having the smallest domain of validity that * cover the ROI. Following lines gradually increase the ROI size and verify that we get CRS for larger domain. */ - final DefaultGeographicBoundingBox regionOfInterest = new DefaultGeographicBoundingBox(-1, +1, 2.1, 2.9); + final var regionOfInterest = new DefaultGeographicBoundingBox(-1, +1, 2.1, 2.9); assertSame(crs[2], CRS.suggestCommonTarget(regionOfInterest, overlappingCRS)); // Best fit for [2.1 … 2.9]°N regionOfInterest.setNorthBoundLatitude(3.1); diff --git a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransformTest.java b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransformTest.java index 210ca7fdc8..fa28f39131 100644 --- a/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransformTest.java +++ b/endorsed/src/org.apache.sis.referencing/test/org/apache/sis/referencing/operation/transform/EllipsoidToCentricTransformTest.java @@ -28,13 +28,16 @@ import org.apache.sis.referencing.CommonCRS; import org.apache.sis.referencing.util.Formulas; import org.apache.sis.geometry.DirectPosition2D; import org.apache.sis.geometry.GeneralDirectPosition; +import org.apache.sis.system.Loggers; import org.apache.sis.measure.Units; // Test dependencies import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; -import org.apache.sis.referencing.operation.provider.GeocentricTranslationTest; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.apache.sis.test.LoggingWatcher; import static org.apache.sis.test.Assertions.assertSerializedEquals; +import org.apache.sis.referencing.operation.provider.GeocentricTranslationTest; // Specific to the geoapi-3.1 and geoapi-4.0 branches: import org.opengis.test.ToleranceModifier; @@ -46,10 +49,17 @@ import org.opengis.test.ToleranceModifier; * @author Martin Desruisseaux (IRD, Geomatys) */ public final class EllipsoidToCentricTransformTest extends MathTransformTestCase { + /** + * A JUnit extension for listening to log events. + */ + @RegisterExtension + public final LoggingWatcher loggings; + /** * Creates a new test case. */ public EllipsoidToCentricTransformTest() { + loggings = new LoggingWatcher(Loggers.CRS_FACTORY); } /** @@ -93,6 +103,7 @@ public final class EllipsoidToCentricTransformTest extends MathTransformTestCase tolerance = GeocentricTranslationTest.precision(2); // Half the precision of target sample point verifyTransform(GeocentricTranslationTest.samplePoint(1), // 53°48'33.820"N, 02°07'46.380"E, 73.00 metres GeocentricTranslationTest.samplePoint(2)); // 3771793.968, 140253.342, 5124304.349 metres + loggings.assertNoUnexpectedLog(); } /** @@ -115,6 +126,7 @@ public final class EllipsoidToCentricTransformTest extends MathTransformTestCase zDimension = new int[] {2}; // Dimension of h where to apply zTolerance verifyTransform(GeocentricTranslationTest.samplePoint(2), // X = 3771793.968, Y = 140253.342, Z = 5124304.349 metres GeocentricTranslationTest.samplePoint(1)); // 53°48'33.820"N, 02°07'46.380"E, 73.00 metres + loggings.assertNoUnexpectedLog(); } /** @@ -131,6 +143,7 @@ public final class EllipsoidToCentricTransformTest extends MathTransformTestCase toleranceModifier = ToleranceModifier.PROJECTION; createGeodeticConversion(CommonCRS.WGS84.ellipsoid(), true); verifyInDomain(CoordinateDomain.GEOGRAPHIC, 306954540); + loggings.assertNoUnexpectedLog(); } /** @@ -151,6 +164,7 @@ public final class EllipsoidToCentricTransformTest extends MathTransformTestCase tolerance = Formulas.LINEAR_TOLERANCE; toleranceModifier = ToleranceModifier.PROJECTION; verifyInverse(40, 30, 10000); + loggings.assertNoUnexpectedLog(); } /** @@ -179,6 +193,7 @@ public final class EllipsoidToCentricTransformTest extends MathTransformTestCase tolerance = 1E-8; derivativeDeltas = new double[] {1}; // Approximately one metre. verifyDerivative(point.getCoordinate()); + loggings.assertNoUnexpectedLog(); } /** @@ -191,6 +206,8 @@ public final class EllipsoidToCentricTransformTest extends MathTransformTestCase public void testDerivativeOnSphere() throws FactoryException, TransformException { testDerivative(CommonCRS.SPHERE.ellipsoid(), true); testDerivative(CommonCRS.SPHERE.ellipsoid(), false); + loggings.skipNextLogIfContains("EPSG:4047"); // No longer supported by EPSG. + loggings.assertNoUnexpectedLog(); } /** @@ -203,6 +220,7 @@ public final class EllipsoidToCentricTransformTest extends MathTransformTestCase public void testDerivative() throws FactoryException, TransformException { testDerivative(CommonCRS.WGS84.ellipsoid(), true); testDerivative(CommonCRS.WGS84.ellipsoid(), false); + loggings.assertNoUnexpectedLog(); } /** @@ -226,6 +244,7 @@ public final class EllipsoidToCentricTransformTest extends MathTransformTestCase tolerance = GeocentricTranslationTest.precision(2); verifyTransform(GeocentricTranslationTest.samplePoint(1), GeocentricTranslationTest.samplePoint(2)); + loggings.assertNoUnexpectedLog(); } /** @@ -270,6 +289,7 @@ public final class EllipsoidToCentricTransformTest extends MathTransformTestCase assertInstanceOf(LinearTransform.class, step = it.next()); assertEquals(2, step.getSourceDimensions()); assertEquals(2, step.getTargetDimensions()); + loggings.assertNoUnexpectedLog(); } /** @@ -290,6 +310,8 @@ public final class EllipsoidToCentricTransformTest extends MathTransformTestCase assertWktEquals("PARAM_MT[“Geocentric_To_Ellipsoid”,\n" + " PARAMETER[“semi_major”, 6378137.0],\n" + " PARAMETER[“semi_minor”, 6356752.314245179]]"); + + loggings.assertNoUnexpectedLog(); } /** @@ -314,6 +336,8 @@ public final class EllipsoidToCentricTransformTest extends MathTransformTestCase " PARAMETER[“semi_major”, 6378137.0],\n" + " PARAMETER[“semi_minor”, 6356752.314245179]],\n" + " PARAM_MT[“Geographic3D to 2D conversion”]]"); + + loggings.assertNoUnexpectedLog(); } /** @@ -365,5 +389,7 @@ public final class EllipsoidToCentricTransformTest extends MathTransformTestCase " Parameter[“elt_0_0”, 57.29577951308232],\n" + " Parameter[“elt_1_1”, 57.29577951308232],\n" + " Parameter[“elt_2_2”, 6378137.0]]]"); + + loggings.assertNoUnexpectedLog(); } } 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 f4047385b7..c3d704e592 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 @@ -16,6 +16,8 @@ */ package org.apache.sis.test; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.Queue; import java.util.LinkedList; import java.util.ConcurrentModificationException; @@ -95,9 +97,42 @@ public final class LoggingWatcher implements BeforeEachCallback, AfterEachCallba public static final String LOCK = "Logging"; /** - * The logged messages. + * The logged messages. All accesses to this list shall be synchronized on {@code this}. */ - private final Queue<String> messages = new LinkedList<>(); + private final Queue<Message> messages = new LinkedList<>(); + + /** + * Elements in the {@link #messages} queue. + */ + private static final class Message extends org.apache.sis.pending.jdk.Record { + /** Formatted text of the log record. */ + final String text; + + /** Stack trace that we can use for finding the emitter, or {@code null} if none. */ + final Throwable trace; + + /** Creates a new message. */ + Message(final String text, Throwable trace) { + this.text = text; + this.trace = trace; + } + + /** + * Returns the formatted log message together with its source. + * This is the string to show if an assertion fail. + */ + @Override public String toString() { + if (trace == null) { + return text; + } + final var buffer = new StringWriter(); + buffer.write(text); + buffer.write(System.lineSeparator()); + buffer.write("Caused by: "); + trace.printStackTrace(new PrintWriter(buffer)); + return buffer.toString(); + } + } /** * The logger to watch. @@ -238,7 +273,7 @@ public final class LoggingWatcher implements BeforeEachCallback, AfterEachCallba return true; } synchronized (owner) { - owner.messages.add(owner.formatter.formatMessage(record)); + owner.messages.add(new Message(owner.formatter.formatMessage(record), record.getThrown())); } } return TestCase.VERBOSE; @@ -254,10 +289,10 @@ public final class LoggingWatcher implements BeforeEachCallback, AfterEachCallba */ @SuppressWarnings("StringEquality") public synchronized void skipNextLogIfContains(final String... keywords) { - final String message = messages.peek(); + final Message message = messages.peek(); if (message != null) { for (final String word : keywords) { - if (!message.contains(word)) { + if (!message.text.contains(word)) { return; } } @@ -278,9 +313,9 @@ public final class LoggingWatcher implements BeforeEachCallback, AfterEachCallba if (messages.isEmpty()) { fail("Expected a logging messages but got no more."); } - final String message = messages.remove(); + final Message message = messages.remove(); for (final String word : keywords) { - if (!message.contains(word)) { + if (!message.text.contains(word)) { fail("Expected the logging message to contains the “" + word + "” word but got:\n" + message); } } @@ -290,7 +325,7 @@ public final class LoggingWatcher implements BeforeEachCallback, AfterEachCallba * Verifies that there is no more log message. */ public synchronized void assertNoUnexpectedLog() { - final String message = messages.peek(); + final Message message = messages.peek(); if (message != null) { fail("Unexpected logging message: " + message); } diff --git a/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/logging/PerformanceLevelTest.java b/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/logging/PerformanceLevelTest.java index 42c217e23c..3ca8b87833 100644 --- a/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/logging/PerformanceLevelTest.java +++ b/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/logging/PerformanceLevelTest.java @@ -24,6 +24,7 @@ import static org.apache.sis.util.logging.PerformanceLevel.*; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.parallel.ResourceLock; +import org.apache.sis.test.LoggingWatcher; import org.apache.sis.test.TestCase; @@ -52,7 +53,7 @@ public final class PerformanceLevelTest extends TestCase { * Tests modifying the configuration. */ @Test - @ResourceLock("Logging") + @ResourceLock(LoggingWatcher.LOCK) public void testSetMinDuration() { final long t1 = SLOWNESS.getMinDuration(TimeUnit.SECONDS); final long t2 = SLOWER .getMinDuration(TimeUnit.SECONDS);