blob: 29fc3cc83d7b386a4b7600f35158751ef739d57c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.sling.feature.extension.apiregions.api.config.validation;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.sling.feature.extension.apiregions.api.config.Mode;
import org.apache.sling.feature.extension.apiregions.api.config.Option;
import org.apache.sling.feature.extension.apiregions.api.config.PlaceholderPolicy;
import org.apache.sling.feature.extension.apiregions.api.config.PropertyDescription;
import org.apache.sling.feature.extension.apiregions.api.config.PropertyType;
import org.apache.sling.feature.extension.apiregions.api.config.Range;
import org.junit.Test;
public class PropertyValidatorTest {
private final PropertyValidator validator = new PropertyValidator();
/**
* Helper method to validate an error based on the validation mode
*/
private void validateError(final PropertyDescription prop, final Object value) {
validateError(prop, value, 1);
}
/**
* Helper method to validate an error based on the validation mode
*/
private void validateError(final PropertyDescription prop, final Object value, final int errors) {
PropertyValidationResult result;
// error - strict mode
result = validator.validate(value, prop, Mode.STRICT);
assertEquals(errors, result.getErrors().size());
assertFalse(result.isValid());
assertFalse(result.isSkipped());
// error - mode lenient
result = validator.validate(value, prop, Mode.LENIENT);
assertEquals(errors, result.getWarnings().size());
assertTrue(result.isValid());
assertFalse(result.isSkipped());
// error - mode silent
result = validator.validate(value, prop, Mode.SILENT);
assertTrue(result.getWarnings().isEmpty());
assertTrue(result.isValid());
assertFalse(result.isSkipped());
// error - mode definitive
result = validator.validate(value, prop, Mode.DEFINITIVE);
assertEquals(errors, result.getWarnings().size());
assertTrue(result.isValid());
assertFalse(result.isSkipped());
assertTrue(result.isUseDefaultValue());
assertEquals(result.getDefaultValue(), prop.getDefaultValue());
// error - mode silent definitive
result = validator.validate(value, prop, Mode.SILENT_DEFINITIVE);
assertTrue(result.getWarnings().isEmpty());
assertTrue(result.isValid());
assertFalse(result.isSkipped());
assertTrue(result.isUseDefaultValue());
assertEquals(result.getDefaultValue(), prop.getDefaultValue());
}
/**
* Helper method to validate that a value is valid and not skipped
*/
private void validateValid(final PropertyDescription prop, final Object value) {
final PropertyValidationResult result = validator.validate(value, prop);
assertTrue(result.isValid());
assertFalse(result.isSkipped());
assertTrue(result.getErrors().isEmpty());
assertFalse(result.isUseDefaultValue());
assertNull(result.getDefaultValue());
}
@Test public void testValidateWithNull() {
final PropertyDescription prop = new PropertyDescription();
// prop not required - no error
validateValid(prop, null);
// prop required - error
prop.setRequired(true);
validateError(prop, null);
}
@Test public void testValidateBoolean() {
final PropertyDescription prop = new PropertyDescription();
prop.setType(PropertyType.BOOLEAN);
validateValid(prop, Boolean.TRUE);
validateValid(prop, Boolean.FALSE);
validateValid(prop, "TRUE");
validateValid(prop, "FALSE");
validateError(prop, "yes");
validateError(prop, 1);
}
@Test public void testValidateByte() {
final PropertyDescription prop = new PropertyDescription();
prop.setType(PropertyType.BYTE);
validateValid(prop, (byte)1);
validateValid(prop, "1");
validateValid(prop, 1);
validateError(prop, "yes");
}
@Test public void testValidateShort() {
final PropertyDescription prop = new PropertyDescription();
prop.setType(PropertyType.SHORT);
validateValid(prop, (short)1);
validateValid(prop, "1");
validateValid(prop, 1);
validateError(prop, "yes");
}
@Test public void testValidateInteger() {
final PropertyDescription prop = new PropertyDescription();
prop.setType(PropertyType.INTEGER);
validateValid(prop, "1");
validateValid(prop, 1);
validateError(prop, "yes");
}
@Test public void testValidateLong() {
final PropertyDescription prop = new PropertyDescription();
prop.setType(PropertyType.LONG);
validateValid(prop, 1L);
validateValid(prop, "1");
validateValid(prop, 1);
validateError(prop, "yes");
}
@Test public void testValidateFloat() {
final PropertyDescription prop = new PropertyDescription();
prop.setType(PropertyType.FLOAT);
validateValid(prop, 1.1);
validateValid(prop, "1.1");
validateValid(prop, 1);
validateError(prop, "yes");
}
@Test public void testValidateDouble() {
final PropertyDescription prop = new PropertyDescription();
prop.setType(PropertyType.DOUBLE);
validateValid(prop, 1.1d);
validateValid(prop, "1.1");
validateValid(prop, 1);
validateError(prop, "yes");
}
@Test public void testValidateChar() {
final PropertyDescription prop = new PropertyDescription();
prop.setType(PropertyType.CHARACTER);
validateValid(prop, 'x');
validateValid(prop, "y");
validateError(prop, "yes");
}
@Test public void testValidateUrl() {
final PropertyDescription prop = new PropertyDescription();
prop.setType(PropertyType.URL);
validateValid(prop, "https://sling.apache.org/documentation");
validateError(prop, "hello world");
}
@Test public void testValidateEmail() {
final PropertyDescription prop = new PropertyDescription();
prop.setType(PropertyType.EMAIL);
validateValid(prop, "a@b.com");
validateError(prop, "hello world");
}
@Test public void testValidatePassword() {
final PropertyDescription prop = new PropertyDescription();
prop.setType(PropertyType.PASSWORD);
validateValid(prop, null);
validateValid(prop, "$[secret:dbpassword]");
validateError(prop, "secret");
}
@Test public void testValidatePath() {
final PropertyDescription prop = new PropertyDescription();
prop.setType(PropertyType.PATH);
validateValid(prop, "/a/b/c");
validateError(prop, "hello world");
}
@Test public void testValidateString() {
final PropertyDescription desc = new PropertyDescription();
validateValid(desc, "hello world");
validateValid(desc, "$[prop:KEY]");
// skip if required
desc.setRequired(true);
PropertyValidationResult result = validator.validate("$[prop:KEY]", desc);
assertTrue(result.isValid());
assertTrue(result.isSkipped());
desc.setRequired(false);
// skip if options
desc.setOptions(Collections.singletonList(new Option()));
result = validator.validate("$[prop:KEY]", desc);
assertTrue(result.isValid());
assertTrue(result.isSkipped());
desc.setOptions(null);
// skip if regexp
desc.setRegex(".*");
result = validator.validate("$[prop:KEY]", desc);
assertTrue(result.isValid());
assertTrue(result.isSkipped());
desc.setRegex(null);
// empty string - not required
validateValid(desc, "");
// empty string - required
desc.setRequired(true);
validateError(desc, "");
desc.setRequired(false);
}
@Test public void testValidateRange() {
final PropertyDescription description = new PropertyDescription();
description.setType(PropertyType.INTEGER);
// no range set
validateValid(description, 2);
// empty range set
description.setRange(new Range());
validateValid(description, 2);
// min set
description.getRange().setMin(5);
validateValid(description, 5);
validateValid(description, 6);
validateError(description, 4);
validateValid(description, 5.0);
validateValid(description, 6.0);
validateError(description, 4.0);
// max set
description.getRange().setMax(6);
validateValid(description, 5);
validateValid(description, 6);
validateError(description, 7);
validateValid(description, 5.0);
validateValid(description, 6.0);
validateError(description, 7.0);
}
@Test public void testValidateRegex() {
final PropertyDescription prop = new PropertyDescription();
// no regex
validateValid(prop, "hello world");
validateValid(prop, "world");
// regex
prop.setRegex("h(.*)");
validateValid(prop, "hello world");
validateError(prop, "world");
// apply default
prop.setDefaultValue("hello world");
validateError(prop, "world");
}
@Test public void testValidateOptions() {
final PropertyDescription prop = new PropertyDescription();
// no options
validateValid(prop, "foo");
validateValid(prop, "bar");
// options - with foo
final List<Option> options = new ArrayList<>();
final Option o1 = new Option();
o1.setValue("foo");
final Option o2 = new Option();
o2.setValue("7");
options.add(o1);
options.add(o2);
prop.setOptions(options);
validateValid(prop, "foo");
validateError(prop, "bar");
validateValid(prop, 7);
}
@Test public void testValidateList() {
final PropertyDescription prop = new PropertyDescription();
final List<Object> values = new ArrayList<>();
values.add("a");
values.add("b");
values.add("c");
// default cardinality - no excludes/includes
validateError(prop, values);
// cardinality 3 - no excludes/includes
prop.setCardinality(3);
validateValid(prop, values);
values.add("d");
validateError(prop, values);
// excludes
prop.setExcludes(new String[] {"d", "e"});
validateError(prop, values, 2);
values.remove("d");
validateValid(prop, values);
// includes
prop.setIncludes(new String[] {"b"});
validateValid(prop, values);
prop.setIncludes(new String[] {"x"});
validateError(prop, values);
values.add("x");
values.remove("a");
validateValid(prop, values);
}
@Test public void testValidateArray() {
final PropertyDescription prop = new PropertyDescription();
String[] values = new String[] {"a", "b", "c"};
// default cardinality - no excludes/includes
validateError(prop, values);
// cardinality 3 - no excludes/includes
prop.setCardinality(3);
validateValid(prop, values);
values = new String[] {"a", "b", "c", "d"};
validateError(prop, values);
// excludes
prop.setExcludes(new String[] {"d", "e"});
validateError(prop, values, 2);
values = new String[] {"a", "b", "c"};
validateValid(prop, values);
// includes
prop.setIncludes(new String[] {"b"});
validateValid(prop, values);
prop.setIncludes(new String[] {"x"});
validateError(prop, values);
values = new String[] {"b", "c", "x"};
validateValid(prop, values);
}
@Test public void testDeprecation() {
final PropertyDescription prop = new PropertyDescription();
prop.setDeprecated("This is deprecated");
final PropertyValidationResult result = validator.validate("foo", prop);
assertTrue(result.isValid());
assertEquals(1, result.getWarnings().size());
assertEquals("This is deprecated", result.getWarnings().get(0));
}
@Test public void testPlaceholdersString() {
final PropertyDescription desc = new PropertyDescription();
desc.setType(PropertyType.PATH);
PropertyValidationResult result = null;
result = validator.validate("$[env:variable]", desc);
assertTrue(result.isValid());
assertTrue(result.isSkipped());
result = validator.validate("$[prop:variable]", desc);
assertTrue(result.isValid());
assertTrue(result.isSkipped());
result = validator.validate("$[secret:variable]", desc);
assertTrue(result.isValid());
assertTrue(result.isSkipped());
}
@Test public void testPlaceholdersNumber() {
final PropertyDescription desc = new PropertyDescription();
desc.setType(PropertyType.INTEGER);
PropertyValidationResult result = null;
result = validator.validate("$[env:variable]", desc);
assertTrue(result.isValid());
assertTrue(result.isSkipped());
result = validator.validate("$[prop:variable]", desc);
assertTrue(result.isValid());
assertTrue(result.isSkipped());
result = validator.validate("$[secret:variable]", desc);
assertTrue(result.isValid());
assertTrue(result.isSkipped());
}
@Test public void testPlaceholdersArray() {
final PropertyDescription desc = new PropertyDescription();
desc.setType(PropertyType.INTEGER);
desc.setCardinality(-1);
PropertyValidationResult result = null;
result = validator.validate(new Object[] {5, "$[env:variable]"}, desc);
assertTrue(result.isValid());
assertTrue(result.isSkipped());
result = validator.validate(new Object[] {"hello", "$[env:variable]"}, desc);
assertFalse(result.isValid());
assertTrue(result.isSkipped());
}
@Test public void testPlaceholderPolicyRequire() {
final PropertyDescription desc = new PropertyDescription();
desc.setPlaceholderPolicy(PlaceholderPolicy.REQUIRE);
PropertyValidationResult result = null;
result = validator.validate("$[env:variable]", desc);
assertTrue(result.isValid());
assertFalse(result.isSkipped());
result = validator.validate("hello", desc);
assertFalse(result.isValid());
assertFalse(result.isSkipped());
}
@Test public void testPlaceholderPolicyDeny() {
final PropertyDescription desc = new PropertyDescription();
desc.setPlaceholderPolicy(PlaceholderPolicy.DENY);
PropertyValidationResult result = null;
result = validator.validate("$[env:variable]", desc);
assertFalse(result.isValid());
assertFalse(result.isSkipped());
result = validator.validate("hello", desc);
assertTrue(result.isValid());
assertFalse(result.isSkipped());
}
@Test
public void testPropertyDescRegex() {
final PropertyDescription desc = new PropertyDescription();
desc.setPlaceholderPolicy(PlaceholderPolicy.ALLOW);
desc.setPlaceholderRegex("^\\w+ [^ ]+$");
PropertyValidationResult result = validator.validate("local $[env:AEM_EXTERNALIZER_LOCAL;default=http://localhost:4502]", desc);
assertTrue(result.isValid());
assertFalse(result.isSkipped());
result = validator.validate("author $[env:AEM_EXTERNALIZER_LOCAL;default=http://localhost:4502] http://abc.def.com:9091", desc);
assertFalse(result.isValid());
assertFalse(result.isSkipped());
result = validator.validate("local http://abc.ghi.com:9091", desc);
assertTrue(result.isValid());
assertFalse(result.isSkipped());
}
@Test
public void testLiveValidation() {
assertFalse(this.validator.isLiveValues());
try {
this.validator.setLiveValues(true);
final PropertyDescription desc = new PropertyDescription();
desc.setPlaceholderPolicy(PlaceholderPolicy.DENY);
PropertyValidationResult result = null;
result = validator.validate("$[env:variable]", desc);
assertTrue(result.isValid());
assertFalse(result.isSkipped());
result = validator.validate("hello", desc);
assertTrue(result.isValid());
assertFalse(result.isSkipped());
} finally {
this.validator.setLiveValues(false);
}
}
}