Initial commit to new repository
This commit is contained in:
165
src/AxCopilot.Tests/Services/SkillServiceRuntimePolicyTests.cs
Normal file
165
src/AxCopilot.Tests/Services/SkillServiceRuntimePolicyTests.cs
Normal file
@@ -0,0 +1,165 @@
|
||||
using AxCopilot.Services.Agent;
|
||||
using FluentAssertions;
|
||||
using Xunit;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace AxCopilot.Tests.Services;
|
||||
|
||||
public class SkillServiceRuntimePolicyTests
|
||||
{
|
||||
[Fact]
|
||||
public void BuildRuntimeDirective_ReturnsEmpty_WhenNoRuntimeMetadata()
|
||||
{
|
||||
var skill = new SkillDefinition
|
||||
{
|
||||
Name = "plain-skill",
|
||||
SystemPrompt = "do work"
|
||||
};
|
||||
|
||||
var directive = SkillService.BuildRuntimeDirective(skill);
|
||||
|
||||
directive.Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildRuntimeDirective_ContainsForkAgentEffortAndModelHints()
|
||||
{
|
||||
var skill = new SkillDefinition
|
||||
{
|
||||
Name = "advanced-skill",
|
||||
ExecutionContext = "fork",
|
||||
Agent = "worker",
|
||||
Effort = "high",
|
||||
Model = "gpt-5.4",
|
||||
DisableModelInvocation = true,
|
||||
AllowedTools = "Read, process, WebFetch",
|
||||
Hooks = "lint-pre, verify-post",
|
||||
HookFilters = "lint-pre@pre@file_edit, verify-post@post@*"
|
||||
};
|
||||
|
||||
var directive = SkillService.BuildRuntimeDirective(skill);
|
||||
|
||||
directive.Should().Contain("[Skill Runtime Policy]");
|
||||
directive.Should().Contain("execution_context: fork");
|
||||
directive.Should().Contain("preferred_agent: worker");
|
||||
directive.Should().Contain("reasoning_effort: high");
|
||||
directive.Should().Contain("preferred_model: gpt-5.4");
|
||||
directive.Should().Contain("allowed_tools: file_read, http_tool, process");
|
||||
directive.Should().Contain("hook_names: lint-pre, verify-post");
|
||||
directive.Should().Contain("hook_filters: lint-pre@pre@file_edit, verify-post@post@*");
|
||||
directive.Should().Contain("disable_model_invocation");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParseSkillFile_HooksMapAndList_AreNormalizedIntoHooksField()
|
||||
{
|
||||
var tempDir = Path.Combine(Path.GetTempPath(), "axcopilot-skill-hooks-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(tempDir);
|
||||
var skillPath = Path.Combine(tempDir, "SKILL.md");
|
||||
try
|
||||
{
|
||||
var content = """
|
||||
---
|
||||
name: hook-skill
|
||||
hooks:
|
||||
pre: lint-pre, verify-pre
|
||||
post:
|
||||
- verify-post
|
||||
- report-post
|
||||
---
|
||||
|
||||
body
|
||||
""";
|
||||
File.WriteAllText(skillPath, content, Encoding.UTF8);
|
||||
|
||||
var method = typeof(SkillService).GetMethod("ParseSkillFile", BindingFlags.NonPublic | BindingFlags.Static);
|
||||
method.Should().NotBeNull();
|
||||
|
||||
var parsed = method!.Invoke(null, [skillPath]) as SkillDefinition;
|
||||
parsed.Should().NotBeNull();
|
||||
parsed!.Hooks.Should().Contain("lint-pre");
|
||||
parsed.Hooks.Should().Contain("verify-pre");
|
||||
parsed.Hooks.Should().Contain("verify-post");
|
||||
parsed.Hooks.Should().Contain("report-post");
|
||||
parsed.HookFilters.Should().Contain("lint-pre@pre@*");
|
||||
parsed.HookFilters.Should().Contain("verify-pre@pre@*");
|
||||
parsed.HookFilters.Should().Contain("*@post@*");
|
||||
}
|
||||
finally
|
||||
{
|
||||
try { if (Directory.Exists(tempDir)) Directory.Delete(tempDir, true); } catch { }
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParseSkillFile_NestedHooksMap_PreservesToolTimingFilters()
|
||||
{
|
||||
var tempDir = Path.Combine(Path.GetTempPath(), "axcopilot-skill-hooks-nested-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(tempDir);
|
||||
var skillPath = Path.Combine(tempDir, "SKILL.md");
|
||||
try
|
||||
{
|
||||
var content = """
|
||||
---
|
||||
name: nested-hook-skill
|
||||
hooks:
|
||||
file_edit:
|
||||
pre:
|
||||
- lint-pre
|
||||
post: verify-post
|
||||
---
|
||||
|
||||
body
|
||||
""";
|
||||
File.WriteAllText(skillPath, content, Encoding.UTF8);
|
||||
|
||||
var method = typeof(SkillService).GetMethod("ParseSkillFile", BindingFlags.NonPublic | BindingFlags.Static);
|
||||
method.Should().NotBeNull();
|
||||
|
||||
var parsed = method!.Invoke(null, [skillPath]) as SkillDefinition;
|
||||
parsed.Should().NotBeNull();
|
||||
parsed!.Hooks.Should().Contain("lint-pre");
|
||||
parsed.Hooks.Should().Contain("verify-post");
|
||||
parsed.HookFilters.Should().Contain("lint-pre@pre@file_edit");
|
||||
parsed.HookFilters.Should().Contain("verify-post@post@file_edit");
|
||||
}
|
||||
finally
|
||||
{
|
||||
try { if (Directory.Exists(tempDir)) Directory.Delete(tempDir, true); } catch { }
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParseSkillFile_SampleFlag_SetsIsSample()
|
||||
{
|
||||
var tempDir = Path.Combine(Path.GetTempPath(), "axcopilot-skill-sample-" + Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(tempDir);
|
||||
var skillPath = Path.Combine(tempDir, "SKILL.md");
|
||||
try
|
||||
{
|
||||
var content = """
|
||||
---
|
||||
name: sample-skill
|
||||
sample: true
|
||||
---
|
||||
|
||||
body
|
||||
""";
|
||||
File.WriteAllText(skillPath, content, Encoding.UTF8);
|
||||
|
||||
var method = typeof(SkillService).GetMethod("ParseSkillFile", BindingFlags.NonPublic | BindingFlags.Static);
|
||||
method.Should().NotBeNull();
|
||||
|
||||
var parsed = method!.Invoke(null, [skillPath]) as SkillDefinition;
|
||||
parsed.Should().NotBeNull();
|
||||
parsed!.IsSample.Should().BeTrue();
|
||||
}
|
||||
finally
|
||||
{
|
||||
try { if (Directory.Exists(tempDir)) Directory.Delete(tempDir, true); } catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user