Skip to content

Commit

Permalink
Migrate tests to slf4j2 custom testing assertion
Browse files Browse the repository at this point in the history
wip
  • Loading branch information
I-Al-Istannen committed Oct 8, 2024
1 parent 44fde7a commit dda6cef
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 40 deletions.
8 changes: 0 additions & 8 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -156,13 +156,6 @@
<version>2.0.1.Final</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/uk.org.lidalia/slf4j-test -->
<dependency>
<groupId>uk.org.lidalia</groupId>
<artifactId>slf4j-test</artifactId>
<version>1.2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.kohsuke.metainf-services</groupId>
<artifactId>metainf-services</artifactId>
Expand Down Expand Up @@ -230,7 +223,6 @@
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<classpathDependencyExcludes>
<classpathDependencyExclude>ch.qos.logback:logback-classic</classpathDependencyExclude>
<trimStackTrace>false</trimStackTrace>
</classpathDependencyExcludes>
</configuration>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package spoon.support.compiler.jdt;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import spoon.Launcher;
import spoon.reflect.CtModel;
import uk.org.lidalia.slf4jtest.TestLogger;
import uk.org.lidalia.slf4jtest.TestLoggerFactory;
import spoon.test.logging.LogTest;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
Expand All @@ -21,13 +21,13 @@ public void testIgnoreSyntaxErrorsCompilation() {
assertEquals(1,model.getAllTypes().size());
}

@ExtendWith(LogTest.LogCaptureExtension.class)
@Test
public void testIgnoreSyntaxErrorsLogging() {
public void testIgnoreSyntaxErrorsLogging(LogTest.LogCapture logCapture) {
// contract: if a file has any syntax errors, the name of the incorrect file is logged
TestLogger logger = TestLoggerFactory.getTestLogger(TreeBuilderCompiler.class);
Launcher launcher = setupLauncher();
launcher.buildModel();
assertTrue(logger.getLoggingEvents().get(0).getMessage().endsWith("InvalidClass.java"));
assertTrue(logCapture.loggingEvents().get(0).getMessage().endsWith("InvalidClass.java"));
}

@Test
Expand Down
134 changes: 107 additions & 27 deletions src/test/java/spoon/test/logging/LogTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,40 +16,47 @@
*/
package spoon.test.logging;

import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.read.ListAppender;
import org.apache.commons.lang3.tuple.Pair;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolver;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.ParameterizedTest;
import org.slf4j.LoggerFactory;
import spoon.FluentLauncher;
import spoon.Launcher;
import spoon.MavenLauncher;
import spoon.processing.AbstractProcessor;
import spoon.reflect.CtModel;
import spoon.reflect.code.CtInvocation;
import spoon.reflect.declaration.CtConstructor;
import spoon.reflect.visitor.Query;
import spoon.reflect.visitor.filter.TypeFilter;
import spoon.support.JavaOutputProcessor;
import spoon.support.Level;
import spoon.testing.utils.GitHubIssue;
import uk.org.lidalia.slf4jtest.TestLogger;
import uk.org.lidalia.slf4jtest.TestLoggerFactory;

import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

@ExtendWith(LogTest.LogCaptureExtension.class)
public class LogTest {

@ParameterizedTest
@MethodSource("getLogLevelsAndExpectedCounts")
public void testAllLevelsForLogs(Pair<Level, Integer> levelAndExpectedCount) {
public void testAllLevelsForLogs(Pair<Level, Integer> levelAndExpectedCount, LogCapture logCapture) {
final Level level = levelAndExpectedCount.getLeft();
final int expectedCount = levelAndExpectedCount.getRight();
final TestLogger logger = TestLoggerFactory.getTestLogger(Launcher.class);
final Launcher launcher = new Launcher();
logger.clear();
launcher.setArgs(new String[] {
"-i", "./src/test/java/spoon/test/logging",
"--level", level.toString()
Expand All @@ -60,15 +67,17 @@ public void testAllLevelsForLogs(Pair<Level, Integer> levelAndExpectedCount) {
launcher.getEnvironment().reportProgressMessage("reportProgressMessage");

// contract: the --level arguments sets the level
assertEquals(level, launcher.getFactory().getEnvironment().getLevel());
assertThat(launcher.getFactory().getEnvironment().getLevel()).isEqualTo(level);

// contract: the number of messages increases with the log level
assertTrue(logger.getLoggingEvents().size() >= expectedCount);

assertThat(logCapture.loggingEvents()).hasSizeGreaterThanOrEqualTo(expectedCount);
if (expectedCount == 0) {
assertThat(logCapture.loggingEvents()).isEmpty();
}
}

/**
* @return log level and expected amount of logs for that level for the
* @return log level and expected number of logs for that level for the
* {@link LogTest::testAllLevelsForLogs} test.
*/
private static Stream<Pair<Level, Integer>> getLogLevelsAndExpectedCounts() {
Expand All @@ -83,33 +92,40 @@ private static Stream<Pair<Level, Integer>> getLogLevelsAndExpectedCounts() {


@Test
public void testMavenLauncherLogs() {
public void testMavenLauncherLogs(LogCapture logCapture) {
// contract: MavenLauncher should output different logs depending on whether the classpath is inferred or manually set
final TestLogger logger = TestLoggerFactory.getTestLogger(MavenLauncher.class);
MavenLauncher mavenLauncher = new MavenLauncher("./pom.xml", MavenLauncher.SOURCE_TYPE.APP_SOURCE);
assertEquals("Running in FULLCLASSPATH mode. Source folders and dependencies are inferred from the pom.xml file (doc: http://spoon.gforge.inria.fr/launcher.html).",logger.getLoggingEvents().get(0).getMessage());
logger.clear();
mavenLauncher = new MavenLauncher("./pom.xml", MavenLauncher.SOURCE_TYPE.APP_SOURCE, new String[]{"./"});
assertEquals("Running in FULLCLASSPATH mode. Classpath is manually set (doc: http://spoon.gforge.inria.fr/launcher.html).",logger.getLoggingEvents().get(0).getMessage());
new MavenLauncher("./pom.xml", MavenLauncher.SOURCE_TYPE.APP_SOURCE);
assertThat(logCapture.loggingEvents(Level.INFO).get(0).getMessage()).isEqualTo(
"Running in FULLCLASSPATH mode. Source folders and dependencies are inferred from the pom.xml file (doc: http://spoon.gforge.inria.fr/launcher.html)."
);

logCapture.clear();

new MavenLauncher("./pom.xml", MavenLauncher.SOURCE_TYPE.APP_SOURCE, new String[]{"./"});
assertThat(logCapture.loggingEvents(Level.INFO).get(0).getMessage()).isEqualTo(
"Running in FULLCLASSPATH mode. Classpath is manually set (doc: http://spoon.gforge.inria.fr/launcher.html)."
);
}

@Test
public void testLoggingOff() {
// contract: When logging is off, no message should me logged independent of logging level.
final TestLogger logger = TestLoggerFactory.getTestLogger(Launcher.class);
final Launcher launcher = new Launcher();
logger.clear();
public void testLoggingOff(LogCapture logCapture) {
// contract: When logging is off, no message should be logged independent of logging level.
Launcher launcher = new Launcher();
logCapture.clear();
launcher.setArgs(new String[] {
"-i", "./src/test/java/spoon/test/logging",
"--level", Level.OFF.toString()
});

// test messages with all logging levels
for (Level level : Level.values()) {
launcher.getEnvironment().report(new JavaOutputProcessor(), level,
"This is a message with level " + level.toString());
launcher.getEnvironment().report(
new JavaOutputProcessor(),
level,
"This is a message with level " + level.toString()
);
}
assertEquals(0, logger.getLoggingEvents().size());
assertThat(logCapture.loggingEvents()).isEmpty();
}

@Test
Expand All @@ -129,4 +145,68 @@ public boolean isToBeProcessed(CtConstructor<?> candidate) {
}};
assertDoesNotThrow(() -> new FluentLauncher().inputResource(codePath).processor(processor).buildModel());
}

public record LogCapture(ListAppender<ILoggingEvent> listAppender) {
public List<ILoggingEvent> loggingEvents() {
return Collections.unmodifiableList(listAppender.list);
}

public List<ILoggingEvent> loggingEvents(Level minLevel) {
return listAppender.list.stream()
.filter(event -> minLevel.compareTo(Level.valueOf(event.getLevel().toString())) >= 0)
.toList();
}

public void start() {
listAppender.start();
}

public void stop() {
listAppender.stop();
}

public void clear() {
listAppender.list.clear();
}
}

public static class LogCaptureExtension implements ParameterResolver, AfterTestExecutionCallback {

private final Logger logger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);

private LogCapture logCapture;

@Override
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {
return parameterContext.getParameter().getType() == LogCapture.class;
}

@Override
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) {
logCapture = new LogCapture(new ListAppender<>());

setup();

return logCapture;
}

@Override
public void afterTestExecution(ExtensionContext context) {
teardown();
}

private void setup() {
logger.addAppender(logCapture.listAppender());
logCapture.start();
}

private void teardown() {
if (logCapture == null || logger == null) {
return;
}

logger.detachAndStopAllAppenders();
logCapture.stop();
}
}
}

0 comments on commit dda6cef

Please sign in to comment.