mirror of
https://github.com/danieldemus/openhab-core.git
synced 2025-01-26 20:21:33 +01:00
[config] Add config validator for parameter options (#2691)
Signed-off-by: Christoph Weitkamp <github@christophweitkamp.de>
This commit is contained in:
parent
9b438d7e12
commit
9cda2c8de8
@ -62,4 +62,13 @@ public final class ConfigDescriptionParameterValidatorFactory {
|
|||||||
public static ConfigDescriptionParameterValidator createPatternValidator() {
|
public static ConfigDescriptionParameterValidator createPatternValidator() {
|
||||||
return new PatternValidator();
|
return new PatternValidator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new validator for the parameter options of a config description parameter.
|
||||||
|
*
|
||||||
|
* @return a new validator for the parameter options of a config description parameter
|
||||||
|
*/
|
||||||
|
public static ConfigDescriptionParameterValidator createOptionsValidator() {
|
||||||
|
return new OptionsValidator();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,8 @@ public final class ConfigDescriptionValidatorImpl implements ConfigDescriptionVa
|
|||||||
ConfigDescriptionParameterValidatorFactory.createRequiredValidator(), //
|
ConfigDescriptionParameterValidatorFactory.createRequiredValidator(), //
|
||||||
ConfigDescriptionParameterValidatorFactory.createTypeValidator(), //
|
ConfigDescriptionParameterValidatorFactory.createTypeValidator(), //
|
||||||
ConfigDescriptionParameterValidatorFactory.createMinMaxValidator(), //
|
ConfigDescriptionParameterValidatorFactory.createMinMaxValidator(), //
|
||||||
ConfigDescriptionParameterValidatorFactory.createPatternValidator() //
|
ConfigDescriptionParameterValidatorFactory.createPatternValidator(), //
|
||||||
|
ConfigDescriptionParameterValidatorFactory.createOptionsValidator() //
|
||||||
);
|
);
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(ConfigDescriptionValidatorImpl.class);
|
private final Logger logger = LoggerFactory.getLogger(ConfigDescriptionValidatorImpl.class);
|
||||||
|
@ -41,6 +41,9 @@ final class MessageKey {
|
|||||||
static final MessageKey PATTERN_VIOLATED = new MessageKey("pattern_violated",
|
static final MessageKey PATTERN_VIOLATED = new MessageKey("pattern_violated",
|
||||||
"The value {0} does not match the pattern {1}.");
|
"The value {0} does not match the pattern {1}.");
|
||||||
|
|
||||||
|
static final MessageKey OPTIONS_VIOLATED = new MessageKey("options_violated",
|
||||||
|
"The value {0} does not match allowed parameter options. Allowed options are: {1}");
|
||||||
|
|
||||||
static final MessageKey MULTIPLE_LIMIT_VIOLATED = new MessageKey("multiple_limit_violated",
|
static final MessageKey MULTIPLE_LIMIT_VIOLATED = new MessageKey("multiple_limit_violated",
|
||||||
"Only {0} elements are allowed but {1} are provided.");
|
"Only {0} elements are allowed but {1} are provided.");
|
||||||
/** The key to be used for internationalization. */
|
/** The key to be used for internationalization. */
|
||||||
|
@ -18,7 +18,6 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
|||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.core.config.core.ConfigDescriptionParameter;
|
import org.openhab.core.config.core.ConfigDescriptionParameter;
|
||||||
import org.openhab.core.config.core.ConfigDescriptionParameter.Type;
|
import org.openhab.core.config.core.ConfigDescriptionParameter.Type;
|
||||||
import org.openhab.core.config.core.ParameterOption;
|
|
||||||
import org.openhab.core.config.core.internal.validation.TypeIntrospections.TypeIntrospection;
|
import org.openhab.core.config.core.internal.validation.TypeIntrospections.TypeIntrospection;
|
||||||
import org.openhab.core.config.core.validation.ConfigValidationMessage;
|
import org.openhab.core.config.core.validation.ConfigValidationMessage;
|
||||||
|
|
||||||
@ -39,15 +38,12 @@ final class MinMaxValidator implements ConfigDescriptionParameterValidator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Allow specified options to be outside of the min/max value
|
// Allow specified options to be outside of the min/max value
|
||||||
for (ParameterOption option : parameter.getOptions()) {
|
// Option values are a string, so we can do a simple compare
|
||||||
// Option values are a string, so we can do a simple compare
|
if (parameter.getOptions().stream().map(o -> o.getValue()).anyMatch(v -> v.equals(value.toString()))) {
|
||||||
if (option.getValue().equals(value.toString())) {
|
return null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeIntrospection typeIntrospection = TypeIntrospections.get(parameter.getType());
|
TypeIntrospection typeIntrospection = TypeIntrospections.get(parameter.getType());
|
||||||
|
|
||||||
if (parameter.getMinimum() != null) {
|
if (parameter.getMinimum() != null) {
|
||||||
BigDecimal min = parameter.getMinimum();
|
BigDecimal min = parameter.getMinimum();
|
||||||
if (typeIntrospection.isMinViolated(value, min)) {
|
if (typeIntrospection.isMinViolated(value, min)) {
|
||||||
@ -55,7 +51,6 @@ final class MinMaxValidator implements ConfigDescriptionParameterValidator {
|
|||||||
min);
|
min);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parameter.getMaximum() != null) {
|
if (parameter.getMaximum() != null) {
|
||||||
BigDecimal max = parameter.getMaximum();
|
BigDecimal max = parameter.getMaximum();
|
||||||
if (typeIntrospection.isMaxViolated(value, max)) {
|
if (typeIntrospection.isMaxViolated(value, max)) {
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
||||||
|
*
|
||||||
|
* See the NOTICE file(s) distributed with this work for additional
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Public License 2.0 which is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-2.0
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*/
|
||||||
|
package org.openhab.core.config.core.internal.validation;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.core.config.core.ConfigDescriptionParameter;
|
||||||
|
import org.openhab.core.config.core.validation.ConfigValidationMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link ConfigDescriptionParameterValidator} for the options of a {@link ConfigDescriptionParameter}.
|
||||||
|
*
|
||||||
|
* @author Christoph Weitkamp - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
final class OptionsValidator implements ConfigDescriptionParameterValidator {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable ConfigValidationMessage validate(ConfigDescriptionParameter param, @Nullable Object value) {
|
||||||
|
if (value == null || !param.getLimitToOptions() || param.getOptions().isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Option values are a string, so we can do a simple compare
|
||||||
|
if (param.getOptions().stream().map(o -> o.getValue()).noneMatch(v -> v.equals(value.toString()))) {
|
||||||
|
MessageKey messageKey = MessageKey.OPTIONS_VIOLATED;
|
||||||
|
return new ConfigValidationMessage(param.getName(), messageKey.defaultMessage, messageKey.key,
|
||||||
|
param.getOptions());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -9,4 +9,5 @@ min_value_txt_violated=The value must not consist of less than {0} characters.
|
|||||||
min_value_numeric_violated=The value must not be less than {0}.
|
min_value_numeric_violated=The value must not be less than {0}.
|
||||||
|
|
||||||
pattern_violated=The value {0} does not match the pattern {1}.
|
pattern_violated=The value {0} does not match the pattern {1}.
|
||||||
|
options_violated=The value {0} does not match allowed parameter options. Allowed options are: {1}
|
||||||
multiple_limit_violated=Only {0} elements are allowed but {1} are provided.
|
multiple_limit_violated=Only {0} elements are allowed but {1} are provided.
|
||||||
|
@ -25,6 +25,8 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -35,6 +37,7 @@ import org.openhab.core.config.core.ConfigDescriptionParameter;
|
|||||||
import org.openhab.core.config.core.ConfigDescriptionParameter.Type;
|
import org.openhab.core.config.core.ConfigDescriptionParameter.Type;
|
||||||
import org.openhab.core.config.core.ConfigDescriptionParameterBuilder;
|
import org.openhab.core.config.core.ConfigDescriptionParameterBuilder;
|
||||||
import org.openhab.core.config.core.ConfigDescriptionRegistry;
|
import org.openhab.core.config.core.ConfigDescriptionRegistry;
|
||||||
|
import org.openhab.core.config.core.ParameterOption;
|
||||||
import org.openhab.core.config.core.validation.ConfigDescriptionValidator;
|
import org.openhab.core.config.core.validation.ConfigDescriptionValidator;
|
||||||
import org.openhab.core.config.core.validation.ConfigValidationException;
|
import org.openhab.core.config.core.validation.ConfigValidationException;
|
||||||
import org.openhab.core.config.core.validation.ConfigValidationMessage;
|
import org.openhab.core.config.core.validation.ConfigValidationMessage;
|
||||||
@ -48,12 +51,13 @@ import org.osgi.framework.BundleContext;
|
|||||||
* @author Thomas Höfer - Initial contribution
|
* @author Thomas Höfer - Initial contribution
|
||||||
* @author Wouter Born - Migrate tests from Groovy to Java
|
* @author Wouter Born - Migrate tests from Groovy to Java
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class ConfigDescriptionValidatorTest {
|
public class ConfigDescriptionValidatorTest {
|
||||||
|
|
||||||
private static final int MIN_VIOLATED = 1;
|
private static final int MIN_VIOLATED = 1;
|
||||||
private static final int MAX_VIOLATED = 1234;
|
private static final int MAX_VIOLATED = 1234;
|
||||||
|
|
||||||
private static final BigDecimal DECIMAL_MIN_VIOLATED = new BigDecimal("1");
|
private static final BigDecimal DECIMAL_MIN_VIOLATED = BigDecimal.ONE;
|
||||||
private static final BigDecimal DECIMAL_MAX_VIOLATED = new BigDecimal("3.5");
|
private static final BigDecimal DECIMAL_MAX_VIOLATED = new BigDecimal("3.5");
|
||||||
|
|
||||||
private static final BigDecimal MIN = BigDecimal.valueOf(2);
|
private static final BigDecimal MIN = BigDecimal.valueOf(2);
|
||||||
@ -76,6 +80,8 @@ public class ConfigDescriptionValidatorTest {
|
|||||||
private static final String TXT_MAX_PARAM_NAME = "txt-max-name";
|
private static final String TXT_MAX_PARAM_NAME = "txt-max-name";
|
||||||
private static final String TXT_PATTERN_PARAM_NAME = "txt-pattern-name";
|
private static final String TXT_PATTERN_PARAM_NAME = "txt-pattern-name";
|
||||||
private static final String TXT_MAX_PATTERN_PARAM_NAME = "txt-max-pattern-name";
|
private static final String TXT_MAX_PATTERN_PARAM_NAME = "txt-max-pattern-name";
|
||||||
|
private static final String TXT_PARAM_WITH_LIMITED_OPTIONS_NAME = "txt-param-with-limited-options-name";
|
||||||
|
private static final String TXT_PARAM_WITH_UNLIMITED_OPTIONS_NAME = "txt-param-with-unlimited-options-name";
|
||||||
private static final String TXT_MULTIPLE_LIMIT_PARAM_NAME = "txt-multiple-limit-name";
|
private static final String TXT_MULTIPLE_LIMIT_PARAM_NAME = "txt-multiple-limit-name";
|
||||||
|
|
||||||
private static final String INT_PARAM_NAME = "int-param";
|
private static final String INT_PARAM_NAME = "int-param";
|
||||||
@ -88,6 +94,11 @@ public class ConfigDescriptionValidatorTest {
|
|||||||
private static final String DECIMAL_MIN_PARAM_NAME = "decimal-min-name";
|
private static final String DECIMAL_MIN_PARAM_NAME = "decimal-min-name";
|
||||||
private static final String DECIMAL_MAX_PARAM_NAME = "decimal-max-name";
|
private static final String DECIMAL_MAX_PARAM_NAME = "decimal-max-name";
|
||||||
|
|
||||||
|
private static final List<ParameterOption> PARAMETER_OPTIONS = List.of( //
|
||||||
|
new ParameterOption("http", "HTTP"), //
|
||||||
|
new ParameterOption("https", "HTTPS") //
|
||||||
|
);
|
||||||
|
|
||||||
private static final ConfigDescriptionParameter BOOL_PARAM = ConfigDescriptionParameterBuilder
|
private static final ConfigDescriptionParameter BOOL_PARAM = ConfigDescriptionParameterBuilder
|
||||||
.create(BOOL_PARAM_NAME, ConfigDescriptionParameter.Type.BOOLEAN).build();
|
.create(BOOL_PARAM_NAME, ConfigDescriptionParameter.Type.BOOLEAN).build();
|
||||||
private static final ConfigDescriptionParameter BOOL_REQUIRED_PARAM = ConfigDescriptionParameterBuilder
|
private static final ConfigDescriptionParameter BOOL_REQUIRED_PARAM = ConfigDescriptionParameterBuilder
|
||||||
@ -106,6 +117,12 @@ public class ConfigDescriptionValidatorTest {
|
|||||||
private static final ConfigDescriptionParameter TXT_MAX_PATTERN_PARAM = ConfigDescriptionParameterBuilder
|
private static final ConfigDescriptionParameter TXT_MAX_PATTERN_PARAM = ConfigDescriptionParameterBuilder
|
||||||
.create(TXT_MAX_PATTERN_PARAM_NAME, ConfigDescriptionParameter.Type.TEXT).withMaximum(MAX)
|
.create(TXT_MAX_PATTERN_PARAM_NAME, ConfigDescriptionParameter.Type.TEXT).withMaximum(MAX)
|
||||||
.withPattern(PATTERN).build();
|
.withPattern(PATTERN).build();
|
||||||
|
private static final ConfigDescriptionParameter TXT_PARAM_WITH_LIMITED_OPTIONS = ConfigDescriptionParameterBuilder
|
||||||
|
.create(TXT_PARAM_WITH_LIMITED_OPTIONS_NAME, ConfigDescriptionParameter.Type.TEXT)
|
||||||
|
.withOptions(PARAMETER_OPTIONS).build();
|
||||||
|
private static final ConfigDescriptionParameter TXT_PARAM_WITH_UNLIMITED_OPTIONS = ConfigDescriptionParameterBuilder
|
||||||
|
.create(TXT_PARAM_WITH_UNLIMITED_OPTIONS_NAME, ConfigDescriptionParameter.Type.TEXT)
|
||||||
|
.withOptions(PARAMETER_OPTIONS).withLimitToOptions(false).build();
|
||||||
private static final ConfigDescriptionParameter TXT_MULTIPLE_LIMIT_PARAM = ConfigDescriptionParameterBuilder
|
private static final ConfigDescriptionParameter TXT_MULTIPLE_LIMIT_PARAM = ConfigDescriptionParameterBuilder
|
||||||
.create(TXT_MULTIPLE_LIMIT_PARAM_NAME, Type.TEXT).withMultiple(true).withMultipleLimit(2).build();
|
.create(TXT_MULTIPLE_LIMIT_PARAM_NAME, Type.TEXT).withMultiple(true).withMultipleLimit(2).build();
|
||||||
|
|
||||||
@ -139,13 +156,14 @@ public class ConfigDescriptionValidatorTest {
|
|||||||
|
|
||||||
private static final ConfigDescription CONFIG_DESCRIPTION = ConfigDescriptionBuilder.create(CONFIG_DESCRIPTION_URI)
|
private static final ConfigDescription CONFIG_DESCRIPTION = ConfigDescriptionBuilder.create(CONFIG_DESCRIPTION_URI)
|
||||||
.withParameters(List.of(BOOL_PARAM, BOOL_REQUIRED_PARAM, TXT_PARAM, TXT_REQUIRED_PARAM, TXT_MIN_PARAM,
|
.withParameters(List.of(BOOL_PARAM, BOOL_REQUIRED_PARAM, TXT_PARAM, TXT_REQUIRED_PARAM, TXT_MIN_PARAM,
|
||||||
TXT_MAX_PARAM, TXT_PATTERN_PARAM, TXT_MAX_PATTERN_PARAM, TXT_MULTIPLE_LIMIT_PARAM, INT_PARAM,
|
TXT_MAX_PARAM, TXT_PATTERN_PARAM, TXT_MAX_PATTERN_PARAM, TXT_PARAM_WITH_LIMITED_OPTIONS,
|
||||||
INT_REQUIRED_PARAM, INT_MIN_PARAM, INT_MAX_PARAM, DECIMAL_PARAM, DECIMAL_REQUIRED_PARAM,
|
TXT_PARAM_WITH_UNLIMITED_OPTIONS, TXT_MULTIPLE_LIMIT_PARAM, INT_PARAM, INT_REQUIRED_PARAM,
|
||||||
DECIMAL_MIN_PARAM, DECIMAL_MAX_PARAM))
|
INT_MIN_PARAM, INT_MAX_PARAM, DECIMAL_PARAM, DECIMAL_REQUIRED_PARAM, DECIMAL_MIN_PARAM,
|
||||||
|
DECIMAL_MAX_PARAM))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
private Map<String, Object> params;
|
private @NonNullByDefault({}) Map<String, Object> params;
|
||||||
private ConfigDescriptionValidatorImpl configDescriptionValidator;
|
private @NonNullByDefault({}) ConfigDescriptionValidatorImpl configDescriptionValidator;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@ -171,6 +189,7 @@ public class ConfigDescriptionValidatorTest {
|
|||||||
params.put(TXT_MAX_PARAM_NAME, String.valueOf(MIN_VIOLATED));
|
params.put(TXT_MAX_PARAM_NAME, String.valueOf(MIN_VIOLATED));
|
||||||
params.put(TXT_PATTERN_PARAM_NAME, "abbbc");
|
params.put(TXT_PATTERN_PARAM_NAME, "abbbc");
|
||||||
params.put(TXT_MAX_PATTERN_PARAM_NAME, "abc");
|
params.put(TXT_MAX_PATTERN_PARAM_NAME, "abc");
|
||||||
|
params.put(TXT_PARAM_WITH_LIMITED_OPTIONS_NAME, "http");
|
||||||
params.put(TXT_MULTIPLE_LIMIT_PARAM_NAME, List.of("1", "2"));
|
params.put(TXT_MULTIPLE_LIMIT_PARAM_NAME, List.of("1", "2"));
|
||||||
params.put(INT_PARAM_NAME, null);
|
params.put(INT_PARAM_NAME, null);
|
||||||
params.put(INT_REQUIRED_PARAM_NAME, 0);
|
params.put(INT_REQUIRED_PARAM_NAME, 0);
|
||||||
@ -408,6 +427,27 @@ public class ConfigDescriptionValidatorTest {
|
|||||||
assertThat(getConfigValidationMessages(exception), is(expected));
|
assertThat(getConfigValidationMessages(exception), is(expected));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ===========================================================================
|
||||||
|
// PARAMETER OPTION VALIDATIONS
|
||||||
|
// ===========================================================================
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void assertValidationThrowsExceptionForNotAllowedLimitedParameterOption() {
|
||||||
|
List<ConfigValidationMessage> expected = List.of(new ConfigValidationMessage(
|
||||||
|
TXT_PARAM_WITH_LIMITED_OPTIONS_NAME, MessageKey.OPTIONS_VIOLATED.defaultMessage,
|
||||||
|
MessageKey.OPTIONS_VIOLATED.key, PARAMETER_OPTIONS));
|
||||||
|
params.put(TXT_PARAM_WITH_LIMITED_OPTIONS_NAME, "ftp");
|
||||||
|
ConfigValidationException exception = Assertions.assertThrows(ConfigValidationException.class,
|
||||||
|
() -> configDescriptionValidator.validate(params, CONFIG_DESCRIPTION_URI));
|
||||||
|
assertThat(getConfigValidationMessages(exception), is(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void assertValidationThrowsNoExceptionForAllowedUnlimitedParameterOption() {
|
||||||
|
params.put(TXT_PARAM_WITH_UNLIMITED_OPTIONS_NAME, "ftp");
|
||||||
|
Assertions.assertDoesNotThrow(() -> configDescriptionValidator.validate(params, CONFIG_DESCRIPTION_URI));
|
||||||
|
}
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
// MISC VALIDATIONS
|
// MISC VALIDATIONS
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
@ -484,7 +524,7 @@ public class ConfigDescriptionValidatorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private static List<ConfigValidationMessage> getConfigValidationMessages(ConfigValidationException cve) {
|
private static @Nullable List<ConfigValidationMessage> getConfigValidationMessages(ConfigValidationException cve) {
|
||||||
try {
|
try {
|
||||||
Field field = cve.getClass().getDeclaredField("configValidationMessages");
|
Field field = cve.getClass().getDeclaredField("configValidationMessages");
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
|
Loading…
Reference in New Issue
Block a user