From ecf1958fd3d1864af3239e719d80fa903fce6570 Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Mon, 1 Jul 2024 12:07:49 -0500 Subject: [PATCH] tests: add more tests for tool class --- .../Unit/Models/ToolTests.cs | 252 ++++++++++++++++++ 1 file changed, 252 insertions(+) diff --git a/tests/AnthropicClient.Tests/Unit/Models/ToolTests.cs b/tests/AnthropicClient.Tests/Unit/Models/ToolTests.cs index e5c164e..cb07982 100644 --- a/tests/AnthropicClient.Tests/Unit/Models/ToolTests.cs +++ b/tests/AnthropicClient.Tests/Unit/Models/ToolTests.cs @@ -1,5 +1,257 @@ +using System.Reflection; +using System.Text.Json.Nodes; + namespace AnthropicClient.Tests.Unit.Models; public class ToolTests : SerializationTest { + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData(" ")] + public void Constructor_WhenGivenInvalidNameValue_ItShouldThrowArgumentException(string name) + { + var method = () => true; + var function = new AnthropicFunction(method.Method); + var action = () => new Tool(name, "description", function); + + action.Should().Throw(); + } + + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData(" ")] + public void Constructor_WhenGivenInvalidDescriptionValue_ItShouldThrowArgumentException(string description) + { + var method = () => true; + var function = new AnthropicFunction(method.Method); + var action = () => new Tool("name", description, function); + + action.Should().Throw(); + } + + [Fact] + public void Constructor_WhenGivenNullFunctionValue_ItShouldThrowArgumentNullException() + { + var action = () => new Tool("name", "description", null!); + + action.Should().Throw(); + } + + [Fact] + public void Constructor_WhenCalled_ItShouldInitializeProperties() + { + var method = () => true; + var function = new AnthropicFunction(method.Method); + var tool = new Tool("test name", "description", function); + + var expectedSchema = new JsonObject() + { + ["type"] = "object", + }; + + tool.Name.Should().Be("test_name"); + tool.DisplayName.Should().Be("test name"); + tool.Description.Should().Be("description"); + tool.Function.Should().Be(function); + tool.InputSchema.Should().BeEquivalentTo( + expectedSchema, + t => t.IgnoringCyclicReferences() + ); + } + + [Fact] + public void Constructor_WhenCalledAndGivenNameIsMoreThanMaxLength_ItShouldTruncateName() + { + var method = () => true; + var function = new AnthropicFunction(method.Method); + var tool = new Tool(new string('a', 65), "description", function); + + tool.Name.Should().HaveLength(64); + } + + [Theory] + [InlineData(typeof(TestClass), null)] + [InlineData(typeof(TestClass), "")] + [InlineData(typeof(TestClass), " ")] + [InlineData(typeof(TestClass), "MadeUpMethod")] + public void CreateFromStaticMethod_WhenGivenInvalidMethodName_ItShouldThrowArgumentException(Type type, string methodName) + { + var action = () => Tool.CreateFromStaticMethod("name", "description", type, methodName); + + action.Should().Throw(); + } + + [Fact] + public void CreateFromStaticMethod_WhenGivenTypeIsNull_ItShouldThrowArgumentNullException() + { + var action = () => Tool.CreateFromStaticMethod("name", "description", null!, "TestStaticMethod"); + + action.Should().Throw(); + } + + [Fact] + public void CreateFromStaticMethod_WhenGivenTypeThatDoesNotContainMethod_ItShouldThrowArgumentException() + { + var action = () => Tool.CreateFromStaticMethod("name", "description", typeof(ToolTests), nameof(TestClass.TestStaticMethod)); + + action.Should().Throw(); + } + + [Fact] + public void CreateFromStaticMethod_WhenCalled_ItShouldReturnTool() + { + var tool = Tool.CreateFromStaticMethod("test name", "description", typeof(TestClass), nameof(TestClass.TestStaticMethod)); + + var expectedSchema = new JsonObject() + { + ["type"] = "object", + }; + + tool.Name.Should().Be("test_name"); + tool.DisplayName.Should().Be("test name"); + tool.Description.Should().Be("description"); + tool.Function.Method.Name.Should().Be(nameof(TestClass.TestStaticMethod)); + tool.Function.Instance.Should().BeNull(); + tool.InputSchema.Should().BeEquivalentTo( + expectedSchema, + t => t.IgnoringCyclicReferences() + ); + } + + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData(" ")] + [InlineData("MadeUpMethod")] + public void CreateFromInstanceMethod_WhenGivenInvalidMethodName_ItShouldThrowArgumentException(string methodName) + { + var action = () => Tool.CreateFromInstanceMethod("name", "description", new TestClass(), methodName); + + action.Should().Throw(); + } + + [Fact] + public void CreateFromInstanceMethod_WhenGivenInstanceIsNull_ItShouldThrowArgumentNullException() + { + var action = () => Tool.CreateFromInstanceMethod("name", "description", null!, "TestMethod"); + + action.Should().Throw(); + } + + [Fact] + public void CreateFromInstanceMethod_WhenGivenInstanceThatDoesNotContainMethod_ItShouldThrowArgumentException() + { + var action = () => Tool.CreateFromInstanceMethod("name", "description", new ToolTests(), nameof(TestClass.TestStaticMethod)); + + action.Should().Throw(); + } + + [Fact] + public void CreateFromInstanceMethod_WhenMethodIsNotAnInstanceMethod_ItShouldThrowArgumentException() + { + var action = () => Tool.CreateFromInstanceMethod("name", "description", new TestClass(), nameof(TestClass.TestStaticMethod)); + + action.Should().Throw(); + } + + [Fact] + public void CreateFromInstanceMethod_WhenCalled_ItShouldReturnTool() + { + var instance = new TestClass(); + var tool = Tool.CreateFromInstanceMethod("test name", "description", instance, nameof(TestClass.TestInstanceMethod)); + + var expectedSchema = new JsonObject() + { + ["type"] = "object", + }; + + tool.Name.Should().Be("test_name"); + tool.DisplayName.Should().Be("test name"); + tool.Description.Should().Be("description"); + tool.Function.Method.Name.Should().Be(nameof(TestClass.TestInstanceMethod)); + tool.Function.Instance.Should().Be(instance); + tool.InputSchema.Should().BeEquivalentTo( + expectedSchema, + t => t.IgnoringCyclicReferences() + ); + } + + [Fact] + public void CreateFromParameterlessFunction_WhenGivenNullFunction_ItShouldThrowArgumentNullException() + { + var action = () => Tool.CreateFromFunction("name", "description", null!); + + action.Should().Throw(); + } + + [Fact] + public void CreateFromParameterlessFunction_WhenCalled_ItShouldReturnTool() + { + var func = () => true; + var tool = Tool.CreateFromFunction("test name", "description", func); + + var expectedSchema = new JsonObject() + { + ["type"] = "object", + }; + + tool.Name.Should().Be("test_name"); + tool.DisplayName.Should().Be("test name"); + tool.Description.Should().Be("description"); + tool.Function.Method.Should().BeSameAs(func.Method); + tool.InputSchema.Should().BeEquivalentTo( + expectedSchema, + t => t.IgnoringCyclicReferences() + ); + } + + [Fact] + public void CreateFromFunctionWithParameter_WhenGivenNullFunction_ItShouldThrowArgumentNullException() + { + var action = () => Tool.CreateFromFunction("name", "description", null!); + + action.Should().Throw(); + } + + [Fact] + public void CreateFromFunctionWithParameter_WhenCalled_ItShouldReturnTool() + { + var func = (string s) => true; + var tool = Tool.CreateFromFunction("test name", "description", func); + + var expectedSchema = new JsonObject() + { + ["type"] = "object", + ["properties"] = new JsonObject() + { + ["s"] = new JsonObject() + { + ["type"] = "string", + }, + }, + ["required"] = new JsonArray() + { + "s", + }, + }; + + tool.Name.Should().Be("test_name"); + tool.DisplayName.Should().Be("test name"); + tool.Description.Should().Be("description"); + tool.Function.Method.Should().BeSameAs(func.Method); + tool.InputSchema.Should().BeEquivalentTo( + expectedSchema, + t => t.IgnoringCyclicReferences() + ); + } +} + +class TestClass +{ + private readonly bool _result = true; + + public static bool TestStaticMethod() => true; + public bool TestInstanceMethod() => _result; } \ No newline at end of file