// Copyright (c) Microsoft. All rights reserved. using System; using System.Text.Json; using System.Threading; using System.Threading.Tasks; namespace Microsoft.Agents.AI.UnitTests.AgentSkills; /// /// Unit tests for . /// public sealed class AgentFileSkillScriptTests { [Fact] public async Task RunAsync_SkillIsNotAgentFileSkill_ThrowsInvalidOperationExceptionAsync() { // Arrange static Task RunnerAsync(AgentFileSkill s, AgentFileSkillScript sc, JsonElement? a, IServiceProvider? sp, CancellationToken ct) => Task.FromResult("result"); var script = CreateScript("test-script", "/path/to/script.py", RunnerAsync); var nonFileSkill = new TestAgentSkill("my-skill", "A skill", "Instructions."); // Act & Assert await Assert.ThrowsAsync( () => script.RunAsync(nonFileSkill, null, null, CancellationToken.None)); } [Fact] public async Task RunAsync_WithAgentFileSkill_DelegatesToRunnerAsync() { // Arrange var runnerCalled = false; Task runnerAsync(AgentFileSkill skill, AgentFileSkillScript scriptArg, JsonElement? args, IServiceProvider? sp, CancellationToken ct) { runnerCalled = true; return Task.FromResult("executed"); } var script = CreateScript("run-me", "/scripts/run-me.sh", runnerAsync); var fileSkill = new AgentFileSkill( new AgentSkillFrontmatter("my-skill", "A file skill"), "---\nname: my-skill\n---\nContent", "/skills/my-skill"); // Act var result = await script.RunAsync(fileSkill, null, null, CancellationToken.None); // Assert Assert.True(runnerCalled); Assert.Equal("executed", result); } [Fact] public async Task RunAsync_RunnerReceivesCorrectArgumentsAsync() { // Arrange AgentFileSkill? capturedSkill = null; AgentFileSkillScript? capturedScript = null; Task runnerAsync(AgentFileSkill skill, AgentFileSkillScript scriptArg, JsonElement? args, IServiceProvider? sp, CancellationToken ct) { capturedSkill = skill; capturedScript = scriptArg; return Task.FromResult(null); } var script = CreateScript("capture", "/scripts/capture.py", runnerAsync); var fileSkill = new AgentFileSkill( new AgentSkillFrontmatter("owner-skill", "Owner"), "Content", "/skills/owner-skill"); // Act await script.RunAsync(fileSkill, null, null, CancellationToken.None); // Assert Assert.Same(fileSkill, capturedSkill); Assert.Same(script, capturedScript); } [Fact] public void Script_HasCorrectNameAndPath() { // Arrange & Act static Task RunnerAsync(AgentFileSkill s, AgentFileSkillScript sc, JsonElement? a, IServiceProvider? sp, CancellationToken ct) => Task.FromResult(null); var script = CreateScript("my-script", "/path/to/my-script.py", RunnerAsync); // Assert Assert.Equal("my-script", script.Name); Assert.Equal("/path/to/my-script.py", script.FullPath); } [Fact] public void ParametersSchema_ReturnsExpectedArraySchema() { // Arrange static Task RunnerAsync(AgentFileSkill s, AgentFileSkillScript sc, JsonElement? a, IServiceProvider? sp, CancellationToken ct) => Task.FromResult(null); var script = CreateScript("my-script", "/path/to/script.py", RunnerAsync); // Act var schema = script.ParametersSchema; // Assert Assert.NotNull(schema); var raw = schema!.Value.GetRawText(); Assert.Contains("\"type\":\"array\"", raw); Assert.Contains("\"items\":{\"type\":\"string\"}", raw); } [Fact] public void Content_WithScripts_AppendsPerScriptEntries() { // Arrange static Task RunnerAsync(AgentFileSkill s, AgentFileSkillScript sc, JsonElement? a, IServiceProvider? sp, CancellationToken ct) => Task.FromResult(null); var script1 = CreateScript("build", "/scripts/build.sh", RunnerAsync); var script2 = CreateScript("deploy", "/scripts/deploy.sh", RunnerAsync); var fileSkill = new AgentFileSkill( new AgentSkillFrontmatter("my-skill", "A skill"), "Original content", "/skills/my-skill", scripts: [script1, script2]); // Act var content = fileSkill.Content; // Assert — content starts with original and appends per-script entries Assert.StartsWith("Original content", content); Assert.Contains("", content); Assert.Contains("