테스트 회귀망 강화: 권한 모드/슬래시 카탈로그 L4 통합 검증 추가
Some checks failed
Release Gate / gate (push) Has been cancelled

- PermissionModeCatalogTests 추가: 글로벌/도구 정규화, 승인 필요 정책, 한국어 표시 라벨 검증

- PermissionModePresentationCatalogTests 추가: 권한 표면 순서와 unknown fallback(Default) 검증

- SlashCommandCatalogTests 추가: dev 전용 명령 필터링과 /compact,/permissions,/mcp 핵심 명령 등록 검증

- OperationModePolicyTests 보강: deny 패턴이 allow 패턴보다 우선되는 충돌 케이스 추가

- README.md, docs/DEVELOPMENT.md에 2026-04-04 13:40(KST) 기준 이력 반영
This commit is contained in:
2026-04-04 13:40:58 +09:00
parent d9169ed3ea
commit b1fa8f692a
6 changed files with 166 additions and 1 deletions

View File

@@ -103,6 +103,23 @@ public class OperationModePolicyTests
askCalled.Should().BeFalse();
}
[Fact]
public void AgentContext_GetEffectiveToolPermission_DenyPatternPrecedesAllowPattern()
{
var context = new AgentContext
{
Permission = "AcceptEdits",
ToolPermissions = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
["process@git *"] = "acceptedits",
["process@git push *"] = "deny",
}
};
context.GetEffectiveToolPermission("process", "git status").Should().Be("Default");
context.GetEffectiveToolPermission("process", "git push origin main").Should().Be("Deny");
}
[Fact]
public void AgentContext_GetEffectiveToolPermission_AcceptEditsAllowsWriteButKeepsProcessPrompted()
{

View File

@@ -0,0 +1,61 @@
using AxCopilot.Services.Agent;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Services;
public class PermissionModeCatalogTests
{
[Theory]
[InlineData(null, PermissionModeCatalog.Default)]
[InlineData("", PermissionModeCatalog.Default)]
[InlineData("ask", PermissionModeCatalog.Default)]
[InlineData("auto", PermissionModeCatalog.AcceptEdits)]
[InlineData("accept", PermissionModeCatalog.AcceptEdits)]
[InlineData("plan", PermissionModeCatalog.Plan)]
[InlineData("bypass", PermissionModeCatalog.BypassPermissions)]
[InlineData("dontask", PermissionModeCatalog.DontAsk)]
[InlineData("deny", PermissionModeCatalog.Deny)]
[InlineData("unknown", PermissionModeCatalog.Default)]
public void NormalizeGlobalMode_ShouldMapExpectedModes(string? input, string expected)
{
PermissionModeCatalog.NormalizeGlobalMode(input).Should().Be(expected);
}
[Theory]
[InlineData("ask", PermissionModeCatalog.Default)]
[InlineData("auto", PermissionModeCatalog.AcceptEdits)]
[InlineData("plan", PermissionModeCatalog.Plan)]
[InlineData("bypass", PermissionModeCatalog.BypassPermissions)]
[InlineData("dontask", PermissionModeCatalog.DontAsk)]
[InlineData("deny", PermissionModeCatalog.Deny)]
[InlineData("unknown", PermissionModeCatalog.Default)]
public void NormalizeToolOverride_ShouldMapExpectedModes(string? input, string expected)
{
PermissionModeCatalog.NormalizeToolOverride(input).Should().Be(expected);
}
[Theory]
[InlineData("ask", true)]
[InlineData("auto", false)]
[InlineData("acceptedits", false)]
[InlineData("bypassPermissions", false)]
[InlineData("dontAsk", false)]
[InlineData("deny", false)]
public void RequiresUserApproval_ShouldMatchPolicy(string? input, bool expected)
{
PermissionModeCatalog.RequiresUserApproval(input).Should().Be(expected);
}
[Theory]
[InlineData(PermissionModeCatalog.Deny, "활용하지 않음")]
[InlineData(PermissionModeCatalog.Default, "소극 활용")]
[InlineData(PermissionModeCatalog.AcceptEdits, "적극 활용")]
[InlineData(PermissionModeCatalog.Plan, "계획 중심")]
[InlineData(PermissionModeCatalog.BypassPermissions, "완전 자동")]
[InlineData(PermissionModeCatalog.DontAsk, "질문 없이 진행")]
public void ToDisplayLabel_ShouldReturnKoreanLabel(string mode, string expected)
{
PermissionModeCatalog.ToDisplayLabel(mode).Should().Be(expected);
}
}

View File

@@ -0,0 +1,29 @@
using AxCopilot.Services.Agent;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Services;
public class PermissionModePresentationCatalogTests
{
[Fact]
public void Ordered_ShouldMatchExpectedModeOrder()
{
PermissionModePresentationCatalog.Ordered.Select(x => x.Mode).Should().ContainInOrder(
[
PermissionModeCatalog.Deny,
PermissionModeCatalog.Default,
PermissionModeCatalog.AcceptEdits,
PermissionModeCatalog.Plan,
PermissionModeCatalog.BypassPermissions,
PermissionModeCatalog.DontAsk,
]);
}
[Fact]
public void Resolve_ShouldFallbackToDefaultPresentation_OnUnknownMode()
{
var resolved = PermissionModePresentationCatalog.Resolve("unknown-mode");
resolved.Mode.Should().Be(PermissionModeCatalog.Default);
}
}

View File

@@ -0,0 +1,31 @@
using AxCopilot.Views;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Views;
public class SlashCommandCatalogTests
{
[Fact]
public void MatchBuiltinCommands_ShouldFilterDevCommandsInChatTab()
{
var chatMatches = SlashCommandCatalog.MatchBuiltinCommands("/rev", isDevTab: false);
var devMatches = SlashCommandCatalog.MatchBuiltinCommands("/rev", isDevTab: true);
chatMatches.Should().BeEmpty();
devMatches.Should().ContainSingle(x => x.Cmd == "/review");
}
[Fact]
public void Catalog_ShouldContainCoreParityCommands()
{
SlashCommandCatalog.TryGetEntry("/compact", out var compactEntry).Should().BeTrue();
compactEntry.SystemPrompt.Should().Be("__COMPACT__");
SlashCommandCatalog.TryGetEntry("/permissions", out var permissionEntry).Should().BeTrue();
permissionEntry.SystemPrompt.Should().Be("__PERMISSIONS__");
SlashCommandCatalog.TryGetEntry("/mcp", out var mcpEntry).Should().BeTrue();
mcpEntry.SystemPrompt.Should().Be("__MCP__");
}
}