194 lines
5.4 KiB
C#
194 lines
5.4 KiB
C#
using Xunit;
|
|
using FluentAssertions;
|
|
using NSubstitute;
|
|
using System;
|
|
using System.Text.Json;
|
|
using FreeCode.Core.Models;
|
|
using FreeCode.Core.Enums;
|
|
|
|
namespace FreeCode.Tests.Unit.Models;
|
|
|
|
public sealed class SDKMessageTests
|
|
{
|
|
[Fact]
|
|
public void SDKMessage_UserMessageWrapsMessage()
|
|
{
|
|
var message = CreateMessage();
|
|
|
|
SDKMessage sdkMessage = new SDKMessage.UserMessage(message);
|
|
|
|
sdkMessage.Should().BeOfType<SDKMessage.UserMessage>();
|
|
((SDKMessage.UserMessage)sdkMessage).Message.Should().BeSameAs(message);
|
|
}
|
|
|
|
[Fact]
|
|
public void SDKMessage_AssistantMessageStoresTextAndMessageId()
|
|
{
|
|
var sdkMessage = new SDKMessage.AssistantMessage("hello", "msg-1");
|
|
|
|
sdkMessage.Text.Should().Be("hello");
|
|
sdkMessage.MessageId.Should().Be("msg-1");
|
|
}
|
|
|
|
[Fact]
|
|
public void SDKMessage_StreamingDeltaStoresText()
|
|
{
|
|
var sdkMessage = new SDKMessage.StreamingDelta("partial");
|
|
|
|
sdkMessage.Text.Should().Be("partial");
|
|
}
|
|
|
|
[Fact]
|
|
public void SDKMessage_ToolUseStartStoresAllFields()
|
|
{
|
|
var input = ParseJson("{\"path\":\"/tmp\"}");
|
|
|
|
var sdkMessage = new SDKMessage.ToolUseStart("tool-use-1", "read", input);
|
|
|
|
sdkMessage.ToolUseId.Should().Be("tool-use-1");
|
|
sdkMessage.ToolName.Should().Be("read");
|
|
sdkMessage.Input.GetProperty("path").GetString().Should().Be("/tmp");
|
|
}
|
|
|
|
[Fact]
|
|
public void SDKMessage_ToolUseResultStoresAllFields()
|
|
{
|
|
var message = CreateMessage();
|
|
|
|
var sdkMessage = new SDKMessage.ToolUseResult("tool-use-1", "ok", true, message);
|
|
|
|
sdkMessage.ToolUseId.Should().Be("tool-use-1");
|
|
sdkMessage.Output.Should().Be("ok");
|
|
sdkMessage.ShouldContinue.Should().BeTrue();
|
|
sdkMessage.Message.Should().BeSameAs(message);
|
|
}
|
|
|
|
[Fact]
|
|
public void SDKMessage_CompactBoundaryStoresReason()
|
|
{
|
|
var sdkMessage = new SDKMessage.CompactBoundary("token_limit");
|
|
|
|
sdkMessage.Reason.Should().Be("token_limit");
|
|
}
|
|
|
|
[Fact]
|
|
public void SDKMessage_AssistantErrorStoresError()
|
|
{
|
|
var sdkMessage = new SDKMessage.AssistantError("boom");
|
|
|
|
sdkMessage.Error.Should().Be("boom");
|
|
}
|
|
|
|
[Fact]
|
|
public void SDKMessage_PermissionDenialStoresFields()
|
|
{
|
|
var sdkMessage = new SDKMessage.PermissionDenial("bash", "tool-use-1");
|
|
|
|
sdkMessage.ToolName.Should().Be("bash");
|
|
sdkMessage.ToolUseId.Should().Be("tool-use-1");
|
|
}
|
|
|
|
[Fact]
|
|
public void SDKMessage_AssistantMessage_UsesValueEquality()
|
|
{
|
|
var left = new SDKMessage.AssistantMessage("hello", "msg-1");
|
|
var right = new SDKMessage.AssistantMessage("hello", "msg-1");
|
|
|
|
left.Should().Be(right);
|
|
}
|
|
|
|
[Fact]
|
|
public void SDKMessage_AssistantMessage_IsNotEqualWhenTextDiffers()
|
|
{
|
|
var left = new SDKMessage.AssistantMessage("hello", "msg-1");
|
|
var right = new SDKMessage.AssistantMessage("bye", "msg-1");
|
|
|
|
left.Should().NotBe(right);
|
|
}
|
|
|
|
[Fact]
|
|
public void SDKMessage_UserMessage_SupportsPatternMatching()
|
|
{
|
|
SDKMessage sdkMessage = new SDKMessage.UserMessage(CreateMessage());
|
|
|
|
var matched = sdkMessage is SDKMessage.UserMessage userMessage
|
|
&& userMessage.Message.Role == MessageRole.User;
|
|
|
|
matched.Should().BeTrue();
|
|
}
|
|
|
|
[Fact]
|
|
public void SDKMessage_ToolUseStart_CanStoreEmptyToolName()
|
|
{
|
|
var sdkMessage = new SDKMessage.ToolUseStart("tool-use-1", string.Empty, ParseJson("{}"));
|
|
|
|
sdkMessage.ToolName.Should().BeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void SDKMessage_ToolUseResult_PreservesFalseContinuationFlag()
|
|
{
|
|
var sdkMessage = new SDKMessage.ToolUseResult("tool-use-1", "output", false, CreateMessage());
|
|
|
|
sdkMessage.ShouldContinue.Should().BeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public void SDKMessage_StreamingDelta_AllowsEmptyText()
|
|
{
|
|
var sdkMessage = new SDKMessage.StreamingDelta(string.Empty);
|
|
|
|
sdkMessage.Text.Should().BeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void SDKMessage_AssistantError_AllowsEmptyErrorText()
|
|
{
|
|
var sdkMessage = new SDKMessage.AssistantError(string.Empty);
|
|
|
|
sdkMessage.Error.Should().BeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void SDKMessage_CompactBoundary_AllowsEmptyReason()
|
|
{
|
|
var sdkMessage = new SDKMessage.CompactBoundary(string.Empty);
|
|
|
|
sdkMessage.Reason.Should().BeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void SDKMessage_PermissionDenial_AllowsEmptyFields()
|
|
{
|
|
var sdkMessage = new SDKMessage.PermissionDenial(string.Empty, string.Empty);
|
|
|
|
sdkMessage.ToolName.Should().BeEmpty();
|
|
sdkMessage.ToolUseId.Should().BeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void SDKMessage_ToolUseStart_InputRemainsObjectJson()
|
|
{
|
|
var sdkMessage = new SDKMessage.ToolUseStart("tool-use-1", "read", ParseJson("{\"path\":\"/repo\"}"));
|
|
|
|
sdkMessage.Input.ValueKind.Should().Be(JsonValueKind.Object);
|
|
}
|
|
|
|
private static Message CreateMessage()
|
|
{
|
|
return new Message
|
|
{
|
|
MessageId = "msg-1",
|
|
Role = MessageRole.User,
|
|
Content = new object(),
|
|
Timestamp = new DateTime(2026, 4, 6, 10, 0, 0, DateTimeKind.Utc)
|
|
};
|
|
}
|
|
|
|
private static JsonElement ParseJson(string json)
|
|
{
|
|
using var document = JsonDocument.Parse(json);
|
|
return document.RootElement.Clone();
|
|
}
|
|
}
|