tests: add additional test coverage

This commit is contained in:
Stevan Freeborn
2025-07-08 21:56:13 -05:00
parent 598eaaad94
commit 2732ae2b21
7 changed files with 198 additions and 10 deletions
+5 -1
View File
@@ -23,8 +23,12 @@ class SourceConverter : JsonConverter<Source>
private static Source DeserializeBase64Source(JsonElement root, JsonSerializerOptions options) private static Source DeserializeBase64Source(JsonElement root, JsonSerializerOptions options)
{ {
var mediaType = root.GetProperty("media_type").GetString() ?? throw new JsonException("Missing 'media_type' property"); var mediaType = root.TryGetProperty("media_type", out var mediaTypeElement)
? mediaTypeElement.GetString() ?? throw new JsonException("Missing 'media_type' property")
: throw new JsonException("Missing 'media_type' property");
var isImage = ImageType.IsValidImageType(mediaType); var isImage = ImageType.IsValidImageType(mediaType);
return isImage return isImage
? JsonSerializer.Deserialize<ImageSource>(root.GetRawText(), options)! ? JsonSerializer.Deserialize<ImageSource>(root.GetRawText(), options)!
: JsonSerializer.Deserialize<DocumentSource>(root.GetRawText(), options)!; : JsonSerializer.Deserialize<DocumentSource>(root.GetRawText(), options)!;
-5
View File
@@ -30,11 +30,6 @@ public abstract class Citation
[JsonPropertyName("document_title")] [JsonPropertyName("document_title")]
public string DocumentTitle { get; init; } = string.Empty; public string DocumentTitle { get; init; } = string.Empty;
[JsonConstructor]
internal Citation()
{
}
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Citation"/> class with a specified type. /// Initializes a new instance of the <see cref="Citation"/> class with a specified type.
/// </summary> /// </summary>
@@ -24,7 +24,13 @@ public class EventTestData : IEnumerable<object[]>
Usage = new Usage { InputTokens = 472, OutputTokens = 91 }, Usage = new Usage { InputTokens = 472, OutputTokens = 91 },
StopReason = "tool_use", StopReason = "tool_use",
Content = [ Content = [
new TextContent("Okay, let's check the weather for San Francisco, CA:"), new TextContent("Okay, let's check the weather for San Francisco, CA:")
{
Citations = [
new CharacterLocationCitation(),
new CharacterLocationCitation(),
]
},
new ToolUseContent() new ToolUseContent()
{ {
Id = "toolu_01T1x1fJ34qAmk2tNTrN7Up6", Id = "toolu_01T1x1fJ34qAmk2tNTrN7Up6",
@@ -380,6 +386,46 @@ public class EventTestData : IEnumerable<object[]>
}, },
}; };
yield return new object[]
{
"""
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"citations_delta","citation": {"type":"char_location","start_char_index":0,"end_char_index":0, "cited_text":"","document_index":0,"document_title":""}}}
""",
new AnthropicEvent()
{
Type = EventType.ContentBlockDelta,
Data = new ContentDeltaEventData()
{
Index = 0,
Delta = new CitationDelta()
{
Citation = new CharacterLocationCitation()
}
},
},
};
yield return new object[]
{
"""
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"citations_delta","citation":{"type":"char_location","start_char_index":0,"end_char_index":0,"cited_text":"","document_index":0,"document_title":""}}}
""",
new AnthropicEvent()
{
Type = EventType.ContentBlockDelta,
Data = new ContentDeltaEventData()
{
Index = 0,
Delta = new CitationDelta()
{
Citation = new CharacterLocationCitation()
},
},
},
};
yield return new object[] yield return new object[]
{ {
""" """
@@ -0,0 +1,31 @@
namespace AnthropicClient.Tests.Unit.Json;
public class SourceConverterTests : SerializationTest
{
[Fact]
public void JsonDeserialization_WhenTypeIsUnknown_ItThrowsException()
{
var json = @"{ ""type"": ""unknown"" }";
var action = () => Deserialize<Source>(json);
action.Should().Throw<JsonException>();
}
[Fact]
public void JsonSerialization_WhenSourceIsNotKnown_ItShouldHaveExpectedShape()
{
var source = new TestSource();
var result = Serialize<Source>(source);
JsonAssert.Equal(@"{ ""type"": ""test"" }", result);
}
private class TestSource : Source
{
public TestSource() : base("test")
{
}
}
}
@@ -1,7 +1,13 @@
namespace AnthropicClient.Tests.Unit.Models; namespace AnthropicClient.Tests.Unit.Models;
public class Base64SourceTests public class Base64SourceTests : SerializationTest
{ {
private readonly string _testJson = @"{
""type"": ""base64"",
""media_type"": ""application/pdf"",
""data"": ""base64data""
}";
[Fact] [Fact]
public void Constructor_WhenCalledWithValidArguments_ItShouldSetProperties() public void Constructor_WhenCalledWithValidArguments_ItShouldSetProperties()
{ {
@@ -36,4 +42,47 @@ public class Base64SourceTests
action.Should().Throw<ArgumentNullException>(); action.Should().Throw<ArgumentNullException>();
} }
[Fact]
public void JsonSerialization_WhenSerialized_ItShouldHaveExpectedShape()
{
var mediaType = "application/pdf";
var data = "base64data";
var source = new Base64Source(mediaType, data);
var result = Serialize<Source>(source);
JsonAssert.Equal(_testJson, result);
}
[Fact]
public void JsonDeserialization_WhenDeserialized_ItShouldHaveExpectedShape()
{
var source = Deserialize<Source>(_testJson);
var base64Source = source.As<Base64Source>();
base64Source!.Type.Should().Be("base64");
base64Source.MediaType.Should().Be("application/pdf");
base64Source.Data.Should().Be("base64data");
}
[Fact]
public void JsonDeserialization_WhenMediaTypeIsMissing_ItShouldThrowException()
{
var json = @"{ ""type"": ""base64"", ""data"": ""base64data"" }";
var action = () => Deserialize<Source>(json);
action.Should().Throw<JsonException>();
}
[Fact]
public void JsonDeserialization_WhenMediaTypeIsNull_ItShouldThrowException()
{
var json = @"{ ""type"": ""base64"", ""media_type"": null, ""data"": ""base64data"" }";
var action = () => Deserialize<Source>(json);
action.Should().Throw<JsonException>();
}
} }
@@ -1,7 +1,17 @@
namespace AnthropicClient.Tests.Unit.Models; namespace AnthropicClient.Tests.Unit.Models;
public class CustomSourceTests public class CustomSourceTests : SerializationTest
{ {
private readonly string _testJson = @"{
""type"": ""content"",
""content"": [
{
""type"": ""text"",
""text"": ""Sample text""
}
]
}";
[Fact] [Fact]
public void Constructor_WhenCalled_ItShouldSetProperties() public void Constructor_WhenCalled_ItShouldSetProperties()
{ {
@@ -32,4 +42,30 @@ public class CustomSourceTests
act.Should().Throw<ArgumentNullException>(); act.Should().Throw<ArgumentNullException>();
} }
[Fact]
public void JsonSerialization_WhenSerialized_ItShouldHaveExpectedShape()
{
var content = new List<TextContent>
{
new("Sample text")
};
var source = new CustomSource(content);
var result = Serialize<Source>(source);
JsonAssert.Equal(_testJson, result);
}
[Fact]
public void JsonDeserialization_WhenDeserialized_ItShouldHaveExpectedShape()
{
var source = Deserialize<Source>(_testJson);
var customSource = source.As<CustomSource>();
customSource!.Type.Should().Be("content");
customSource.Content.Should().HaveCount(1);
customSource.Content[0].Type.Should().Be("text");
customSource.Content[0].Text.Should().Be("Sample text");
}
} }
@@ -1,7 +1,13 @@
namespace AnthropicClient.Tests.Unit.Models; namespace AnthropicClient.Tests.Unit.Models;
public class TextSourceTests public class TextSourceTests : SerializationTest
{ {
private readonly string _testJson = @"{
""type"": ""text"",
""media_type"": ""text/plain"",
""data"": ""data""
}";
[Fact] [Fact]
public void Constructor_WhenCalled_ItShouldSetProperties() public void Constructor_WhenCalled_ItShouldSetProperties()
{ {
@@ -11,4 +17,25 @@ public class TextSourceTests
result.MediaType.Should().Be("text/plain"); result.MediaType.Should().Be("text/plain");
result.Data.Should().Be("data"); result.Data.Should().Be("data");
} }
[Fact]
public void JsonSerialization_WhenSerialized_ItShouldHaveExpectedShape()
{
var source = new TextSource("data");
var result = Serialize<Source>(source);
JsonAssert.Equal(_testJson, result);
}
[Fact]
public void JsonDeserialization_WhenDeserialized_ItShouldHaveExpectedShape()
{
var source = Deserialize<Source>(_testJson);
var textSource = source.As<TextSource>();
textSource!.Type.Should().Be("text");
textSource.MediaType.Should().Be("text/plain");
textSource.Data.Should().Be("data");
}
} }