fix(default-exts): Fix order of read fallback and validation extensions
This commit is contained in:
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [unreleased]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- **Breaking**: Inverted the order in which middlewares are applied.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- `default-extensions`: Fixed `ReadFallbackExtension` being applied too late.
|
||||||
|
|
||||||
## [0.6.0] - 2025-12-14
|
## [0.6.0] - 2025-12-14
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -3,15 +3,16 @@ package de.siphalor.tweed5.defaultextensions.readfallback.impl;
|
|||||||
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
||||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||||
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
||||||
import de.siphalor.tweed5.defaultextensions.readfallback.api.ReadFallbackExtension;
|
|
||||||
import de.siphalor.tweed5.data.extension.api.TweedEntryReadException;
|
import de.siphalor.tweed5.data.extension.api.TweedEntryReadException;
|
||||||
import de.siphalor.tweed5.data.extension.api.TweedEntryReader;
|
import de.siphalor.tweed5.data.extension.api.TweedEntryReader;
|
||||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteExtensionSetupContext;
|
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteExtensionSetupContext;
|
||||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteRelatedExtension;
|
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteRelatedExtension;
|
||||||
|
import de.siphalor.tweed5.defaultextensions.pather.api.PatherExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension;
|
import de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension;
|
||||||
|
import de.siphalor.tweed5.defaultextensions.readfallback.api.ReadFallbackExtension;
|
||||||
|
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension;
|
||||||
import lombok.extern.apachecommons.CommonsLog;
|
import lombok.extern.apachecommons.CommonsLog;
|
||||||
import org.jspecify.annotations.NonNull;
|
import org.jspecify.annotations.NonNull;
|
||||||
import org.jspecify.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -19,22 +20,17 @@ import java.util.Set;
|
|||||||
@CommonsLog
|
@CommonsLog
|
||||||
public class ReadFallbackExtensionImpl implements ReadFallbackExtension, ReadWriteRelatedExtension {
|
public class ReadFallbackExtensionImpl implements ReadFallbackExtension, ReadWriteRelatedExtension {
|
||||||
private final ConfigContainer<?> configContainer;
|
private final ConfigContainer<?> configContainer;
|
||||||
private @Nullable PresetsExtension presetsExtension;
|
|
||||||
|
|
||||||
public ReadFallbackExtensionImpl(ConfigContainer<?> configContainer) {
|
public ReadFallbackExtensionImpl(ConfigContainer<?> configContainer) {
|
||||||
this.configContainer = configContainer;
|
this.configContainer = configContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void extensionsFinalized() {
|
public void setupReadWriteExtension(ReadWriteExtensionSetupContext context) {
|
||||||
presetsExtension = configContainer.extension(PresetsExtension.class)
|
PresetsExtension presetsExtension = configContainer.extension(PresetsExtension.class)
|
||||||
.orElseThrow(() -> new IllegalStateException(getClass().getSimpleName()
|
.orElseThrow(() -> new IllegalStateException(getClass().getSimpleName()
|
||||||
+ " requires " + ReadFallbackExtension.class.getSimpleName()));
|
+ " requires " + ReadFallbackExtension.class.getSimpleName()));
|
||||||
}
|
PatherExtension patherExtension = configContainer.extension(PatherExtension.class).orElse(null);
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setupReadWriteExtension(ReadWriteExtensionSetupContext context) {
|
|
||||||
assert presetsExtension != null;
|
|
||||||
|
|
||||||
context.registerReaderMiddleware(new Middleware<TweedEntryReader<?, ?>>() {
|
context.registerReaderMiddleware(new Middleware<TweedEntryReader<?, ?>>() {
|
||||||
@Override
|
@Override
|
||||||
@@ -44,12 +40,12 @@ public class ReadFallbackExtensionImpl implements ReadFallbackExtension, ReadWri
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> mustComeBefore() {
|
public Set<String> mustComeBefore() {
|
||||||
return Collections.singleton(DEFAULT_START);
|
return Collections.singleton(PatherExtension.EXTENSION_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> mustComeAfter() {
|
public Set<String> mustComeAfter() {
|
||||||
return Collections.emptySet();
|
return Collections.singleton(ValidationExtension.EXTENSION_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -57,11 +53,19 @@ public class ReadFallbackExtensionImpl implements ReadFallbackExtension, ReadWri
|
|||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
TweedEntryReader<Object, ConfigEntry<Object>> castedInner =
|
TweedEntryReader<Object, ConfigEntry<Object>> castedInner =
|
||||||
(TweedEntryReader<Object, @NonNull ConfigEntry<Object>>) inner;
|
(TweedEntryReader<Object, @NonNull ConfigEntry<Object>>) inner;
|
||||||
return (TweedEntryReader<Object, @NonNull ConfigEntry<Object>>) (reader, entry, context1) -> {
|
return (TweedEntryReader<Object, @NonNull ConfigEntry<Object>>) (reader, entry, context) -> {
|
||||||
try {
|
try {
|
||||||
return castedInner.read(reader, entry, context1);
|
return castedInner.read(reader, entry, context);
|
||||||
} catch (TweedEntryReadException e) {
|
} catch (TweedEntryReadException e) {
|
||||||
|
if (patherExtension == null) {
|
||||||
log.error("Failed to read entry: " + e.getMessage(), e);
|
log.error("Failed to read entry: " + e.getMessage(), e);
|
||||||
|
} else {
|
||||||
|
log.error(
|
||||||
|
"Failed to read entry: " + e.getMessage()
|
||||||
|
+ " at " + patherExtension.getPath(context),
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
return presetsExtension.presetValue(entry, PresetsExtension.DEFAULT_PRESET_NAME);
|
return presetsExtension.presetValue(entry, PresetsExtension.DEFAULT_PRESET_NAME);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> mustComeAfter() {
|
public Set<String> mustComeBefore() {
|
||||||
return Collections.singleton(PatherExtension.EXTENSION_ID);
|
return Collections.singleton(PatherExtension.EXTENSION_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,33 +1,51 @@
|
|||||||
package de.siphalor.tweed5.defaultextensions.readfallback.impl;
|
package de.siphalor.tweed5.defaultextensions.readfallback.impl;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.Level;
|
||||||
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
|
import de.siphalor.tweed5.core.api.entry.CompoundConfigEntry;
|
||||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||||
import de.siphalor.tweed5.core.impl.DefaultConfigContainer;
|
import de.siphalor.tweed5.core.impl.DefaultConfigContainer;
|
||||||
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
|
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
|
||||||
|
import de.siphalor.tweed5.core.impl.entry.StaticMapCompoundConfigEntryImpl;
|
||||||
import de.siphalor.tweed5.data.extension.api.ReadWriteExtension;
|
import de.siphalor.tweed5.data.extension.api.ReadWriteExtension;
|
||||||
import de.siphalor.tweed5.data.extension.api.TweedEntryReadException;
|
import de.siphalor.tweed5.data.extension.api.TweedEntryReadException;
|
||||||
import de.siphalor.tweed5.data.extension.api.TweedReadContext;
|
import de.siphalor.tweed5.data.extension.api.TweedReadContext;
|
||||||
import de.siphalor.tweed5.data.extension.api.TweedWriteContext;
|
import de.siphalor.tweed5.data.extension.api.TweedWriteContext;
|
||||||
import de.siphalor.tweed5.data.extension.api.readwrite.TweedEntryReaderWriter;
|
import de.siphalor.tweed5.data.extension.api.readwrite.TweedEntryReaderWriter;
|
||||||
|
import de.siphalor.tweed5.data.extension.api.readwrite.TweedEntryReaderWriters;
|
||||||
import de.siphalor.tweed5.data.hjson.HjsonLexer;
|
import de.siphalor.tweed5.data.hjson.HjsonLexer;
|
||||||
import de.siphalor.tweed5.data.hjson.HjsonReader;
|
import de.siphalor.tweed5.data.hjson.HjsonReader;
|
||||||
import de.siphalor.tweed5.dataapi.api.*;
|
import de.siphalor.tweed5.dataapi.api.TweedDataReadException;
|
||||||
|
import de.siphalor.tweed5.dataapi.api.TweedDataReader;
|
||||||
|
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
|
||||||
|
import de.siphalor.tweed5.dataapi.api.TweedDataWriteException;
|
||||||
|
import de.siphalor.tweed5.defaultextensions.pather.api.PatherExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension;
|
import de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.readfallback.api.ReadFallbackExtension;
|
import de.siphalor.tweed5.defaultextensions.readfallback.api.ReadFallbackExtension;
|
||||||
|
import de.siphalor.tweed5.testutils.generic.log.LogCaptureMockitoExtension;
|
||||||
|
import de.siphalor.tweed5.testutils.generic.log.LogsCaptor;
|
||||||
import org.jspecify.annotations.NullMarked;
|
import org.jspecify.annotations.NullMarked;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import static de.siphalor.tweed5.data.extension.api.ReadWriteExtension.entryReaderWriter;
|
import static de.siphalor.tweed5.data.extension.api.ReadWriteExtension.entryReaderWriter;
|
||||||
import static de.siphalor.tweed5.data.extension.api.ReadWriteExtension.read;
|
import static de.siphalor.tweed5.data.extension.api.ReadWriteExtension.read;
|
||||||
|
import static de.siphalor.tweed5.data.extension.api.readwrite.TweedEntryReaderWriters.compoundReaderWriter;
|
||||||
import static de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension.presetValue;
|
import static de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension.presetValue;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.InstanceOfAssertFactories.STRING;
|
||||||
|
|
||||||
|
@ExtendWith(LogCaptureMockitoExtension.class)
|
||||||
@NullMarked
|
@NullMarked
|
||||||
class ReadFallbackExtensionImplTest {
|
class ReadFallbackExtensionImplTest {
|
||||||
@Test
|
@Test
|
||||||
void test() {
|
void test(LogsCaptor<ReadFallbackExtensionImpl> logsCaptor) {
|
||||||
DefaultConfigContainer<Integer> configContainer = new DefaultConfigContainer<>();
|
DefaultConfigContainer<Integer> configContainer = new DefaultConfigContainer<>();
|
||||||
configContainer.registerExtension(ReadWriteExtension.class);
|
configContainer.registerExtension(ReadWriteExtension.class);
|
||||||
configContainer.registerExtension(PresetsExtension.class);
|
configContainer.registerExtension(PresetsExtension.class);
|
||||||
@@ -36,7 +54,76 @@ class ReadFallbackExtensionImplTest {
|
|||||||
|
|
||||||
ConfigEntry<Integer> entry = new SimpleConfigEntryImpl<>(configContainer, Integer.class)
|
ConfigEntry<Integer> entry = new SimpleConfigEntryImpl<>(configContainer, Integer.class)
|
||||||
.apply(presetValue(PresetsExtension.DEFAULT_PRESET_NAME, -1))
|
.apply(presetValue(PresetsExtension.DEFAULT_PRESET_NAME, -1))
|
||||||
.apply(entryReaderWriter(new TweedEntryReaderWriter<>() {
|
.apply(entryReaderWriter(new EvenIntReader()));
|
||||||
|
|
||||||
|
configContainer.attachTree(entry);
|
||||||
|
configContainer.initialize();
|
||||||
|
|
||||||
|
assertThat(entry.call(read(new HjsonReader(new HjsonLexer(new StringReader("12")))))).isEqualTo(12);
|
||||||
|
assertThat(logsCaptor.getLogsForLevel(Level.ERROR)).isEmpty();
|
||||||
|
logsCaptor.clear();
|
||||||
|
|
||||||
|
assertThat(entry.call(read(new HjsonReader(new HjsonLexer(new StringReader("13")))))).isEqualTo(-1);
|
||||||
|
assertThat(logsCaptor.getLogsForLevel(Level.ERROR)).hasSize(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
|
@Test
|
||||||
|
void nestedWithPather(LogsCaptor<ReadFallbackExtensionImpl> logsCaptor) {
|
||||||
|
DefaultConfigContainer<Map<String, Object>> configContainer = new DefaultConfigContainer<>();
|
||||||
|
configContainer.registerExtension(ReadWriteExtension.class);
|
||||||
|
configContainer.registerExtension(PatherExtension.class);
|
||||||
|
configContainer.registerExtension(PresetsExtension.class);
|
||||||
|
configContainer.registerExtension(ReadFallbackExtension.DEFAULT);
|
||||||
|
configContainer.finishExtensionSetup();
|
||||||
|
|
||||||
|
CompoundConfigEntry<Map<String, Object>> root = new StaticMapCompoundConfigEntryImpl<>(
|
||||||
|
configContainer,
|
||||||
|
(Class<Map<String, Object>>) (Class) Map.class,
|
||||||
|
HashMap::new,
|
||||||
|
Collections.singletonMap(
|
||||||
|
"first",
|
||||||
|
new StaticMapCompoundConfigEntryImpl<>(
|
||||||
|
configContainer,
|
||||||
|
(Class<Map<String, Object>>) (Class) Map.class,
|
||||||
|
HashMap::new,
|
||||||
|
Collections.singletonMap(
|
||||||
|
"second",
|
||||||
|
new SimpleConfigEntryImpl<>(
|
||||||
|
configContainer,
|
||||||
|
Integer.class
|
||||||
|
).apply(presetValue(PresetsExtension.DEFAULT_PRESET_NAME, -1))
|
||||||
|
.apply(entryReaderWriter(new EvenIntReader()))
|
||||||
|
)
|
||||||
|
).apply(entryReaderWriter(TweedEntryReaderWriters.compoundReaderWriter()))
|
||||||
|
)
|
||||||
|
).apply(entryReaderWriter(compoundReaderWriter()));
|
||||||
|
|
||||||
|
configContainer.attachTree(root);
|
||||||
|
configContainer.initialize();
|
||||||
|
|
||||||
|
assertThat(root.call(read(new HjsonReader(new HjsonLexer(new StringReader(
|
||||||
|
"{first: {second: 12}}"
|
||||||
|
))))))
|
||||||
|
.extracting(map -> (Map<String, Object>) map.get("first"))
|
||||||
|
.extracting(map -> (Integer) map.get("second"))
|
||||||
|
.isEqualTo(12);
|
||||||
|
assertThat(logsCaptor.getLogsForLevel(Level.ERROR)).isEmpty();
|
||||||
|
logsCaptor.clear();
|
||||||
|
|
||||||
|
assertThat(root.call(read(new HjsonReader(new HjsonLexer(new StringReader(
|
||||||
|
"{first: {second: 13}}"
|
||||||
|
))))))
|
||||||
|
.extracting(map -> (Map<String, Object>) map.get("first"))
|
||||||
|
.extracting(map -> (Integer) map.get("second"))
|
||||||
|
.isEqualTo(-1);
|
||||||
|
assertThat(logsCaptor.getLogsForLevel(Level.ERROR)).singleElement()
|
||||||
|
.extracting(ILoggingEvent::getMessage)
|
||||||
|
.asInstanceOf(STRING)
|
||||||
|
.contains("first.second");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class EvenIntReader implements TweedEntryReaderWriter<Integer, ConfigEntry<Integer>> {
|
||||||
@Override
|
@Override
|
||||||
public Integer read(
|
public Integer read(
|
||||||
TweedDataReader reader,
|
TweedDataReader reader,
|
||||||
@@ -65,12 +152,5 @@ class ReadFallbackExtensionImplTest {
|
|||||||
) throws TweedDataWriteException {
|
) throws TweedDataWriteException {
|
||||||
throw new IllegalStateException("Should not be called");
|
throw new IllegalStateException("Should not be called");
|
||||||
}
|
}
|
||||||
}));
|
|
||||||
|
|
||||||
configContainer.attachTree(entry);
|
|
||||||
configContainer.initialize();
|
|
||||||
|
|
||||||
assertThat(entry.call(read(new HjsonReader(new HjsonLexer(new StringReader("12")))))).isEqualTo(12);
|
|
||||||
assertThat(entry.call(read(new HjsonReader(new HjsonLexer(new StringReader("13")))))).isEqualTo(-1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("de.siphalor.tweed5.test-utils")
|
id("de.siphalor.tweed5.test-utils")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(libs.acl)
|
||||||
|
implementation(libs.slf4j.api)
|
||||||
|
implementation(libs.slf4j.rt)
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package de.siphalor.tweed5.testutils.generic.log;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.Logger;
|
||||||
|
import org.junit.jupiter.api.extension.*;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class LogCaptureMockitoExtension implements Extension, ParameterResolver, AfterEachCallback {
|
||||||
|
@Override
|
||||||
|
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws
|
||||||
|
ParameterResolutionException {
|
||||||
|
return parameterContext.getParameter().getType() == LogsCaptor.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws
|
||||||
|
ParameterResolutionException {
|
||||||
|
Type logsCaptorType = parameterContext.getParameter().getParameterizedType();
|
||||||
|
if (logsCaptorType instanceof ParameterizedType logsCaptorParameterizedType) {
|
||||||
|
Type targetType = logsCaptorParameterizedType.getActualTypeArguments()[0];
|
||||||
|
Class<?> targetClass = (Class<?>) targetType;
|
||||||
|
Logger logger = (Logger) LoggerFactory.getLogger(targetClass);
|
||||||
|
|
||||||
|
logger.info("Resolved logger to {}", Objects.toIdentityString(logger));
|
||||||
|
|
||||||
|
LogsCaptor<?> appender = new LogsCaptor<>(logger);
|
||||||
|
appender.setName("test log appender/" + targetClass.getName());
|
||||||
|
appender.start();
|
||||||
|
|
||||||
|
getStoreData(extensionContext).appenders.add(appender);
|
||||||
|
|
||||||
|
logger.addAppender(appender);
|
||||||
|
|
||||||
|
return appender;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ParameterResolutionException("Failed to resolve parameter " + parameterContext.getParameter());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterEach(ExtensionContext context) {
|
||||||
|
for (LogsCaptor<?> appender : getStoreData(context).appenders) {
|
||||||
|
appender.detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private StoreData getStoreData(ExtensionContext extensionContext) {
|
||||||
|
return extensionContext.getStore(ExtensionContext.Namespace.create(getClass(), extensionContext.getRequiredTestMethod()))
|
||||||
|
.getOrComputeIfAbsent(StoreData.class, k -> new StoreData(), StoreData.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class StoreData {
|
||||||
|
private final Collection<LogsCaptor<?>> appenders = new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package de.siphalor.tweed5.testutils.generic.log;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.Level;
|
||||||
|
import ch.qos.logback.classic.Logger;
|
||||||
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
|
import ch.qos.logback.core.AppenderBase;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class LogsCaptor<T> extends AppenderBase<ILoggingEvent> {
|
||||||
|
private final Logger logger;
|
||||||
|
private final List<ILoggingEvent> logs = new ArrayList<>();
|
||||||
|
|
||||||
|
public List<ILoggingEvent> getLogsForLevel(Level level) {
|
||||||
|
return logs.stream().filter(log -> log.getLevel().equals(level)).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void append(ILoggingEvent event) {
|
||||||
|
logs.add(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
logs.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void detach() {
|
||||||
|
logger.detachAppender(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user