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; }