package io.eguan.configuration; /* * #%L * Project eguan * %% * Copyright (C) 2012 - 2017 Oodrive * %% * Licensed 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. * #L% */ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import io.eguan.configuration.AbstractConfigKey; import io.eguan.configuration.ConfigValidationException; import io.eguan.configuration.MetaConfiguration; import io.eguan.configuration.ValidationError; import io.eguan.configuration.ValidationError.ErrorType; import java.io.IOException; import java.util.AbstractList; import org.junit.Test; /** * Tests the methods directly implemented by {@link AbstractConfigKey} not covered by {@link TestMetaConfiguration}. * * @author oodrive * @author pwehrle * @author llambert * */ public final class TestAbstractConfigKey { /** * Valid {@link AbstractConfigKey} names to test with {@link TestAbstractConfigKey#testIsValidName()}. */ private static final String[] VALID_CONFIG_KEY_NAMES = new String[] { "k", "key", "test.key", "test.key.eguan", "test.key.eguan.k.valid", "test.Key.EGUAN", "test.Key2.EGUAN3" }; /** * Invalid {@link AbstractConfigKey} names to test with * {@link TestAbstractConfigKey#testIsValidNameFailValidation()}. */ private static final String[] INVALID_CONFIG_KEY_NAMES = new String[] { null, "", " ", ".", "test..key", "test.invalid.key.", "test.invalid.key..", "test.invalid.key.#" }; /** * An abstract subclass of {@link AbstractConfigKey} implementing the methods not relevant to the tests. * * */ private abstract static class TestableAbstractConfigKey extends AbstractConfigKey { /** * The default value to be returned by {@link #getDefaultValue()}. */ private final Object defaultValue; /** * Default constructor with a fail-safe name value. * * @param defaultValue * the default value to be returned by {@link #getDefaultValue()} */ public TestableAbstractConfigKey(final Object defaultValue) { super("testable.key"); this.defaultValue = defaultValue; } @Override protected final Object getDefaultValue() { return defaultValue; } @Override public final Object getTypedValue(final MetaConfiguration configuration) throws IllegalStateException, ClassCastException, NullPointerException { return null; } @Override protected final Object parseValue(final String value) throws IllegalArgumentException, NullPointerException { return null; } @Override protected final String valueToString(final Object value) throws IllegalArgumentException, NullPointerException { return null; } // intentionally non-final @Override protected ValidationError checkValue(final Object value) { return null; } } /** * {@link TestableAbstractConfigKey} implementation with an exact class-checking * {@link AbstractConfigKey#checkValue(Object)} implementation based on * {@link AbstractConfigKey#checkSameClass(Object, Class)}. * * */ private static final class TestableClassCheckingConfigKey extends TestableAbstractConfigKey { private final Class<?> checkClass; public TestableClassCheckingConfigKey(final Class<?> classToCheckAgainst) { super(null); checkClass = classToCheckAgainst; } @Override protected final ValidationError checkValue(final Object value) { return checkSameClass(value, checkClass); } } /** * Tests consistency of the default implementation where a key is required if it has a default value. */ @Test public final void testRequiredIfDefault() { final TestableAbstractConfigKey targetNoDefault = new TestableAbstractConfigKey(null) { }; assertFalse("key claims to have no default value", targetNoDefault.hasDefaultValue()); assertTrue("key is required", targetNoDefault.isRequired()); final TestableAbstractConfigKey targetWithDefault = new TestableAbstractConfigKey("default value") { }; assertTrue("key claims to have a default value", targetWithDefault.hasDefaultValue()); assertFalse("key is not required", targetWithDefault.isRequired()); } /** * Tests consistency of the default implementation with inverted required return value. */ @Test public void testhasDefaultWithOverriddenRequired() { final TestableAbstractConfigKey targetDefaultRequired = new TestableAbstractConfigKey("default value") { @Override public boolean isRequired() { return !super.isRequired(); } }; assertFalse("key claims to have no default value", targetDefaultRequired.hasDefaultValue()); assertTrue("key is required", targetDefaultRequired.isRequired()); final TestableAbstractConfigKey targetNoDefaultNotRequired = new TestableAbstractConfigKey(null) { @Override public boolean isRequired() { return !super.isRequired(); } }; assertFalse("key claims to have no default value", targetNoDefaultNotRequired.hasDefaultValue()); assertFalse("key is not required", targetNoDefaultNotRequired.isRequired()); } /** * Tests failure when calling {@link AbstractConfigKey#checkConfigForKey(MetaConfiguration)} with a configuration * not managing the key. * * @throws IllegalStateException * the exception thrown on a key unknown to the configuration. Expected in this test. * @throws IOException * if loading the configuration fails. Not part of this test. * @throws ConfigValidationException * if validation of the configuration fails. Not part of this test. * @throws RuntimeException * if parameters are {@code null} or construction otherwise fails. Not part of this test. */ @Test(expected = IllegalStateException.class) public void testCheckConfigForKeyFail() throws IllegalStateException, IOException, ConfigValidationException, RuntimeException { final MetaConfiguration config = MetaConfiguration.newConfiguration( ConfigTestHelper.getPropertiesAsInputStream(ConfigTestHelper.getDefaultTestConfiguration()), ConfigTestContext.getInstance()); final TestableAbstractConfigKey target = new TestableAbstractConfigKey(null) { }; target.checkConfigForKey(config); } /** * Test successful validation of names with {@link AbstractConfigKey#isNameValid(String)}. */ @Test public void testIsValidName() { for (final String currName : VALID_CONFIG_KEY_NAMES) { assertTrue("Name is valid; name='" + currName + "'", AbstractConfigKey.isNameValid(currName)); } } /** * Test validation failure calling {@link AbstractConfigKey#isNameValid(String)} with empty,{@code null} or * otherwise invalid names. */ @Test public void testIsValidNameFailValidation() { for (final String currName : INVALID_CONFIG_KEY_NAMES) { assertFalse("Name is invalid; name='" + currName + "'", AbstractConfigKey.isNameValid(currName)); } } /** * Indirectly tests {@link AbstractConfigKey#checkSameClass(Object, Class)} through * {@link TestableClassCheckingConfigKey} given a subclass instance as argument. */ @Test public void testCheckValueExactClassFailNotExactClass() { final TestableAbstractConfigKey target = new TestableClassCheckingConfigKey(AbstractList.class); final AbstractList<Object> listInstance = new AbstractList<Object>() { @Override public Object get(final int index) { return null; } @Override public int size() { return 0; } }; final ValidationError report = target.checkValue(listInstance); assertEquals(ErrorType.VALUE_INVALID, report.getType()); } /** * Indirectly tests {@link AbstractConfigKey#checkSameClass(Object, Class)} through * {@link TestableClassCheckingConfigKey} given an enum constant as argument. */ @Test public void testCheckValueExactClassWithEnum() { final TestableAbstractConfigKey target = new TestableClassCheckingConfigKey(EnumTestValue.class); final ValidationError report = target.checkValue(EnumTestValue.TEST_VALUE_2); assertEquals(ValidationError.NO_ERROR, report); } }