[default-extensions] Introduce patch extension
This commit is contained in:
@@ -35,11 +35,11 @@ import java.util.*;
|
|||||||
|
|
||||||
public class AttributesReadWriteFilterExtensionImpl
|
public class AttributesReadWriteFilterExtensionImpl
|
||||||
implements AttributesReadWriteFilterExtension, AttributesRelatedExtension, ReadWriteRelatedExtension {
|
implements AttributesReadWriteFilterExtension, AttributesRelatedExtension, ReadWriteRelatedExtension {
|
||||||
private static final Set<String> MIDDLEWARES_MUST_COME_BEFORE = new HashSet<>(Arrays.asList(
|
private static final Set<String> MIDDLEWARES_MUST_COME_BEFORE = Collections.emptySet();
|
||||||
Middleware.DEFAULT_START,
|
private static final Set<String> MIDDLEWARES_MUST_COME_AFTER = new HashSet<>(Arrays.asList(
|
||||||
|
Middleware.DEFAULT_END,
|
||||||
"validation"
|
"validation"
|
||||||
));
|
));
|
||||||
private static final Set<String> MIDDLEWARES_MUST_COME_AFTER = Collections.emptySet();
|
|
||||||
private static final UniqueSymbol TWEED_DATA_NOTHING_VALUE = new UniqueSymbol("nothing (skip value)");
|
private static final UniqueSymbol TWEED_DATA_NOTHING_VALUE = new UniqueSymbol("nothing (skip value)");
|
||||||
|
|
||||||
private final ConfigContainer<?> configContainer;
|
private final ConfigContainer<?> configContainer;
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package de.siphalor.tweed5.defaultextensions.patch.api;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||||
|
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
||||||
|
import de.siphalor.tweed5.defaultextensions.patch.impl.PatchExtensionImpl;
|
||||||
|
import de.siphalor.tweed5.patchwork.api.Patchwork;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public interface PatchExtension extends TweedExtension {
|
||||||
|
Class<? extends PatchExtension> DEFAULT = PatchExtensionImpl.class;
|
||||||
|
String EXTENSION_ID = "patch";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default String getId() {
|
||||||
|
return EXTENSION_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
PatchInfo collectPatchInfo(Patchwork readWriteContextExtensionsData);
|
||||||
|
|
||||||
|
<T extends @Nullable Object> T patch(ConfigEntry<T> entry, T targetValue, T patchValue, PatchInfo patchInfo);
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package de.siphalor.tweed5.defaultextensions.patch.api;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||||
|
|
||||||
|
public interface PatchInfo {
|
||||||
|
boolean containsEntry(ConfigEntry<?> entry);
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
@NullMarked
|
||||||
|
package de.siphalor.tweed5.defaultextensions.patch.api;
|
||||||
|
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
package de.siphalor.tweed5.defaultextensions.patch.impl;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.core.api.entry.CompoundConfigEntry;
|
||||||
|
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||||
|
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
||||||
|
import de.siphalor.tweed5.data.extension.api.TweedEntryReadException;
|
||||||
|
import de.siphalor.tweed5.data.extension.api.TweedEntryReader;
|
||||||
|
import de.siphalor.tweed5.data.extension.api.TweedReadContext;
|
||||||
|
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteExtensionSetupContext;
|
||||||
|
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteRelatedExtension;
|
||||||
|
import de.siphalor.tweed5.dataapi.api.TweedDataReader;
|
||||||
|
import de.siphalor.tweed5.defaultextensions.patch.api.PatchExtension;
|
||||||
|
import de.siphalor.tweed5.defaultextensions.patch.api.PatchInfo;
|
||||||
|
import de.siphalor.tweed5.patchwork.api.Patchwork;
|
||||||
|
import de.siphalor.tweed5.patchwork.api.PatchworkPartAccess;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.jspecify.annotations.NonNull;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
public class PatchExtensionImpl implements PatchExtension, ReadWriteRelatedExtension {
|
||||||
|
private @Nullable PatchworkPartAccess<ReadWriteContextCustomData> readWriteContextDataAccess;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setupReadWriteExtension(ReadWriteExtensionSetupContext context) {
|
||||||
|
readWriteContextDataAccess = context.registerReadWriteContextExtensionData(ReadWriteContextCustomData.class);
|
||||||
|
context.registerReaderMiddleware(new ReaderMiddleware());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PatchInfo collectPatchInfo(Patchwork readWriteContextExtensionsData) {
|
||||||
|
ReadWriteContextCustomData customData = getOrCreateCustomData(readWriteContextExtensionsData);
|
||||||
|
PatchInfoImpl patchInfo = customData.patchInfo();
|
||||||
|
if (patchInfo == null) {
|
||||||
|
patchInfo = new PatchInfoImpl();
|
||||||
|
customData.patchInfo(patchInfo);
|
||||||
|
}
|
||||||
|
return patchInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReadWriteContextCustomData getOrCreateCustomData(Patchwork readWriteContextExtensionsData) {
|
||||||
|
assert readWriteContextDataAccess != null;
|
||||||
|
ReadWriteContextCustomData customData = readWriteContextExtensionsData.get(readWriteContextDataAccess);
|
||||||
|
if (customData == null) {
|
||||||
|
customData = new ReadWriteContextCustomData();
|
||||||
|
readWriteContextExtensionsData.set(readWriteContextDataAccess, customData);
|
||||||
|
}
|
||||||
|
return customData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends @Nullable Object> T patch(ConfigEntry<T> entry, T targetValue, T patchValue, PatchInfo patchInfo) {
|
||||||
|
if (!patchInfo.containsEntry(entry)) {
|
||||||
|
return targetValue;
|
||||||
|
} else if (patchValue == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry instanceof CompoundConfigEntry) {
|
||||||
|
CompoundConfigEntry<T> compoundEntry = (CompoundConfigEntry<T>) entry;
|
||||||
|
|
||||||
|
T targetCompoundValue;
|
||||||
|
if (targetValue != null) {
|
||||||
|
targetCompoundValue = targetValue;
|
||||||
|
} else {
|
||||||
|
targetCompoundValue = compoundEntry.instantiateCompoundValue();
|
||||||
|
}
|
||||||
|
compoundEntry.subEntries().forEach((key, subEntry) -> {
|
||||||
|
if (!patchInfo.containsEntry(subEntry)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
compoundEntry.set(
|
||||||
|
targetCompoundValue, key, patch(
|
||||||
|
subEntry,
|
||||||
|
compoundEntry.get(targetCompoundValue, key),
|
||||||
|
compoundEntry.get(patchValue, key),
|
||||||
|
patchInfo
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return targetCompoundValue;
|
||||||
|
} else {
|
||||||
|
return patchValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ReaderMiddleware implements Middleware<TweedEntryReader<?, ?>> {
|
||||||
|
@Override
|
||||||
|
public String id() {
|
||||||
|
return "patch-info-collector";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TweedEntryReader<?, ?> process(TweedEntryReader<?, ?> inner) {
|
||||||
|
assert readWriteContextDataAccess != null;
|
||||||
|
|
||||||
|
//noinspection unchecked
|
||||||
|
TweedEntryReader<Object, ConfigEntry<Object>> innerCasted =
|
||||||
|
(TweedEntryReader<Object, @NonNull ConfigEntry<Object>>) inner;
|
||||||
|
return new TweedEntryReader<@Nullable Object, ConfigEntry<Object>>() {
|
||||||
|
@Override
|
||||||
|
public @Nullable Object read(
|
||||||
|
TweedDataReader reader,
|
||||||
|
ConfigEntry<Object> entry,
|
||||||
|
TweedReadContext context
|
||||||
|
) throws TweedEntryReadException {
|
||||||
|
Object readValue = innerCasted.read(reader, entry, context);
|
||||||
|
ReadWriteContextCustomData customData = context.extensionsData().get(readWriteContextDataAccess);
|
||||||
|
if (customData != null && customData.patchInfo() != null) {
|
||||||
|
customData.patchInfo().addEntry(entry);
|
||||||
|
}
|
||||||
|
return readValue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
private static class ReadWriteContextCustomData {
|
||||||
|
private @Nullable PatchInfoImpl patchInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package de.siphalor.tweed5.defaultextensions.patch.impl;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||||
|
import de.siphalor.tweed5.defaultextensions.patch.api.PatchInfo;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.IdentityHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class PatchInfoImpl implements PatchInfo {
|
||||||
|
private final Map<ConfigEntry<?>, @Nullable Void> subPatchInfos = new IdentityHashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean containsEntry(ConfigEntry<?> entry) {
|
||||||
|
return subPatchInfos.containsKey(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addEntry(ConfigEntry<?> entry) {
|
||||||
|
subPatchInfos.put(entry, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
@ApiStatus.Internal
|
||||||
|
@NullMarked
|
||||||
|
package de.siphalor.tweed5.defaultextensions.patch.impl;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
||||||
@@ -0,0 +1,217 @@
|
|||||||
|
package de.siphalor.tweed5.defaultextensions.patch.impl;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
||||||
|
import de.siphalor.tweed5.core.api.entry.CompoundConfigEntry;
|
||||||
|
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||||
|
import de.siphalor.tweed5.core.impl.DefaultConfigContainer;
|
||||||
|
import de.siphalor.tweed5.core.impl.entry.CollectionConfigEntryImpl;
|
||||||
|
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.hjson.HjsonLexer;
|
||||||
|
import de.siphalor.tweed5.data.hjson.HjsonReader;
|
||||||
|
import de.siphalor.tweed5.defaultextensions.patch.api.PatchExtension;
|
||||||
|
import de.siphalor.tweed5.defaultextensions.patch.api.PatchInfo;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.jspecify.annotations.NullUnmarked;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
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.readwrite.TweedEntryReaderWriters.*;
|
||||||
|
import static de.siphalor.tweed5.testutils.MapTestUtils.sequencedMap;
|
||||||
|
import static java.util.Map.entry;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.jupiter.params.provider.Arguments.argumentSet;
|
||||||
|
import static org.junit.jupiter.params.provider.Arguments.arguments;
|
||||||
|
|
||||||
|
@NullUnmarked
|
||||||
|
class PatchExtensionImplTest {
|
||||||
|
private ConfigContainer<Map<String, Object>> configContainer;
|
||||||
|
private CompoundConfigEntry<Map<String, Object>> rootEntry;
|
||||||
|
|
||||||
|
private Map<String, ConfigEntry<?>> entries;
|
||||||
|
|
||||||
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
configContainer = new DefaultConfigContainer<>();
|
||||||
|
configContainer.registerExtension(ReadWriteExtension.class);
|
||||||
|
configContainer.registerExtension(PatchExtension.class);
|
||||||
|
configContainer.finishExtensionSetup();
|
||||||
|
|
||||||
|
var int1Entry = new SimpleConfigEntryImpl<>(configContainer, Integer.class)
|
||||||
|
.apply(entryReaderWriter(intReaderWriter()));
|
||||||
|
var int2Entry = new SimpleConfigEntryImpl<>(configContainer, Integer.class)
|
||||||
|
.apply(entryReaderWriter(
|
||||||
|
nullableReader(intReaderWriter()),
|
||||||
|
nullableWriter(intReaderWriter())
|
||||||
|
));
|
||||||
|
var listEntry = new CollectionConfigEntryImpl<>(
|
||||||
|
configContainer,
|
||||||
|
(Class<List<Integer>>)(Class) List.class,
|
||||||
|
ArrayList::new,
|
||||||
|
new SimpleConfigEntryImpl<>(configContainer, Integer.class)
|
||||||
|
.apply(entryReaderWriter(intReaderWriter()))
|
||||||
|
)
|
||||||
|
.apply(entryReaderWriter(
|
||||||
|
nullableReader(collectionReaderWriter()),
|
||||||
|
nullableWriter(collectionReaderWriter())
|
||||||
|
));
|
||||||
|
|
||||||
|
var nestedInt1Entry = new SimpleConfigEntryImpl<>(configContainer, Integer.class)
|
||||||
|
.apply(entryReaderWriter(intReaderWriter()));
|
||||||
|
var nestedInt2Entry = new SimpleConfigEntryImpl<>(configContainer, Integer.class)
|
||||||
|
.apply(entryReaderWriter(intReaderWriter()));
|
||||||
|
var compoundEntry = new StaticMapCompoundConfigEntryImpl<>(
|
||||||
|
configContainer,
|
||||||
|
(Class<Map<String, Object>>)(Class) Map.class,
|
||||||
|
HashMap::new,
|
||||||
|
sequencedMap(List.of(
|
||||||
|
entry("int1", nestedInt1Entry),
|
||||||
|
entry("int2", nestedInt2Entry)
|
||||||
|
))
|
||||||
|
)
|
||||||
|
.apply(entryReaderWriter(
|
||||||
|
nullableReader(compoundReaderWriter()),
|
||||||
|
nullableWriter(compoundReaderWriter())
|
||||||
|
));
|
||||||
|
|
||||||
|
rootEntry = new StaticMapCompoundConfigEntryImpl<>(
|
||||||
|
configContainer,
|
||||||
|
(Class<Map<String, Object>>)(Class) Map.class,
|
||||||
|
HashMap::new,
|
||||||
|
sequencedMap(List.of(
|
||||||
|
entry("int1", int1Entry),
|
||||||
|
entry("int2", int2Entry),
|
||||||
|
entry("list", listEntry),
|
||||||
|
entry("compound", compoundEntry)
|
||||||
|
))
|
||||||
|
)
|
||||||
|
.apply(entryReaderWriter(compoundReaderWriter()));
|
||||||
|
|
||||||
|
configContainer.attachTree(rootEntry);
|
||||||
|
configContainer.initialize();
|
||||||
|
|
||||||
|
entries = Map.of(
|
||||||
|
"root", rootEntry,
|
||||||
|
"int1", int1Entry,
|
||||||
|
"int2", int2Entry,
|
||||||
|
"list", listEntry,
|
||||||
|
"compound", compoundEntry,
|
||||||
|
"compound.int1", nestedInt1Entry,
|
||||||
|
"compound.int2", nestedInt2Entry
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("collectPathInfoParams")
|
||||||
|
void collectPatchInfo(String patch, Set<String> expectedEntries) {
|
||||||
|
var reader = new HjsonReader(new HjsonLexer(new StringReader(patch)));
|
||||||
|
|
||||||
|
PatchExtension patchExtension = configContainer.extension(PatchExtension.class).orElseThrow();
|
||||||
|
|
||||||
|
var patchInfo = new AtomicReference<@Nullable PatchInfo>();
|
||||||
|
rootEntry.call(read(
|
||||||
|
reader, extensionsData ->
|
||||||
|
patchInfo.set(patchExtension.collectPatchInfo(extensionsData))
|
||||||
|
));
|
||||||
|
assertThat(patchInfo.get()).isNotNull();
|
||||||
|
|
||||||
|
entries.forEach((key, entry) ->
|
||||||
|
assertThat(Objects.requireNonNull(patchInfo.get()).containsEntry(entry))
|
||||||
|
.as("PatchInfo should contain entry %s", key)
|
||||||
|
.isEqualTo(expectedEntries.contains(key))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Stream<Arguments> collectPathInfoParams() {
|
||||||
|
return Stream.of(
|
||||||
|
arguments("{int1:123}", Set.of("root", "int1")),
|
||||||
|
arguments("{compound:{int2:123}}", Set.of("root", "compound", "compound.int2"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("patchParams")
|
||||||
|
void patch(Map<String, Object> baseValue, String patch, Map<String, Object> expectedValue) {
|
||||||
|
var reader = new HjsonReader(new HjsonLexer(new StringReader(patch)));
|
||||||
|
|
||||||
|
PatchExtension patchExtension = configContainer.extension(PatchExtension.class).orElseThrow();
|
||||||
|
|
||||||
|
var patchInfo = new AtomicReference<@Nullable PatchInfo>();
|
||||||
|
Map<String, Object> patchValue = rootEntry.call(read(
|
||||||
|
reader, extensionsData ->
|
||||||
|
patchInfo.set(patchExtension.collectPatchInfo(extensionsData))
|
||||||
|
));
|
||||||
|
|
||||||
|
Map<String, Object> resultValue = patchExtension.patch(
|
||||||
|
rootEntry,
|
||||||
|
baseValue,
|
||||||
|
patchValue,
|
||||||
|
Objects.requireNonNull(patchInfo.get())
|
||||||
|
);
|
||||||
|
|
||||||
|
assertThat(resultValue).isEqualTo(expectedValue).isSameAs(baseValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Stream<Arguments> patchParams() {
|
||||||
|
Map<String, Object> mapForNullCase = new LinkedHashMap<>();
|
||||||
|
mapForNullCase.put("int2", null);
|
||||||
|
mapForNullCase.put("list", null);
|
||||||
|
mapForNullCase.put("compound", null);
|
||||||
|
|
||||||
|
return Stream.of(
|
||||||
|
argumentSet(
|
||||||
|
"empty patch should not have effect",
|
||||||
|
new HashMap<>(Map.of("int1", 123, "compound", new HashMap<>(Map.of("int1", 456)))),
|
||||||
|
"{}",
|
||||||
|
Map.of("int1", 123, "compound", Map.of("int1", 456))
|
||||||
|
),
|
||||||
|
argumentSet(
|
||||||
|
"overriding only existing values",
|
||||||
|
new HashMap<>(Map.of("int1", 123, "compound", new HashMap<>(Map.of("int1", 456)))),
|
||||||
|
"{int1:1230,compound:{int1:4560}}",
|
||||||
|
Map.of("int1", 1230, "compound", Map.of("int1", 4560))
|
||||||
|
),
|
||||||
|
argumentSet(
|
||||||
|
"overriding lists",
|
||||||
|
new HashMap<>(Map.of("int1", 123, "list", new ArrayList<>(List.of(12, 34, 56)))),
|
||||||
|
"{list:[987]}",
|
||||||
|
Map.of("int1", 123, "list", List.of(987))
|
||||||
|
),
|
||||||
|
argumentSet(
|
||||||
|
"creating new compound on override",
|
||||||
|
new HashMap<>(Map.of("int1", 123)),
|
||||||
|
"{compound:{int1:456, int2:789}}",
|
||||||
|
Map.of("int1", 123, "compound", Map.of("int1", 456, "int2", 789))
|
||||||
|
),
|
||||||
|
argumentSet(
|
||||||
|
"null overrides",
|
||||||
|
new HashMap<>(Map.of(
|
||||||
|
"int2", 123,
|
||||||
|
"list", new ArrayList<>(List.of(12, 34)),
|
||||||
|
"compound", new HashMap<>(Map.of("int1", 98, "int2", 76))
|
||||||
|
)),
|
||||||
|
"{int2:null, list:null, compound:null}",
|
||||||
|
mapForNullCase
|
||||||
|
),
|
||||||
|
argumentSet(
|
||||||
|
"mixed overrides",
|
||||||
|
new HashMap<>(Map.of("int1", 123, "compound", new HashMap<>(Map.of("int1", 456)))),
|
||||||
|
"{int1:1230,compound:{int1:4560,int2:7890}}",
|
||||||
|
Map.of("int1", 1230, "compound", Map.of("int1", 4560, "int2", 7890))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ import org.jspecify.annotations.Nullable;
|
|||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.CsvSource;
|
||||||
import org.junit.jupiter.params.provider.ValueSource;
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
@@ -28,14 +29,15 @@ import java.util.Collections;
|
|||||||
|
|
||||||
import static de.siphalor.tweed5.data.extension.api.ReadWriteExtension.*;
|
import static de.siphalor.tweed5.data.extension.api.ReadWriteExtension.*;
|
||||||
import static de.siphalor.tweed5.data.extension.api.readwrite.TweedEntryReaderWriters.*;
|
import static de.siphalor.tweed5.data.extension.api.readwrite.TweedEntryReaderWriters.*;
|
||||||
|
import static de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension.validate;
|
||||||
import static de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension.validators;
|
import static de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension.validators;
|
||||||
import static de.siphalor.tweed5.defaultextensions.validationfallback.api.ValidationFallbackExtension.validationFallbackValue;
|
import static de.siphalor.tweed5.defaultextensions.validationfallback.api.ValidationFallbackExtension.validationFallbackValue;
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
class ValidationFallbackExtensionImplTest {
|
class ValidationFallbackExtensionImplTest {
|
||||||
private DefaultConfigContainer<Integer> configContainer;
|
private DefaultConfigContainer<@Nullable Integer> configContainer;
|
||||||
private SimpleConfigEntry<Integer> intEntry;
|
private SimpleConfigEntry<@Nullable Integer> intEntry;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() {
|
void setUp() {
|
||||||
|
|||||||
Reference in New Issue
Block a user