// Copyright (c) Microsoft. All rights reserved. using System; using System.Reflection; using System.Threading; using System.Threading.Tasks; namespace Microsoft.Agents.AI.UnitTests.AgentSkills; /// /// Unit tests for . /// public sealed class AgentInlineSkillResourceTests { [Fact] public async Task ReadAsync_StaticValue_ReturnsValueAsync() { // Arrange var resource = new AgentInlineSkillResource("config", "my-value"); // Act var result = await resource.ReadAsync(); // Assert Assert.Equal("my-value", result); } [Fact] public async Task ReadAsync_StaticObjectValue_ReturnsSameInstanceAsync() { // Arrange var obj = new object(); var resource = new AgentInlineSkillResource("ref", obj); // Act var result = await resource.ReadAsync(); // Assert Assert.Same(obj, result); } [Fact] public async Task ReadAsync_Delegate_InvokesFunctionAsync() { // Arrange int callCount = 0; var resource = new AgentInlineSkillResource("dynamic", () => { callCount++; return "computed"; }); // Act var result = await resource.ReadAsync(); // Assert Assert.Equal("computed", result?.ToString()); Assert.Equal(1, callCount); } [Fact] public async Task ReadAsync_Delegate_InvokesEachTimeAsync() { // Arrange int callCount = 0; var resource = new AgentInlineSkillResource("counter", () => ++callCount); // Act await resource.ReadAsync(); await resource.ReadAsync(); var result = await resource.ReadAsync(); // Assert Assert.Equal(3, callCount); } [Fact] public void Constructor_StaticValue_SetsNameAndDescription() { // Arrange & Act var resource = new AgentInlineSkillResource("my-res", "val", "A description."); // Assert Assert.Equal("my-res", resource.Name); Assert.Equal("A description.", resource.Description); } [Fact] public void Constructor_StaticValue_NullDescription_DescriptionIsNull() { // Arrange & Act var resource = new AgentInlineSkillResource("my-res", "val"); // Assert Assert.Null(resource.Description); } [Fact] public void Constructor_StaticValue_NullValue_Throws() { // Act & Assert — cast needed to target the object overload #pragma warning disable IDE0004 Assert.Throws(() => new AgentInlineSkillResource("my-res", (object)null!)); #pragma warning restore IDE0004 } [Fact] public void Constructor_Delegate_NullMethod_Throws() { // Act & Assert Assert.Throws(() => new AgentInlineSkillResource("my-res", null!)); } [Fact] public void Constructor_NullName_Throws() { // Act & Assert Assert.Throws(() => new AgentInlineSkillResource(null!, "val")); } [Fact] public void Constructor_WhitespaceName_Throws() { // Act & Assert Assert.Throws(() => new AgentInlineSkillResource(" ", "val")); } [Fact] public void Constructor_Delegate_SetsNameAndDescription() { // Arrange & Act var resource = new AgentInlineSkillResource("dyn-res", () => "hello", "Dynamic resource."); // Assert Assert.Equal("dyn-res", resource.Name); Assert.Equal("Dynamic resource.", resource.Description); } [Fact] public async Task ReadAsync_WithSerializerOptions_SerializesReturnCustomTypeAsync() { // Arrange — delegate resource returns a custom type; the JSO includes a source-generated context for it var jso = SkillTestJsonContext.Default.Options; var resource = new AgentInlineSkillResource("config", () => new SkillConfig { Theme = "dark", Verbose = true }, serializerOptions: jso); // Act var result = await resource.ReadAsync(); // Assert — the custom type was returned successfully Assert.NotNull(result); Assert.Contains("dark", result!.ToString()!); } [Fact] public async Task ReadAsync_SupportsCancellationTokenAsync() { // Arrange using var cts = new CancellationTokenSource(); var resource = new AgentInlineSkillResource("cancellable", "value"); // Act — should not throw with a non-cancelled token var result = await resource.ReadAsync(cancellationToken: cts.Token); // Assert Assert.Equal("value", result); } [Fact] public void Constructor_MethodInfo_SetsNameAndDescription() { // Arrange var method = typeof(AgentInlineSkillResourceTests).GetMethod(nameof(StaticResourceHelper), BindingFlags.NonPublic | BindingFlags.Static)!; // Act var resource = new AgentInlineSkillResource("method-resource", method, target: null, description: "A method resource."); // Assert Assert.Equal("method-resource", resource.Name); Assert.Equal("A method resource.", resource.Description); } [Fact] public async Task ReadAsync_MethodInfo_StaticMethod_ReturnsValueAsync() { // Arrange var method = typeof(AgentInlineSkillResourceTests).GetMethod(nameof(StaticResourceHelper), BindingFlags.NonPublic | BindingFlags.Static)!; var resource = new AgentInlineSkillResource("static-method-res", method, target: null); // Act var result = await resource.ReadAsync(); // Assert Assert.Equal("static-resource-value", result?.ToString()); } [Fact] public async Task ReadAsync_MethodInfo_InstanceMethod_ReturnsValueAsync() { // Arrange var method = typeof(AgentInlineSkillResourceTests).GetMethod(nameof(InstanceResourceHelper), BindingFlags.NonPublic | BindingFlags.Instance)!; var resource = new AgentInlineSkillResource("instance-method-res", method, target: this); // Act var result = await resource.ReadAsync(); // Assert Assert.Equal("instance-resource-value", result?.ToString()); } [Fact] public void Constructor_MethodInfo_NullMethod_Throws() { // Act & Assert Assert.Throws(() => new AgentInlineSkillResource("my-res", null!, target: null)); } private static string StaticResourceHelper() => "static-resource-value"; private string InstanceResourceHelper() => "instance-resource-value"; }