From 949c3ab04fadc1c518532862f037246a2f1f16b0 Mon Sep 17 00:00:00 2001 From: Angel98518 Date: Fri, 6 Feb 2026 05:22:15 +0800 Subject: [PATCH] [2.x] Replace commented System.err.println with proper logger.debug (#8693) **Problem** The writeSuite() method in JUnitXmlTestsListener had a commented-out System.err.println statement with a TODO to use proper logging. --- build.sbt | 2 + .../scala/sbt/JUnitXmlTestsListener.scala | 5 +- .../scala/sbt/JUnitXmlTestsListenerSpec.scala | 105 ++++++++++++++++++ 3 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 testing/src/test/scala/sbt/JUnitXmlTestsListenerSpec.scala diff --git a/build.sbt b/build.sbt index ef647f110..0734b6987 100644 --- a/build.sbt +++ b/build.sbt @@ -424,7 +424,9 @@ lazy val testingProj = (project in file("testing")) launcherInterface, sjsonNewScalaJson.value, sjsonNewCore.value, + scalaVerify % Test, ), + testFrameworks += TestFramework("verify.runner.Framework"), conflictWarning := ConflictWarning.disable, contrabandSettings, mimaSettings, diff --git a/testing/src/main/scala/sbt/JUnitXmlTestsListener.scala b/testing/src/main/scala/sbt/JUnitXmlTestsListener.scala index 14d96ecea..bfb2adacd 100644 --- a/testing/src/main/scala/sbt/JUnitXmlTestsListener.scala +++ b/testing/src/main/scala/sbt/JUnitXmlTestsListener.scala @@ -278,8 +278,9 @@ class JUnitXmlTestsListener(val targetDir: File, legacyTestReport: Boolean, logg } else { new File(targetDir, s"TEST-${normalizeName(withTestSuite(_.name))}.xml").getAbsolutePath } - // TODO would be nice to have a logger and log this with level debug - // System.err.println("Writing JUnit XML test report: " + file) + if (logger != null) { + logger.debug(s"writing JUnit XML test report: $file") + } val testSuiteResult = withTestSuite(_.stop()) XML.save(file, testSuiteResult, "UTF-8", xmlDecl = true, null) testSuite.remove() diff --git a/testing/src/test/scala/sbt/JUnitXmlTestsListenerSpec.scala b/testing/src/test/scala/sbt/JUnitXmlTestsListenerSpec.scala new file mode 100644 index 000000000..98074f666 --- /dev/null +++ b/testing/src/test/scala/sbt/JUnitXmlTestsListenerSpec.scala @@ -0,0 +1,105 @@ +/* + * sbt + * Copyright 2023, Scala center + * Copyright 2011 - 2022, Lightbend, Inc. + * Copyright 2008 - 2010, Mark Harrah + * Licensed under Apache License 2.0 (see LICENSE) + */ + +package sbt + +import java.io.File +import java.util.concurrent.atomic.AtomicReference + +import testing.{ Event as TEvent, OptionalThrowable, Status as TStatus, TestSelector } +import util.{ AbstractLogger, Level, ControlEvent, LogEvent } +import sbt.protocol.testing.TestResult +import verify.BasicTestSuite + +object JUnitXmlTestsListenerSpec extends BasicTestSuite: + + test("JUnitXmlTestsListener should log debug message when writing test report"): + val tempDir = File.createTempFile("junit-test", "") + tempDir.delete() + tempDir.mkdirs() + try + val loggedMessages = new AtomicReference[List[String]](Nil) + val mockLogger = new AbstractLogger: + def getLevel: Level.Value = Level.Debug + def setLevel(newLevel: Level.Value): Unit = () + def getTrace: Int = 0 + def setTrace(flag: Int): Unit = () + def successEnabled: Boolean = false + def setSuccessEnabled(flag: Boolean): Unit = () + def control(event: ControlEvent.Value, message: => String): Unit = () + def logAll(events: Seq[LogEvent]): Unit = () + def trace(t: => Throwable): Unit = () + def success(message: => String): Unit = () + def log(level: Level.Value, message: => String): Unit = + if level == Level.Debug then loggedMessages.updateAndGet(_ :+ message) + + val listener = new JUnitXmlTestsListener(tempDir, false, mockLogger) + listener.doInit() + listener.startGroup("TestSuite") + + // Create a test event + val testEvent = new TEvent: + def fullyQualifiedName = "TestSuite.testMethod" + def duration() = 100L + def status = TStatus.Success + def fingerprint = null + def selector = new TestSelector("testMethod") + def throwable = new OptionalThrowable() + + listener.testEvent(sbt.TestEvent(Seq(testEvent))) + + // End the group to trigger writeSuite() + listener.endGroup("TestSuite", TestResult.Passed) + + // Verify that the debug message was logged + val messages = loggedMessages.get() + assert( + messages.exists(_.contains("writing JUnit XML test report")), + s"Expected log message containing 'writing JUnit XML test report', but got: $messages" + ) + assert( + messages.exists(_.contains("TEST-TestSuite.xml")), + s"Expected log message containing 'TEST-TestSuite.xml', but got: $messages" + ) + finally + // Cleanup + if tempDir.exists() then + tempDir.listFiles().foreach(_.delete()) + tempDir.delete() + + test("JUnitXmlTestsListener should handle null logger gracefully"): + val tempDir = File.createTempFile("junit-test", "") + tempDir.delete() + tempDir.mkdirs() + try + val listener = new JUnitXmlTestsListener(tempDir, false, null) + listener.doInit() + listener.startGroup("TestSuite") + + val testEvent = new TEvent: + def fullyQualifiedName = "TestSuite.testMethod" + def duration() = 100L + def status = TStatus.Success + def fingerprint = null + def selector = new TestSelector("testMethod") + def throwable = new OptionalThrowable() + + listener.testEvent(sbt.TestEvent(Seq(testEvent))) + + // Should not throw when logger is null + listener.endGroup("TestSuite", TestResult.Passed) + + // Verify XML file was still created + val xmlFile = new File(tempDir, "TEST-TestSuite.xml") + assert(xmlFile.exists(), "XML file should be created even when logger is null") + finally + if tempDir.exists() then + tempDir.listFiles().foreach(_.delete()) + tempDir.delete() + +end JUnitXmlTestsListenerSpec