Skip to content

Commit 9f4545f

Browse files
committed
Improve test coverage
1 parent cd52736 commit 9f4545f

File tree

7 files changed

+245
-2
lines changed

7 files changed

+245
-2
lines changed

Src/SharpConfig.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,10 @@
5454
</None>
5555
</ItemGroup>
5656

57+
<ItemGroup>
58+
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
59+
<_Parameter1>Tests</_Parameter1>
60+
</AssemblyAttribute>
61+
</ItemGroup>
62+
5763
</Project>

Tests/ExceptionsTest.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) 2013-2025 Cem Dervis, MIT License.
2+
// https://sharpconfig.org
3+
4+
using System;
5+
using NUnit.Framework;
6+
7+
namespace SharpConfig
8+
{
9+
[TestFixture]
10+
public sealed class ExceptionsTest
11+
{
12+
[Test]
13+
public void ParserException()
14+
{
15+
var ex = new ParserException("Some Message", 123);
16+
Assert.AreEqual("Line 123: Some Message", ex.Message);
17+
Assert.AreEqual(123, ex.Line);
18+
}
19+
}
20+
}

Tests/InvalidInputTest.cs

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// Copyright (c) 2013-2025 Cem Dervis, MIT License.
2+
// https://sharpconfig.org
3+
4+
using NUnit.Framework;
5+
using SharpConfig;
6+
7+
namespace Tests
8+
{
9+
internal sealed class DummyClass
10+
{
11+
public int Value;
12+
}
13+
14+
internal sealed class DummyTypeStringConverter : ITypeStringConverter
15+
{
16+
public Type ConvertibleType => typeof(DummyClass);
17+
18+
public string ConvertToString(object value)
19+
{
20+
return (value as DummyClass)!.Value.ToString();
21+
}
22+
23+
public object? TryConvertFromString(string value, Type hint)
24+
{
25+
return int.TryParse(value, out int result) ? new DummyClass { Value = result } : null;
26+
}
27+
}
28+
29+
[TestFixture]
30+
public sealed class InvalidInputTest
31+
{
32+
[Test]
33+
public void ConfigLoading()
34+
{
35+
var cfg = new Configuration();
36+
37+
Assert.Throws<ArgumentNullException>(() => Configuration.LoadFromFile(null));
38+
Assert.Throws<FileNotFoundException>(() => Configuration.LoadFromFile("doesnotexist.ini"));
39+
Assert.Throws<ArgumentNullException>(() => Configuration.LoadFromStream(null));
40+
Assert.Throws<ArgumentNullException>(() => Configuration.LoadFromString(null));
41+
Assert.Throws<ArgumentNullException>(() => Configuration.LoadFromBinaryFile(null));
42+
Assert.Throws<ArgumentNullException>(() => Configuration.LoadFromBinaryStream(null));
43+
Assert.Throws<ArgumentNullException>(() => cfg.SaveToFile(null));
44+
Assert.Throws<ArgumentNullException>(() => cfg.SaveToStream(null));
45+
Assert.Throws<ArgumentNullException>(() => cfg.SaveToBinaryFile(null));
46+
Assert.Throws<ArgumentNullException>(() => cfg.SaveToBinaryStream(null));
47+
}
48+
49+
[Test]
50+
public void EmptyObjects()
51+
{
52+
Assert.Throws<ArgumentNullException>(() => new Setting(null));
53+
Assert.Throws<ArgumentNullException>(() => new Section(null));
54+
}
55+
56+
[Test]
57+
public void Options()
58+
{
59+
Assert.Throws<ArgumentNullException>(() => Configuration.CultureInfo = null);
60+
Assert.Throws<ArgumentException>(() => Configuration.PreferredCommentChar = 'a');
61+
Assert.Throws<ArgumentException>(() => Configuration.ArrayElementSeparator = '\0');
62+
}
63+
64+
[Test]
65+
public void ConfigSectionOperations()
66+
{
67+
var cfg = new Configuration();
68+
Assert.Throws<ArgumentNullException>(() => cfg.Add((Section)null));
69+
70+
var section = new Section("SomeSection");
71+
Assert.DoesNotThrow(() => cfg.Add(section));
72+
73+
Assert.Throws<ArgumentException>(() => cfg.Add(section));
74+
75+
Assert.Throws<ArgumentNullException>(() => cfg.Remove((string)null));
76+
Assert.DoesNotThrow(() => cfg.Remove("SomeSection"));
77+
78+
Assert.Throws<ArgumentNullException>(() => cfg.RemoveAllNamed((string)null));
79+
Assert.Throws<ArgumentNullException>(() => cfg.Contains((string)null));
80+
Assert.Throws<ArgumentNullException>(() => cfg.Contains("A", null));
81+
Assert.Throws<ArgumentNullException>(() => cfg.Contains(null, "B"));
82+
Assert.DoesNotThrow(() => cfg.Contains("A", "B"));
83+
84+
Assert.DoesNotThrow(() => cfg.Add("SomeSection"));
85+
86+
Assert.DoesNotThrow(() => cfg[0].ToString());
87+
Assert.Throws<ArgumentOutOfRangeException>(() => cfg[-1].ToString());
88+
}
89+
90+
[Test]
91+
public void Sections()
92+
{
93+
var section = new Section("SomeSection");
94+
section.Add("S");
95+
96+
Assert.Throws<ArgumentException>(() => Section.FromObject(null, 1));
97+
Assert.Throws<ArgumentNullException>(() => Section.FromObject("A", null));
98+
Assert.Throws<ArgumentNullException>(() => section.ToObject(null));
99+
Assert.Throws<ArgumentNullException>(() => section.GetValuesFrom(null));
100+
Assert.Throws<ArgumentNullException>(() => section.SetValuesTo(null));
101+
Assert.Throws<ArgumentNullException>(() => section.Remove((string)null));
102+
Assert.Throws<ArgumentNullException>(() => section.Remove((Setting)null));
103+
Assert.Throws<ArgumentNullException>(() => section.Remove(""));
104+
Assert.Throws<ArgumentNullException>(() => section.RemoveAllNamed(null));
105+
Assert.Throws<ArgumentNullException>(() => section.Contains((string)null));
106+
Assert.DoesNotThrow(() => section[0].ToString());
107+
Assert.Throws<ArgumentOutOfRangeException>(() => section[-1].ToString());
108+
Assert.Throws<ArgumentOutOfRangeException>(() => section[1].ToString());
109+
}
110+
111+
[Test]
112+
public void TypeStringConverterRegistration()
113+
{
114+
Assert.Throws<ArgumentNullException>(() => Configuration.RegisterTypeStringConverter(null));
115+
116+
var converter = new DummyTypeStringConverter();
117+
Assert.DoesNotThrow(() => Configuration.RegisterTypeStringConverter(converter));
118+
119+
Assert.Throws<InvalidOperationException>(() => Configuration.RegisterTypeStringConverter(converter));
120+
121+
Assert.Throws<ArgumentNullException>(() => Configuration.DeregisterTypeStringConverter(null));
122+
Assert.DoesNotThrow(() => Configuration.DeregisterTypeStringConverter(typeof(DummyClass)));
123+
Assert.Throws<InvalidOperationException>(() => Configuration.DeregisterTypeStringConverter(typeof(DummyClass)));
124+
125+
Assert.Throws<ArgumentNullException>(() => Configuration.FindTypeStringConverter(null));
126+
}
127+
}
128+
}

Tests/MultilineValuesTest.txt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
[Section]
2+
MultilineValue1=[[
3+
Line1
4+
Line2
5+
Line3 (indented)
6+
"Line4 with quote at start
7+
Line5 with quote at end"
8+
Line6 with " in the middle
9+
Line7 with "" in the middle
10+
""
11+
]]
12+
13+
SomeSetting=SomeValue
14+
15+
MultlineValue2ButInASingleLine=[[This is one \n line, verbatim]]
16+
17+
RegexPattern=[[
18+
IP\s*Address(?!s)
19+
[\s\S]{0,64}?
20+
(?<IP>
21+
(?:
22+
(?:\[)?
23+
(?>
24+
[23][A-Fa-f0-9]{3}
25+
(?:
26+
(?::[A-Fa-f0-9]{1,4}){1,7}
27+
|
28+
(?:(?::[A-Fa-f0-9]{1,4}){0,6}::(?:[A-Fa-f0-9]{1,4}(?::[A-Fa-f0-9]{1,4}){0,6})?)
29+
)
30+
)
31+
(?:\])?
32+
|
33+
(?>
34+
(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.){3}
35+
(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)
36+
)
37+
)
38+
)
39+
(?::\d+)?
40+
[\s\S]{0,64}?
41+
Time
42+
[\s\S]{0,64}?
43+
(?<Time>\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2}\s+UTC)
44+
]]

Tests/OptionsTest.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) 2013-2025 Cem Dervis, MIT License.
2+
// https://sharpconfig.org
3+
4+
using NUnit.Framework;
5+
using SharpConfig;
6+
7+
namespace Tests
8+
{
9+
[TestFixture]
10+
public sealed class OptionsTest
11+
{
12+
[Test]
13+
public void TestArrayElementSeparator()
14+
{
15+
Configuration.ResetOptions();
16+
Configuration.ArrayElementSeparator = '|';
17+
18+
var cfg = new Configuration();
19+
20+
cfg["TestSection"]["Setting"].StringValueArray = new[] { "String1", "String2", "String3" };
21+
22+
Assert.AreEqual("{String1|String2|String3}", cfg["TestSection"]["Setting"].RawValue);
23+
24+
Configuration.ResetOptions();
25+
}
26+
}
27+
}

Tests/SimpleConfigTest.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -564,9 +564,21 @@ public void Chars()
564564
}
565565

566566
[Test]
567-
public void Regex()
567+
public void MultilineValues()
568568
{
569-
// var cfg = Configuration.LoadFromFile("RegexTest.txt");
569+
var cfg = Configuration.LoadFromFile("MultilineValuesTest.txt");
570+
571+
var lines1 = cfg["Section"]["MultilineValue1"].RawValue.Split('\n');
572+
Assert.AreEqual("[[Line1", lines1[0]);
573+
Assert.AreEqual("Line2", lines1[1]);
574+
Assert.AreEqual(" Line3 (indented)", lines1[2]);
575+
Assert.AreEqual("\"Line4 with quote at start", lines1[3]);
576+
Assert.AreEqual("Line5 with quote at end\"", lines1[4]);
577+
Assert.AreEqual("Line6 with \" in the middle", lines1[5]);
578+
Assert.AreEqual("Line7 with \"\" in the middle", lines1[6]);
579+
Assert.AreEqual("\"\"]]", lines1[7]);
580+
581+
Assert.AreEqual("SomeValue", cfg["Section"]["SomeSetting"].StringValue);
570582
}
571583

572584
[Test]

Tests/Tests.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,10 @@
1616
<ProjectReference Include="..\Src\SharpConfig.csproj" />
1717
</ItemGroup>
1818

19+
<ItemGroup>
20+
<None Update="MultilineValuesTest.txt">
21+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
22+
</None>
23+
</ItemGroup>
24+
1925
</Project>

0 commit comments

Comments
 (0)