Added Configuration tests
This commit is contained in:
@@ -16,7 +16,7 @@ public abstract class ConfigurationBase : IConfiguration
|
|||||||
this._Logger = logger;
|
this._Logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Add(string key, object value)
|
public virtual void Add(string key, object? value)
|
||||||
{
|
{
|
||||||
if (_InternalDictionary.ContainsKey(key))
|
if (_InternalDictionary.ContainsKey(key))
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{8F27B3EA
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests.DiscordBotCore.Logging", "Tests\Tests.DiscordBotCore.Logging\Tests.DiscordBotCore.Logging.csproj", "{94238D37-60C6-4E40-80EC-4B4D242F5914}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests.DiscordBotCore.Logging", "Tests\Tests.DiscordBotCore.Logging\Tests.DiscordBotCore.Logging.csproj", "{94238D37-60C6-4E40-80EC-4B4D242F5914}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests.DiscordBotCore.Configuration", "Tests\Tests.DiscordBotCore.Configuration\Tests.DiscordBotCore.Configuration.csproj", "{52C59C73-C23C-4608-8827-383577DEB8D8}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -231,6 +233,18 @@ Global
|
|||||||
{94238D37-60C6-4E40-80EC-4B4D242F5914}.Release|ARM64.Build.0 = Release|Any CPU
|
{94238D37-60C6-4E40-80EC-4B4D242F5914}.Release|ARM64.Build.0 = Release|Any CPU
|
||||||
{94238D37-60C6-4E40-80EC-4B4D242F5914}.Release|x64.ActiveCfg = Release|Any CPU
|
{94238D37-60C6-4E40-80EC-4B4D242F5914}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
{94238D37-60C6-4E40-80EC-4B4D242F5914}.Release|x64.Build.0 = Release|Any CPU
|
{94238D37-60C6-4E40-80EC-4B4D242F5914}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{52C59C73-C23C-4608-8827-383577DEB8D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{52C59C73-C23C-4608-8827-383577DEB8D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{52C59C73-C23C-4608-8827-383577DEB8D8}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||||
|
{52C59C73-C23C-4608-8827-383577DEB8D8}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||||
|
{52C59C73-C23C-4608-8827-383577DEB8D8}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{52C59C73-C23C-4608-8827-383577DEB8D8}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{52C59C73-C23C-4608-8827-383577DEB8D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{52C59C73-C23C-4608-8827-383577DEB8D8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{52C59C73-C23C-4608-8827-383577DEB8D8}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||||
|
{52C59C73-C23C-4608-8827-383577DEB8D8}.Release|ARM64.Build.0 = Release|Any CPU
|
||||||
|
{52C59C73-C23C-4608-8827-383577DEB8D8}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{52C59C73-C23C-4608-8827-383577DEB8D8}.Release|x64.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -241,6 +255,7 @@ Global
|
|||||||
{C67908F9-4A55-4DD8-B993-C26C648226F1} = {EA4FA308-7B2C-458E-8485-8747D745DD59}
|
{C67908F9-4A55-4DD8-B993-C26C648226F1} = {EA4FA308-7B2C-458E-8485-8747D745DD59}
|
||||||
{9A4B98C1-00AC-481C-BE55-A70C0B9D3BE7} = {5CF9AD7B-6BF0-4035-835F-722F989C01E1}
|
{9A4B98C1-00AC-481C-BE55-A70C0B9D3BE7} = {5CF9AD7B-6BF0-4035-835F-722F989C01E1}
|
||||||
{94238D37-60C6-4E40-80EC-4B4D242F5914} = {8F27B3EA-F292-40DF-B9B3-4B0E6BEA4E70}
|
{94238D37-60C6-4E40-80EC-4B4D242F5914} = {8F27B3EA-F292-40DF-B9B3-4B0E6BEA4E70}
|
||||||
|
{52C59C73-C23C-4608-8827-383577DEB8D8} = {8F27B3EA-F292-40DF-B9B3-4B0E6BEA4E70}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {3FB3C5DE-ED21-4D2E-ABDD-3A00EE4A2FFF}
|
SolutionGuid = {3FB3C5DE-ED21-4D2E-ABDD-3A00EE4A2FFF}
|
||||||
|
|||||||
246
Tests/Tests.DiscordBotCore.Configuration/ConfigurationTests.cs
Normal file
246
Tests/Tests.DiscordBotCore.Configuration/ConfigurationTests.cs
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
using DiscordBotCore.Configuration;
|
||||||
|
using DiscordBotCore.Logging;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace Tests.DiscordBotCore.Configuration;
|
||||||
|
|
||||||
|
public class ConfigurationTests
|
||||||
|
{
|
||||||
|
private readonly Mock<ILogger> _loggerMock;
|
||||||
|
private readonly string _testFilePath;
|
||||||
|
|
||||||
|
public ConfigurationTests()
|
||||||
|
{
|
||||||
|
_loggerMock = new Mock<ILogger>();
|
||||||
|
_testFilePath = Path.GetTempFileName();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Basic Operations
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Add_ShouldAddKeyValuePair()
|
||||||
|
{
|
||||||
|
var config = new TestableConfigurationBase(_loggerMock.Object, _testFilePath);
|
||||||
|
config.Add("Key1", 100);
|
||||||
|
Assert.True(config.ContainsKey("Key1"));
|
||||||
|
Assert.Equal(100, config.Get("Key1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Add_ShouldIgnoreNullKey()
|
||||||
|
{
|
||||||
|
var config = new TestableConfigurationBase(_loggerMock.Object, _testFilePath);
|
||||||
|
config.Add("Key1", null);
|
||||||
|
Assert.False(config.ContainsKey("Key1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Set_ShouldOverrideValue()
|
||||||
|
{
|
||||||
|
var config = new TestableConfigurationBase(_loggerMock.Object, _testFilePath);
|
||||||
|
config.Add("Key1", 1);
|
||||||
|
config.Set("Key1", 2);
|
||||||
|
Assert.Equal(2, config.Get("Key1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Remove_ShouldDeleteKey()
|
||||||
|
{
|
||||||
|
var config = new TestableConfigurationBase(_loggerMock.Object, _testFilePath);
|
||||||
|
config.Add("Key1", 1);
|
||||||
|
config.Remove("Key1");
|
||||||
|
Assert.False(config.ContainsKey("Key1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Clear_ShouldEmptyDictionary()
|
||||||
|
{
|
||||||
|
var config = new TestableConfigurationBase(_loggerMock.Object, _testFilePath);
|
||||||
|
config.Add("Key1", 1);
|
||||||
|
config.Clear();
|
||||||
|
Assert.False(config.ContainsKey("Key1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Retrieval
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Get_ShouldReturnStoredValue()
|
||||||
|
{
|
||||||
|
var config = new TestableConfigurationBase(_loggerMock.Object, _testFilePath);
|
||||||
|
config.Add("Key1", 123);
|
||||||
|
Assert.Equal(123, config.Get<int>("Key1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Get_WithDefault_ShouldReturnStoredValue()
|
||||||
|
{
|
||||||
|
var config = new TestableConfigurationBase(_loggerMock.Object, _testFilePath);
|
||||||
|
config.Add("Key1", 50);
|
||||||
|
Assert.Equal(50, config.Get("Key1", 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Get_WithDefault_ShouldReturnDefaultWithoutAutoAddIfDisabled()
|
||||||
|
{
|
||||||
|
var config = new TestableConfigurationBase(_loggerMock.Object, _testFilePath);
|
||||||
|
int result = config.Get("MissingKey", 300);
|
||||||
|
Assert.Equal(300, result);
|
||||||
|
Assert.False(config.ContainsKey("MissingKey"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetValue_ShouldReturnTrueIfKeyExists()
|
||||||
|
{
|
||||||
|
var config = new TestableConfigurationBase(_loggerMock.Object, _testFilePath);
|
||||||
|
config.Add("Key1", 5);
|
||||||
|
bool result = config.TryGetValue("Key1", out object? val);
|
||||||
|
Assert.True(result);
|
||||||
|
Assert.Equal(5, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetValue_ShouldReturnFalseIfKeyDoesNotExist()
|
||||||
|
{
|
||||||
|
var config = new TestableConfigurationBase(_loggerMock.Object, _testFilePath);
|
||||||
|
bool result = config.TryGetValue("KeyX", out object? val);
|
||||||
|
Assert.False(result);
|
||||||
|
Assert.Null(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Type Conversion and Complex Types
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Get_WithTypeConversion_ShouldReturnConvertedValue()
|
||||||
|
{
|
||||||
|
var config = new TestableConfigurationBase(_loggerMock.Object, _testFilePath);
|
||||||
|
config.Add("Key1", "123");
|
||||||
|
int result = config.Get<int>("Key1");
|
||||||
|
Assert.Equal(123, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetList_ShouldReturnStoredList()
|
||||||
|
{
|
||||||
|
var config = new TestableConfigurationBase(_loggerMock.Object, _testFilePath);
|
||||||
|
var expected = new List<int> { 1, 2, 3 };
|
||||||
|
config.Set("KeyList", expected);
|
||||||
|
var result = config.GetList("KeyList", new List<int>());
|
||||||
|
Assert.Equal(expected, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetList_ShouldReturnDefaultAndLogIfMissing()
|
||||||
|
{
|
||||||
|
var config = new TestableConfigurationBase(_loggerMock.Object, _testFilePath);
|
||||||
|
var defaultList = new List<int> { 10 };
|
||||||
|
var result = config.GetList("MissingList", defaultList);
|
||||||
|
Assert.Equal(defaultList, result);
|
||||||
|
_loggerMock.Verify(log => log.Log(It.Is<string>(s => s.Contains("Key 'MissingList' not found")), LogType.Warning), Times.Once);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetDictionary_ShouldReturnStoredDictionary()
|
||||||
|
{
|
||||||
|
var config = new TestableConfigurationBase(_loggerMock.Object, _testFilePath);
|
||||||
|
var dict = new Dictionary<string, object> { { "a", 1 }, { "b", 2 } };
|
||||||
|
config.Set("DictKey", dict);
|
||||||
|
var result = config.GetDictionary<string, int>("DictKey");
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
Assert.Equal(1, result["a"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetDictionary_ShouldThrowIfNotDictionary()
|
||||||
|
{
|
||||||
|
var config = new TestableConfigurationBase(_loggerMock.Object, _testFilePath);
|
||||||
|
config.Set("NotDict", 123);
|
||||||
|
Assert.Throws<Exception>(() => config.GetDictionary<string, int>("NotDict"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region LINQ Operations
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ContainsKey_ShouldReturnTrueForExistingKey()
|
||||||
|
{
|
||||||
|
var config = new TestableConfigurationBase(_loggerMock.Object, _testFilePath);
|
||||||
|
config.Add("Key1", 1);
|
||||||
|
Assert.True(config.ContainsKey("Key1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ContainsKey_ShouldReturnFalseForMissingKey()
|
||||||
|
{
|
||||||
|
var config = new TestableConfigurationBase(_loggerMock.Object, _testFilePath);
|
||||||
|
Assert.False(config.ContainsKey("KeyX"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ContainsAllKeys_ShouldReturnTrueIfAllKeysExist()
|
||||||
|
{
|
||||||
|
var config = new TestableConfigurationBase(_loggerMock.Object, _testFilePath);
|
||||||
|
config.Add("A", 1);
|
||||||
|
config.Add("B", 2);
|
||||||
|
Assert.True(config.ContainsAllKeys("A", "B"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ContainsAllKeys_ShouldReturnFalseIfAnyKeyMissing()
|
||||||
|
{
|
||||||
|
var config = new TestableConfigurationBase(_loggerMock.Object, _testFilePath);
|
||||||
|
config.Add("A", 1);
|
||||||
|
Assert.False(config.ContainsAllKeys("A", "C"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Where_WithPredicate_ShouldFilterResults()
|
||||||
|
{
|
||||||
|
var config = new TestableConfigurationBase(_loggerMock.Object, _testFilePath);
|
||||||
|
config.Add("A", 1);
|
||||||
|
config.Add("B", 2);
|
||||||
|
var result = config.Where(pair => (int)pair.Value > 1);
|
||||||
|
Assert.Single(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Where_WithSelector_ShouldMapResults()
|
||||||
|
{
|
||||||
|
var config = new TestableConfigurationBase(_loggerMock.Object, _testFilePath);
|
||||||
|
config.Add("A", 1);
|
||||||
|
config.Add("B", 2);
|
||||||
|
var result = config.Where(pair => pair.Key);
|
||||||
|
Assert.Contains("A", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FirstOrDefault_WithPredicate_ShouldReturnMatchingElement()
|
||||||
|
{
|
||||||
|
var config = new TestableConfigurationBase(_loggerMock.Object, _testFilePath);
|
||||||
|
config.Add("A", 1);
|
||||||
|
config.Add("B", 2);
|
||||||
|
var result = config.FirstOrDefault(pair => (int)pair.Value == 2);
|
||||||
|
Assert.Equal("B", result.Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void FirstOrDefault_ShouldReturnFirstElement()
|
||||||
|
{
|
||||||
|
var config = new TestableConfigurationBase(_loggerMock.Object, _testFilePath);
|
||||||
|
config.Add("A", 1);
|
||||||
|
var result = config.FirstOrDefault();
|
||||||
|
Assert.Equal("A", result.Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private class TestableConfigurationBase(ILogger logger, string path) : ConfigurationBase(logger, path)
|
||||||
|
{
|
||||||
|
public override Task SaveToFile() => Task.CompletedTask;
|
||||||
|
public override void LoadFromFile() { }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<IsTestProject>true</IsTestProject>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="6.0.0"/>
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0"/>
|
||||||
|
<PackageReference Include="Moq" Version="4.20.72" />
|
||||||
|
<PackageReference Include="xunit" Version="2.5.3"/>
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Using Include="Xunit"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\DiscordBotCore.Configuration\DiscordBotCore.Configuration.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
Reference in New Issue
Block a user