Configuration file parsing should be complete now (but creation and changing not so much)
git-svn-id: file:///srv/devel/repo-conversion/nusu@303 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
parent
7e39bd684f
commit
0753aeb220
|
@ -116,7 +116,7 @@ namespace Nuclex.Support.Settings {
|
|||
if(nameStartIndex >= lastCharacterIndex) {
|
||||
return; // No space left for closing brace
|
||||
}
|
||||
|
||||
|
||||
int nameEndIndex = line.IndexOf(']', nameStartIndex);
|
||||
if(nameEndIndex == -1) {
|
||||
return; // No closing brace in line
|
||||
|
@ -163,15 +163,10 @@ namespace Nuclex.Support.Settings {
|
|||
LineIndex = state.Store.lines.Count - 1,
|
||||
OptionName = new StringSegment(
|
||||
line, firstCharacterIndex, nameEndIndex - firstCharacterIndex + 1
|
||||
),
|
||||
)
|
||||
};
|
||||
|
||||
// If there is a value in this assignment, parse it too
|
||||
int valueStartIndex = assignmentIndex + 1;
|
||||
ParserHelper.SkipSpaces(line, ref valueStartIndex);
|
||||
if(valueStartIndex < line.Length) {
|
||||
parseOptionValue(option, line, valueStartIndex);
|
||||
}
|
||||
parseOptionValue(option, line, assignmentIndex + 1);
|
||||
|
||||
// We've got the option assignment, either with an empty or proper value
|
||||
state.Store.options.Add(option);
|
||||
|
@ -181,9 +176,54 @@ namespace Nuclex.Support.Settings {
|
|||
/// <summary>Parses the value assigned to an option</summary>
|
||||
/// <param name="option">Option to which a value is being assigned</param>
|
||||
/// <param name="line">Line containing the option assignment</param>
|
||||
/// <param name="valueStartIndex">Index of the value's first character</param>
|
||||
private static void parseOptionValue(Option option, string line, int valueStartIndex) {
|
||||
|
||||
/// <param name="assignmentEndIndex">Index one after the assignment character</param>
|
||||
private static void parseOptionValue(Option option, string line, int assignmentEndIndex) {
|
||||
int firstCharacterIndex = assignmentEndIndex;
|
||||
ParserHelper.SkipSpaces(line, ref firstCharacterIndex);
|
||||
|
||||
// Just for beauty, when the option value is empty but padded with spaces,
|
||||
// leave one space between the equals sign and the value.
|
||||
if(firstCharacterIndex > assignmentEndIndex) {
|
||||
++assignmentEndIndex;
|
||||
}
|
||||
|
||||
// If the line consists of only whitespace, create an empty value
|
||||
if(firstCharacterIndex == line.Length) {
|
||||
option.OptionValue = new StringSegment(line, assignmentEndIndex, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
char firstCharacter = line[firstCharacterIndex];
|
||||
|
||||
// Values can be quoted to allow for comments characters appearing in them
|
||||
int lastCharacterIndex;
|
||||
if(firstCharacter == '"') {
|
||||
lastCharacterIndex = line.LastIndexOf('"');
|
||||
} else {
|
||||
lastCharacterIndex = firstCharacterIndex;
|
||||
}
|
||||
|
||||
int commentStartIndex = line.IndexOf(';', lastCharacterIndex);
|
||||
if(commentStartIndex == -1) {
|
||||
commentStartIndex = line.IndexOf('#', lastCharacterIndex);
|
||||
}
|
||||
if(commentStartIndex == -1) {
|
||||
lastCharacterIndex = line.Length - 1;
|
||||
} else {
|
||||
lastCharacterIndex = commentStartIndex - 1;
|
||||
}
|
||||
|
||||
while(lastCharacterIndex > firstCharacterIndex) {
|
||||
if(char.IsWhiteSpace(line, lastCharacterIndex)) {
|
||||
--lastCharacterIndex;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
option.OptionValue = new StringSegment(
|
||||
line, firstCharacterIndex, lastCharacterIndex - firstCharacterIndex + 1
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>Determines the best matching type for an option value</summary>
|
||||
|
|
|
@ -21,10 +21,10 @@ License along with this library
|
|||
#if UNITTEST
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Nuclex.Support.Settings {
|
||||
|
||||
|
@ -32,6 +32,9 @@ namespace Nuclex.Support.Settings {
|
|||
[TestFixture]
|
||||
internal class ConfigurationFileStoreTest {
|
||||
|
||||
/// <summary>Loads a configuration file from a string</summary>
|
||||
/// <param name="fileContents">Contents of the configuration file</param>
|
||||
/// <returns>The configuration file loaded from the string</returns>
|
||||
private static ConfigurationFileStore load(string fileContents) {
|
||||
using(var reader = new StringReader(fileContents)) {
|
||||
return ConfigurationFileStore.Parse(reader);
|
||||
|
@ -128,11 +131,84 @@ namespace Nuclex.Support.Settings {
|
|||
|
||||
for(int index = 0; index < options.Count; ++index) {
|
||||
Assert.That(
|
||||
configurationFile.Get<string>(null, options[index].Name), Is.Null
|
||||
configurationFile.Get<string>(null, options[index].Name), Is.Null.Or.Empty
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that values assigned to options can contain space charcters
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void OptionValuesCanContainSpaces() {
|
||||
string fileContents =
|
||||
"test = hello world";
|
||||
ConfigurationFileStore configurationFile = load(fileContents);
|
||||
|
||||
Assert.That(configurationFile.Get<string>(null, "test"), Is.EqualTo("hello world"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that values enclosed in quotes can embed comment characters
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void OptionValuesWithQuotesCanEmbedComments() {
|
||||
string fileContents =
|
||||
"test = \"This ; is # not a comment\" # but this is";
|
||||
ConfigurationFileStore configurationFile = load(fileContents);
|
||||
|
||||
Assert.That(
|
||||
configurationFile.Get<string>(null, "test"),
|
||||
Is.EqualTo("\"This ; is # not a comment\"")
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that values can end on a quote without causing trouble
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void CommentsCanEndWithAQuote() {
|
||||
string fileContents =
|
||||
"test = \"This value ends with a quote\"";
|
||||
ConfigurationFileStore configurationFile = load(fileContents);
|
||||
|
||||
Assert.That(
|
||||
configurationFile.Get<string>(null, "test"),
|
||||
Is.EqualTo("\"This value ends with a quote\"")
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that values can forget the closing quote without causing trouble
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void ClosingQuoteCanBeOmmitted() {
|
||||
string fileContents =
|
||||
"test = \"No closing quote";
|
||||
ConfigurationFileStore configurationFile = load(fileContents);
|
||||
|
||||
Assert.That(
|
||||
configurationFile.Get<string>(null, "test"),
|
||||
Is.EqualTo("\"No closing quote")
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that text placed after the closing quote will also be part of
|
||||
/// an option's value
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TextAfterClosingQuoteBecomesPartOfValue() {
|
||||
string fileContents =
|
||||
"test = \"Begins here\" end ends here";
|
||||
ConfigurationFileStore configurationFile = load(fileContents);
|
||||
|
||||
Assert.That(
|
||||
configurationFile.Get<string>(null, "test"),
|
||||
Is.EqualTo("\"Begins here\" end ends here")
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Settings
|
||||
|
|
|
@ -21,8 +21,6 @@ License along with this library
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using Nuclex.Support.Parsing;
|
||||
using System.Text;
|
||||
|
||||
namespace Nuclex.Support.Settings {
|
||||
|
|
Loading…
Reference in New Issue
Block a user