blob: 0676542886c056f45e4ada2073dd283e3356e9ea [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.commons.configuration2;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.apache.commons.configuration2.SynchronizerTestImpl.Methods;
import org.apache.commons.configuration2.builder.FileBasedBuilderParametersImpl;
import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
import org.apache.commons.configuration2.builder.fluent.Parameters;
import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler;
import org.apache.commons.configuration2.ex.ConfigurationException;
import org.apache.commons.configuration2.sync.ReadWriteSynchronizer;
import org.apache.commons.configuration2.tree.DefaultExpressionEngine;
import org.apache.commons.configuration2.tree.DefaultExpressionEngineSymbols;
import org.apache.commons.configuration2.tree.ImmutableNode;
import org.apache.commons.configuration2.tree.NodeHandler;
import org.apache.commons.configuration2.tree.NodeNameMatchers;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
/**
* Test class for {@code INIConfiguration}.
*
*/
public class TestINIConfiguration
{
private static String LINE_SEPARATOR = System.getProperty("line.separator");
/** Constant for the content of an ini file. */
private static final String INI_DATA = "[section1]" + LINE_SEPARATOR
+ "var1 = foo" + LINE_SEPARATOR + "var2 = 451" + LINE_SEPARATOR
+ LINE_SEPARATOR + "[section2]" + LINE_SEPARATOR + "var1 = 123.45"
+ LINE_SEPARATOR + "var2 = bar" + LINE_SEPARATOR + LINE_SEPARATOR
+ "[section3]" + LINE_SEPARATOR + "var1 = true" + LINE_SEPARATOR
+ "interpolated = ${section3.var1}" + LINE_SEPARATOR
+ "multi = foo" + LINE_SEPARATOR + "multi = bar" + LINE_SEPARATOR
+ LINE_SEPARATOR;
private static final String INI_DATA2 = "[section4]" + LINE_SEPARATOR
+ "var1 = \"quoted value\"" + LINE_SEPARATOR
+ "var2 = \"quoted value\\nwith \\\"quotes\\\"\"" + LINE_SEPARATOR
+ "var3 = 123 ; comment" + LINE_SEPARATOR
+ "var4 = \"1;2;3\" ; comment" + LINE_SEPARATOR
+ "var5 = '\\'quoted\\' \"value\"' ; comment" + LINE_SEPARATOR
+ "var6 = \"\"" + LINE_SEPARATOR;
private static final String INI_DATA3 = "[section5]" + LINE_SEPARATOR
+ "multiLine = one \\" + LINE_SEPARATOR
+ " two \\" + LINE_SEPARATOR
+ " three" + LINE_SEPARATOR
+ "singleLine = C:\\Temp\\" + LINE_SEPARATOR
+ "multiQuoted = one \\" + LINE_SEPARATOR
+ "\" two \" \\" + LINE_SEPARATOR
+ " three" + LINE_SEPARATOR
+ "multiComment = one \\ ; a comment" + LINE_SEPARATOR
+ "two" + LINE_SEPARATOR
+ "multiQuotedComment = \" one \" \\ ; comment" + LINE_SEPARATOR
+ "two" + LINE_SEPARATOR
+ "noFirstLine = \\" + LINE_SEPARATOR
+ " line 2" + LINE_SEPARATOR
+ "continueNoLine = one \\" + LINE_SEPARATOR;
private static final String INI_DATA4 = "[section6]" + LINE_SEPARATOR
+ "key1{0}value1" + LINE_SEPARATOR
+ "key2{0}value2" + LINE_SEPARATOR + LINE_SEPARATOR
+ "[section7]" + LINE_SEPARATOR
+ "key3{0}value3" + LINE_SEPARATOR;
private static final String INI_DATA_SEPARATORS = "[section]"
+ LINE_SEPARATOR + "var1 = value1" + LINE_SEPARATOR
+ "var2 : value2" + LINE_SEPARATOR
+ "var3=value3" + LINE_SEPARATOR
+ "var4:value4" + LINE_SEPARATOR
+ "var5 : value=5" + LINE_SEPARATOR
+ "var:6=value" + LINE_SEPARATOR
+ "var:7=\"value7\"" + LINE_SEPARATOR
+ "var:8 = \"value8\"" + LINE_SEPARATOR;
/** An ini file that contains only a property in the global section. */
private static final String INI_DATA_GLOBAL_ONLY = "globalVar = testGlobal"
+ LINE_SEPARATOR + LINE_SEPARATOR;
/** An ini file with a global section. */
private static final String INI_DATA_GLOBAL = INI_DATA_GLOBAL_ONLY
+ INI_DATA;
/** A helper object for creating temporary files. */
@Rule
public TemporaryFolder folder = new TemporaryFolder();
/**
* Creates a INIConfiguration object that is initialized from
* the given data.
*
* @param data the data of the configuration (an ini file as string)
* @return the initialized configuration
* @throws ConfigurationException if an error occurs
*/
private static INIConfiguration setUpConfig(final String data)
throws ConfigurationException
{
final INIConfiguration instance = new INIConfiguration();
instance.setListDelimiterHandler(new DefaultListDelimiterHandler(','));
load(instance, data);
return instance;
}
/**
* Loads the specified content into the given configuration instance.
*
* @param instance the configuration
* @param data the data to be loaded
* @throws ConfigurationException if an error occurs
*/
private static void load(final INIConfiguration instance, final String data)
throws ConfigurationException
{
final StringReader reader = new StringReader(data);
try
{
instance.read(reader);
}
catch (final IOException e)
{
throw new ConfigurationException(e);
}
reader.close();
}
/**
* Saves the specified configuration to a string. The string can be compared
* with an expected value or again loaded into a configuration.
*
* @param config the configuration to be saved
* @return the content of this configuration saved to a string
* @throws ConfigurationException if an error occurs
*/
private static String saveToString(final INIConfiguration config)
throws ConfigurationException
{
final StringWriter writer = new StringWriter();
try
{
config.write(writer);
}
catch (final IOException e)
{
throw new ConfigurationException(e);
}
return writer.toString();
}
/**
* Writes a test ini file.
*
* @param content the content of the file
* @return the newly created file
* @throws IOException if an error occurs
*/
private File writeTestFile(final String content) throws IOException
{
final File file = folder.newFile();
try (PrintWriter out = new PrintWriter(new FileWriter(file)))
{
out.println(content);
}
return file;
}
/**
* Test of save method, of class {@link INIConfiguration}.
*/
@Test
public void testSave() throws Exception
{
final Writer writer = new StringWriter();
final INIConfiguration instance = new INIConfiguration();
instance.addProperty("section1.var1", "foo");
instance.addProperty("section1.var2", "451");
instance.addProperty("section2.var1", "123.45");
instance.addProperty("section2.var2", "bar");
instance.addProperty("section3.var1", "true");
instance.addProperty("section3.interpolated", "${section3.var1}");
instance.addProperty("section3.multi", "foo");
instance.addProperty("section3.multi", "bar");
instance.write(writer);
assertEquals("Wrong content of ini file", INI_DATA, writer.toString());
}
/**
* Test of save method with changed separator
*/
@Test
public void testSeparatorUsedInINIOutput() throws Exception
{
final String outputSeparator = ": ";
final String input = MessageFormat.format(INI_DATA4, "=").trim();
final String expectedOutput = MessageFormat.format(INI_DATA4, outputSeparator).trim();
final INIConfiguration instance = new FileBasedConfigurationBuilder<>(
INIConfiguration.class)
.configure(new Parameters().ini().setSeparatorUsedInOutput(outputSeparator))
.getConfiguration();
load(instance, input);
final Writer writer = new StringWriter();
instance.write(writer);
final String result = writer.toString().trim();
assertEquals("Wrong content of ini file", expectedOutput, result);
}
/**
* Test of read method with changed separator.
*/
@Test
public void testSeparatorUsedInINIInput() throws Exception
{
final String inputSeparator = "=";
final String input = "[section]" + LINE_SEPARATOR
+ "k1:v1$key1=value1" + LINE_SEPARATOR
+ "k1:v1,k2:v2$key2=value2" + LINE_SEPARATOR
+ "key3:value3" + LINE_SEPARATOR
+ "key4 = value4" + LINE_SEPARATOR;
final INIConfiguration instance = new FileBasedConfigurationBuilder<>(
INIConfiguration.class)
.configure(new Parameters().ini().setSeparatorUsedInInput(inputSeparator))
.getConfiguration();
load(instance, input);
assertEquals("value1", instance.getString("section.k1:v1$key1"));
assertEquals("value2", instance.getString("section.k1:v1,k2:v2$key2"));
assertEquals("", instance.getString("section.key3:value3"));
assertEquals("value4", instance.getString("section.key4").trim());
}
/**
* Test of read method with changed comment leading separator
*/
@Test
public void testCommentLeadingSeparatorUsedInINIInput() throws Exception
{
final String inputCommentLeadingSeparator = ";";
final String input = "[section]" + LINE_SEPARATOR
+ "key1=a;b;c" + LINE_SEPARATOR
+ "key2=a#b#c" + LINE_SEPARATOR
+ ";key3=value3" + LINE_SEPARATOR
+ "#key4=value4" + LINE_SEPARATOR;
final INIConfiguration instance = new FileBasedConfigurationBuilder<>(
INIConfiguration.class)
.configure(new Parameters().ini()
.setCommentLeadingCharsUsedInInput(inputCommentLeadingSeparator))
.getConfiguration();
load(instance, input);
assertEquals("a;b;c", instance.getString("section.key1"));
assertEquals("a#b#c", instance.getString("section.key2"));
assertNull("", instance.getString("section.;key3"));
assertEquals("value4", instance.getString("section.#key4"));
}
/**
* Helper method for testing a save operation. This method constructs a
* configuration from the specified content string. Then it saves this
* configuration and checks whether the result matches the original content.
*
* @param content the content of the configuration
* @throws ConfigurationException if an error occurs
*/
private void checkSave(final String content) throws ConfigurationException
{
final INIConfiguration config = setUpConfig(content);
final String sOutput = saveToString(config);
assertEquals("Wrong content of ini file", content, sOutput);
}
/**
* Tests saving a configuration that contains a global section.
*/
@Test
public void testSaveWithGlobalSection() throws ConfigurationException
{
checkSave(INI_DATA_GLOBAL);
}
/**
* Tests whether a configuration that contains only a global section can be
* saved correctly.
*/
@Test
public void testSaveWithOnlyGlobalSection() throws ConfigurationException
{
checkSave(INI_DATA_GLOBAL_ONLY);
}
/**
* Tests whether list delimiter parsing can be disabled.
*/
@Test
public void testSaveWithDelimiterParsingDisabled()
throws ConfigurationException
{
final INIConfiguration config = new INIConfiguration();
final String data =
INI_DATA.substring(0, INI_DATA.length() - LINE_SEPARATOR.length())
+ "nolist = 1,2, 3";
load(config, data);
assertEquals("Wrong property value", "1,2, 3",
config.getString("section3.nolist"));
final String content = saveToString(config);
final INIConfiguration config2 = new INIConfiguration();
load(config2, content);
assertEquals("Wrong property value after reload", "1,2, 3",
config2.getString("section3.nolist"));
}
/**
* Test of load method, of class {@link INIConfiguration}.
*/
@Test
public void testLoad() throws Exception
{
checkLoad(INI_DATA);
}
/**
* Tests the load() method when the alternative value separator is used (a
* ':' for '=').
*/
@Test
public void testLoadAlternativeSeparator() throws Exception
{
checkLoad(INI_DATA.replace('=', ':'));
}
/**
* Tests whether an instance can be created using a file-based builder.
*/
@Test
public void testLoadFromBuilder() throws ConfigurationException,
IOException
{
final File file = writeTestFile(INI_DATA);
final FileBasedConfigurationBuilder<INIConfiguration> builder =
new FileBasedConfigurationBuilder<>(
INIConfiguration.class);
builder.configure(new FileBasedBuilderParametersImpl()
.setFile(file));
final INIConfiguration config = builder.getConfiguration();
checkContent(config);
}
/**
* Tests the values of some properties to ensure that the configuration was
* correctly loaded.
*
* @param instance the configuration to check
*/
private void checkContent(final INIConfiguration instance)
{
assertEquals("var1", "foo", instance.getString("section1.var1"));
assertEquals("var2", 451, instance.getInt("section1.var2"));
assertEquals("section2.var1", 123.45,
instance.getDouble("section2.var1"), .001);
assertEquals("section2.var2", "bar",
instance.getString("section2.var2"));
assertEquals("section3.var1", true,
instance.getBoolean("section3.var1"));
assertEquals("Wrong number of sections", 3, instance.getSections()
.size());
assertTrue(
"Wrong sections",
instance.getSections().containsAll(
Arrays.asList("section1", "section2", "section3")));
}
/**
* Helper method for testing the load operation. Loads the specified content
* into a configuration and then checks some properties.
*
* @param data the data to load
*/
private void checkLoad(final String data) throws ConfigurationException
{
final INIConfiguration instance = setUpConfig(data);
checkContent(instance);
}
/**
* Test of isCommentLine method, of class
* {@link INIConfiguration}.
*/
@Test
public void testIsCommentLine()
{
final INIConfiguration instance = new INIConfiguration();
assertTrue(instance.isCommentLine("#comment1"));
assertTrue(instance.isCommentLine(";comment1"));
assertFalse(instance.isCommentLine("nocomment=true"));
assertFalse(instance.isCommentLine(null));
}
/**
* Test of isSectionLine method, of class
* {@link INIConfiguration}.
*/
@Test
public void testIsSectionLine()
{
final INIConfiguration instance = new INIConfiguration();
assertTrue(instance.isSectionLine("[section]"));
assertFalse(instance.isSectionLine("nosection=true"));
assertFalse(instance.isSectionLine(null));
}
/**
* Test of getSections method, of class {@link INIConfiguration}
* .
*/
@Test
public void testGetSections()
{
final INIConfiguration instance = new INIConfiguration();
instance.addProperty("test1.foo", "bar");
instance.addProperty("test2.foo", "abc");
final Set<String> expResult = new HashSet<>();
expResult.add("test1");
expResult.add("test2");
final Set<String> result = instance.getSections();
assertEquals(expResult, result);
}
@Test
public void testQuotedValue() throws Exception
{
final INIConfiguration config = setUpConfig(INI_DATA2);
assertEquals("value", "quoted value", config.getString("section4.var1"));
}
@Test
public void testQuotedValueWithQuotes() throws Exception
{
final INIConfiguration config = setUpConfig(INI_DATA2);
assertEquals("value", "quoted value\\nwith \"quotes\"", config
.getString("section4.var2"));
}
@Test
public void testValueWithComment() throws Exception
{
final INIConfiguration config = setUpConfig(INI_DATA2);
assertEquals("value", "123", config.getString("section4.var3"));
}
@Test
public void testQuotedValueWithComment() throws Exception
{
final INIConfiguration config = setUpConfig(INI_DATA2);
assertEquals("value", "1;2;3", config.getString("section4.var4"));
}
@Test
public void testQuotedValueWithSingleQuotes() throws Exception
{
final INIConfiguration config = setUpConfig(INI_DATA2);
assertEquals("value", "'quoted' \"value\"", config
.getString("section4.var5"));
}
@Test
public void testWriteValueWithCommentChar() throws Exception
{
final INIConfiguration config = new INIConfiguration();
config.setProperty("section.key1", "1;2;3");
final StringWriter writer = new StringWriter();
config.write(writer);
final INIConfiguration config2 = new INIConfiguration();
config2.read(new StringReader(writer.toString()));
assertEquals("value", "1;2;3", config2.getString("section.key1"));
}
/**
* Tests whether whitespace is left unchanged for quoted values.
*/
@Test
public void testQuotedValueWithWhitespace() throws Exception
{
final String content = "CmdPrompt = \" [test@cmd ~]$ \"";
final INIConfiguration config = setUpConfig(content);
assertEquals("Wrong propert value", " [test@cmd ~]$ ", config
.getString("CmdPrompt"));
}
/**
* Tests a quoted value with space and a comment.
*/
@Test
public void testQuotedValueWithWhitespaceAndComment() throws Exception
{
final String content = "CmdPrompt = \" [test@cmd ~]$ \" ; a comment";
final INIConfiguration config = setUpConfig(content);
assertEquals("Wrong propert value", " [test@cmd ~]$ ", config
.getString("CmdPrompt"));
}
/**
* Tests an empty quoted value.
*/
@Test
public void testQuotedValueEmpty() throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA2);
assertEquals("Wrong value for empty property", "", config
.getString("section4.var6"));
}
/**
* Tests a property that has no value.
*/
@Test
public void testGetPropertyNoValue() throws ConfigurationException
{
final String data = INI_DATA2 + LINE_SEPARATOR + "noValue ="
+ LINE_SEPARATOR;
final INIConfiguration config = setUpConfig(data);
assertEquals("Wrong value of key", "", config
.getString("section4.noValue"));
}
/**
* Tests a property that has no key.
*/
@Test
public void testGetPropertyNoKey() throws ConfigurationException
{
final String data = INI_DATA2 + LINE_SEPARATOR + "= noKey"
+ LINE_SEPARATOR;
final INIConfiguration config = setUpConfig(data);
assertEquals("Cannot find property with no key", "noKey", config
.getString("section4. "));
}
/**
* Tests reading a property from the global section.
*/
@Test
public void testGlobalProperty() throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA_GLOBAL);
assertEquals("Wrong value of global property", "testGlobal", config
.getString("globalVar"));
}
/**
* Tests whether the sub configuration for the global section is connected
* to its parent.
*/
@Test
public void testGlobalSectionConnected() throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA_GLOBAL);
final HierarchicalConfiguration<ImmutableNode> sub = config.getSection(null);
config.setProperty("globalVar", "changed");
assertEquals("Wrong value in sub", "changed",
sub.getString("globalVar"));
}
/**
* Tests whether the specified configuration contains exactly the expected
* sections.
*
* @param config the configuration to check
* @param expected an array with the expected sections
*/
private void checkSectionNames(final INIConfiguration config,
final String[] expected)
{
final Set<String> sectionNames = config.getSections();
final Iterator<String> it = sectionNames.iterator();
for (int idx = 0; idx < expected.length; idx++)
{
assertEquals("Wrong section at " + idx, expected[idx], it.next());
}
assertFalse("Too many sections", it.hasNext());
}
/**
* Tests the names of the sections returned by the configuration.
*
* @param data the data of the ini configuration
* @param expected the expected section names
* @return the configuration instance
*/
private INIConfiguration checkSectionNames(final String data,
final String[] expected) throws ConfigurationException
{
final INIConfiguration config = setUpConfig(data);
checkSectionNames(config, expected);
return config;
}
/**
* Tests querying the sections if a global section if available.
*/
@Test
public void testGetSectionsWithGlobal() throws ConfigurationException
{
checkSectionNames(INI_DATA_GLOBAL, new String[]{
null, "section1", "section2", "section3"
});
}
/**
* Tests querying the sections if there is no global section.
*/
@Test
public void testGetSectionsNoGlobal() throws ConfigurationException
{
checkSectionNames(INI_DATA, new String[]{
"section1", "section2", "section3"
});
}
/**
* Tests whether the sections of a configuration can be queried that
* contains only a global section.
*/
@Test
public void testGetSectionsGlobalOnly() throws ConfigurationException
{
checkSectionNames(INI_DATA_GLOBAL_ONLY, new String[]{
null
});
}
/**
* Tests whether variables containing a dot are not misinterpreted as
* sections. This test is related to CONFIGURATION-327.
*/
@Test
public void testGetSectionsDottedVar() throws ConfigurationException
{
final String data = "dotted.var = 1" + LINE_SEPARATOR + INI_DATA_GLOBAL;
final INIConfiguration config = checkSectionNames(data,
new String[] {
null, "section1", "section2", "section3"
});
assertEquals("Wrong value of dotted variable", 1, config
.getInt("dotted..var"));
}
/**
* Tests whether a section added later is also found by getSections().
*/
@Test
public void testGetSectionsAdded() throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA2);
config.addProperty("section5.test", Boolean.TRUE);
checkSectionNames(config, new String[]{
"section4", "section5"
});
}
/**
* Tests querying the properties of an existing section.
*/
@Test
public void testGetSectionExisting() throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA);
final HierarchicalConfiguration<ImmutableNode> section =
config.getSection("section1");
assertEquals("Wrong value of var1", "foo", section.getString("var1"));
assertEquals("Wrong value of var2", "451", section.getString("var2"));
}
/**
* Tests whether the sub configuration returned by getSection() is connected
* to the parent.
*/
@Test
public void testGetSectionConnected() throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA);
final HierarchicalConfiguration<ImmutableNode> section =
config.getSection("section1");
section.setProperty("var1", "foo2");
assertEquals("Not connected to parent", "foo2",
config.getString("section1.var1"));
}
/**
* Tests querying the properties of a section that was merged from two
* sections with the same name.
*/
@Test
public void testGetSectionMerged() throws ConfigurationException
{
final String data = INI_DATA + "[section1]" + LINE_SEPARATOR
+ "var3 = merged" + LINE_SEPARATOR;
final INIConfiguration config = setUpConfig(data);
final HierarchicalConfiguration<ImmutableNode> section = config.getSection("section1");
assertEquals("Wrong value of var1", "foo", section.getString("var1"));
assertEquals("Wrong value of var2", "451", section.getString("var2"));
assertEquals("Wrong value of var3", "merged", section.getString("var3"));
}
/**
* Tests querying the content of the global section.
*/
@Test
public void testGetSectionGlobal() throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA_GLOBAL);
final HierarchicalConfiguration<ImmutableNode> section = config.getSection(null);
assertEquals("Wrong value of global variable", "testGlobal", section
.getString("globalVar"));
}
/**
* Tests concurrent access to the global section.
*/
@Test
public void testGetSectionGloabalMultiThreaded()
throws ConfigurationException, InterruptedException
{
final INIConfiguration config = setUpConfig(INI_DATA_GLOBAL);
config.setSynchronizer(new ReadWriteSynchronizer());
final int threadCount = 10;
final GlobalSectionTestThread[] threads = new GlobalSectionTestThread[threadCount];
for (int i = 0; i < threadCount; i++)
{
threads[i] = new GlobalSectionTestThread(config);
threads[i].start();
}
for (int i = 0; i < threadCount; i++)
{
threads[i].join();
assertFalse("Exception occurred", threads[i].error);
}
}
/**
* Tests querying the content of the global section if there is none.
*/
@Test
public void testGetSectionGlobalNonExisting() throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA);
final HierarchicalConfiguration<ImmutableNode> section = config.getSection(null);
assertTrue("Sub config not empty", section.isEmpty());
}
/**
* Tests querying a non existing section.
*/
@Test
public void testGetSectionNonExisting() throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA);
final HierarchicalConfiguration<ImmutableNode> section = config
.getSection("Non existing section");
assertTrue("Sub config not empty", section.isEmpty());
}
/**
* Tests a property whose value spans multiple lines.
*/
@Test
public void testLineContinuation() throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA3);
assertEquals("Wrong value", "one" + LINE_SEPARATOR + "two"
+ LINE_SEPARATOR + "three", config
.getString("section5.multiLine"));
}
/**
* Tests a property value that ends on a backslash, which is no line
* continuation character.
*/
@Test
public void testLineContinuationNone() throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA3);
assertEquals("Wrong value", "C:\\Temp\\", config
.getString("section5.singleLine"));
}
/**
* Tests a property whose value spans multiple lines when quoting is
* involved. In this case whitespace must not be trimmed.
*/
@Test
public void testLineContinuationQuoted() throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA3);
assertEquals("Wrong value", "one" + LINE_SEPARATOR + " two "
+ LINE_SEPARATOR + "three", config
.getString("section5.multiQuoted"));
}
/**
* Tests a property whose value spans multiple lines with a comment.
*/
@Test
public void testLineContinuationComment() throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA3);
assertEquals("Wrong value", "one" + LINE_SEPARATOR + "two", config
.getString("section5.multiComment"));
}
/**
* Tests a property with a quoted value spanning multiple lines and a
* comment.
*/
@Test
public void testLineContinuationQuotedComment()
throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA3);
assertEquals("Wrong value", " one " + LINE_SEPARATOR + "two", config
.getString("section5.multiQuotedComment"));
}
/**
* Tests a multi-line property value with an empty line.
*/
@Test
public void testLineContinuationEmptyLine() throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA3);
assertEquals("Wrong value", LINE_SEPARATOR + "line 2", config
.getString("section5.noFirstLine"));
}
/**
* Tests a line continuation at the end of the file.
*/
@Test
public void testLineContinuationAtEnd() throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA3);
assertEquals("Wrong value", "one" + LINE_SEPARATOR, config
.getString("section5.continueNoLine"));
}
/**
* Tests whether a configuration can be saved that contains section keys
* with delimiter characters. This test is related to CONFIGURATION-409.
*/
@Test
public void testSaveKeysWithDelimiters() throws ConfigurationException, IOException
{
INIConfiguration conf = new INIConfiguration();
final String section = "Section..with..dots";
conf.addProperty(section + ".test1", "test1");
conf.addProperty(section + ".test2", "test2");
final StringWriter writer = new StringWriter();
conf.write(writer);
conf = new INIConfiguration();
conf.read(new StringReader(writer.toString()));
assertEquals("Wrong value (1)", "test1", conf.getString(section + ".test1"));
assertEquals("Wrong value (2)", "test2", conf.getString(section + ".test2"));
}
/**
* Tests that loading and saving a configuration that contains keys with
* delimiter characters works correctly. This test is related to
* CONFIGURATION-622.
*/
@Test
public void testPropertyWithDelimiter() throws ConfigurationException
{
final String data = INI_DATA + "key.dot = dotValue";
final INIConfiguration conf = new INIConfiguration();
load(conf, data);
assertEquals("Wrong property value", "dotValue",
conf.getString("section3.key..dot"));
final String output = saveToString(conf);
assertThat(output, containsString("key.dot = dotValue"));
}
/**
* Tests whether a value which contains a semicolon can be loaded
* successfully. This test is related to CONFIGURATION-434.
*/
@Test
public void testValueWithSemicolon() throws ConfigurationException
{
final String path =
"C:\\Program Files\\jar\\manage.jar;"
+ "C:\\Program Files\\jar\\guiLauncher.jar";
final String content =
"[Environment]" + LINE_SEPARATOR + "Application Type=any"
+ LINE_SEPARATOR + "Class Path=" + path + " ;comment"
+ LINE_SEPARATOR + "Path=" + path
+ "\t; another comment";
final INIConfiguration config = setUpConfig(content);
assertEquals("Wrong class path", path,
config.getString("Environment.Class Path"));
assertEquals("Wrong path", path, config.getString("Environment.Path"));
}
/**
* Tests whether the different separators with or without whitespace are
* recognized.
*/
@Test
public void testSeparators() throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA_SEPARATORS);
for (int i = 1; i <= 4; i++)
{
assertEquals("Wrong value", "value" + i,
config.getString("section.var" + i));
}
}
/**
* Tests property definitions containing multiple separators.
*/
@Test
public void testMultipleSeparators() throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA_SEPARATORS);
assertEquals("Wrong value for var5", "value=5",
config.getString("section.var5"));
assertEquals("Wrong value for var6", "6=value",
config.getString("section.var"));
}
/**
* Tests property definitions containing multiple separators that are
* quoted.
*/
@Test
public void testMultipleSeparatorsQuoted() throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA_SEPARATORS);
assertEquals("Wrong value for var7", "value7",
config.getString("section.var:7"));
assertEquals("Wrong value for var8", "value8",
config.getString("section.var:8"));
}
/**
* Tests whether a section that has been cleared can be manipulated and
* saved later.
*/
@Test
public void testSaveClearedSection() throws ConfigurationException, IOException
{
final String data = "[section]\ntest = failed\n";
final INIConfiguration config = setUpConfig(data);
SubnodeConfiguration sub = config.getSection("section");
assertFalse("No content", sub.isEmpty());
sub.clear();
sub.close();
sub = config.getSection("section");
sub.setProperty("test", "success");
final StringWriter writer = new StringWriter();
config.write(writer);
final HierarchicalConfiguration<?> config2 = setUpConfig(writer.toString());
assertEquals("Wrong value", "success",
config2.getString("section.test"));
}
/**
* Tests whether a duplicate session is merged.
*/
@Test
public void testMergeDuplicateSection() throws ConfigurationException, IOException
{
final String data =
"[section]\nvar1 = sec1\n\n" + "[section]\nvar2 = sec2\n";
final INIConfiguration config = setUpConfig(data);
assertEquals("Wrong value 1", "sec1", config.getString("section.var1"));
assertEquals("Wrong value 2", "sec2", config.getString("section.var2"));
final HierarchicalConfiguration<ImmutableNode> sub = config.getSection("section");
assertEquals("Wrong sub value 1", "sec1", sub.getString("var1"));
assertEquals("Wrong sub value 2", "sec2", sub.getString("var2"));
final StringWriter writer = new StringWriter();
config.write(writer);
final String content = writer.toString();
final int pos = content.indexOf("[section]");
assertTrue("Section not found: " + content, pos >= 0);
assertTrue("Section found multiple times: " + content,
content.indexOf("[section]", pos + 1) < 0);
}
/**
* Tests whether a section that was created by getSection() can be
* manipulated.
*/
@Test
public void testGetSectionNonExistingManipulate()
throws ConfigurationException, IOException
{
final INIConfiguration config = setUpConfig(INI_DATA);
HierarchicalConfiguration<ImmutableNode> section = config.getSection("newSection");
section.addProperty("test", "success");
assertEquals("Main config not updated", "success",
config.getString("newSection.test"));
final StringWriter writer = new StringWriter();
config.write(writer);
final INIConfiguration config2 = setUpConfig(writer.toString());
section = config2.getSection("newSection");
assertEquals("Wrong value", "success", section.getString("test"));
}
/**
* Tests whether getSection() can deal with duplicate sections.
*/
@Test
public void testGetSectionDuplicate()
{
final INIConfiguration config =
new INIConfiguration();
config.addProperty("section.var1", "value1");
config.addProperty("section(-1).var2", "value2");
final HierarchicalConfiguration<ImmutableNode> section = config.getSection("section");
final Iterator<String> keys = section.getKeys();
assertEquals("Wrong key", "var1", keys.next());
assertFalse("Too many keys", keys.hasNext());
}
/**
* Tests whether the list delimiter character is recognized.
*/
@Test
public void testValueWithDelimiters() throws ConfigurationException
{
final INIConfiguration config =
setUpConfig("[test]" + LINE_SEPARATOR + "list=1,2,3"
+ LINE_SEPARATOR);
final List<Object> list = config.getList("test.list");
assertEquals("Wrong number of elements", 3, list.size());
assertEquals("Wrong element at 1", "1", list.get(0));
assertEquals("Wrong element at 2", "2", list.get(1));
assertEquals("Wrong element at 3", "3", list.get(2));
}
/**
* Tests whether parsing of lists can be disabled.
*/
@Test
public void testListParsingDisabled() throws ConfigurationException
{
final INIConfiguration config =
new INIConfiguration();
load(config, "[test]" + LINE_SEPARATOR + "nolist=1,2,3");
assertEquals("Wrong value", "1,2,3", config.getString("test.nolist"));
}
/**
* Tests whether synchronization is performed when querying the
* configuration's sections.
*/
@Test
public void testGetSectionsSynchronized() throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA);
final SynchronizerTestImpl sync = new SynchronizerTestImpl();
config.setSynchronizer(sync);
assertFalse("No sections", config.getSections().isEmpty());
sync.verify(Methods.BEGIN_READ, Methods.END_READ);
}
/**
* Tests whether the configuration deals correctly with list delimiters.
*/
@Test
public void testListDelimiterHandling() throws ConfigurationException
{
final INIConfiguration config = new INIConfiguration();
config.setListDelimiterHandler(new DefaultListDelimiterHandler(','));
config.addProperty("list", "a,b,c");
config.addProperty("listesc", "3\\,1415");
final String output = saveToString(config);
final INIConfiguration config2 = setUpConfig(output);
assertEquals("Wrong list size", 3, config2.getList("list").size());
assertEquals("Wrong list element", "b", config2.getList("list").get(1));
assertEquals("Wrong escaped list element", "3,1415",
config2.getString("listesc"));
}
/**
* Tests whether property values are correctly escaped even if they are part
* of a property with multiple values.
*/
@Test
public void testListDelimiterHandlingInList() throws ConfigurationException
{
final String data =
INI_DATA + "[sectest]" + LINE_SEPARATOR
+ "list = 3\\,1415,pi,\\\\Test\\,5" + LINE_SEPARATOR;
final INIConfiguration config = setUpConfig(data);
final INIConfiguration config2 = setUpConfig(saveToString(config));
final List<Object> list = config2.getList("sectest.list");
assertEquals("Wrong number of values", 3, list.size());
assertEquals("Wrong element 1", "3,1415", list.get(0));
assertEquals("Wrong element 3", "\\Test,5", list.get(2));
}
/**
* Tests whether only properties with values occur in the enumeration of the
* global section.
*/
@Test
public void testKeysOfGlobalSection() throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA_GLOBAL);
final HierarchicalConfiguration<ImmutableNode> sub = config.getSection(null);
final Iterator<String> keys = sub.getKeys();
assertEquals("Wrong key", "globalVar", keys.next());
if (keys.hasNext())
{
final StringBuilder buf = new StringBuilder();
do
{
buf.append(keys.next()).append(' ');
} while (keys.hasNext());
fail("Got additional keys: " + buf);
}
}
/**
* Tests whether the node handler of a global section correctly filters
* named children.
*/
@Test
public void testGlobalSectionNodeHandlerGetChildrenByName()
throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA_GLOBAL);
final SubnodeConfiguration sub = config.getSection(null);
final NodeHandler<ImmutableNode> handler = sub.getModel().getNodeHandler();
assertTrue(
"Sections not filtered",
handler.getChildren(
sub.getModel().getNodeHandler().getRootNode(),
"section1").isEmpty());
}
/**
* Tests whether the node handler of a global section correctly determines
* the number of children.
*/
@Test
public void testGlobalSectionNodeHandlerGetChildrenCount()
throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA_GLOBAL);
final SubnodeConfiguration sub = config.getSection(null);
final NodeHandler<ImmutableNode> handler = sub.getModel().getNodeHandler();
assertEquals("Wrong number of children", 1,
handler.getChildrenCount(handler.getRootNode(), null));
}
/**
* Tests whether the node handler of a global section correctly returns a
* child by index.
*/
@Test
public void testGlobalSectionNodeHandlerGetChildByIndex()
throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA_GLOBAL);
final SubnodeConfiguration sub = config.getSection(null);
final NodeHandler<ImmutableNode> handler = sub.getModel().getNodeHandler();
final ImmutableNode child = handler.getChild(handler.getRootNode(), 0);
assertEquals("Wrong child", "globalVar", child.getNodeName());
try
{
handler.getChild(handler.getRootNode(), 1);
fail("Could obtain child with invalid index!");
}
catch (final IndexOutOfBoundsException iex)
{
// ok
}
}
/**
* Tests whether the node handler of a global section correctly determines
* the index of a child.
*/
@Test
public void testGlobalSectionNodeHandlerIndexOfChild()
throws ConfigurationException
{
final INIConfiguration config = setUpConfig(INI_DATA_GLOBAL);
final SubnodeConfiguration sub = config.getSection(null);
final NodeHandler<ImmutableNode> handler = sub.getModel().getNodeHandler();
final List<ImmutableNode> children = handler.getRootNode().getChildren();
assertEquals("Wrong index", 0,
handler.indexOfChild(handler.getRootNode(), children.get(0)));
assertEquals("Wrong index of section child", -1,
handler.indexOfChild(handler.getRootNode(), children.get(1)));
}
/**
* Tests whether an expression engine can be used which ignores case.
*/
@Test
public void testExpressionEngineIgnoringCase()
throws ConfigurationException
{
final DefaultExpressionEngine engine =
new DefaultExpressionEngine(
DefaultExpressionEngineSymbols.DEFAULT_SYMBOLS,
NodeNameMatchers.EQUALS_IGNORE_CASE);
final INIConfiguration config = new INIConfiguration();
config.setExpressionEngine(engine);
load(config, INI_DATA);
checkContent(config);
assertEquals("Wrong result (1)", "foo",
config.getString("Section1.var1"));
assertEquals("Wrong result (2)", "foo",
config.getString("section1.Var1"));
assertEquals("Wrong result (1)", "foo",
config.getString("SECTION1.VAR1"));
}
/**
* Tests whether an empty section can be saved. This is related to
* CONFIGURATION-671.
*/
@Test
public void testWriteEmptySection()
throws ConfigurationException, IOException
{
final String section = "[EmptySection]";
final INIConfiguration config = setUpConfig(section);
assertEquals("Wrong number of sections", 1,
config.getSections().size());
assertTrue("Section not found",
config.getSections().contains("EmptySection"));
final StringWriter writer = new StringWriter();
config.write(writer);
assertEquals("Wrong saved configuration",
section + LINE_SEPARATOR + LINE_SEPARATOR, writer.toString());
}
/**
* A thread class for testing concurrent access to the global section.
*/
private static class GlobalSectionTestThread extends Thread
{
/** The configuration. */
private final INIConfiguration config;
/** A flag whether an error was found. */
volatile boolean error;
/**
* Creates a new instance of {@code GlobalSectionTestThread} and
* initializes it.
*
* @param conf the configuration object
*/
public GlobalSectionTestThread(final INIConfiguration conf)
{
config = conf;
}
/**
* Accesses the global section in a loop. If there is no correct
* synchronization, this can cause an exception.
*/
@Override
public void run()
{
final int loopCount = 250;
for (int i = 0; i < loopCount && !error; i++)
{
try
{
config.getSection(null);
}
catch (final IllegalStateException istex)
{
error = true;
}
}
}
}
}