diff --git a/test/OpenChat.PlaygroundApp.Tests/Abstractions/ArgumentOptionsTests.cs b/test/OpenChat.PlaygroundApp.Tests/Abstractions/ArgumentOptionsTests.cs index b0ecb2f0..d3652000 100644 --- a/test/OpenChat.PlaygroundApp.Tests/Abstractions/ArgumentOptionsTests.cs +++ b/test/OpenChat.PlaygroundApp.Tests/Abstractions/ArgumentOptionsTests.cs @@ -165,9 +165,10 @@ public void Given_Unimplemented_ConnectorType_When_Parse_Invoked_Then_It_Should_ var config = BuildConfig((key, value)); var args = Array.Empty(); - var ex = Assert.Throws(() => ArgumentOptions.Parse(config, args)); + var action = () => ArgumentOptions.Parse(config, args); - ex.Message.ShouldContain($"{value}ArgumentOptions"); + action.ShouldThrow() + .Message.ShouldContain($"{value}ArgumentOptions"); } [Trait("Category", "UnitTest")] @@ -190,7 +191,7 @@ public void Given_Empty_ConnectorType_When_Parse_Invoked_Then_It_Should_Return_U [InlineData(AppSettingConstants.ConnectorType, "AzureAIFoundry", ConnectorType.AzureAIFoundry)] [InlineData(AppSettingConstants.ConnectorType, "GitHubModels", ConnectorType.GitHubModels)] [InlineData(AppSettingConstants.ConnectorType, "GoogleVertexAI", ConnectorType.GoogleVertexAI)] - // [InlineData(AppSettingConstants.ConnectorType, "DockerModelRunner", ConnectorType.DockerModelRunner)] + [InlineData(AppSettingConstants.ConnectorType, "DockerModelRunner", ConnectorType.DockerModelRunner)] [InlineData(AppSettingConstants.ConnectorType, "FoundryLocal", ConnectorType.FoundryLocal)] [InlineData(AppSettingConstants.ConnectorType, "HuggingFace", ConnectorType.HuggingFace)] [InlineData(AppSettingConstants.ConnectorType, "Ollama", ConnectorType.Ollama)] @@ -217,11 +218,11 @@ public void Given_ConnectorType_When_Parse_Invoked_Then_It_Should_Return_Result( [InlineData(AppSettingConstants.ConnectorType, "AzureAIFoundry", "OpenAI", ConnectorType.OpenAI)] // [InlineData(AppSettingConstants.ConnectorType, "GitHubModels", "Naver", ConnectorType.Naver)] [InlineData(AppSettingConstants.ConnectorType, "GoogleVertexAI", "LG", ConnectorType.LG)] - // [InlineData(AppSettingConstants.ConnectorType, "DockerModelRunner", "Anthropic", ConnectorType.Anthropic)] + [InlineData(AppSettingConstants.ConnectorType, "DockerModelRunner", "Anthropic", ConnectorType.Anthropic)] [InlineData(AppSettingConstants.ConnectorType, "FoundryLocal", "Ollama", ConnectorType.Ollama)] [InlineData(AppSettingConstants.ConnectorType, "HuggingFace", "Ollama", ConnectorType.Ollama)] [InlineData(AppSettingConstants.ConnectorType, "Ollama", "FoundryLocal", ConnectorType.FoundryLocal)] - // [InlineData(AppSettingConstants.ConnectorType, "Anthropic", "DockerModelRunner", ConnectorType.DockerModelRunner)] + [InlineData(AppSettingConstants.ConnectorType, "Anthropic", "DockerModelRunner", ConnectorType.DockerModelRunner)] [InlineData(AppSettingConstants.ConnectorType, "LG", "GoogleVertexAI", ConnectorType.GoogleVertexAI)] [InlineData(AppSettingConstants.ConnectorType, "Naver", "GitHubModels", ConnectorType.GitHubModels)] [InlineData(AppSettingConstants.ConnectorType, "OpenAI", "AzureAIFoundry", ConnectorType.AzureAIFoundry)] @@ -244,7 +245,7 @@ public void Given_ConnectorType_And_Argument_When_Parse_Invoked_Then_It_Should_R [InlineData(AppSettingConstants.ConnectorType, "AzureAIFoundry", "MaaS", ConnectorType.AzureAIFoundry)] [InlineData(AppSettingConstants.ConnectorType, "GitHubModels", "MaaS", ConnectorType.GitHubModels)] [InlineData(AppSettingConstants.ConnectorType, "GoogleVertexAI", "MaaS", ConnectorType.GoogleVertexAI)] - // [InlineData(AppSettingConstants.ConnectorType, "DockerModelRunner", "Local", ConnectorType.DockerModelRunner)] + [InlineData(AppSettingConstants.ConnectorType, "DockerModelRunner", "Local", ConnectorType.DockerModelRunner)] [InlineData(AppSettingConstants.ConnectorType, "FoundryLocal", "Local", ConnectorType.FoundryLocal)] [InlineData(AppSettingConstants.ConnectorType, "HuggingFace", "Local", ConnectorType.HuggingFace)] [InlineData(AppSettingConstants.ConnectorType, "Ollama", "Local", ConnectorType.Ollama)] @@ -280,30 +281,6 @@ public void Given_Help_When_Parse_Invoked_Then_It_Should_Return_Help(string argu settings.Help.ShouldBe(expected); } - [Trait("Category", "UnitTest")] - [Theory] - [InlineData(typeof(AmazonBedrockArgumentOptions))] - [InlineData(typeof(AzureAIFoundryArgumentOptions))] - [InlineData(typeof(GitHubModelsArgumentOptions))] - [InlineData(typeof(GoogleVertexAIArgumentOptions))] - // [InlineData(typeof(DockerModelRunnerArgumentOptions))] - [InlineData(typeof(FoundryLocalArgumentOptions))] - [InlineData(typeof(HuggingFaceArgumentOptions))] - [InlineData(typeof(OllamaArgumentOptions))] - [InlineData(typeof(AnthropicArgumentOptions))] - [InlineData(typeof(LGArgumentOptions))] - // [InlineData(typeof(NaverArgumentOptions))] - [InlineData(typeof(OpenAIArgumentOptions))] - [InlineData(typeof(UpstageArgumentOptions))] - public void Given_Concrete_ArgumentOptions_When_Checking_Inheritance_Then_Should_Inherit_From_ArgumentOptions(Type type) - { - // Act - var isSubclass = type.IsSubclassOf(typeof(ArgumentOptions)); - - // Assert - isSubclass.ShouldBeTrue(); - } - [Trait("Category", "UnitTest")] [Theory] [InlineData(AppSettingConstants.ConnectorType, "AmazonBedrock", "AmazonBedrock:ModelId", "test-model-id", "test-model-id")] diff --git a/test/OpenChat.PlaygroundApp.Tests/Abstractions/LanguageModelConnectorTests.cs b/test/OpenChat.PlaygroundApp.Tests/Abstractions/LanguageModelConnectorTests.cs index 8efc9cf3..dc52a413 100644 --- a/test/OpenChat.PlaygroundApp.Tests/Abstractions/LanguageModelConnectorTests.cs +++ b/test/OpenChat.PlaygroundApp.Tests/Abstractions/LanguageModelConnectorTests.cs @@ -1,3 +1,5 @@ +using Microsoft.Extensions.AI; + using OpenChat.PlaygroundApp.Abstractions; using OpenChat.PlaygroundApp.Configurations; using OpenChat.PlaygroundApp.Connectors; @@ -36,47 +38,59 @@ public async Task Given_GitHubModels_Settings_When_CreateChatClient_Invoked_Then // Assert client.ShouldNotBeNull(); + client.ShouldBeAssignableTo(); } [Trait("Category", "UnitTest")] - [Theory] - [InlineData(ConnectorType.Unknown)] - public async Task Given_Unsupported_ConnectorType_When_CreateChatClient_Invoked_Then_It_Should_Throw(ConnectorType connectorType) + [Fact] + public void Given_Invalid_Settings_When_CreateChatClientAsync_Invoked_Then_It_Should_Throw() { // Arrange - var settings = BuildAppSettings(connectorType: connectorType); + var settings = BuildAppSettings(endpoint: null); // Act - var ex = await Assert.ThrowsAsync(() => LanguageModelConnector.CreateChatClientAsync(settings)); + Func func = async () => await LanguageModelConnector.CreateChatClientAsync(settings); // Assert - ex.Message.ShouldContain($"Connector type '{connectorType}'"); + func.ShouldThrow() + .Message.ShouldContain("Object reference not set to an instance of an object."); + } + + [Trait("Category", "UnitTest")] + [Fact] + public void Given_Null_Settings_When_CreateChatClient_Invoked_Then_It_Should_Throw() + { + // Arrange + AppSettings settings = null!; + + // Act + Func func = async () => await LanguageModelConnector.CreateChatClientAsync(settings); + + // Assert + func.ShouldThrow() + .Message.ShouldContain("Object reference not set to an instance of an object."); } [Trait("Category", "UnitTest")] [Theory] - // [InlineData(typeof(AmazonBedrockConnector))] - // [InlineData(typeof(AzureAIFoundryConnector))] - [InlineData(typeof(GitHubModelsConnector))] - // [InlineData(typeof(GoogleVertexAIConnector))] - // [InlineData(typeof(DockerModelRunnerConnector))] - // [InlineData(typeof(FoundryLocalConnector))] - [InlineData(typeof(HuggingFaceConnector))] - // [InlineData(typeof(OllamaConnector))] - // [InlineData(typeof(AnthropicConnector))] - // [InlineData(typeof(LGConnector))] - // [InlineData(typeof(NaverConnector))] - [InlineData(typeof(OpenAIConnector))] - // [InlineData(typeof(UpstageConnector))] - public void Given_Concrete_Connectors_When_Checking_Inheritance_Then_Should_Inherit_From_LanguageModelConnector(Type derivedType) + [InlineData(ConnectorType.Unknown)] + [InlineData(ConnectorType.AmazonBedrock)] + [InlineData(ConnectorType.GoogleVertexAI)] + [InlineData(ConnectorType.DockerModelRunner)] + [InlineData(ConnectorType.FoundryLocal)] + [InlineData(ConnectorType.Ollama)] + [InlineData(ConnectorType.Anthropic)] + [InlineData(ConnectorType.Naver)] + public void Given_Unsupported_ConnectorType_When_CreateChatClient_Invoked_Then_It_Should_Throw(ConnectorType connectorType) { // Arrange - var baseType = typeof(LanguageModelConnector); + var settings = BuildAppSettings(connectorType: connectorType); // Act - var result = baseType.IsAssignableFrom(derivedType); + Func func = async () => await LanguageModelConnector.CreateChatClientAsync(settings); // Assert - result.ShouldBeTrue(); + func.ShouldThrow() + .Message.ShouldContain($"Connector type '{connectorType}'"); } -} +} \ No newline at end of file diff --git a/test/OpenChat.PlaygroundApp.Tests/Abstractions/LanguageModelSettingsTests.cs b/test/OpenChat.PlaygroundApp.Tests/Abstractions/LanguageModelSettingsTests.cs index 19a0de34..af10db9b 100644 --- a/test/OpenChat.PlaygroundApp.Tests/Abstractions/LanguageModelSettingsTests.cs +++ b/test/OpenChat.PlaygroundApp.Tests/Abstractions/LanguageModelSettingsTests.cs @@ -22,10 +22,15 @@ public class LanguageModelSettingsTests [InlineData(typeof(UpstageSettings))] public void Given_Concrete_Settings_When_Checking_Inheritance_Then_Should_Inherit_From_LanguageModelSettings(Type type) { - // Act - var isSubclass = type.IsSubclassOf(typeof(LanguageModelSettings)); + // Arrange + var baseType = typeof(LanguageModelSettings); + // Act + var isBaseAssignableFromDerived = baseType.IsAssignableFrom(type); + var isDerivedAssignableFromBase = type.IsAssignableFrom(baseType); + // Assert - isSubclass.ShouldBeTrue(); + isBaseAssignableFromDerived.ShouldBeTrue(); + isDerivedAssignableFromBase.ShouldBeFalse(); } } \ No newline at end of file diff --git a/test/OpenChat.PlaygroundApp.Tests/Connectors/AzureAIFoundryConnectorTests.cs b/test/OpenChat.PlaygroundApp.Tests/Connectors/AzureAIFoundryConnectorTests.cs index 8cd46b31..a1b073ea 100644 --- a/test/OpenChat.PlaygroundApp.Tests/Connectors/AzureAIFoundryConnectorTests.cs +++ b/test/OpenChat.PlaygroundApp.Tests/Connectors/AzureAIFoundryConnectorTests.cs @@ -90,6 +90,7 @@ public void Given_Null_Settings_When_EnsureLanguageModelSettingsValid_Invoked_Th [InlineData(null, typeof(InvalidOperationException), "AzureAIFoundry:Endpoint")] [InlineData("", typeof(InvalidOperationException), "AzureAIFoundry:Endpoint")] [InlineData(" ", typeof(InvalidOperationException), "AzureAIFoundry:Endpoint")] + [InlineData("\t\r\n", typeof(InvalidOperationException), "AzureAIFoundry:Endpoint")] public void Given_Invalid_Endpoint_When_EnsureLanguageModelSettingsValid_Invoked_Then_It_Should_Throw(string? endpoint, Type expectedType, string expectedMessage) { // Arrange @@ -109,6 +110,7 @@ public void Given_Invalid_Endpoint_When_EnsureLanguageModelSettingsValid_Invoked [InlineData(null, typeof(InvalidOperationException), "AzureAIFoundry:ApiKey")] [InlineData("", typeof(InvalidOperationException), "AzureAIFoundry:ApiKey")] [InlineData(" ", typeof(InvalidOperationException), "AzureAIFoundry:ApiKey")] + [InlineData("\t\r\n", typeof(InvalidOperationException), "AzureAIFoundry:ApiKey")] public void Given_Invalid_ApiKey_When_EnsureLanguageModelSettingsValid_Invoked_Then_It_Should_Throw(string? apiKey, Type expectedType, string expectedMessage) { // Arrange @@ -128,6 +130,7 @@ public void Given_Invalid_ApiKey_When_EnsureLanguageModelSettingsValid_Invoked_T [InlineData(null, typeof(InvalidOperationException), "AzureAIFoundry:DeploymentName")] [InlineData("", typeof(InvalidOperationException), "AzureAIFoundry:DeploymentName")] [InlineData(" ", typeof(InvalidOperationException), "AzureAIFoundry:DeploymentName")] + [InlineData("\t\r\n", typeof(InvalidOperationException), "AzureAIFoundry:DeploymentName")] public void Given_Invalid_DeploymentName_When_EnsureLanguageModelSettingsValid_Invoked_Then_It_Should_Throw(string? deploymentName, Type expectedType, string expectedMessage) { // Arrange @@ -159,7 +162,7 @@ public void Given_Valid_Settings_When_EnsureLanguageModelSettingsValid_Invoked_T [Trait("Category", "UnitTest")] [Fact] - public void Given_Null_Settings_When_GetChatClientAsync_Invoked_Then_It_Should_Throw() + public void Given_Null_AzureAIFoundrySettings_When_GetChatClientAsync_Invoked_Then_It_Should_Throw() { // Arrange var settings = new AppSettings @@ -247,6 +250,7 @@ public async Task Given_Valid_Settings_When_GetChatClient_Invoked_Then_It_Should // Assert result.ShouldNotBeNull(); + result.ShouldBeAssignableTo(); } [Trait("Category", "UnitTest")] @@ -296,4 +300,4 @@ public async Task Given_Valid_Settings_When_CreateChatClientAsync_Invoked_Then_I result.ShouldNotBeNull(); result.ShouldBeAssignableTo(); } -} +} \ No newline at end of file diff --git a/test/OpenChat.PlaygroundApp.Tests/Connectors/GitHubModelsConnectorTests.cs b/test/OpenChat.PlaygroundApp.Tests/Connectors/GitHubModelsConnectorTests.cs index dbdf259f..1e966a0d 100644 --- a/test/OpenChat.PlaygroundApp.Tests/Connectors/GitHubModelsConnectorTests.cs +++ b/test/OpenChat.PlaygroundApp.Tests/Connectors/GitHubModelsConnectorTests.cs @@ -1,3 +1,6 @@ +using Microsoft.Extensions.AI; + +using OpenChat.PlaygroundApp.Abstractions; using OpenChat.PlaygroundApp.Configurations; using OpenChat.PlaygroundApp.Connectors; @@ -5,7 +8,11 @@ namespace OpenChat.PlaygroundApp.Tests.Connectors; public class GitHubModelsConnectorTests { - private static AppSettings BuildAppSettings(string? endpoint = "https://models.github.ai/inference", string? token = "test-token", string? model = "openai/gpt-4o-mini") + private const string Endpoint = "https://models.github.ai/inference"; + private const string Token = "test-token"; + private const string Model = "openai/gpt-4o-mini"; + + private static AppSettings BuildAppSettings(string? endpoint = Endpoint, string? token = Token, string? model = Model) { return new AppSettings { @@ -19,19 +26,63 @@ private static AppSettings BuildAppSettings(string? endpoint = "https://models.g }; } + [Trait("Category", "UnitTest")] + [Theory] + [InlineData(typeof(LanguageModelConnector), typeof(GitHubModelsConnector), true)] + [InlineData(typeof(GitHubModelsConnector), typeof(LanguageModelConnector), false)] + public void Given_BaseType_Then_It_Should_Be_AssignableFrom_DerivedType(Type baseType, Type derivedType, bool expected) + { + // Act + var result = baseType.IsAssignableFrom(derivedType); + + // Assert + result.ShouldBe(expected); + } + + [Trait("Category", "UnitTest")] + [Fact] + public void Given_Null_Settings_When_Instantiated_Then_It_Should_Throw() + { + // Act + Action action = () => new GitHubModelsConnector(null!); + + // Assert + action.ShouldThrow() + .Message.ShouldContain("settings"); + } + + [Trait("Category", "UnitTest")] + [Fact] + public void Given_Settings_When_Instantiated_Then_It_Should_Return() + { + // Arrange + var settings = BuildAppSettings(); + + // Act + var result = new GitHubModelsConnector(settings); + + // Assert + result.ShouldNotBeNull(); + } + [Trait("Category", "UnitTest")] [Fact] public void Given_Settings_Is_Null_When_EnsureLanguageModelSettingsValid_Invoked_Then_It_Should_Throw() { // Arrange - var settings = new AppSettings { ConnectorType = ConnectorType.GitHubModels, GitHubModels = null }; + var settings = new AppSettings + { + ConnectorType = ConnectorType.GitHubModels, + GitHubModels = null + }; var connector = new GitHubModelsConnector(settings); // Act - var ex = Assert.Throws(() => connector.EnsureLanguageModelSettingsValid()); + Action action = () => connector.EnsureLanguageModelSettingsValid(); // Assert - ex.Message.ShouldContain("GitHubModels"); + action.ShouldThrow() + .Message.ShouldContain("GitHubModels"); } [Trait("Category", "UnitTest")] @@ -39,6 +90,7 @@ public void Given_Settings_Is_Null_When_EnsureLanguageModelSettingsValid_Invoked [InlineData(null, typeof(NullReferenceException), "Object reference not set to an instance of an object")] [InlineData("", typeof(InvalidOperationException), "GitHubModels:Endpoint")] [InlineData(" ", typeof(InvalidOperationException), "GitHubModels:Endpoint")] + [InlineData("\t\n\r", typeof(InvalidOperationException), "GitHubModels:Endpoint")] public void Given_Invalid_Endpoint_When_EnsureLanguageModelSettingsValid_Invoked_Then_It_Should_Throw(string? endpoint, Type expectedType, string expectedMessage) { // Arrange @@ -46,10 +98,11 @@ public void Given_Invalid_Endpoint_When_EnsureLanguageModelSettingsValid_Invoked var connector = new GitHubModelsConnector(settings); // Act - var ex = Assert.Throws(expectedType, () => connector.EnsureLanguageModelSettingsValid()); + Action action = () => connector.EnsureLanguageModelSettingsValid(); // Assert - ex.Message.ShouldContain(expectedMessage); + action.ShouldThrow(expectedType) + .Message.ShouldContain(expectedMessage); } [Trait("Category", "UnitTest")] @@ -57,6 +110,7 @@ public void Given_Invalid_Endpoint_When_EnsureLanguageModelSettingsValid_Invoked [InlineData(null, typeof(NullReferenceException), "Object reference not set to an instance of an object")] [InlineData("", typeof(InvalidOperationException), "GitHubModels:Token")] [InlineData(" ", typeof(InvalidOperationException), "GitHubModels:Token")] + [InlineData("\t\n\r", typeof(InvalidOperationException), "GitHubModels:Token")] public void Given_Invalid_Token_When_EnsureLanguageModelSettingsValid_Invoked_Then_It_Should_Throw(string? token, Type expectedType, string expectedMessage) { // Arrange @@ -64,10 +118,11 @@ public void Given_Invalid_Token_When_EnsureLanguageModelSettingsValid_Invoked_Th var connector = new GitHubModelsConnector(settings); // Act - var ex = Assert.Throws(expectedType, () => connector.EnsureLanguageModelSettingsValid()); + Action action = () => connector.EnsureLanguageModelSettingsValid(); // Assert - ex.Message.ShouldContain(expectedMessage); + action.ShouldThrow(expectedType) + .Message.ShouldContain(expectedMessage); } [Trait("Category", "UnitTest")] @@ -75,6 +130,7 @@ public void Given_Invalid_Token_When_EnsureLanguageModelSettingsValid_Invoked_Th [InlineData(null, typeof(NullReferenceException), "Object reference not set to an instance of an object")] [InlineData("", typeof(InvalidOperationException), "GitHubModels:Model")] [InlineData(" ", typeof(InvalidOperationException), "GitHubModels:Model")] + [InlineData("\t\n\r", typeof(InvalidOperationException), "GitHubModels:Model")] public void Given_Invalid_Model_When_EnsureLanguageModelSettingsValid_Invoked_Then_It_Should_Throw(string? model, Type expectedType, string expectedMessage) { // Arrange @@ -82,10 +138,11 @@ public void Given_Invalid_Model_When_EnsureLanguageModelSettingsValid_Invoked_Th var connector = new GitHubModelsConnector(settings); // Act - var ex = Assert.Throws(expectedType, () => connector.EnsureLanguageModelSettingsValid()); + Action action = () => connector.EnsureLanguageModelSettingsValid(); // Assert - ex.Message.ShouldContain(expectedMessage); + action.ShouldThrow(expectedType) + .Message.ShouldContain(expectedMessage); } [Trait("Category", "UnitTest")] @@ -105,67 +162,139 @@ public void Given_Valid_Settings_When_EnsureLanguageModelSettingsValid_Invoked_T [Trait("Category", "UnitTest")] [Fact] - public async Task Given_Valid_Settings_When_GetChatClient_Invoked_Then_It_Should_Return_ChatClient() + public void Given_Null_GitHubModelsSettings_When_GetChatClientAsync_Invoked_Then_It_Should_Throw() { // Arrange - var settings = BuildAppSettings(); + var settings = new AppSettings + { + ConnectorType = ConnectorType.GitHubModels, + GitHubModels = null + }; var connector = new GitHubModelsConnector(settings); // Act - var client = await connector.GetChatClientAsync(); + Func func = async () => await connector.GetChatClientAsync(); // Assert - client.ShouldNotBeNull(); + func.ShouldThrow() + .Message.ShouldContain("Missing configuration"); } [Trait("Category", "UnitTest")] [Theory] [InlineData(null, typeof(InvalidOperationException), "GitHubModels:Token")] [InlineData("", typeof(ArgumentException), "key")] - public async Task Given_Missing_Token_When_GetChatClient_Invoked_Then_It_Should_Throw(string? token, Type expected, string message) + public void Given_Missing_Token_When_GetChatClient_Invoked_Then_It_Should_Throw(string? token, Type expected, string message) { // Arrange var settings = BuildAppSettings(token: token); var connector = new GitHubModelsConnector(settings); // Act - var ex = await Assert.ThrowsAsync(expected, connector.GetChatClientAsync); + Func func = async () => await connector.GetChatClientAsync(); // Assert - ex.Message.ShouldContain(message); + func.ShouldThrow(expected) + .Message.ShouldContain(message); } [Trait("Category", "UnitTest")] [Theory] [InlineData(null, typeof(InvalidOperationException), "GitHubModels:Endpoint")] [InlineData("", typeof(UriFormatException), "empty")] - public async Task Given_Missing_Endpoint_When_GetChatClient_Invoked_Then_It_Should_Throw(string? endpoint, Type expected, string message) + public void Given_Missing_Endpoint_When_GetChatClient_Invoked_Then_It_Should_Throw(string? endpoint, Type expected, string message) { // Arrange var settings = BuildAppSettings(endpoint: endpoint); var connector = new GitHubModelsConnector(settings); // Act - var ex = await Assert.ThrowsAsync(expected, connector.GetChatClientAsync); + Func func = async () => await connector.GetChatClientAsync(); // Assert - ex.Message.ShouldContain(message); + func.ShouldThrow(expected) + .Message.ShouldContain(message); } [Trait("Category", "UnitTest")] [Theory] [InlineData(null, typeof(ArgumentNullException), "model")] [InlineData("", typeof(ArgumentException), "model")] - public async Task Given_Missing_Model_When_GetChatClient_Invoked_Then_It_Should_Throw(string? model, Type expected, string message) + public void Given_Missing_Model_When_GetChatClient_Invoked_Then_It_Should_Throw(string? model, Type expected, string message) { // Arrange var settings = BuildAppSettings(model: model); var connector = new GitHubModelsConnector(settings); // Act - var ex = await Assert.ThrowsAsync(expected, connector.GetChatClientAsync); + Func func = async () => await connector.GetChatClientAsync(); + + // Assert + func.ShouldThrow(expected) + .Message.ShouldContain(message); + } + + [Trait("Category", "UnitTest")] + [Fact] + public async Task Given_Valid_Settings_When_GetChatClient_Invoked_Then_It_Should_Return_ChatClient() + { + // Arrange + var settings = BuildAppSettings(); + var connector = new GitHubModelsConnector(settings); + + // Act + var client = await connector.GetChatClientAsync(); + + // Assert + client.ShouldNotBeNull(); + client.ShouldBeAssignableTo(); + } + + [Trait("Category", "UnitTest")] + [Theory] + [InlineData(null, null, null, typeof(NullReferenceException), "Object reference not set to an instance of an object.")] + [InlineData("", Token, Model, typeof(InvalidOperationException), "Missing configuration: GitHubModels:Endpoint")] + [InlineData(" ", Token, Model, typeof(InvalidOperationException), "Missing configuration: GitHubModels:Endpoint")] + [InlineData(Endpoint, null, Model, typeof(NullReferenceException), "Object reference not set to an instance of an object.")] + [InlineData(Endpoint, "", Model, typeof(InvalidOperationException), "Missing configuration: GitHubModels:Token")] + [InlineData(Endpoint, " ", Model, typeof(InvalidOperationException), "Missing configuration: GitHubModels:Token")] + [InlineData(Endpoint, Token, null, typeof(NullReferenceException), "Object reference not set to an instance of an object.")] + [InlineData(Endpoint, Token, "", typeof(InvalidOperationException), "Missing configuration: GitHubModels:Model")] + [InlineData(Endpoint, Token, " ", typeof(InvalidOperationException), "Missing configuration: GitHubModels:Model")] + public void Given_Invalid_Settings_When_CreateChatClientAsync_Invoked_Then_It_Should_Throw(string? endpoint, string? token, string? model, Type expected, string expectedMessage) + { + // Arrange + var settings = new AppSettings + { + ConnectorType = ConnectorType.GitHubModels, + GitHubModels = new GitHubModelsSettings + { + Endpoint = endpoint, + Token = token, + Model = model + } + }; + + // Act + Func func = async () => await LanguageModelConnector.CreateChatClientAsync(settings); + + // Assert + func.ShouldThrow(expected) + .Message.ShouldContain(expectedMessage); + } + + [Trait("Category", "UnitTest")] + [Fact] + public async Task Given_Valid_Settings_When_CreateChatClientAsync_Invoked_Then_It_Should_Return_IChatClient() + { + // Arrange + var settings = BuildAppSettings(); + + // Act + var result = await LanguageModelConnector.CreateChatClientAsync(settings); // Assert - ex.Message.ShouldContain(message); + result.ShouldNotBeNull(); + result.ShouldBeAssignableTo(); } -} +} \ No newline at end of file diff --git a/test/OpenChat.PlaygroundApp.Tests/Connectors/HuggingFaceConnectorTests.cs b/test/OpenChat.PlaygroundApp.Tests/Connectors/HuggingFaceConnectorTests.cs index 1b184ac7..47f3415b 100644 --- a/test/OpenChat.PlaygroundApp.Tests/Connectors/HuggingFaceConnectorTests.cs +++ b/test/OpenChat.PlaygroundApp.Tests/Connectors/HuggingFaceConnectorTests.cs @@ -1,3 +1,5 @@ +using Microsoft.Extensions.AI; + using OpenChat.PlaygroundApp.Abstractions; using OpenChat.PlaygroundApp.Configurations; using OpenChat.PlaygroundApp.Connectors; @@ -34,27 +36,79 @@ public void Given_BaseType_Then_It_Should_Be_AssignableFrom_DerivedType(Type bas // Assert result.ShouldBe(expected); } + + [Trait("Category", "UnitTest")] + [Fact] + public void Given_Null_Settings_When_Instantiated_Then_It_Should_Throw() + { + // Act + Action action = () => new HuggingFaceConnector(null!); + + // Assert + action.ShouldThrow() + .Message.ShouldContain("settings"); + } [Trait("Category", "UnitTest")] [Fact] public void Given_Settings_Is_Null_When_EnsureLanguageModelSettingsValid_Invoked_Then_It_Should_Throw() { - // Arrange - var settings = new AppSettings { ConnectorType = ConnectorType.HuggingFace, HuggingFace = null }; - var connector = new HuggingFaceConnector(settings); + // Arrange + var settings = new AppSettings + { + ConnectorType = ConnectorType.HuggingFace, + HuggingFace = null + }; + var connector = new HuggingFaceConnector(settings); + + // Act + Action action = () => connector.EnsureLanguageModelSettingsValid(); + + // Assert + action.ShouldThrow() + .Message.ShouldContain("HuggingFace"); + } + + [Trait("Category", "UnitTest")] + [Fact] + public void Given_Settings_When_Instantiated_Then_It_Should_Return() + { + // Arrange + var settings = BuildAppSettings(); // Act - var ex = Assert.Throws(() => connector.EnsureLanguageModelSettingsValid()); + var result = new HuggingFaceConnector(settings); // Assert - ex.Message.ShouldContain("HuggingFace"); + result.ShouldNotBeNull(); } + + [Trait("Category", "UnitTest")] + [Fact] + public void Given_Null_Settings_When_EnsureLanguageModelSettingsValid_Invoked_Then_It_Should_Throw() + { + // Arrange + var settings = new AppSettings + { + ConnectorType = ConnectorType.HuggingFace, + HuggingFace = null + }; + var connector = new HuggingFaceConnector(settings); + + // Act + Action action = () => connector.EnsureLanguageModelSettingsValid(); + + // Assert + action.ShouldThrow() + .Message.ShouldContain("HuggingFace"); + } [Trait("Category", "UnitTest")] [Theory] [InlineData(null, typeof(NullReferenceException), "Object reference not set to an instance of an object")] [InlineData("", typeof(InvalidOperationException), "HuggingFace:BaseUrl")] [InlineData(" ", typeof(InvalidOperationException), "HuggingFace:BaseUrl")] + [InlineData("\t\n\r", typeof(InvalidOperationException), "HuggingFace:BaseUrl")] public void Given_Invalid_BaseUrl_When_EnsureLanguageModelSettingsValid_Invoked_Then_It_Should_Throw(string? baseUrl, Type expectedType, string expectedMessage) { // Arrange @@ -62,10 +116,11 @@ public void Given_Invalid_BaseUrl_When_EnsureLanguageModelSettingsValid_Invoked_ var connector = new HuggingFaceConnector(settings); // Act - var ex = Assert.Throws(expectedType, () => connector.EnsureLanguageModelSettingsValid()); + Action action = () => connector.EnsureLanguageModelSettingsValid(); // Assert - ex.Message.ShouldContain(expectedMessage); + action.ShouldThrow(expectedType) + .Message.ShouldContain(expectedMessage); } [Trait("Category", "UnitTest")] @@ -73,6 +128,7 @@ public void Given_Invalid_BaseUrl_When_EnsureLanguageModelSettingsValid_Invoked_ [InlineData(null, typeof(NullReferenceException), "Object reference not set to an instance of an object")] [InlineData("", typeof(InvalidOperationException), "HuggingFace:Model")] [InlineData(" ", typeof(InvalidOperationException), "HuggingFace:Model")] + [InlineData("\t\n\r", typeof(InvalidOperationException), "HuggingFace:Model")] [InlineData("hf.co/org/model", typeof(InvalidOperationException), "HuggingFace:Model format")] [InlineData("org/model-gguf", typeof(InvalidOperationException), "HuggingFace:Model format")] [InlineData("hf.co//model-gguf", typeof(InvalidOperationException), "HuggingFace:Model format")] @@ -83,10 +139,11 @@ public void Given_Invalid_Model_When_EnsureLanguageModelSettingsValid_Invoked_Th var connector = new HuggingFaceConnector(settings); // Act - var ex = Assert.Throws(expectedType, () => connector.EnsureLanguageModelSettingsValid()); + Action action = () => connector.EnsureLanguageModelSettingsValid(); // Assert - ex.Message.ShouldContain(expectedMessage); + action.ShouldThrow(expectedType) + .Message.ShouldContain(expectedMessage); } [Trait("Category", "UnitTest")] @@ -95,7 +152,7 @@ public void Given_Valid_Settings_When_EnsureLanguageModelSettingsValid_Invoked_T { // Arrange var settings = BuildAppSettings(); - var connector = new HuggingFaceConnector(settings); + var connector = new HuggingFaceConnector(settings); // Act var result = connector.EnsureLanguageModelSettingsValid(); @@ -104,36 +161,114 @@ public void Given_Valid_Settings_When_EnsureLanguageModelSettingsValid_Invoked_T result.ShouldBeTrue(); } - [Trait("Category", "IntegrationTest")] - [Trait("Category", "LLMRequired")] - [Fact] - public async Task Given_Valid_Settings_When_GetChatClient_Invoked_Then_It_Should_Return_ChatClient() + [Trait("Category", "UnitTest")] + [Theory] + [InlineData(null, typeof(ArgumentNullException), "null")] + [InlineData("", typeof(UriFormatException), "empty")] + [InlineData(" ", typeof(UriFormatException), "Invalid URI: The format of the URI could not be determined.")] + [InlineData("invalid-uri-format", typeof(UriFormatException), "Invalid URI: The format of the URI could not be determined.")] + [InlineData("not-a-url", typeof(UriFormatException), "Invalid URI: The format of the URI could not be determined.")] + public void Given_Invalid_BaseUrl_When_GetChatClient_Invoked_Then_It_Should_Throw(string? baseUrl, Type expected, string message) { // Arrange - var settings = BuildAppSettings(); - var connector = new HuggingFaceConnector(settings); + var settings = BuildAppSettings(baseUrl: baseUrl); + var connector = new HuggingFaceConnector(settings); // Act - var client = await connector.GetChatClientAsync(); + Func func = async () => await connector.GetChatClientAsync(); // Assert - client.ShouldNotBeNull(); + func.ShouldThrow(expected) + .Message.ShouldContain(message); } - [Trait("Category", "UnitTest")] + [Trait("Category", "IntegrationTest")] + [Trait("Category", "LLMRequired")] [Theory] - [InlineData(null, typeof(ArgumentNullException), "null")] - [InlineData("", typeof(UriFormatException), "empty")] - public async Task Given_Missing_BaseUrl_When_GetChatClient_Invoked_Then_It_Should_Throw(string? baseUrl, Type expected, string message) + [InlineData(null, typeof(HttpRequestException), "The requested name is valid, but no data of the requested type was found")] + [InlineData("", typeof(HttpRequestException), "The requested name is valid, but no data of the requested type was found")] + [InlineData(" ", typeof(HttpRequestException), "The requested name is valid, but no data of the requested type was found")] + [InlineData("\t\n\r", typeof(HttpRequestException), "The requested name is valid, but no data of the requested type was found")] + [InlineData("hf.co/org/model", typeof(HttpRequestException), "The requested name is valid, but no data of the requested type was found")] + [InlineData("org/model-gguf", typeof(HttpRequestException), "The requested name is valid, but no data of the requested type was found")] + [InlineData("hf.co//model-gguf", typeof(HttpRequestException), "The requested name is valid, but no data of the requested type was found")] + public void Given_Invalid_Model_When_GetChatClient_Invoked_Then_It_Should_Throw(string? model, Type expected, string message) + { + // Arrange + var settings = BuildAppSettings(model: model); + var connector = new HuggingFaceConnector(settings); + + // Act + Func func = async () => await connector.GetChatClientAsync(); + + // Assert + func.ShouldThrow(expected) + .Message.ShouldContain(message); + } + + [Trait("Category", "IntegrationTest")] + [Trait("Category", "LLMRequired")] + [Fact] + public async Task Given_Valid_Settings_When_GetChatClient_Invoked_Then_It_Should_Return_ChatClient() { // Arrange - var settings = BuildAppSettings(baseUrl: baseUrl); - var connector = new HuggingFaceConnector(settings); + var settings = BuildAppSettings(); + var connector = new HuggingFaceConnector(settings); // Act - var ex = await Assert.ThrowsAsync(expected, connector.GetChatClientAsync); + var client = await connector.GetChatClientAsync(); // Assert - ex.Message.ShouldContain(message); + client.ShouldNotBeNull(); + client.ShouldBeAssignableTo(); } -} + + [Trait("Category", "UnitTest")] + [Theory] + [InlineData(null, null, typeof(NullReferenceException), "Object reference not set to an instance of an object")] + [InlineData(null, Model, typeof(NullReferenceException),"Object reference not set to an instance of an object")] + [InlineData("", Model, typeof(InvalidOperationException), "Missing configuration: HUggingFace")] + [InlineData(" ", Model, typeof(InvalidOperationException), "Missing configuration: HUggingFace")] + [InlineData(BaseUrl, null, typeof(NullReferenceException), "Object reference not set to an instance of an object")] + [InlineData(BaseUrl, "", typeof(InvalidOperationException), "Missing configuration: HUggingFace")] + [InlineData(BaseUrl, " ", typeof(InvalidOperationException), "Missing configuration: HUggingFace")] + [InlineData(BaseUrl, "hf.co/org/model", typeof(InvalidOperationException), "Invalid configuration: HuggingFace:Model format")] + [InlineData(BaseUrl, "org/model-gguf", typeof(InvalidOperationException), "Invalid configuration: HuggingFace:Model format")] + [InlineData(BaseUrl, "hf.co//model-gguf", typeof(InvalidOperationException), "Invalid configuration: HuggingFace:Model format")] + public void Given_Invalid_Settings_When_CreateChatClientAsync_Invoked_Then_It_Should_Throw(string? baseUrl, string? model, Type expected, string expectedMessage) + { + // Arrange + var settings = new AppSettings + { + ConnectorType = ConnectorType.HuggingFace, + HuggingFace = new HuggingFaceSettings + { + BaseUrl = baseUrl, + Model = model + } + }; + + // Act + Func func = async () => await LanguageModelConnector.CreateChatClientAsync(settings); + + // Assert + func.ShouldThrow(expected) + .Message.ShouldContain(expectedMessage); + } + + [Trait("Category", "IntegrationTest")] + [Trait("Category", "LLMRequired")] + [Fact] + public async Task Given_Valid_Settings_When_CreateChatClientAsync_Invoked_Then_It_Should_Return_IChatClient() + { + // Arrange + var settings = BuildAppSettings(); + + // Act + var result = await LanguageModelConnector.CreateChatClientAsync(settings); + + // Assert + result.ShouldNotBeNull(); + result.ShouldBeAssignableTo(); + } +} \ No newline at end of file diff --git a/test/OpenChat.PlaygroundApp.Tests/Connectors/LGConnectorTests.cs b/test/OpenChat.PlaygroundApp.Tests/Connectors/LGConnectorTests.cs index 4d9d11e5..e67dede6 100644 --- a/test/OpenChat.PlaygroundApp.Tests/Connectors/LGConnectorTests.cs +++ b/test/OpenChat.PlaygroundApp.Tests/Connectors/LGConnectorTests.cs @@ -88,6 +88,7 @@ public void Given_Null_Settings_When_EnsureLanguageModelSettingsValid_Invoked_Th [InlineData(null, typeof(NullReferenceException), "Object reference not set to an instance of an object")] [InlineData("", typeof(InvalidOperationException), "LG:BaseUrl")] [InlineData(" ", typeof(InvalidOperationException), "LG:BaseUrl")] + [InlineData("\t\n\r", typeof(InvalidOperationException), "LG:BaseUrl")] public void Given_Invalid_BaseUrl_When_EnsureLanguageModelSettingsValid_Invoked_Then_It_Should_Throw(string? baseUrl, Type expectedType, string expectedMessage) { // Arrange @@ -107,6 +108,7 @@ public void Given_Invalid_BaseUrl_When_EnsureLanguageModelSettingsValid_Invoked_ [InlineData(null, typeof(NullReferenceException), "Object reference not set to an instance of an object")] [InlineData("", typeof(InvalidOperationException), "LG:Model")] [InlineData(" ", typeof(InvalidOperationException), "LG:Model")] + [InlineData("\t\n\r", typeof(InvalidOperationException), "LG:Model")] [InlineData("invalid-model-format", typeof(InvalidOperationException), "Expected 'hf.co/LGAI-EXAONE/EXAONE-*-GGUF' format")] [InlineData("random-name", typeof(InvalidOperationException), "Expected 'hf.co/LGAI-EXAONE/EXAONE-*-GGUF' format")] [InlineData("hf.co/other-org/model-GGUF", typeof(InvalidOperationException), "Expected 'hf.co/LGAI-EXAONE/EXAONE-*-GGUF' format")] @@ -148,6 +150,9 @@ public void Given_Valid_Model_Format_When_EnsureLanguageModelSettingsValid_Invok [Theory] [InlineData(null, typeof(ArgumentNullException), "null")] [InlineData("", typeof(UriFormatException), "empty")] + [InlineData(" ", typeof(UriFormatException), "Invalid URI: The format of the URI could not be determined.")] + [InlineData("invalid-uri-format", typeof(UriFormatException), "Invalid URI: The format of the URI could not be determined.")] + [InlineData("not-a-url", typeof(UriFormatException), "Invalid URI: The format of the URI could not be determined.")] public void Given_Invalid_BaseUrl_When_GetChatClient_Invoked_Then_It_Should_Throw(string? baseUrl, Type expectedType, string message) { // Arrange @@ -165,15 +170,15 @@ public void Given_Invalid_BaseUrl_When_GetChatClient_Invoked_Then_It_Should_Thro [Trait("Category", "IntegrationTest")] [Trait("Category", "LLMRequired")] [Theory] - [InlineData(null, typeof(ArgumentNullException), "null")] - [InlineData("", typeof(UriFormatException), "empty")] - [InlineData(" ", typeof(InvalidOperationException), "LG:Model")] - [InlineData("invalid-model-format", typeof(InvalidOperationException), "Expected 'hf.co/LGAI-EXAONE/EXAONE-*-GGUF' format")] - [InlineData("random-name", typeof(InvalidOperationException), "Expected 'hf.co/LGAI-EXAONE/EXAONE-*-GGUF' format")] - [InlineData("hf.co/other-org/model-GGUF", typeof(InvalidOperationException), "Expected 'hf.co/LGAI-EXAONE/EXAONE-*-GGUF' format")] - [InlineData("hf.co/LGAI-EXAONE/other-model-GGUF", typeof(InvalidOperationException), "Expected 'hf.co/LGAI-EXAONE/EXAONE-*-GGUF' format")] - [InlineData("hf.co/LGAI-EXAONE/EXAONE-4.0-1.2B", typeof(InvalidOperationException), "Expected 'hf.co/LGAI-EXAONE/EXAONE-*-GGUF' format")] - [InlineData("hf.co/LGAI-EXAONE/EXAONE-4.0-1.2B-FP8", typeof(InvalidOperationException), "Expected 'hf.co/LGAI-EXAONE/EXAONE-*-GGUF' format")] + [InlineData(null, typeof(OllamaSharp.Models.Exceptions.OllamaException), "invalid model name")] + [InlineData("", typeof(OllamaSharp.Models.Exceptions.OllamaException), "invalid model name")] + [InlineData(" ", typeof(OllamaSharp.Models.Exceptions.OllamaException), "invalid model name")] + [InlineData("invalid-model-format", typeof(OllamaSharp.Models.Exceptions.ResponseError), "pull model manifest")] + [InlineData("random-name", typeof(OllamaSharp.Models.Exceptions.ResponseError), "pull model manifest")] + [InlineData("hf.co/other-org/model-GGUF", typeof(OllamaSharp.Models.Exceptions.ResponseError), "pull model manifest")] + [InlineData("hf.co/LGAI-EXAONE/other-model-GGUF", typeof(OllamaSharp.Models.Exceptions.ResponseError), "pull model manifest")] + [InlineData("hf.co/LGAI-EXAONE/EXAONE-4.0-1.2B", typeof(OllamaSharp.Models.Exceptions.ResponseError), "pull model manifest")] + [InlineData("hf.co/LGAI-EXAONE/EXAONE-4.0-1.2B-FP8", typeof(OllamaSharp.Models.Exceptions.ResponseError), "pull model manifest")] public void Given_Invalid_Model_When_GetChatClient_Invoked_Then_It_Should_Throw(string? model, Type expectedType, string message) { // Arrange @@ -202,23 +207,25 @@ public async Task Given_Valid_Settings_When_GetChatClient_Invoked_Then_It_Should // Assert client.ShouldNotBeNull(); + client.ShouldBeAssignableTo(); } [Trait("Category", "UnitTest")] [Theory] - [InlineData(null, "hf.co/LGAI-EXAONE/EXAONE-4.0-1.2B-GGUF", typeof(NullReferenceException))] - [InlineData("", "hf.co/LGAI-EXAONE/EXAONE-4.0-32B-GGUF", typeof(InvalidOperationException))] - [InlineData(" ", "hf.co/LGAI-EXAONE/EXAONE-4.0-32B-GGUF", typeof(InvalidOperationException))] - [InlineData("https://test.lg-exaone/api", null, typeof(NullReferenceException))] - [InlineData("https://test.lg-exaone/api", "", typeof(InvalidOperationException))] - [InlineData("https://test.lg-exaone/api", " ", typeof(InvalidOperationException))] - [InlineData("https://test.lg-exaone/api", "invalid-model-format", typeof(InvalidOperationException))] - [InlineData("https://test.lg-exaone/api", "random-name", typeof(InvalidOperationException))] - [InlineData("https://test.lg-exaone/api", "hf.co/other-org/model-GGUF", typeof(InvalidOperationException))] - [InlineData("https://test.lg-exaone/api", "hf.co/LGAI-EXAONE/other-model-GGUF", typeof(InvalidOperationException))] - [InlineData("https://test.lg-exaone/api", "hf.co/LGAI-EXAONE/EXAONE-4.0-1.2B", typeof(InvalidOperationException))] - [InlineData("https://test.lg-exaone/api", "hf.co/LGAI-EXAONE/EXAONE-4.0-1.2B-FP8", typeof(InvalidOperationException))] - public void Given_Invalid_Settings_When_CreateChatClientAsync_Invoked_Then_It_Should_Throw(string? baseUrl, string? model, Type expectedType) + [InlineData(null, null, typeof(NullReferenceException), "Object reference not set to an instance of an object")] + [InlineData(null, Model, typeof(NullReferenceException), "Object reference not set to an instance of an object")] + [InlineData("", Model, typeof(InvalidOperationException), "Missing configuration: LG:BaseUrl")] + [InlineData(" ", Model, typeof(InvalidOperationException), "Missing configuration: LG:BaseUrl")] + [InlineData(BaseUrl, null, typeof(NullReferenceException), "Object reference not set to an instance of an object")] + [InlineData(BaseUrl, "", typeof(InvalidOperationException), "Missing configuration: LG:Model")] + [InlineData(BaseUrl, " ", typeof(InvalidOperationException), "Missing configuration: LG:Model")] + [InlineData(BaseUrl, "invalid-model-format", typeof(InvalidOperationException), "Invalid configuration: Expected 'hf.co/LGAI-EXAONE/EXAONE-*-GGUF' format")] + [InlineData(BaseUrl, "random-name", typeof(InvalidOperationException), "Invalid configuration: Expected 'hf.co/LGAI-EXAONE/EXAONE-*-GGUF' format")] + [InlineData(BaseUrl, "hf.co/other-org/model-GGUF", typeof(InvalidOperationException), "Invalid configuration: Expected 'hf.co/LGAI-EXAONE/EXAONE-*-GGUF' format")] + [InlineData(BaseUrl, "hf.co/LGAI-EXAONE/other-model-GGUF", typeof(InvalidOperationException), "Invalid configuration: Expected 'hf.co/LGAI-EXAONE/EXAONE-*-GGUF' format")] + [InlineData(BaseUrl, "hf.co/LGAI-EXAONE/EXAONE-4.0-1.2B", typeof(InvalidOperationException), "Invalid configuration: Expected 'hf.co/LGAI-EXAONE/EXAONE-*-GGUF' format")] + [InlineData(BaseUrl, "hf.co/LGAI-EXAONE/EXAONE-4.0-1.2B-FP8", typeof(InvalidOperationException), "Invalid configuration: Expected 'hf.co/LGAI-EXAONE/EXAONE-*-GGUF' format")] + public void Given_Invalid_Settings_When_CreateChatClientAsync_Invoked_Then_It_Should_Throw(string? baseUrl, string? model, Type expected, string message) { // Arrange var settings = BuildAppSettings(baseUrl: baseUrl, model: model); @@ -227,7 +234,8 @@ public void Given_Invalid_Settings_When_CreateChatClientAsync_Invoked_Then_It_Sh Func func = async () => await LanguageModelConnector.CreateChatClientAsync(settings); // Assert - func.ShouldThrow(expectedType); + func.ShouldThrow(expected) + .Message.ShouldContain(message); } [Trait("Category", "IntegrationTest")] @@ -245,4 +253,4 @@ public async Task Given_Valid_Settings_When_CreateChatClientAsync_Invoked_Then_I result.ShouldNotBeNull(); result.ShouldBeAssignableTo(); } -} +} \ No newline at end of file diff --git a/test/OpenChat.PlaygroundApp.Tests/Connectors/OpenAIConnectorTests.cs b/test/OpenChat.PlaygroundApp.Tests/Connectors/OpenAIConnectorTests.cs index 83d0678d..95feeece 100644 --- a/test/OpenChat.PlaygroundApp.Tests/Connectors/OpenAIConnectorTests.cs +++ b/test/OpenChat.PlaygroundApp.Tests/Connectors/OpenAIConnectorTests.cs @@ -24,12 +24,54 @@ private static AppSettings BuildAppSettings(string? apiKey = ApiKey, string? mod }; } + [Trait("Category", "UnitTest")] + [Theory] + [InlineData(typeof(LanguageModelConnector), typeof(OpenAIConnector), true)] + [InlineData(typeof(OpenAIConnector), typeof(LanguageModelConnector), false)] + public void Given_BaseType_Then_It_Should_Be_AssignableFrom_DerivedType(Type baseType, Type derivedType, bool expected) + { + // Act + var result = baseType.IsAssignableFrom(derivedType); + + // Assert + result.ShouldBe(expected); + } + + [Trait("Category", "UnitTest")] + [Fact] + public void Given_Null_Settings_When_Instantiated_Then_It_Should_Throw() + { + // Act + Action action = () => new OpenAIConnector(null!); + + // Assert + action.ShouldThrow() + .Message.ShouldContain("settings"); + } + + [Trait("Category", "UnitTest")] + [Fact] + public void Given_Settings_When_Instantiated_Then_It_Should_Return() + { + // Arrange + var settings = BuildAppSettings(); + + // Act + var result = new OpenAIConnector(settings); + + // Assert + result.ShouldNotBeNull(); + } + [Trait("Category", "UnitTest")] [Fact] public void Given_Settings_Is_Null_When_EnsureLanguageModelSettingsValid_Invoked_Then_It_Should_Throw() { // Arrange - var settings = new AppSettings { ConnectorType = ConnectorType.OpenAI, OpenAI = null }; + var settings = new AppSettings { + ConnectorType = ConnectorType.OpenAI, + OpenAI = null + }; var connector = new OpenAIConnector(settings); // Act @@ -60,21 +102,6 @@ public void Given_Invalid_ApiKey_When_EnsureLanguageModelSettingsValid_Invoked_T .Message.ShouldContain(expectedMessage); } - [Trait("Category", "UnitTest")] - [Fact] - public void Given_Valid_Settings_When_EnsureLanguageModelSettingsValid_Invoked_Then_It_Should_Return_True() - { - // Arrange - var settings = BuildAppSettings(); - var connector = new OpenAIConnector(settings); - - // Act - var result = connector.EnsureLanguageModelSettingsValid(); - - // Assert - result.ShouldBeTrue(); - } - [Trait("Category", "UnitTest")] [Theory] [InlineData(null, typeof(NullReferenceException), "Object reference not set to an instance of an object")] @@ -84,7 +111,7 @@ public void Given_Valid_Settings_When_EnsureLanguageModelSettingsValid_Invoked_T public void Given_Invalid_Model_When_EnsureLanguageModelSettingsValid_Invoked_Then_It_Should_Throw(string? model, Type expectedType, string expectedMessage) { // Arrange - var settings = BuildAppSettings(apiKey: "valid-key", model: model); + var settings = BuildAppSettings(model: model); var connector = new OpenAIConnector(settings); // Act @@ -94,28 +121,32 @@ public void Given_Invalid_Model_When_EnsureLanguageModelSettingsValid_Invoked_Th action.ShouldThrow(expectedType) .Message.ShouldContain(expectedMessage); } - + [Trait("Category", "UnitTest")] [Fact] - public async Task Given_Valid_Settings_When_GetChatClientAsync_Invoked_Then_It_Should_Return_ChatClient() + public void Given_Valid_Settings_When_EnsureLanguageModelSettingsValid_Invoked_Then_It_Should_Return_True() { // Arrange var settings = BuildAppSettings(); var connector = new OpenAIConnector(settings); // Act - var client = await connector.GetChatClientAsync(); + var result = connector.EnsureLanguageModelSettingsValid(); // Assert - client.ShouldNotBeNull(); + result.ShouldBeTrue(); } - + [Trait("Category", "UnitTest")] [Fact] public void Given_Settings_Is_Null_When_GetChatClientAsync_Invoked_Then_It_Should_Throw() { // Arrange - var settings = new AppSettings { ConnectorType = ConnectorType.OpenAI, OpenAI = null }; + var settings = new AppSettings + { + ConnectorType = ConnectorType.OpenAI, + OpenAI = null! + }; var connector = new OpenAIConnector(settings); // Act @@ -123,9 +154,9 @@ public void Given_Settings_Is_Null_When_GetChatClientAsync_Invoked_Then_It_Shoul // Assert func.ShouldThrow() - .Message.ShouldContain("Missing configuration: OpenAI:ApiKey."); + .Message.ShouldContain("Missing configuration"); } - + [Trait("Category", "UnitTest")] [Theory] [InlineData(null, typeof(InvalidOperationException), "OpenAI:ApiKey")] @@ -143,7 +174,7 @@ public void Given_Missing_ApiKey_When_GetChatClientAsync_Invoked_Then_It_Should_ func.ShouldThrow(expected) .Message.ShouldContain(message); } - + [Trait("Category", "UnitTest")] [Theory] [InlineData(null, typeof(ArgumentNullException), "model")] @@ -164,37 +195,30 @@ public void Given_Missing_Model_When_GetChatClientAsync_Invoked_Then_It_Should_T [Trait("Category", "UnitTest")] [Fact] - public void Given_Valid_Format_Settings_When_GetChatClientAsync_Invoked_Then_It_Should_Pass() - { - // Arrange - var settings = BuildAppSettings(apiKey: "sk-test-key-with-proper-format", model: "gpt-3.5-turbo"); - var connector = new OpenAIConnector(settings); - - // Act - Func func = async () => await connector.GetChatClientAsync(); - - // Assert - func.ShouldNotThrow(); - } - - [Trait("Category", "UnitTest")] - [Fact] - public async Task Given_Valid_Settings_When_CreateChatClientAsync_Invoked_Then_It_Should_Return_ChatClient() + public async Task Given_Valid_Settings_When_GetChatClientAsync_Invoked_Then_It_Should_Return_ChatClient() { // Arrange var settings = BuildAppSettings(); + var connector = new OpenAIConnector(settings); // Act - var result = await LanguageModelConnector.CreateChatClientAsync(settings); + var client = await connector.GetChatClientAsync(); // Assert - result.ShouldNotBeNull(); - result.ShouldBeAssignableTo(); + client.ShouldNotBeNull(); + client.ShouldBeAssignableTo(); } - + [Trait("Category", "UnitTest")] - [Fact] - public void Given_Invalid_Settings_When_CreateChatClientAsync_Invoked_Then_It_Should_Throw() + [Theory] + [InlineData(null, null, typeof(NullReferenceException), "Object reference not set to an instance of an object")] + [InlineData(null, Model, typeof(NullReferenceException), "Object reference not set to an instance of an object")] + [InlineData("", Model, typeof(InvalidOperationException), "Missing configuration: OpenAI")] + [InlineData(" ", Model, typeof(InvalidOperationException), "Missing configuration: OpenAI")] + [InlineData(ApiKey, null, typeof(NullReferenceException), "Object reference not set to an instance of an object")] + [InlineData(ApiKey, "", typeof(InvalidOperationException), "Missing configuration: OpenAI")] + [InlineData(ApiKey, " ", typeof(InvalidOperationException), "Missing configuration: OpenAI")] + public void Given_Invalid_Settings_When_CreateChatClientAsync_Invoked_Then_It_Should_Throw(string? apiKey, string? model, Type expected, string expectedMessage) { // Arrange var settings = new AppSettings @@ -202,15 +226,31 @@ public void Given_Invalid_Settings_When_CreateChatClientAsync_Invoked_Then_It_Sh ConnectorType = ConnectorType.OpenAI, OpenAI = new OpenAISettings { - ApiKey = null, - Model = "test-model" + ApiKey = apiKey, + Model = model } }; // Act Func func = async () => await LanguageModelConnector.CreateChatClientAsync(settings); + // Assert + func.ShouldThrow(expected) + .Message.ShouldContain(expectedMessage); + } + + [Trait("Category", "UnitTest")] + [Fact] + public async Task Given_Valid_Settings_When_CreateChatClientAsync_Invoked_Then_It_Should_Return_IChatClient() + { + // Arrange + var settings = BuildAppSettings(); + + // Act + var result = await LanguageModelConnector.CreateChatClientAsync(settings); + // Assert - func.ShouldThrow(); + result.ShouldNotBeNull(); + result.ShouldBeAssignableTo(); } } \ No newline at end of file diff --git a/test/OpenChat.PlaygroundApp.Tests/Connectors/UpstageConnectorTests.cs b/test/OpenChat.PlaygroundApp.Tests/Connectors/UpstageConnectorTests.cs index 88d158cd..a1e9a417 100644 --- a/test/OpenChat.PlaygroundApp.Tests/Connectors/UpstageConnectorTests.cs +++ b/test/OpenChat.PlaygroundApp.Tests/Connectors/UpstageConnectorTests.cs @@ -1,11 +1,11 @@ +using Microsoft.Extensions.AI; + using OpenChat.PlaygroundApp.Abstractions; using OpenChat.PlaygroundApp.Configurations; using OpenChat.PlaygroundApp.Connectors; namespace OpenChat.PlaygroundApp.Tests.Connectors; - - public class UpstageConnectorTests { private const string BaseUrl = "https://api.upstage.ai/v1/solar"; @@ -39,12 +39,41 @@ public void Given_BaseType_Then_It_Should_Be_AssignableFrom_DerivedType(Type bas result.ShouldBe(expected); } + [Trait("Category", "UnitTest")] + [Fact] + public void Given_Null_Settings_When_Instantiated_Then_It_Should_Throw() + { + // Act + Action action = () => new UpstageConnector(null!); + + // Assert + action.ShouldThrow() + .Message.ShouldContain("Object reference not set to an instance of an object"); + } + + [Trait("Category", "UnitTest")] + [Fact] + public void Given_Settings_When_Instantiated_Then_It_Should_Return() + { + // Arrange + var settings = BuildAppSettings(); + + // Act + var result = new UpstageConnector(settings); + + // Assert + result.ShouldNotBeNull(); + } + [Trait("Category", "UnitTest")] [Fact] public void Given_Settings_Is_Null_When_EnsureLanguageModelSettingsValid_Invoked_Then_It_Should_Throw() { // Arrange - var appSettings = new AppSettings { ConnectorType = ConnectorType.Upstage, Upstage = null }; + var appSettings = new AppSettings { + ConnectorType = ConnectorType.Upstage, + Upstage = null + }; var connector = new UpstageConnector(appSettings); // Act @@ -60,6 +89,7 @@ public void Given_Settings_Is_Null_When_EnsureLanguageModelSettingsValid_Invoked [InlineData(null, typeof(InvalidOperationException), "Upstage:BaseUrl")] [InlineData("", typeof(InvalidOperationException), "Upstage:BaseUrl")] [InlineData(" ", typeof(InvalidOperationException), "Upstage:BaseUrl")] + [InlineData("\t\r\n", typeof(InvalidOperationException), "Upstage:BaseUrl")] public void Given_Invalid_BaseUrl_When_EnsureLanguageModelSettingsValid_Invoked_Then_It_Should_Throw(string? baseUrl, Type expectedType, string expectedMessage) { // Arrange @@ -79,6 +109,7 @@ public void Given_Invalid_BaseUrl_When_EnsureLanguageModelSettingsValid_Invoked_ [InlineData(null, typeof(InvalidOperationException), "Upstage:ApiKey")] [InlineData("", typeof(InvalidOperationException), "Upstage:ApiKey")] [InlineData(" ", typeof(InvalidOperationException), "Upstage:ApiKey")] + [InlineData("\t\r\n", typeof(InvalidOperationException), "Upstage:ApiKey")] public void Given_Invalid_ApiKey_When_EnsureLanguageModelSettingsValid_Invoked_Then_It_Should_Throw(string? apiKey, Type expectedType, string expectedMessage) { // Arrange @@ -98,6 +129,7 @@ public void Given_Invalid_ApiKey_When_EnsureLanguageModelSettingsValid_Invoked_T [InlineData(null, typeof(InvalidOperationException), "Upstage:Model")] [InlineData("", typeof(InvalidOperationException), "Upstage:Model")] [InlineData(" ", typeof(InvalidOperationException), "Upstage:Model")] + [InlineData("\t\r\n", typeof(InvalidOperationException), "Upstage:Model")] public void Given_Invalid_Model_When_EnsureLanguageModelSettingsValid_Invoked_Then_It_Should_Throw(string? model, Type expectedType, string expectedMessage) { // Arrange @@ -129,43 +161,35 @@ public void Given_Valid_Settings_When_EnsureLanguageModelSettingsValid_Invoked_T [Trait("Category", "UnitTest")] [Fact] - public async Task Given_Valid_Settings_When_GetChatClient_Invoked_Then_It_Should_Return_ChatClient() + public void Given_Null_UpstageSettings_When_GetChatClientAsync_Invoked_Then_It_Should_Throw() { // Arrange - var settings = BuildAppSettings(); + var settings = new AppSettings + { + ConnectorType = ConnectorType.Upstage, + Upstage = null + }; var connector = new UpstageConnector(settings); - // Act - var client = await connector.GetChatClientAsync(); - - // Assert - client.ShouldNotBeNull(); - } - - [Trait("Category", "UnitTest")] - [Fact] - public void Given_Settings_Is_Null_When_GetChatClientAsync_Invoked_Then_It_Should_Throw() - { - // Arrange - var appSettings = new AppSettings { ConnectorType = ConnectorType.Upstage, Upstage = null }; - var connector = new UpstageConnector(appSettings); - // Act Func func = async () => await connector.GetChatClientAsync(); // Assert func.ShouldThrow() - .Message.ShouldContain("Missing configuration: Upstage:ApiKey."); + .Message.ShouldContain("Missing configuration"); } [Trait("Category", "UnitTest")] [Theory] - [InlineData(null, typeof(InvalidOperationException), "Upstage:ApiKey")] - [InlineData("", typeof(ArgumentException), "key")] - public void Given_Missing_ApiKey_When_GetChatClient_Invoked_Then_It_Should_Throw(string? apiKey, Type expected, string message) + [InlineData(null, typeof(InvalidOperationException), "Upstage:BaseUrl")] + [InlineData("", typeof(UriFormatException), "empty")] + [InlineData("invalid-uri-format", typeof(UriFormatException), "Invalid URI: The format of the URI could not be determined.")] + [InlineData("not-a-url", typeof(UriFormatException), "Invalid URI: The format of the URI could not be determined.")] + [InlineData(" ", typeof(UriFormatException), "Invalid URI: The format of the URI could not be determined.")] + public void Given_Missing_BaseUrl_When_GetChatClient_Invoked_Then_It_Should_Throw(string? baseUrl, Type expected, string message) { // Arrange - var settings = BuildAppSettings(apiKey: apiKey); + var settings = BuildAppSettings(baseUrl: baseUrl); var connector = new UpstageConnector(settings); // Act @@ -178,12 +202,12 @@ public void Given_Missing_ApiKey_When_GetChatClient_Invoked_Then_It_Should_Throw [Trait("Category", "UnitTest")] [Theory] - [InlineData(null, typeof(InvalidOperationException), "Upstage:BaseUrl")] - [InlineData("", typeof(UriFormatException), "empty")] - public void Given_Missing_BaseUrl_When_GetChatClient_Invoked_Then_It_Should_Throw(string? baseUrl, Type expected, string message) + [InlineData(null, typeof(InvalidOperationException), "Upstage:ApiKey")] + [InlineData("", typeof(ArgumentException), "key")] + public void Given_Missing_ApiKey_When_GetChatClient_Invoked_Then_It_Should_Throw(string? apiKey, Type expected, string message) { // Arrange - var settings = BuildAppSettings(baseUrl: baseUrl); + var settings = BuildAppSettings(apiKey: apiKey); var connector = new UpstageConnector(settings); // Act @@ -214,16 +238,18 @@ public void Given_Missing_Model_When_GetChatClient_Invoked_Then_It_Should_Throw( [Trait("Category", "UnitTest")] [Fact] - public async Task Given_Valid_Settings_When_CreateChatClientAsync_Invoked_Then_It_Should_Return_ChatClient() + public async Task Given_Valid_Settings_When_GetChatClient_Invoked_Then_It_Should_Return_ChatClient() { // Arrange var settings = BuildAppSettings(); + var connector = new UpstageConnector(settings); // Act - var client = await LanguageModelConnector.CreateChatClientAsync(settings); + var client = await connector.GetChatClientAsync(); // Assert client.ShouldNotBeNull(); + client.ShouldBeAssignableTo(); } [Trait("Category", "UnitTest")] @@ -258,4 +284,19 @@ public void Given_Invalid_Settings_When_CreateChatClientAsync_Invoked_Then_It_Sh func.ShouldThrow(expectedType) .Message.ShouldContain(expectedMessage); } -} + + [Trait("Category", "UnitTest")] + [Fact] + public async Task Given_Valid_Settings_When_CreateChatClientAsync_Invoked_Then_It_Should_Return_ChatClient() + { + // Arrange + var settings = BuildAppSettings(); + + // Act + var client = await LanguageModelConnector.CreateChatClientAsync(settings); + + // Assert + client.ShouldNotBeNull(); + client.ShouldBeAssignableTo(); + } +} \ No newline at end of file diff --git a/test/OpenChat.PlaygroundApp.Tests/Options/AmazonBedrockArgumentOptionsTests.cs b/test/OpenChat.PlaygroundApp.Tests/Options/AmazonBedrockArgumentOptionsTests.cs index eaa1989d..584550cd 100644 --- a/test/OpenChat.PlaygroundApp.Tests/Options/AmazonBedrockArgumentOptionsTests.cs +++ b/test/OpenChat.PlaygroundApp.Tests/Options/AmazonBedrockArgumentOptionsTests.cs @@ -3,6 +3,7 @@ using OpenChat.PlaygroundApp.Abstractions; using OpenChat.PlaygroundApp.Connectors; using OpenChat.PlaygroundApp.Constants; +using OpenChat.PlaygroundApp.Options; namespace OpenChat.PlaygroundApp.Tests.Options; @@ -83,6 +84,19 @@ private static IConfiguration BuildConfigWithAmazonBedrock( .Build(); } + [Trait("Category", "UnitTest")] + [Theory] + [InlineData(typeof(ArgumentOptions), typeof(AmazonBedrockArgumentOptions), true)] + [InlineData(typeof(AmazonBedrockArgumentOptions), typeof(ArgumentOptions), false)] + public void Given_BaseType_Then_It_Should_Be_AssignableFrom_DerivedType(Type baseType, Type derivedType, bool expected) + { + // Act + var result = baseType.IsAssignableFrom(derivedType); + + // Assert + result.ShouldBe(expected); + } + [Trait("Category", "UnitTest")] [Fact] public void Given_Nothing_When_Parse_Invoked_Then_It_Should_Set_Config() diff --git a/test/OpenChat.PlaygroundApp.Tests/Options/GitHubModelsArgumentOptionsTests.cs b/test/OpenChat.PlaygroundApp.Tests/Options/GitHubModelsArgumentOptionsTests.cs index 4ee847f9..e9f2e7df 100644 --- a/test/OpenChat.PlaygroundApp.Tests/Options/GitHubModelsArgumentOptionsTests.cs +++ b/test/OpenChat.PlaygroundApp.Tests/Options/GitHubModelsArgumentOptionsTests.cs @@ -3,6 +3,7 @@ using OpenChat.PlaygroundApp.Abstractions; using OpenChat.PlaygroundApp.Connectors; using OpenChat.PlaygroundApp.Constants; +using OpenChat.PlaygroundApp.Options; namespace OpenChat.PlaygroundApp.Tests.Options; @@ -72,6 +73,19 @@ private static IConfiguration BuildConfigWithGitHubModels( .Build(); } + [Trait("Category", "UnitTest")] + [Theory] + [InlineData(typeof(ArgumentOptions), typeof(GitHubModelsArgumentOptions), true)] + [InlineData(typeof(GitHubModelsArgumentOptions), typeof(ArgumentOptions), false)] + public void Given_BaseType_Then_It_Should_Be_AssignableFrom_DerivedType(Type baseType, Type derivedType, bool expected) + { + // Act + var result = baseType.IsAssignableFrom(derivedType); + + // Assert + result.ShouldBe(expected); + } + [Trait("Category", "UnitTest")] [Fact] public void Given_Nothing_When_Parse_Invoked_Then_It_Should_Set_Config() diff --git a/test/OpenChat.PlaygroundApp.Tests/Options/GoogleVertexAIArgumentOptionsTests.cs b/test/OpenChat.PlaygroundApp.Tests/Options/GoogleVertexAIArgumentOptionsTests.cs index c2c0fbec..ddff6eb8 100644 --- a/test/OpenChat.PlaygroundApp.Tests/Options/GoogleVertexAIArgumentOptionsTests.cs +++ b/test/OpenChat.PlaygroundApp.Tests/Options/GoogleVertexAIArgumentOptionsTests.cs @@ -3,6 +3,7 @@ using OpenChat.PlaygroundApp.Abstractions; using OpenChat.PlaygroundApp.Connectors; using OpenChat.PlaygroundApp.Constants; +using OpenChat.PlaygroundApp.Options; namespace OpenChat.PlaygroundApp.Tests.Options; @@ -56,6 +57,19 @@ private static IConfiguration BuildConfigWithGoogleVertexAI( .Build(); } + [Trait("Category", "UnitTest")] + [Theory] + [InlineData(typeof(ArgumentOptions), typeof(GoogleVertexAIArgumentOptions), true)] + [InlineData(typeof(GoogleVertexAIArgumentOptions), typeof(ArgumentOptions), false)] + public void Given_BaseType_Then_It_Should_Be_AssignableFrom_DerivedType(Type baseType, Type derivedType, bool expected) + { + // Act + var result = baseType.IsAssignableFrom(derivedType); + + // Assert + result.ShouldBe(expected); + } + [Trait("Category", "UnitTest")] [Fact] public void Given_Nothing_When_Parse_Invoked_Then_It_Should_Set_Config() diff --git a/test/OpenChat.PlaygroundApp.Tests/Options/HuggingFaceArgumentOptionsTests.cs b/test/OpenChat.PlaygroundApp.Tests/Options/HuggingFaceArgumentOptionsTests.cs index 74ed38db..10277e77 100644 --- a/test/OpenChat.PlaygroundApp.Tests/Options/HuggingFaceArgumentOptionsTests.cs +++ b/test/OpenChat.PlaygroundApp.Tests/Options/HuggingFaceArgumentOptionsTests.cs @@ -3,6 +3,7 @@ using OpenChat.PlaygroundApp.Abstractions; using OpenChat.PlaygroundApp.Connectors; using OpenChat.PlaygroundApp.Constants; +using OpenChat.PlaygroundApp.Options; namespace OpenChat.PlaygroundApp.Tests.Options; @@ -59,6 +60,19 @@ private static IConfiguration BuildConfigWithHuggingFace( .Build(); } + [Trait("Category", "UnitTest")] + [Theory] + [InlineData(typeof(ArgumentOptions), typeof(HuggingFaceArgumentOptions), true)] + [InlineData(typeof(HuggingFaceArgumentOptions), typeof(ArgumentOptions), false)] + public void Given_BaseType_Then_It_Should_Be_AssignableFrom_DerivedType(Type baseType, Type derivedType, bool expected) + { + // Act + var result = baseType.IsAssignableFrom(derivedType); + + // Assert + result.ShouldBe(expected); + } + [Trait("Category", "UnitTest")] [Fact] public void Given_Nothing_When_Parse_Invoked_Then_It_Should_Set_Config() diff --git a/test/OpenChat.PlaygroundApp.Tests/Options/OpenAIArgumentOptionsTests.cs b/test/OpenChat.PlaygroundApp.Tests/Options/OpenAIArgumentOptionsTests.cs index cc05113f..7b79e234 100644 --- a/test/OpenChat.PlaygroundApp.Tests/Options/OpenAIArgumentOptionsTests.cs +++ b/test/OpenChat.PlaygroundApp.Tests/Options/OpenAIArgumentOptionsTests.cs @@ -3,6 +3,7 @@ using OpenChat.PlaygroundApp.Abstractions; using OpenChat.PlaygroundApp.Connectors; using OpenChat.PlaygroundApp.Constants; +using OpenChat.PlaygroundApp.Options; namespace OpenChat.PlaygroundApp.Tests.Options; @@ -58,6 +59,19 @@ private static IConfiguration BuildConfigWithOpenAI( .Build(); } + [Trait("Category", "UnitTest")] + [Theory] + [InlineData(typeof(ArgumentOptions), typeof(OpenAIArgumentOptions), true)] + [InlineData(typeof(OpenAIArgumentOptions), typeof(ArgumentOptions), false)] + public void Given_BaseType_Then_It_Should_Be_AssignableFrom_DerivedType(Type baseType, Type derivedType, bool expected) + { + // Act + var result = baseType.IsAssignableFrom(derivedType); + + // Assert + result.ShouldBe(expected); + } + [Trait("Category", "UnitTest")] [Fact] public void Given_Nothing_When_Parse_Invoked_Then_It_Should_Set_Config() diff --git a/test/OpenChat.PlaygroundApp.Tests/Options/UpstageArgumentOptionsTests.cs b/test/OpenChat.PlaygroundApp.Tests/Options/UpstageArgumentOptionsTests.cs index 2a07716a..7c2b237f 100644 --- a/test/OpenChat.PlaygroundApp.Tests/Options/UpstageArgumentOptionsTests.cs +++ b/test/OpenChat.PlaygroundApp.Tests/Options/UpstageArgumentOptionsTests.cs @@ -3,6 +3,7 @@ using OpenChat.PlaygroundApp.Abstractions; using OpenChat.PlaygroundApp.Connectors; using OpenChat.PlaygroundApp.Constants; +using OpenChat.PlaygroundApp.Options; namespace OpenChat.PlaygroundApp.Tests.Options; @@ -70,6 +71,19 @@ private static IConfiguration BuildConfigWithUpstage( .Build(); } + [Trait("Category", "UnitTest")] + [Theory] + [InlineData(typeof(ArgumentOptions), typeof(UpstageArgumentOptions), true)] + [InlineData(typeof(UpstageArgumentOptions), typeof(ArgumentOptions), false)] + public void Given_BaseType_Then_It_Should_Be_AssignableFrom_DerivedType(Type baseType, Type derivedType, bool expected) + { + // Act + var result = baseType.IsAssignableFrom(derivedType); + + // Assert + result.ShouldBe(expected); + } + [Trait("Category", "UnitTest")] [Fact] public void Given_Nothing_When_Parse_Invoked_Then_It_Should_Set_Config()