From 28b7bf6a897cf3b2e2aad7df767b0f4428bec7a4 Mon Sep 17 00:00:00 2001
From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com>
Date: Thu, 2 Jan 2025 21:45:37 -0600
Subject: [PATCH] feat: add classes to model response to get model list
endpoint
---
src/AnthropicClient/Models/AnthropicModel.cs | 31 +++++
src/AnthropicClient/Models/Page.cs | 38 ++++++
.../Unit/Models/AnthropicModelTests.cs | 57 +++++++++
.../Unit/Models/PageTests.cs | 111 ++++++++++++++++++
4 files changed, 237 insertions(+)
create mode 100644 src/AnthropicClient/Models/AnthropicModel.cs
create mode 100644 src/AnthropicClient/Models/Page.cs
create mode 100644 tests/AnthropicClient.Tests/Unit/Models/AnthropicModelTests.cs
create mode 100644 tests/AnthropicClient.Tests/Unit/Models/PageTests.cs
diff --git a/src/AnthropicClient/Models/AnthropicModel.cs b/src/AnthropicClient/Models/AnthropicModel.cs
new file mode 100644
index 0000000..50be8c1
--- /dev/null
+++ b/src/AnthropicClient/Models/AnthropicModel.cs
@@ -0,0 +1,31 @@
+using System.Text.Json.Serialization;
+
+namespace AnthropicClient.Models;
+
+///
+/// Represents an Anthropic model.
+///
+public class AnthropicModel
+{
+ ///
+ /// The type of the model.
+ ///
+ public string Type { get; init; } = string.Empty;
+
+ ///
+ /// The id of the model.
+ ///
+ public string Id { get; init; } = string.Empty;
+
+ ///
+ /// The display name of the model.
+ ///
+ [JsonPropertyName("display_name")]
+ public string DisplayName { get; init; } = string.Empty;
+
+ ///
+ /// The created date of the model.
+ ///
+ [JsonPropertyName("created_at")]
+ public DateTimeOffset CreatedAt { get; init; }
+}
diff --git a/src/AnthropicClient/Models/Page.cs b/src/AnthropicClient/Models/Page.cs
new file mode 100644
index 0000000..e0ec5a8
--- /dev/null
+++ b/src/AnthropicClient/Models/Page.cs
@@ -0,0 +1,38 @@
+using System.Text.Json.Serialization;
+
+namespace AnthropicClient.Models;
+
+///
+/// Represents a page.
+///
+public class Page
+{
+ ///
+ /// The id of the first item in the page.
+ ///
+ [JsonPropertyName("first_id")]
+ public string FirstId { get; init; } = string.Empty;
+
+ ///
+ /// The id of the last item in the page.
+ ///
+ [JsonPropertyName("last_id")]
+ public string LastId { get; init; } = string.Empty;
+
+ ///
+ /// Indicates whether there is more data to be retrieved.
+ ///
+ [JsonPropertyName("has_more")]
+ public bool HasMore { get; init; }
+}
+
+///
+/// Represents a page with data.
+///
+public class Page : Page
+{
+ ///
+ /// The data in the page.
+ ///
+ public T[] Data { get; init; } = [];
+}
\ No newline at end of file
diff --git a/tests/AnthropicClient.Tests/Unit/Models/AnthropicModelTests.cs b/tests/AnthropicClient.Tests/Unit/Models/AnthropicModelTests.cs
new file mode 100644
index 0000000..b7d1662
--- /dev/null
+++ b/tests/AnthropicClient.Tests/Unit/Models/AnthropicModelTests.cs
@@ -0,0 +1,57 @@
+namespace AnthropicClient.Tests.Unit.Models;
+
+public class AnthropicModelTests : SerializationTest
+{
+ private const string SampleJson = @"{
+ ""type"": ""model"",
+ ""id"": ""claude-3-opus-20240229"",
+ ""display_name"": ""Claude 3 Opus"",
+ ""created_at"": ""2024-02-29T00:00:00Z""
+ }";
+
+ [Fact]
+ public void Constructor_WhenCalled_ItShouldReturnAnInstanceWithPropertiesSet()
+ {
+ var model = new AnthropicModel();
+
+ model.Type.Should().BeEmpty();
+ model.Id.Should().BeEmpty();
+ model.DisplayName.Should().BeEmpty();
+ model.CreatedAt.Should().Be(default);
+ }
+
+ [Fact]
+ public void JsonDeserialization_WhenDeserialized_ItShouldHaveExpectedValues()
+ {
+ var result = Deserialize(SampleJson);
+
+ result.Should().NotBeNull();
+ result!.Type.Should().Be("model");
+ result.Id.Should().Be("claude-3-opus-20240229");
+ result.DisplayName.Should().Be("Claude 3 Opus");
+ result.CreatedAt.Should().Be(new DateTimeOffset(2024, 2, 29, 0, 0, 0, TimeSpan.Zero));
+ }
+
+ [Fact]
+ public void JsonSerialization_WhenSerialized_ItShouldReturnExpectedShape()
+ {
+ var model = new AnthropicModel
+ {
+ Type = "model",
+ Id = "claude-3-opus-20240229",
+ DisplayName = "Claude 3 Opus",
+ CreatedAt = new DateTimeOffset(2024, 2, 29, 0, 0, 0, TimeSpan.Zero)
+ };
+
+ var result = Serialize(model);
+
+ var expectedJson = @"{
+ ""type"": ""model"",
+ ""id"": ""claude-3-opus-20240229"",
+ ""display_name"": ""Claude 3 Opus"",
+ ""created_at"": ""2024-02-29T00:00:00+00:00""
+ }";
+
+ JsonAssert.Equal(expectedJson, result);
+ }
+}
\ No newline at end of file
diff --git a/tests/AnthropicClient.Tests/Unit/Models/PageTests.cs b/tests/AnthropicClient.Tests/Unit/Models/PageTests.cs
new file mode 100644
index 0000000..61a2780
--- /dev/null
+++ b/tests/AnthropicClient.Tests/Unit/Models/PageTests.cs
@@ -0,0 +1,111 @@
+namespace AnthropicClient.Tests.Unit.Models;
+
+public class PageTests : SerializationTest
+{
+ private const string BasePageJson = @"{
+ ""first_id"": ""msg_123"",
+ ""last_id"": ""msg_456"",
+ ""has_more"": true
+ }";
+
+ private const string GenericPageJson = @"{
+ ""first_id"": ""msg_123"",
+ ""last_id"": ""msg_456"",
+ ""has_more"": true,
+ ""data"": [""item1"", ""item2""]
+ }";
+
+ private const string EmptyPageJson = @"{
+ ""first_id"": """",
+ ""last_id"": """",
+ ""has_more"": false,
+ ""data"": []
+ }";
+
+ [Fact]
+ public void Constructor_WhenCalled_ItShouldReturnAnInstanceWithPropertiesSet()
+ {
+ var page = new Page();
+
+ page.FirstId.Should().BeEmpty();
+ page.LastId.Should().BeEmpty();
+ page.HasMore.Should().BeFalse();
+ }
+
+ [Fact]
+ public void Constructor_WhenCalledWithGeneric_ItShouldReturnAnInstanceWithPropertiesSet()
+ {
+ var page = new Page();
+
+ page.FirstId.Should().BeEmpty();
+ page.LastId.Should().BeEmpty();
+ page.HasMore.Should().BeFalse();
+ page.Data.Should().BeEmpty();
+ }
+
+ [Fact]
+ public void JsonDeserialization_WhenCalled_ItShouldHaveCorrectValues()
+ {
+ var result = Deserialize(BasePageJson);
+
+ result.Should().NotBeNull();
+ result!.FirstId.Should().Be("msg_123");
+ result.LastId.Should().Be("msg_456");
+ result.HasMore.Should().BeTrue();
+ }
+
+ [Fact]
+ public void JsonSerialization_WhenCalled_ItShouldHaveExpectedShape()
+ {
+ var page = new Page
+ {
+ FirstId = "msg_123",
+ LastId = "msg_456",
+ HasMore = true
+ };
+
+ var result = Serialize(page);
+
+ JsonAssert.Equal(BasePageJson, result);
+ }
+
+ [Fact]
+ public void JsonDeserialization_WhenCalledWithData_ItShouldHaveCorrectValues()
+ {
+ var result = Deserialize>(GenericPageJson);
+
+ result.Should().NotBeNull();
+ result!.FirstId.Should().Be("msg_123");
+ result.LastId.Should().Be("msg_456");
+ result.HasMore.Should().BeTrue();
+ result.Data.Should().BeEquivalentTo(["item1", "item2"]);
+ }
+
+ [Fact]
+ public void JsonSerialization_WhenCalledWithData_ItShouldHaveExpectedShape()
+ {
+ var page = new Page
+ {
+ FirstId = "msg_123",
+ LastId = "msg_456",
+ HasMore = true,
+ Data = ["item1", "item2"]
+ };
+
+ var result = Serialize(page);
+
+ JsonAssert.Equal(GenericPageJson, result);
+ }
+
+ [Fact]
+ public void JsonDeserialization_WhenCalledWithEmptyData_ItShouldHaveCorrectValues()
+ {
+ var result = Deserialize>(EmptyPageJson);
+
+ result.Should().NotBeNull();
+ result!.FirstId.Should().BeEmpty();
+ result.LastId.Should().BeEmpty();
+ result.HasMore.Should().BeFalse();
+ result.Data.Should().BeEmpty();
+ }
+}
\ No newline at end of file