using System;
using System.Threading;
using PolyTrader.Core.Agents;
using Xunit;
namespace PolyTrader.Tests
{
///
/// Sicherheitsnetz für die aus ClawdDotNet übernommenen Agenten-Bausteine: LoopGuard (Kostendeckel
/// Schritte/Tokens/Zeit) und PermissionGate (Tool-Allow-List).
///
public class AgentGuardTests
{
// ----- LoopGuard -----
[Fact]
public void LoopGuard_throws_when_step_limit_exceeded()
{
var guard = new LoopGuard(new AgentBudget { MaxSteps = 2, MaxTokens = 1_000_000, Timeout = TimeSpan.FromMinutes(5) });
guard.RecordStep(); // 1
guard.RecordStep(); // 2
var ex = Assert.Throws(() => guard.RecordStep()); // 3 -> Abbruch
Assert.Equal(AgentBudgetKind.Steps, ex.Kind);
}
[Fact]
public void LoopGuard_throws_when_token_budget_exceeded()
{
var guard = new LoopGuard(new AgentBudget { MaxSteps = 100, MaxTokens = 100, Timeout = TimeSpan.FromMinutes(5) });
guard.RecordTokens(60);
var ex = Assert.Throws(() => guard.RecordTokens(60)); // 120 > 100
Assert.Equal(AgentBudgetKind.Tokens, ex.Kind);
Assert.Equal(120, guard.Tokens);
}
[Fact]
public void LoopGuard_ignores_non_positive_token_counts()
{
var guard = new LoopGuard(new AgentBudget { MaxTokens = 10 });
guard.RecordTokens(0);
guard.RecordTokens(-5);
Assert.Equal(0, guard.Tokens);
}
[Fact]
public void LoopGuard_throws_when_time_budget_exceeded()
{
var guard = new LoopGuard(new AgentBudget { MaxSteps = 100, MaxTokens = 1_000_000, Timeout = TimeSpan.FromMilliseconds(10) });
Thread.Sleep(40);
var ex = Assert.Throws(() => guard.ThrowIfExpired());
Assert.Equal(AgentBudgetKind.Time, ex.Kind);
}
// ----- PermissionGate -----
[Fact]
public void PermissionGate_allows_listed_tool_case_insensitive()
{
var gate = new PermissionGate();
var allowed = new[] { "read_logs", "query_trades" };
Assert.True(gate.IsAllowed("READ_LOGS", allowed));
Assert.False(gate.IsAllowed("place_order", allowed));
}
[Fact]
public void PermissionGate_null_allowlist_permits_everything()
{
var gate = new PermissionGate();
Assert.True(gate.IsAllowed("anything", null));
}
[Fact]
public void PermissionGate_enforce_throws_for_denied_tool()
{
var gate = new PermissionGate();
Assert.Throws(() => gate.Enforce("place_order", new[] { "read_logs" }));
}
}
}