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 213762448ce4ba5b7304d710871e6d68db3e2f05
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Mon Feb 19 10:11:51 2024 +0100

    Print the logging summary after all tests instead of after each class.
---
 .../apache/sis/test/FailureDetailsReporter.java    |  22 +---
 .../org/apache/sis/test/LogRecordCollector.java    | 122 ++++++++++++++-------
 2 files changed, 82 insertions(+), 62 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.util/test/org/apache/sis/test/FailureDetailsReporter.java
 
b/endorsed/src/org.apache.sis.util/test/org/apache/sis/test/FailureDetailsReporter.java
index f67b3a2eff..12b15e7f2b 100644
--- 
a/endorsed/src/org.apache.sis.util/test/org/apache/sis/test/FailureDetailsReporter.java
+++ 
b/endorsed/src/org.apache.sis.util/test/org/apache/sis/test/FailureDetailsReporter.java
@@ -17,9 +17,6 @@
 package org.apache.sis.test;
 
 import java.io.PrintStream;
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import org.junit.jupiter.api.extension.AfterAllCallback;
 import org.junit.jupiter.api.extension.AfterEachCallback;
 import org.junit.jupiter.api.extension.BeforeEachCallback;
 import org.junit.jupiter.api.extension.ExtensionContext;
@@ -32,7 +29,7 @@ import org.junit.jupiter.api.extension.ExtensionContext;
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
-public final class FailureDetailsReporter implements BeforeEachCallback, 
AfterEachCallback, AfterAllCallback {
+public final class FailureDetailsReporter implements BeforeEachCallback, 
AfterEachCallback {
     /**
      * Creates a new reporter.
      */
@@ -84,21 +81,4 @@ public final class FailureDetailsReporter implements 
BeforeEachCallback, AfterEa
             TestCase.flushOutput();
         }
     }
-
-    /**
-     * If some tests in the class emitted unexpected log records,
-     * prints a table showing which tests caused logging.
-     *
-     * @param  description  description of the test container.
-     */
-    @Override
-    @SuppressWarnings("UseOfSystemOutOrSystemErr")
-    public final void afterAll(final ExtensionContext description) {
-        try {
-            LogRecordCollector.INSTANCE.report(System.err);     // Same stream 
as logging console handler.
-        } catch (IOException e) {
-            throw new UncheckedIOException(e);                  // Should 
never happen.
-        }
-        TestCase.flushOutput();
-    }
 }
diff --git 
a/endorsed/src/org.apache.sis.util/test/org/apache/sis/test/LogRecordCollector.java
 
b/endorsed/src/org.apache.sis.util/test/org/apache/sis/test/LogRecordCollector.java
index b277deb2d6..fc80f985e2 100644
--- 
a/endorsed/src/org.apache.sis.util/test/org/apache/sis/test/LogRecordCollector.java
+++ 
b/endorsed/src/org.apache.sis.util/test/org/apache/sis/test/LogRecordCollector.java
@@ -25,6 +25,7 @@ import java.util.logging.Logger;
 import java.util.logging.LogRecord;
 import java.util.logging.ConsoleHandler;
 import java.io.IOException;
+import java.io.UncheckedIOException;
 import java.io.UnsupportedEncodingException;
 import org.apache.sis.system.Loggers;
 import org.apache.sis.system.Modules;
@@ -41,17 +42,20 @@ import org.junit.jupiter.api.extension.ExtensionContext;
  *
  * @author  Martin Desruisseaux (Geomatys)
  */
-final class LogRecordCollector extends Handler {
+final class LogRecordCollector extends Handler implements Runnable {
     /**
      * Expected suffix in name of test classes.
      */
     private static final String CLASSNAME_SUFFIX = "Test";
 
     /**
-     * The parent logger of all Apache SIS loggers.
-     * Needs to be retained by strong reference.
+     * The parent loggers to observe.
+     * The need to be retained by strong references.
      */
-    private static final Logger LOGGER = Logger.getLogger(Loggers.ROOT);
+    private static final Logger[] LOGGERS = {
+        Logger.getLogger(Loggers.ROOT),
+        Logger.getLogger("ucar.nc2")
+    };
 
     /**
      * The unique instance.
@@ -61,7 +65,7 @@ final class LogRecordCollector extends Handler {
     /**
      * Sets the encoding of the console logging handler, if an encoding has 
been specified.
      * Note that we look specifically for {@link ConsoleHandler}, we do not 
generalize to
-     * {@link StreamHandler} because the log files may not be intended for 
being show in
+     * {@link StreamHandler} because the log files may not be intended for 
being shown in
      * the console.
      *
      * <p>In case of failure to use the given encoding, we will just print a 
short error
@@ -69,21 +73,27 @@ final class LogRecordCollector extends Handler {
      */
     static {
         final String encoding = 
System.getProperty(TestConfiguration.OUTPUT_ENCODING_KEY);
-        if (encoding != null) try {
-            for (Logger logger=LOGGER; logger!=null; 
logger=logger.getParent()) {
-                for (final Handler handler : logger.getHandlers()) {
-                    if (handler instanceof ConsoleHandler) {
-                        handler.setEncoding(encoding);
+        if (encoding != null) {
+            for (Logger logger : LOGGERS) try {
+                while (logger != null) {
+                    for (final Handler handler : logger.getHandlers()) {
+                        if (handler instanceof ConsoleHandler) {
+                            handler.setEncoding(encoding);
+                        }
                     }
+                    if (!logger.getUseParentHandlers()) {
+                        break;
+                    }
+                    logger = logger.getParent();
                 }
-                if (!logger.getUseParentHandlers()) {
-                    break;
-                }
+            } catch (UnsupportedEncodingException e) {
+                Logging.recoverableException(logger, LogRecordCollector.class, 
"<clinit>", e);
+                break;
             }
-        } catch (UnsupportedEncodingException e) {
-            Logging.recoverableException(LOGGER, LogRecordCollector.class, 
"<clinit>", e);
         }
-        LOGGER.addHandler(INSTANCE);
+        for (Logger logger : LOGGERS) {
+            logger.addHandler(INSTANCE);
+        }
     }
 
     /**
@@ -95,27 +105,32 @@ final class LogRecordCollector extends Handler {
      *   <li>Target logger</li>
      *   <li>Logging level</li>
      * </ul>
+     *
+     * All accesses to this list must be synchronized on {@code records}.
      */
     private final List<String> records = new ArrayList<>();
 
     /**
      * The description of the test currently running.
      */
-    private ExtensionContext currentTest;
+    private final ThreadLocal<ExtensionContext> currentTest;
 
     /**
      * Creates a new log record collector.
      */
     private LogRecordCollector() {
         setLevel(Level.INFO);
+        currentTest = new ThreadLocal<>();
     }
 
     /**
      * Sets the description of the tests which is currently running, or {@code 
null} if the test finished.
      */
     final void setCurrentTest(final ExtensionContext description) {
-        synchronized (records) {
-            currentTest = description;
+        if (description != null) {
+            currentTest.set(description);
+        } else {
+            currentTest.remove();
         }
     }
 
@@ -125,28 +140,32 @@ final class LogRecordCollector extends Handler {
      */
     @Override
     public void publish(final LogRecord record) {
-        synchronized (records) {
-            String cname;
-            String method;
-            if (currentTest != null) {
-                cname  = currentTest.getRequiredTestClass().getCanonicalName();
-                method = currentTest.getRequiredTestMethod().getName();
-            } else {
-                /*
-                 * If the test does not extent TestCase, we are not notified 
about its execution.
-                 * So we will use the stack trace. This happen mostly when 
execution GeoAPI tests.
-                 */
-                cname  = "<unknown>";
-                method = "<unknown>";
-                for (final StackTraceElement t : 
Thread.currentThread().getStackTrace()) {
-                    final String c = t.getClassName();
-                    if (c.startsWith(Modules.CLASSNAME_PREFIX) && 
c.endsWith(CLASSNAME_SUFFIX)) {
-                        cname  = c;
-                        method = t.getMethodName();
-                        break;
-                    }
+        String cname;
+        String method;
+        ExtensionContext source = currentTest.get();
+        if (source != null) {
+            cname  = source.getRequiredTestClass().getCanonicalName();
+            method = source.getRequiredTestMethod().getName();
+        } else {
+            /*
+             * If the test does not extent TestCase, we are not notified about 
its execution.
+             * So we will use the stack trace. This happen mostly when 
execution GeoAPI tests.
+             */
+            cname  = "<unknown>";
+            method = "<unknown>";
+            for (final StackTraceElement t : 
Thread.currentThread().getStackTrace()) {
+                final String c = t.getClassName();
+                if (c.startsWith(Modules.CLASSNAME_PREFIX) && 
c.endsWith(CLASSNAME_SUFFIX)) {
+                    cname  = c;
+                    method = t.getMethodName();
+                    break;
                 }
             }
+        }
+        synchronized (records) {
+            if (records.isEmpty()) {
+                Runtime.getRuntime().addShutdownHook(new Thread(this));
+            }
             records.add(cname);
             records.add(method);
             records.add(record.getLoggerName());
@@ -156,10 +175,13 @@ final class LogRecordCollector extends Handler {
 
     /**
      * If any tests has emitted log records, report them.
+     *
+     * @param  out  where to print the report.
+     * @throws IOException if an error occurred while writing to {@code out}.
      */
-    final void report(final Appendable out) throws IOException {
+    private void report(final Appendable out) throws IOException {
+        final String lineSeparator = System.lineSeparator();
         synchronized (records) {
-            final String lineSeparator = System.lineSeparator();
             if (!records.isEmpty()) {
                 out.append(lineSeparator)
                    .append("The following tests have logged messages at level 
INFO or higher:").append(lineSeparator)
@@ -199,4 +221,22 @@ final class LogRecordCollector extends Handler {
     @Override
     public void close() {
     }
+
+    /**
+     * If some tests in the class emitted unexpected log records,
+     * prints a table showing which tests caused logging.
+     *
+     * <p>Note: this was use to be a JUnit {@code afterAll(ExtensionContext)} 
method.
+     * But we want this method to be executed after all tests in the project,
+     * not after each class.</p>
+     */
+    @Override
+    @SuppressWarnings("UseOfSystemOutOrSystemErr")
+    public final void run() {
+        try {
+            LogRecordCollector.INSTANCE.report(System.err);     // Same stream 
as logging console handler.
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);                  // Should 
never happen.
+        }
+    }
 }

Reply via email to