// Copyright (c) Microsoft. All rights reserved. using System; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.AI; using Moq; namespace Microsoft.Agents.AI.UnitTests; /// /// Unit tests for the class. /// public class DelegateLoopEvaluatorTests { /// /// Verify that the constructor throws when the evaluate delegate is null. /// [Fact] public void DelegateLoopEvaluator_NullDelegate_Throws() { // Act & Assert Assert.Throws("evaluate", () => new DelegateLoopEvaluator(null!)); } /// /// Verify that EvaluateAsync throws when the context is null. /// [Fact] public async Task EvaluateAsync_NullContext_ThrowsAsync() { // Arrange var evaluator = new DelegateLoopEvaluator((_, _) => new ValueTask(LoopEvaluation.Stop())); // Act & Assert await Assert.ThrowsAsync("context", async () => await evaluator.EvaluateAsync(null!)); } /// /// Verify that EvaluateAsync invokes the supplied delegate and returns the evaluation it produces. /// [Fact] public async Task EvaluateAsync_InvokesDelegate_AndReturnsItsEvaluationAsync() { // Arrange bool invoked = false; var expected = LoopEvaluation.Continue("feedback"); var evaluator = new DelegateLoopEvaluator((_, _) => { invoked = true; return new ValueTask(expected); }); LoopContext context = CreateContext(); // Act LoopEvaluation evaluation = await evaluator.EvaluateAsync(context); // Assert Assert.True(invoked); Assert.Same(expected, evaluation); } /// /// Verify that EvaluateAsync passes the same context instance to the delegate. /// [Fact] public async Task EvaluateAsync_PassesContextToDelegateAsync() { // Arrange LoopContext? received = null; var evaluator = new DelegateLoopEvaluator((ctx, _) => { received = ctx; return new ValueTask(LoopEvaluation.Stop()); }); LoopContext context = CreateContext(); // Act await evaluator.EvaluateAsync(context); // Assert Assert.Same(context, received); } /// /// Verify that EvaluateAsync forwards the cancellation token to the delegate. /// [Fact] public async Task EvaluateAsync_ForwardsCancellationTokenToDelegateAsync() { // Arrange using var cts = new CancellationTokenSource(); CancellationToken received = default; var evaluator = new DelegateLoopEvaluator((_, ct) => { received = ct; return new ValueTask(LoopEvaluation.Stop()); }); LoopContext context = CreateContext(); // Act await evaluator.EvaluateAsync(context, cts.Token); // Assert Assert.Equal(cts.Token, received); } private static LoopContext CreateContext() => new( new Mock().Object, new ChatClientAgentSession(), [new ChatMessage(ChatRole.User, "go")], new AgentResponse([new ChatMessage(ChatRole.Assistant, "response")])); }