blob: ba63cac41f7721f31f28f5cbfccf13ed85545baf [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
*
* https://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.commons.configuration2.tree;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.NoSuchElementException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/**
* Test class for DefaultConfigurationKey.
*/
public class TestDefaultConfigurationKey {
/** Constant for a test key. */
private static final String TESTPROPS = "tables.table(0).fields.field(1)";
/** Constant for a test attribute key. */
private static final String TESTATTR = "[@dataType]";
/** Constant for a complex attribute key. */
private static final String TESTKEY = TESTPROPS + TESTATTR;
/** Stores the expression engine of the key to test. */
private DefaultExpressionEngine expressionEngine;
/** Stores the object to be tested. */
private DefaultConfigurationKey key;
/**
* Helper method to create a key instance with the given content.
*
* @param k the key for initialization
* @return the newly created {@code DefaultConfigurationKey} instance
*/
private DefaultConfigurationKey key(final String k) {
return new DefaultConfigurationKey(expressionEngine, k);
}
@BeforeEach
public void setUp() throws Exception {
expressionEngine = DefaultExpressionEngine.INSTANCE;
key = new DefaultConfigurationKey(expressionEngine);
}
/**
* Returns a builder for symbols with default property settings.
*
* @return the initialized builder object
*/
private DefaultExpressionEngineSymbols.Builder symbols() {
return new DefaultExpressionEngineSymbols.Builder(expressionEngine.getSymbols());
}
/**
* Tests appending keys.
*/
@Test
void testAppend() {
key.append("tables").append("table(0).");
key.append("fields.").append("field(1)");
key.append(null).append(TESTATTR);
assertEquals(TESTKEY, key.toString());
}
/**
* Tests appending attribute keys.
*/
@Test
void testAppendAttribute() {
key.appendAttribute("dataType");
assertEquals(TESTATTR, key.toString());
}
/**
* Tests constructing a complex key by chaining multiple append operations.
*/
@Test
void testAppendComplexKey() {
key.append("tables").append("table.").appendIndex(0);
key.append("fields.").append("field").appendIndex(1);
key.appendAttribute("dataType");
assertEquals(TESTKEY, key.toString());
}
/**
* Tests appending an attribute key that is already decorated-
*/
@Test
void testAppendDecoratedAttributeKey() {
key.appendAttribute(TESTATTR);
assertEquals(TESTATTR, key.toString());
}
/**
* Tests appending keys that contain delimiters.
*/
@Test
void testAppendDelimiters() {
key.append("key..").append("test").append(".");
key.append(".more").append("..tests");
assertEquals("key...test.more...tests", key.toString());
}
/**
* Tests appending keys that contain delimiters when no escaped delimiter is defined.
*/
@Test
void testAppendDelimitersWithoutEscaping() {
expressionEngine = new DefaultExpressionEngine(symbols().setEscapedDelimiter(null).create());
key = new DefaultConfigurationKey(expressionEngine);
key.append("key.......").append("test").append(".");
key.append(".more").append("..tests");
assertEquals("key.test.more.tests", key.toString());
}
/**
* Tests appending an index to a key.
*/
@Test
void testAppendIndex() {
key.append("test").appendIndex(42);
assertEquals("test(42)", key.toString());
}
/**
* Tests appending a null attribute key.
*/
@Test
void testAppendNullAttributeKey() {
key.appendAttribute(null);
assertEquals("", key.toString());
}
/**
* Tests calling append with the escape flag.
*/
@Test
void testAppendWithEscapeFlag() {
key.append(".key.test.", true);
key.append(".more").append(".tests", true);
assertEquals("..key..test...more...tests", key.toString());
}
/**
* Tests iterating over an attribute key that has an index.
*/
@Test
void testAttributeKeyWithIndex() {
key.append(TESTATTR);
key.appendIndex(0);
assertEquals(TESTATTR + "(0)", key.toString());
final DefaultConfigurationKey.KeyIterator it = key.iterator();
assertTrue(it.hasNext());
it.next();
assertTrue(it.hasIndex());
assertEquals(0, it.getIndex());
assertTrue(it.isAttribute());
assertEquals("dataType", it.currentKey(false));
assertEquals(TESTATTR, it.currentKey(true));
}
/**
* Tests determining an attribute key's name.
*/
@Test
void testAttributeName() {
assertEquals("test", key.attributeName("test"));
assertEquals("dataType", key.attributeName(TESTATTR));
assertNull(key.attributeName(null));
}
/**
* Tests whether common key parts can be extracted.
*/
@Test
void testCommonKey() {
final DefaultConfigurationKey k1 = key(TESTKEY);
DefaultConfigurationKey k2 = key("tables.table(0).name");
DefaultConfigurationKey kc = k1.commonKey(k2);
assertEquals(key("tables.table(0)"), kc);
assertEquals(kc, k2.commonKey(k1));
k2 = key("tables.table(1).fields.field(1)");
kc = k1.commonKey(k2);
assertEquals(key("tables"), kc);
k2 = key("completely.different.key");
kc = k1.commonKey(k2);
assertEquals(0, kc.length());
kc = k1.commonKey(key);
assertEquals(0, kc.length());
kc = k1.commonKey(k1);
assertEquals(kc, k1);
}
/**
* Tries to call commonKey() with null input.
*/
@Test
void testCommonKeyNull() {
assertThrows(IllegalArgumentException.class, () -> key.commonKey(null));
}
/**
* Tests constructing keys for attributes.
*/
@Test
void testConstructAttributeKey() {
assertEquals(TESTATTR, key.constructAttributeKey("dataType"));
assertEquals(TESTATTR, key.constructAttributeKey(TESTATTR));
assertEquals("", key.constructAttributeKey(null));
}
/**
* Tests constructing attribute keys when no end markers are defined. In this test case we use the property delimiter as
* attribute prefix.
*/
@Test
void testConstructAttributeKeyWithoutEndMarkers() {
final DefaultExpressionEngineSymbols symbols = symbols().setAttributeEnd(null).setAttributeStart(expressionEngine.getSymbols().getPropertyDelimiter())
.create();
expressionEngine = new DefaultExpressionEngine(symbols);
key = new DefaultConfigurationKey(expressionEngine);
assertEquals(".test", key.constructAttributeKey("test"));
assertEquals(".test", key.constructAttributeKey(".test"));
}
/**
* Tests the differenceKey() method.
*/
@Test
void testDifferenceKey() {
final DefaultConfigurationKey k1 = key(TESTKEY);
DefaultConfigurationKey k2 = key("tables.table(0).name");
DefaultConfigurationKey kd = k1.differenceKey(k2);
assertEquals("name", kd.toString());
k2 = key("tables.table(1).fields.field(1)");
kd = k1.differenceKey(k2);
assertEquals("table(1).fields.field(1)", kd.toString());
k2 = key("completely.different.key");
kd = k1.differenceKey(k2);
assertEquals(k2, kd);
}
/**
* Tests differenceKey() on the same object.
*/
@Test
void testDifferenceKeySame() {
final DefaultConfigurationKey k1 = key(TESTKEY);
final DefaultConfigurationKey kd = k1.differenceKey(k1);
assertEquals(0, kd.length());
}
/**
* Tests comparing configuration keys.
*/
@Test
void testEquals() {
final DefaultConfigurationKey k1 = key(TESTKEY);
assertEquals(k1, k1);
final DefaultConfigurationKey k2 = key(TESTKEY);
assertEquals(k1, k2);
assertEquals(k2, k1);
assertEquals(k1.hashCode(), k2.hashCode());
k2.append("anotherPart");
assertNotEquals(k1, k2);
assertNotEquals(k2, k1);
assertNotEquals(null, k1);
assertNotEquals(TESTKEY, k1);
}
/**
* Tests the isAttributeKey() method with several keys.
*/
@Test
void testIsAttributeKey() {
assertTrue(key.isAttributeKey(TESTATTR));
assertFalse(key.isAttributeKey(TESTPROPS));
assertFalse(key.isAttributeKey(null));
}
/**
* Tests if attribute keys are correctly detected if no end markers are set. (In this test case we use the same
* delimiter for attributes as for simple properties.)
*/
@Test
void testIsAttributeKeyWithoutEndMarkers() {
final DefaultExpressionEngineSymbols symbols = symbols().setAttributeEnd(null)
.setAttributeStart(DefaultExpressionEngineSymbols.DEFAULT_PROPERTY_DELIMITER).create();
expressionEngine = new DefaultExpressionEngine(symbols);
key = new DefaultConfigurationKey(expressionEngine);
assertTrue(key.isAttributeKey(DefaultExpressionEngineSymbols.DEFAULT_PROPERTY_DELIMITER + "test"));
assertFalse(key.isAttributeKey(TESTATTR));
}
/**
* Tests to iterate over a simple key.
*/
@Test
void testIterate() {
key.append(TESTKEY);
final DefaultConfigurationKey.KeyIterator it = key.iterator();
assertTrue(it.hasNext());
assertEquals("tables", it.nextKey());
assertEquals("table", it.nextKey());
assertTrue(it.hasIndex());
assertEquals(0, it.getIndex());
assertEquals("fields", it.nextKey());
assertFalse(it.hasIndex());
assertEquals("field", it.nextKey(true));
assertEquals(1, it.getIndex());
assertFalse(it.isAttribute());
assertEquals("field", it.currentKey(true));
assertEquals("dataType", it.nextKey());
assertEquals("[@dataType]", it.currentKey(true));
assertTrue(it.isAttribute());
assertFalse(it.hasNext());
assertThrows(NoSuchElementException.class, it::next);
}
/**
* Tests iterating over keys when a different escaped delimiter is used.
*/
@Test
void testIterateAlternativeEscapeDelimiter() {
expressionEngine = new DefaultExpressionEngine(symbols().setEscapedDelimiter("\\.").create());
key = new DefaultConfigurationKey(expressionEngine);
key.append("\\.my\\.elem");
key.append("trailing\\.dot\\.");
key.append(".strange");
assertEquals("\\.my\\.elem.trailing\\.dot\\..strange", key.toString());
final DefaultConfigurationKey.KeyIterator kit = key.iterator();
assertEquals(".my.elem", kit.nextKey());
assertEquals("trailing.dot.", kit.nextKey());
assertEquals("strange", kit.nextKey());
assertFalse(kit.hasNext());
}
/**
* Tests iteration when the attribute markers equals the property delimiter.
*/
@Test
void testIterateAttributeEqualsPropertyDelimiter() {
expressionEngine = new DefaultExpressionEngine(
symbols().setAttributeEnd(null).setAttributeStart(DefaultExpressionEngineSymbols.DEFAULT_PROPERTY_DELIMITER).create());
key = new DefaultConfigurationKey(expressionEngine);
key.append("this.isa.key");
final DefaultConfigurationKey.KeyIterator kit = key.iterator();
assertEquals("this", kit.next());
assertFalse(kit.isAttribute());
assertTrue(kit.isPropertyKey());
assertEquals("isa", kit.next());
assertFalse(kit.isAttribute());
assertTrue(kit.isPropertyKey());
assertEquals("key", kit.next());
assertTrue(kit.isAttribute());
assertTrue(kit.isPropertyKey());
assertEquals("key", kit.currentKey(true));
}
/**
* Tests iterating over keys with escaped delimiters.
*/
@Test
void testIterateEscapedDelimiters() {
key.append("my..elem");
key.append("trailing..dot..");
key.append(".strange");
assertEquals("my..elem.trailing..dot...strange", key.toString());
final DefaultConfigurationKey.KeyIterator kit = key.iterator();
assertEquals("my.elem", kit.nextKey());
assertEquals("trailing.dot.", kit.nextKey());
assertEquals("strange", kit.nextKey());
assertFalse(kit.hasNext());
}
/**
* Tests iterating over some funny keys.
*/
@Test
void testIterateStrangeKeys() {
key = new DefaultConfigurationKey(expressionEngine, "key.");
DefaultConfigurationKey.KeyIterator it = key.iterator();
assertTrue(it.hasNext());
assertEquals("key", it.next());
assertFalse(it.hasNext());
key = new DefaultConfigurationKey(expressionEngine, ".");
it = key.iterator();
assertFalse(it.hasNext());
key = new DefaultConfigurationKey(expressionEngine, "key().index()undefined(0).test");
it = key.iterator();
assertEquals("key()", it.next());
assertFalse(it.hasIndex());
assertEquals("index()undefined", it.nextKey(false));
assertTrue(it.hasIndex());
assertEquals(0, it.getIndex());
}
/**
* Tests whether a key with brackets in it can be iterated over.
*/
@Test
void testIterateWithBrackets() {
key.append("directory.platform(x86).path");
final DefaultConfigurationKey.KeyIterator kit = key.iterator();
String part = kit.nextKey();
assertEquals("directory", part);
assertFalse(kit.hasIndex());
part = kit.nextKey();
assertEquals("platform(x86)", part);
assertFalse(kit.hasIndex());
part = kit.nextKey();
assertEquals("path", part);
assertFalse(kit.hasIndex());
assertFalse(kit.hasNext());
}
/**
* Tests iterating when no escape delimiter is defined.
*/
@Test
void testIterateWithoutEscapeDelimiter() {
expressionEngine = new DefaultExpressionEngine(symbols().setEscapedDelimiter(null).create());
key = new DefaultConfigurationKey(expressionEngine);
key.append("..my..elem.trailing..dot...strange");
assertEquals("my..elem.trailing..dot...strange", key.toString());
final DefaultConfigurationKey.KeyIterator kit = key.iterator();
final String[] parts = {"my", "elem", "trailing", "dot", "strange"};
for (int i = 0; i < parts.length; i++) {
assertEquals(parts[i], kit.next(), "Wrong key part " + i);
}
assertFalse(kit.hasNext());
}
/**
* Tests an iteration where the remove() method is called. This is not supported.
*/
@Test
void testIterateWithRemove() {
assertFalse(key.iterator().hasNext());
key.append("simple");
final DefaultConfigurationKey.KeyIterator it = key.iterator();
assertTrue(it.hasNext());
assertEquals("simple", it.next());
assertThrows(UnsupportedOperationException.class, it::remove);
}
/**
* Tests getting and setting the key's length.
*/
@Test
void testLength() {
key.append(TESTPROPS);
assertEquals(TESTPROPS.length(), key.length());
key.appendAttribute("dataType");
assertEquals(TESTKEY.length(), key.length());
key.setLength(TESTPROPS.length());
assertEquals(TESTPROPS.length(), key.length());
assertEquals(TESTPROPS, key.toString());
}
/**
* Tests setting the expression engine to null. This should not be allowed.
*/
@Test
void testSetNullExpressionEngine() {
assertThrows(IllegalArgumentException.class, () -> new DefaultConfigurationKey(null));
}
/**
* Tests removing delimiters.
*/
@Test
void testTrim() {
assertEquals("test", key.trim(".test."));
assertEquals("", key.trim(null));
assertEquals("", key.trim(DefaultExpressionEngineSymbols.DEFAULT_PROPERTY_DELIMITER));
}
/**
* Tests removing leading delimiters.
*/
@Test
void testTrimLeft() {
assertEquals("test.", key.trimLeft(".test."));
assertEquals("..test.", key.trimLeft("..test."));
}
/**
* Tests removing trailing delimiters.
*/
@Test
void testTrimRight() {
assertEquals(".test", key.trimRight(".test."));
assertEquals(".test..", key.trimRight(".test.."));
}
}