Validation fallback values, tests and fixes
This commit is contained in:
@@ -34,7 +34,6 @@ import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResu
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Value;
|
||||
import lombok.var;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -75,7 +74,6 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
||||
|
||||
private RegisteredExtensionData<EntryExtensionsData, InternalValidationEntryData> validationEntryDataExtension;
|
||||
private MiddlewareContainer<ConfigEntryValidator> entryValidatorMiddlewareContainer;
|
||||
private EntryValidationReaderMiddleware readerMiddleware;
|
||||
private RegisteredExtensionData<ReadWriteContextExtensionsData, ValidationIssues> readContextValidationIssuesExtensionData;
|
||||
|
||||
@Override
|
||||
@@ -97,8 +95,6 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
||||
}
|
||||
}
|
||||
entryValidatorMiddlewareContainer.seal();
|
||||
|
||||
readerMiddleware = new EntryValidationReaderMiddleware();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -143,7 +139,7 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
||||
}
|
||||
|
||||
ConfigEntryValidator entryValidator;
|
||||
var entrySpecificValidators = getEntrySpecificValidators(configEntry);
|
||||
Collection<Middleware<ConfigEntryValidator>> entrySpecificValidators = getEntrySpecificValidators(configEntry);
|
||||
if (entrySpecificValidators.isEmpty()) {
|
||||
entryValidator = entryValidatorMiddlewareContainer.process(baseValidator);
|
||||
} else {
|
||||
@@ -166,7 +162,7 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
||||
|
||||
@Override
|
||||
public @Nullable Middleware<TweedEntryReader<?, ?>> entryReaderMiddleware() {
|
||||
return readerMiddleware;
|
||||
return new EntryValidationReaderMiddleware();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package de.siphalor.tweed5.defaultextensions.validationfallback.api;
|
||||
|
||||
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
||||
|
||||
public interface ValidationFallbackExtension extends TweedExtension {
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package de.siphalor.tweed5.defaultextensions.validationfallback.api;
|
||||
|
||||
public interface ValidationFallbackValue {
|
||||
Object validationFallbackValue();
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package de.siphalor.tweed5.defaultextensions.validationfallback.impl;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.extension.TweedExtensionSetupContext;
|
||||
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.ConfigEntryValidator;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationProvidingExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssue;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssueLevel;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult;
|
||||
import de.siphalor.tweed5.defaultextensions.validationfallback.api.ValidationFallbackExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.validationfallback.api.ValidationFallbackValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@AutoService(ValidationFallbackExtension.class)
|
||||
public class ValidationFallbackExtensionImpl implements ValidationFallbackExtension, ValidationProvidingExtension {
|
||||
@Override
|
||||
public String getId() {
|
||||
return "validation-fallback";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setup(TweedExtensionSetupContext context) {
|
||||
context.registerEntryExtensionData(ValidationFallbackValue.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Middleware<ConfigEntryValidator> validationMiddleware() {
|
||||
return new ValidationFallbackMiddleware();
|
||||
}
|
||||
|
||||
private static class ValidationFallbackMiddleware implements Middleware<ConfigEntryValidator> {
|
||||
@Override
|
||||
public String id() {
|
||||
return "validation-fallback";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> mustComeBefore() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> mustComeAfter() {
|
||||
return Collections.singleton("$default.end");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigEntryValidator process(ConfigEntryValidator inner) {
|
||||
return new ConfigEntryValidator() {
|
||||
@Override
|
||||
public <T> ValidationResult<T> validate(ConfigEntry<T> configEntry, T value) {
|
||||
ValidationResult<T> result = inner.validate(configEntry, value);
|
||||
if (!result.hasError()) {
|
||||
return result;
|
||||
}
|
||||
if (!configEntry.extensionsData().isPatchworkPartSet(ValidationFallbackValue.class)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Object fallbackValue = ((ValidationFallbackValue) configEntry.extensionsData()).validationFallbackValue();
|
||||
if (fallbackValue != null) {
|
||||
if (fallbackValue.getClass() == configEntry.valueClass()) {
|
||||
//noinspection unchecked
|
||||
fallbackValue = configEntry.deepCopy((T) fallbackValue);
|
||||
} else {
|
||||
ArrayList<ValidationIssue> issues = new ArrayList<>(result.issues());
|
||||
issues.add(new ValidationIssue(
|
||||
"Fallback value is not of correct class, expected " + configEntry.valueClass().getName() +
|
||||
", but got " + fallbackValue.getClass().getName(),
|
||||
ValidationIssueLevel.ERROR
|
||||
));
|
||||
return ValidationResult.withIssues(value, issues);
|
||||
}
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
return ValidationResult.withIssues(
|
||||
(T) fallbackValue,
|
||||
result.issues().stream()
|
||||
.map(issue -> new ValidationIssue(issue.message(), ValidationIssueLevel.WARN))
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull <T> String description(ConfigEntry<T> configEntry) {
|
||||
if (!configEntry.extensionsData().isPatchworkPartSet(ValidationFallbackValue.class)) {
|
||||
return inner.description(configEntry);
|
||||
}
|
||||
return inner.description(configEntry) +
|
||||
"\n\nDefault/Fallback value: " +
|
||||
((ValidationFallbackValue) configEntry.extensionsData()).validationFallbackValue();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
package de.siphalor.tweed5.defaultextensions.validationfallback.impl;
|
||||
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.extension.EntryExtensionsData;
|
||||
import de.siphalor.tweed5.core.api.extension.RegisteredExtensionData;
|
||||
import de.siphalor.tweed5.core.impl.DefaultConfigContainer;
|
||||
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
|
||||
import de.siphalor.tweed5.data.extension.api.EntryReaderWriterDefinition;
|
||||
import de.siphalor.tweed5.data.extension.api.ReadWriteExtension;
|
||||
import de.siphalor.tweed5.data.extension.api.TweedEntryReader;
|
||||
import de.siphalor.tweed5.data.extension.api.TweedEntryWriter;
|
||||
import de.siphalor.tweed5.data.extension.api.readwrite.TweedEntryReaderWriters;
|
||||
import de.siphalor.tweed5.data.extension.impl.ReadWriteExtensionImpl;
|
||||
import de.siphalor.tweed5.data.hjson.HjsonCommentType;
|
||||
import de.siphalor.tweed5.data.hjson.HjsonLexer;
|
||||
import de.siphalor.tweed5.data.hjson.HjsonReader;
|
||||
import de.siphalor.tweed5.data.hjson.HjsonWriter;
|
||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.comment.impl.CommentExtensionImpl;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.ConfigEntryValidator;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.EntrySpecificValidation;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssue;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationIssueLevel;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.result.ValidationResult;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.api.validators.SimpleValidatorMiddleware;
|
||||
import de.siphalor.tweed5.defaultextensions.validation.impl.ValidationExtensionImpl;
|
||||
import de.siphalor.tweed5.defaultextensions.validationfallback.api.ValidationFallbackExtension;
|
||||
import de.siphalor.tweed5.defaultextensions.validationfallback.api.ValidationFallbackValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class ValidationFallbackExtensionImplTest {
|
||||
private DefaultConfigContainer<Integer> configContainer;
|
||||
private CommentExtension commentExtension;
|
||||
private ValidationExtension validationExtension;
|
||||
private ValidationFallbackExtension validationFallbackExtension;
|
||||
private ReadWriteExtension readWriteExtension;
|
||||
private SimpleConfigEntryImpl<Integer> intEntry;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
configContainer = new DefaultConfigContainer<>();
|
||||
commentExtension = new CommentExtensionImpl();
|
||||
configContainer.registerExtension(commentExtension);
|
||||
validationExtension = new ValidationExtensionImpl();
|
||||
configContainer.registerExtension(validationExtension);
|
||||
validationFallbackExtension = new ValidationFallbackExtensionImpl();
|
||||
configContainer.registerExtension(validationFallbackExtension);
|
||||
readWriteExtension = new ReadWriteExtensionImpl();
|
||||
configContainer.registerExtension(readWriteExtension);
|
||||
|
||||
configContainer.finishExtensionSetup();
|
||||
|
||||
intEntry = new SimpleConfigEntryImpl<>(Integer.class);
|
||||
|
||||
configContainer.attachAndSealTree(intEntry);
|
||||
|
||||
RegisteredExtensionData<EntryExtensionsData, EntrySpecificValidation> entrySpecificValidation = (RegisteredExtensionData<EntryExtensionsData, EntrySpecificValidation>) configContainer.entryDataExtensions().get(EntrySpecificValidation.class);
|
||||
entrySpecificValidation.set(intEntry.extensionsData(), () -> Arrays.asList(
|
||||
new SimpleValidatorMiddleware("non-null", new ConfigEntryValidator() {
|
||||
@Override
|
||||
public <T> ValidationResult<T> validate(ConfigEntry<T> configEntry, T value) {
|
||||
if (value == null) {
|
||||
return ValidationResult.withIssues(null, Collections.singleton(
|
||||
new ValidationIssue("Value must not be null", ValidationIssueLevel.ERROR)
|
||||
));
|
||||
}
|
||||
return ValidationResult.ok(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull <T> String description(ConfigEntry<T> configEntry) {
|
||||
return "Must not be null.";
|
||||
}
|
||||
}),
|
||||
new SimpleValidatorMiddleware("range", new ConfigEntryValidator() {
|
||||
@Override
|
||||
public <T> ValidationResult<T> validate(ConfigEntry<T> configEntry, T value) {
|
||||
Integer intValue = (Integer) value;
|
||||
if (intValue < 1) {
|
||||
return ValidationResult.withIssues(value, Collections.singleton(new ValidationIssue("Must be greater or equal to 1", ValidationIssueLevel.ERROR)));
|
||||
}
|
||||
if (intValue > 6) {
|
||||
return ValidationResult.withIssues(value, Collections.singleton(new ValidationIssue("Must be smaller or equal to 6", ValidationIssueLevel.ERROR)));
|
||||
}
|
||||
return ValidationResult.ok(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull <T> String description(ConfigEntry<T> configEntry) {
|
||||
return "Must be between 1 and 6";
|
||||
}
|
||||
}) {
|
||||
@Override
|
||||
public Set<String> mustComeAfter() {
|
||||
return Collections.singleton("non-null");
|
||||
}
|
||||
}
|
||||
));
|
||||
|
||||
RegisteredExtensionData<EntryExtensionsData, ValidationFallbackValue> validationFallbackValue = (RegisteredExtensionData<EntryExtensionsData, ValidationFallbackValue>) configContainer.entryDataExtensions().get(ValidationFallbackValue.class);
|
||||
validationFallbackValue.set(intEntry.extensionsData(), () -> 3);
|
||||
|
||||
RegisteredExtensionData<EntryExtensionsData, EntryReaderWriterDefinition> readerWriterData = (RegisteredExtensionData<EntryExtensionsData, EntryReaderWriterDefinition>) configContainer.entryDataExtensions().get(EntryReaderWriterDefinition.class);
|
||||
readerWriterData.set(intEntry.extensionsData(), new EntryReaderWriterDefinition() {
|
||||
@Override
|
||||
public TweedEntryReader<?, ?> reader() {
|
||||
return TweedEntryReaderWriters.nullableReaderWriter(TweedEntryReaderWriters.intReaderWriter());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TweedEntryWriter<?, ?> writer() {
|
||||
return TweedEntryReaderWriters.nullableReaderWriter(TweedEntryReaderWriters.intReaderWriter());
|
||||
}
|
||||
});
|
||||
|
||||
configContainer.initialize();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"0", "7", "123", "null"})
|
||||
void fallbackTriggers(String input) {
|
||||
Integer result = assertDoesNotThrow(() -> readWriteExtension.read(
|
||||
new HjsonReader(new HjsonLexer(new StringReader(input))),
|
||||
intEntry,
|
||||
readWriteExtension.createReadWriteContextExtensionsData()
|
||||
));
|
||||
assertEquals(3, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void description() {
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
assertDoesNotThrow(() -> readWriteExtension.write(
|
||||
new HjsonWriter(stringWriter, new HjsonWriter.Options().multilineCommentType(HjsonCommentType.SLASHES)),
|
||||
5,
|
||||
intEntry,
|
||||
readWriteExtension.createReadWriteContextExtensionsData()
|
||||
));
|
||||
|
||||
assertEquals("// Must not be null.\n// Must be between 1 and 6\n// \n// Default/Fallback value: 3\n5\n", stringWriter.toString());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user