using System.Text.Json;
using NewLife.Studio.AI.Models;
using Xunit;
namespace NewLife.Studio.AI.Tests;
public class ChatModelsTests
{
private static readonly JsonSerializerOptions JsonOptions = new()
{
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower
};
[Fact]
public void ChatMessage_Serialize_ProducesCorrectJson()
{
var message = new ChatMessage
{
Role = "user",
Content = "Hello, how are you?"
};
var json = JsonSerializer.Serialize(message, JsonOptions);
Assert.Contains("\"role\"", json);
Assert.Contains("\"user\"", json);
Assert.Contains("\"content\"", json);
Assert.Contains("Hello, how are you?", json);
}
[Fact]
public void ChatMessage_Deserialize_FromValidJson()
{
var json = """{"role":"assistant","content":"I am fine, thank you!"}""";
var message = JsonSerializer.Deserialize<ChatMessage>(json, JsonOptions);
Assert.NotNull(message);
Assert.Equal("assistant", message.Role);
Assert.Equal("I am fine, thank you!", message.Content);
}
[Fact]
public void ChatMessage_WithToolCalls_SerializeAndDeserialize()
{
var message = new ChatMessage
{
Role = "assistant",
Content = null,
ToolCalls = new List<ToolCall>
{
new()
{
Id = "call_abc123",
Type = "function",
Function = new FunctionCall
{
Name = "get_weather",
Arguments = "{\"location\":\"Beijing\"}"
}
}
}
};
var json = JsonSerializer.Serialize(message, JsonOptions);
var deserialized = JsonSerializer.Deserialize<ChatMessage>(json, JsonOptions);
Assert.NotNull(deserialized);
Assert.Equal("assistant", deserialized.Role);
Assert.Null(deserialized.Content);
Assert.NotNull(deserialized.ToolCalls);
Assert.Single(deserialized.ToolCalls);
Assert.Equal("call_abc123", deserialized.ToolCalls[0].Id);
Assert.Equal("get_weather", deserialized.ToolCalls[0].Function.Name);
}
[Fact]
public void ChatMessage_ToolMessage_SerializeAndDeserialize()
{
var message = new ChatMessage
{
Role = "tool",
ToolCallId = "call_abc123",
Content = "25°C, sunny"
};
var json = JsonSerializer.Serialize(message, JsonOptions);
var deserialized = JsonSerializer.Deserialize<ChatMessage>(json, JsonOptions);
Assert.NotNull(deserialized);
Assert.Equal("tool", deserialized.Role);
Assert.Equal("call_abc123", deserialized.ToolCallId);
Assert.Equal("25°C, sunny", deserialized.Content);
}
[Fact]
public void ChatMessage_SystemRole_SerializeCorrectly()
{
var message = new ChatMessage
{
Role = "system",
Content = "You are a helpful assistant."
};
var json = JsonSerializer.Serialize(message, JsonOptions);
Assert.Contains("\"role\":\"system\"", json);
Assert.Contains("\"content\":\"You are a helpful assistant.\"", json);
}
[Fact]
public void ChatRequest_Serialize_IncludesAllFields()
{
var request = new ChatRequest
{
Model = "gpt-4o",
Messages = new List<ChatMessage>
{
new() { Role = "system", Content = "You are a helpful assistant." },
new() { Role = "user", Content = "What is the weather?" }
},
MaxTokens = 2048,
Temperature = 0.5
};
var json = JsonSerializer.Serialize(request, JsonOptions);
Assert.Contains("\"model\":\"gpt-4o\"", json);
Assert.Contains("\"messages\"", json);
Assert.Contains("\"max_tokens\":2048", json);
Assert.Contains("\"temperature\":0.5", json);
}
[Fact]
public void ChatRequest_Serialize_WithToolsArray()
{
var request = new ChatRequest
{
Model = "gpt-4o",
Messages = new List<ChatMessage>
{
new() { Role = "user", Content = "Find users" }
},
Tools = new List<ToolDefinition>
{
new()
{
Type = "function",
Function = new FunctionDef
{
Name = "search_users",
Description = "Search users by criteria",
Parameters = new { type = "object", properties = new { } }
}
}
}
};
var json = JsonSerializer.Serialize(request, JsonOptions);
Assert.Contains("\"tools\"", json);
Assert.Contains("\"search_users\"", json);
}
[Fact]
public void ChatRequest_Serialize_WithNullTools_SerializesAsNull()
{
var request = new ChatRequest
{
Model = "gpt-4o",
Messages = new List<ChatMessage>
{
new() { Role = "user", Content = "Hello" }
},
Tools = null
};
var json = JsonSerializer.Serialize(request, JsonOptions);
Assert.Contains("\"tools\":null", json);
}
[Fact]
public void ChatRequest_Deserialize_FromCompleteJson()
{
var json = """
{
"model": "gpt-4o",
"messages": [
{"role": "system", "content": "You are helpful."},
{"role": "user", "content": "Query data"}
],
"max_tokens": 4096,
"temperature": 0.1
}
""";
var request = JsonSerializer.Deserialize<ChatRequest>(json, JsonOptions);
Assert.NotNull(request);
Assert.Equal("gpt-4o", request.Model);
Assert.Equal(2, request.Messages.Count);
Assert.Equal(4096, request.MaxTokens);
Assert.Equal(0.1, request.Temperature);
}
[Fact]
public void ChatResponse_Deserialize_FromSampleJson()
{
var json = """
{
"choices": [
{
"message": {
"role": "assistant",
"content": "I can help you with that!"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 25,
"completion_tokens": 15
}
}
""";
var response = JsonSerializer.Deserialize<ChatResponse>(json, JsonOptions);
Assert.NotNull(response);
Assert.Single(response.Choices);
Assert.Equal("assistant", response.Choices[0].Message.Role);
Assert.Equal("I can help you with that!", response.Choices[0].Message.Content);
Assert.Equal("stop", response.Choices[0].FinishReason);
Assert.NotNull(response.Usage);
Assert.Equal(25, response.Usage.PromptTokens);
Assert.Equal(15, response.Usage.CompletionTokens);
}
[Fact]
public void ChatResponse_Deserialize_WithToolCalls()
{
var json = """
{
"choices": [
{
"message": {
"role": "assistant",
"content": null,
"tool_calls": [
{
"id": "call_001",
"type": "function",
"function": {
"name": "query.select",
"arguments": "{\\\"sql\\\":\\\"SELECT * FROM users\\\"}"
}
}
]
},
"finish_reason": "tool_calls"
}
],
"usage": {
"prompt_tokens": 50,
"completion_tokens": 20
}
}
""";
var response = JsonSerializer.Deserialize<ChatResponse>(json, JsonOptions);
Assert.NotNull(response);
Assert.Single(response.Choices);
Assert.Equal("tool_calls", response.Choices[0].FinishReason);
var toolCalls = response.Choices[0].Message.ToolCalls;
Assert.NotNull(toolCalls);
Assert.Single(toolCalls!);
Assert.Equal("call_001", toolCalls![0].Id);
Assert.Equal("query.select", toolCalls[0].Function.Name);
}
[Fact]
public void ChatResponse_Deserialize_EmptyChoices_ReturnsEmpty()
{
var json = """{"choices":[],"usage":null}""";
var response = JsonSerializer.Deserialize<ChatResponse>(json, JsonOptions);
Assert.NotNull(response);
Assert.Empty(response.Choices);
}
[Fact]
public void ToolCall_DefaultValues_AreCorrect()
{
var toolCall = new ToolCall();
Assert.Equal("", toolCall.Id);
Assert.Equal("function", toolCall.Type);
Assert.NotNull(toolCall.Function);
}
[Fact]
public void ToolDefinition_DefaultValues_AreCorrect()
{
var definition = new ToolDefinition();
Assert.Equal("function", definition.Type);
Assert.NotNull(definition.Function);
}
[Fact]
public void FunctionDef_DefaultValues_AreCorrect()
{
var def = new FunctionDef();
Assert.Equal("", def.Name);
Assert.Equal("", def.Description);
Assert.Null(def.Parameters);
}
[Fact]
public void ChatRequest_DefaultValues_AreCorrect()
{
var request = new ChatRequest();
Assert.Equal("gpt-4o", request.Model);
Assert.NotNull(request.Messages);
Assert.Empty(request.Messages);
Assert.Null(request.Tools);
Assert.Equal(4096, request.MaxTokens);
Assert.Equal(0.1, request.Temperature);
}
[Fact]
public void ToolResult_SetProperties_WorkCorrectly()
{
var result = new ToolResult
{
ToolCallId = "call_test",
Output = "Query executed successfully",
Error = null
};
Assert.Equal("call_test", result.ToolCallId);
Assert.Equal("Query executed successfully", result.Output);
Assert.Null(result.Error);
}
[Fact]
public void ToolResult_ErrorScenario_WorksCorrectly()
{
var result = new ToolResult
{
ToolCallId = "call_error",
Output = null,
Error = "Unknown tool: invalid.tool"
};
Assert.Equal("call_error", result.ToolCallId);
Assert.Null(result.Output);
Assert.Equal("Unknown tool: invalid.tool", result.Error);
}
[Fact]
public void ChatRequest_SerializeDeserialize_RoundTrip()
{
var original = new ChatRequest
{
Model = "gpt-4o",
Messages = new List<ChatMessage>
{
new() { Role = "system", Content = "System message" },
new() { Role = "user", Content = "User message" }
},
Tools = new List<ToolDefinition>
{
new()
{
Function = new FunctionDef
{
Name = "test_tool",
Description = "A test tool"
}
}
},
MaxTokens = 100,
Temperature = 0.7
};
var json = JsonSerializer.Serialize(original, JsonOptions);
var deserialized = JsonSerializer.Deserialize<ChatRequest>(json, JsonOptions);
Assert.NotNull(deserialized);
Assert.Equal(original.Model, deserialized.Model);
Assert.Equal(original.Messages.Count, deserialized.Messages.Count);
Assert.Equal(original.MaxTokens, deserialized.MaxTokens);
Assert.Equal(original.Temperature, deserialized.Temperature);
Assert.NotNull(deserialized.Tools);
Assert.Single(deserialized.Tools);
}
}
|