free-code-dotnet/tests/FreeCode.Tests.Unit/Models/OperationResultAndTokenUsageTests.cs
应文浩wenhao.ying@xiaobao100.com bce2612b64 feat: 完善具体实现
2026-04-06 15:25:34 +08:00

183 lines
4.6 KiB
C#

using Xunit;
using FluentAssertions;
using NSubstitute;
using System.Collections.Generic;
using FreeCode.Core.Models;
namespace FreeCode.Tests.Unit.Models;
public sealed class OperationResultAndTokenUsageTests
{
[Fact]
public void PermissionResult_Allowed_ReturnsAllowedWithNullReason()
{
var result = PermissionResult.Allowed();
result.IsAllowed.Should().BeTrue();
result.Reason.Should().BeNull();
}
[Fact]
public void PermissionResult_Denied_ReturnsDeniedWithReason()
{
var result = PermissionResult.Denied("not allowed");
result.IsAllowed.Should().BeFalse();
result.Reason.Should().Be("not allowed");
}
[Fact]
public void PermissionResult_Constructor_CanCreateAllowedWithReason()
{
var result = new PermissionResult(true, "manual");
result.IsAllowed.Should().BeTrue();
result.Reason.Should().Be("manual");
}
[Fact]
public void PermissionResult_UsesValueEquality()
{
var left = PermissionResult.Denied("reason");
var right = PermissionResult.Denied("reason");
left.Should().Be(right);
}
[Fact]
public void ValidationResult_Success_ReturnsValidWithoutErrors()
{
var result = ValidationResult.Success();
result.IsValid.Should().BeTrue();
result.Errors.Should().BeEmpty();
}
[Fact]
public void ValidationResult_Failure_ReturnsInvalidWithSingleError()
{
var result = ValidationResult.Failure(["missing field"]);
result.IsValid.Should().BeFalse();
result.Errors.Should().ContainSingle().Which.Should().Be("missing field");
}
[Fact]
public void ValidationResult_Failure_PreservesErrorOrder()
{
var result = ValidationResult.Failure(["first", "second", "third"]);
result.Errors.Should().ContainInOrder("first", "second", "third");
}
[Fact]
public void ValidationResult_Failure_AllowsEmptyEnumerable()
{
var result = ValidationResult.Failure([]);
result.IsValid.Should().BeFalse();
result.Errors.Should().BeEmpty();
}
[Fact]
public void ValidationResult_Success_UsesValueEquality()
{
var left = ValidationResult.Success();
var right = ValidationResult.Success();
left.Should().Be(right);
}
[Fact]
public void ValidationResult_Failure_CopiesInputSequence()
{
var errors = new List<string> { "first" };
var result = ValidationResult.Failure(errors);
errors.Add("second");
result.Errors.Should().ContainSingle().Which.Should().Be("first");
}
[Fact]
public void TokenUsage_HoldsAllCounts()
{
var usage = new TokenUsage(10, 20, 30, 40);
usage.InputTokens.Should().Be(10);
usage.OutputTokens.Should().Be(20);
usage.CacheCreationTokens.Should().Be(30);
usage.CacheReadTokens.Should().Be(40);
}
[Fact]
public void TokenUsage_UsesValueEquality()
{
var left = new TokenUsage(1, 2, 3, 4);
var right = new TokenUsage(1, 2, 3, 4);
left.Should().Be(right);
}
[Fact]
public void TokenUsage_DeconstructsIntoOriginalValues()
{
var usage = new TokenUsage(1, 2, 3, 4);
var (input, output, cacheCreation, cacheRead) = usage;
input.Should().Be(1);
output.Should().Be(2);
cacheCreation.Should().Be(3);
cacheRead.Should().Be(4);
}
[Fact]
public void TokenUsage_AllowsZeroCounts()
{
var usage = new TokenUsage(0, 0, 0, 0);
usage.Should().Be(new TokenUsage(0, 0, 0, 0));
}
[Fact]
public void TokenUsage_PassivelyStoresNegativeCounts()
{
var usage = new TokenUsage(-1, -2, -3, -4);
usage.InputTokens.Should().Be(-1);
usage.OutputTokens.Should().Be(-2);
usage.CacheCreationTokens.Should().Be(-3);
usage.CacheReadTokens.Should().Be(-4);
}
[Fact]
public void TokenUsage_CanBeSummedByConsumerCode()
{
var usage = new TokenUsage(10, 20, 30, 40);
var total = usage.InputTokens + usage.OutputTokens + usage.CacheCreationTokens + usage.CacheReadTokens;
total.Should().Be(100);
}
[Fact]
public void TokenUsage_CanBeStoredInsideASubstituteConsumer()
{
var usage = new TokenUsage(2, 4, 6, 8);
var holder = new TokenUsageHolder(usage);
holder.Usage.Should().Be(usage);
}
private sealed class TokenUsageHolder(TokenUsage usage) : ITokenUsageHolder
{
public TokenUsage Usage { get; } = usage;
}
public interface ITokenUsageHolder
{
TokenUsage Usage { get; }
}
}