From fda7ee37e539047db1f358ae8fa2fc4f05dfc8d2 Mon Sep 17 00:00:00 2001 From: Michael Crawford Date: Fri, 12 Jun 2015 15:20:42 -0400 Subject: [PATCH 1/2] Added TryGetKey/GetKey to IniData --- .../Unit/Model/INIDataTests.cs | 94 +++++++++++++++++++ .../Configuration/IniParserConfiguration.cs | 14 ++- src/IniFileParser/Model/IniData.cs | 68 ++++++++++++++ 3 files changed, 175 insertions(+), 1 deletion(-) diff --git a/src/IniFileParser.Tests/Unit/Model/INIDataTests.cs b/src/IniFileParser.Tests/Unit/Model/INIDataTests.cs index 2728417b..bee7f8df 100644 --- a/src/IniFileParser.Tests/Unit/Model/INIDataTests.cs +++ b/src/IniFileParser.Tests/Unit/Model/INIDataTests.cs @@ -45,6 +45,100 @@ public void check_add_keydata_method_using_key_and_value_strings() Assert.That(newData["newSection"]["newKey1"], Is.EqualTo("value1")); } + + [Test, Description("Tests preconditions for TryGetKey")] + public void TryGetKey_preconditions() + { + var data = new IniDataParser().Parse(""); + var separator = data.Configuration.SectionKeySeparator; + string result; + + // ensure that various good keys aren't rejected + var goodKey = ""; + Assert.DoesNotThrow(() => data.TryGetKey(goodKey, out result)); + goodKey = "key"; + Assert.DoesNotThrow(() => data.TryGetKey(goodKey, out result)); + goodKey = string.Format("section{0}key", separator); + Assert.DoesNotThrow(() => data.TryGetKey(goodKey, out result)); + + // should be rejected + var badKey = string.Format("section{0}subsection{0}key", separator); + Assert.Throws(() => data.TryGetKey(badKey, out result)); + } + + [Test, Description("Tests retrieving data with TryGetKey")] + public void TryGetKey_data_retrieval() + { + var input = @" +global = 1 +[section1] +key1 = 2 + +[section1\subsection] +key2 = 3 +"; + var data = new IniDataParser().Parse(input); + var separator = data.Configuration.SectionKeySeparator; + string key; + string result; + + // keys should all be retrieved + Assert.IsTrue(data.TryGetKey("global", out result)); + Assert.AreEqual(result, "1"); + + key = string.Format("section1{0}key1", separator); + Assert.IsTrue(data.TryGetKey(key, out result)); + Assert.AreEqual(result, "2"); + + key = string.Format(@"section1\subsection{0}key2", separator); + Assert.IsTrue(data.TryGetKey(key, out result)); + Assert.AreEqual(result, "3"); + + // invalid keys should fail... + Assert.IsFalse(data.TryGetKey(null, out result)); + Assert.That(result, Is.Empty); + + Assert.IsFalse(data.TryGetKey("", out result)); + Assert.That(result, Is.Empty); + + Assert.IsFalse(data.TryGetKey("badglobal", out result)); + Assert.That(result, Is.Empty); + + key = string.Format("badsection{0}badkey", separator); + Assert.IsFalse(data.TryGetKey(key, out result)); + Assert.That(result, Is.Empty); + } + + // GetKey shares preconditions with TryGetKey, so tests are not duplicated + [Test, Description("Tests retrieving data with GetKey")] + public void GeyKey_data_retrieval() + { + var input = @" +global = 1 +[section] +key = 2 +"; + var data = new IniDataParser().Parse(input); + var separator = data.Configuration.SectionKeySeparator; + string key; + + // should succeed + key = "global"; + Assert.AreEqual(data.GetKey(key), "1"); + + key = string.Format("section{0}key", separator); + Assert.AreEqual(data.GetKey(key), "2"); + + // should fail + key = null; + Assert.IsNull(data.GetKey(key)); + + key = "badglobal"; + Assert.IsNull(data.GetKey(key)); + + key = string.Format("badsection{0}badkey", separator); + Assert.IsNull(data.GetKey(key)); + } } } diff --git a/src/IniFileParser/Model/Configuration/IniParserConfiguration.cs b/src/IniFileParser/Model/Configuration/IniParserConfiguration.cs index dc8c1521..534cb04a 100644 --- a/src/IniFileParser/Model/Configuration/IniParserConfiguration.cs +++ b/src/IniFileParser/Model/Configuration/IniParserConfiguration.cs @@ -57,6 +57,7 @@ public IniParserConfiguration() AllowDuplicateSections = false; ThrowExceptionsOnError = true; SkipInvalidLines = false; + SectionKeySeparator = ':'; } /// @@ -77,7 +78,9 @@ public IniParserConfiguration(IniParserConfiguration ori) CommentString = ori.CommentString; ThrowExceptionsOnError = ori.ThrowExceptionsOnError; - // Regex values should recreate themselves. + SectionKeySeparator = ori.SectionKeySeparator; + + // Regex values should recreate themselves. } #endregion @@ -251,6 +254,15 @@ public string CommentString public bool SkipInvalidLines { get; set; } + /// + /// Used to mark the separation between the section name and the key name + /// when using . + /// + /// + /// Defaults to ':'. + /// + public char SectionKeySeparator { get; set; } + #endregion #region Fields diff --git a/src/IniFileParser/Model/IniData.cs b/src/IniFileParser/Model/IniData.cs index e4249fe1..addf3ea7 100644 --- a/src/IniFileParser/Model/IniData.cs +++ b/src/IniFileParser/Model/IniData.cs @@ -1,4 +1,5 @@ using System; +using System.Net; using IniParser.Model.Configuration; using IniParser.Model.Formatting; @@ -171,6 +172,73 @@ public void Merge(IniData toMergeIniData) } + /// + /// Attempts to retrieve a key, using a single string combining section and + /// key name. + /// + /// + /// The section and key name to retrieve, separated by . + /// + /// If key contains no separator, it is treated as a key in the section. + /// + /// Key may contain no more than one separator character. + /// + /// + /// If true is returned, is set to the value retrieved. Otherwise, is set + /// to an empty string. + /// + /// + /// True if key was found, otherwise false. + /// + /// + /// key contained multiple separators. + /// + public bool TryGetKey(string key, out string value) + { + value = string.Empty; + if (string.IsNullOrEmpty(key)) return false; + + var splitKey = key.Split(Configuration.SectionKeySeparator); + var separatorCount = splitKey.Length - 1; + if (separatorCount > 1) + throw new ArgumentException("key contains multiple separators", "key"); + + if (separatorCount == 0) + { + if (!Global.ContainsKey(key)) return false; + + value = Global[key]; + return true; + } + + var section = splitKey[0]; + key = splitKey[1]; + + if (!_sections.ContainsSection(section)) return false; + var sectionData = _sections[section]; + if (!sectionData.ContainsKey(key)) return false; + + value = sectionData[key]; + return true; + } + + /// + /// Retrieves a key using a single input string combining section and key name. + /// + /// + /// The section and key name to retrieve, separated by . + /// + /// Has the same requirements as the key parameter of + /// + /// + /// The key's value if it was found, otherwise null. + /// + public string GetKey(string key) + { + string result; + return TryGetKey(key, out result) ? result : null; + } + /// /// Merge the sections into this by overwriting this sections. /// From 9d9f6cdf4288d76d28fac48fcf95a337bf32aec6 Mon Sep 17 00:00:00 2001 From: Michael Crawford Date: Fri, 19 Jun 2015 12:07:25 -0400 Subject: [PATCH 2/2] Tweaked commenting --- src/IniFileParser/Model/IniData.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/IniFileParser/Model/IniData.cs b/src/IniFileParser/Model/IniData.cs index addf3ea7..5f78ed2f 100644 --- a/src/IniFileParser/Model/IniData.cs +++ b/src/IniFileParser/Model/IniData.cs @@ -228,11 +228,16 @@ public bool TryGetKey(string key, out string value) /// /// The section and key name to retrieve, separated by . /// - /// Has the same requirements as the key parameter of + /// If key contains no separator, it is treated as a key in the section. + /// + /// Key may contain no more than one separator character. /// /// /// The key's value if it was found, otherwise null. /// + /// + /// key contained multiple separators. + /// public string GetKey(string key) { string result;