Skip to content

Commit

Permalink
.Net: Adding the ability to redirect system.Console output to test ou…
Browse files Browse the repository at this point in the history
…tput. (#9023)

### Description

The PR adds the ability to redirect `system.Console` output to test
output. The implementation requires a test to opt-in to this
functionality so that existing tests will not change functionality by
default.

***Why not just use `ITestOutputHelper ` or the `BaseTest` built in
`WriteX(...)`?***

Because the process tests make use of several other classes that are
writing console logs from within their functions. In order to use
`ITestOutputHelper ` we would need to inject this object into those
classes. While this is possible, it adds extra code that is unrelated to
what the sample is demonstrating and increases the cognitive load on
people using the samples to learn.

fixes #9009 

After this change, running Step01_Processes produces the following test
output:

<img width="751" alt="image"
src="https://github.com/user-attachments/assets/d1aab358-213e-4d98-9e67-c9bf4d564853">


### Contribution Checklist

<!-- Before submitting this PR, please make sure: -->

- [x] The code builds clean without any errors or warnings
- [x] The PR follows the [SK Contribution
Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md)
and the [pre-submission formatting
script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts)
raises no violations
- [x] All unit tests pass, and I have added new tests where possible
- [x] I didn't break anyone 😄

---------

Co-authored-by: Ben Thomas <bentho@microsoft.com>
Co-authored-by: Chris <66376200+crickman@users.noreply.github.com>
  • Loading branch information
3 people committed Sep 27, 2024
1 parent c20f0fc commit 2724f34
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 35 deletions.
18 changes: 14 additions & 4 deletions dotnet/samples/Concepts/PromptTemplates/SafeChatPrompts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@

namespace PromptTemplates;

public sealed class SafeChatPrompts : BaseTest, IDisposable
public sealed class SafeChatPrompts : BaseTest
{
private readonly LoggingHandler _handler;
private readonly HttpClient _httpClient;
private readonly Kernel _kernel;
private bool _isDisposed;

public SafeChatPrompts(ITestOutputHelper output) : base(output)
{
Expand All @@ -25,10 +26,19 @@ public SafeChatPrompts(ITestOutputHelper output) : base(output)
.Build();
}

public void Dispose()
protected override void Dispose(bool disposing)
{
this._handler.Dispose();
this._httpClient.Dispose();
if (!this._isDisposed)
{
if (disposing)
{
this._handler.Dispose();
this._httpClient.Dispose();
}

this._isDisposed = true;
}
base.Dispose(disposing);
}

/// <summary>
Expand Down
17 changes: 13 additions & 4 deletions dotnet/samples/GettingStartedWithProcesses/Step01_Processes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace GettingStartedWithProcesses;
/// Demonstrate creation of <see cref="KernelProcess"/> and
/// eliciting its response to three explicit user messages.
/// </summary>
public class Step01_Processes(ITestOutputHelper output) : BaseTest(output)
public class Step01_Processes(ITestOutputHelper output) : BaseTest(output, redirectSystemConsoleOutput: true)
{
/// <summary>
/// Demonstrates the creation of a simple process that has multiple steps, takes
Expand Down Expand Up @@ -103,7 +103,9 @@ public override ValueTask ActivateAsync(KernelProcessStepState<UserInputState> s
_state = state.State;

_state.UserInputs.Add("Hello");
_state.UserInputs.Add("How are you?");
_state.UserInputs.Add("How tall is the tallest mountain?");
_state.UserInputs.Add("How low is the lowest valley?");
_state.UserInputs.Add("How wide is the widest river?");
_state.UserInputs.Add("exit");

return ValueTask.CompletedTask;
Expand All @@ -121,6 +123,8 @@ public async ValueTask GetUserInputAsync(KernelProcessStepContext context)
var input = _state!.UserInputs[_state.CurrentInputIndex];
_state.CurrentInputIndex++;

System.Console.WriteLine($"User: {input}");

if (input.Equals("exit", StringComparison.OrdinalIgnoreCase))
{
// Emit the exit event
Expand Down Expand Up @@ -168,11 +172,16 @@ public async Task GetChatResponseAsync(KernelProcessStepContext context, string
_state!.ChatMessages.Add(new(AuthorRole.User, userMessage));
IChatCompletionService chatService = _kernel.Services.GetRequiredService<IChatCompletionService>();
ChatMessageContent response = await chatService.GetChatMessageContentAsync(_state.ChatMessages).ConfigureAwait(false);
if (response != null)
if (response == null)
{
_state.ChatMessages.Add(response!);
throw new InvalidOperationException("Failed to get a response from the chat completion service.");
}

System.Console.WriteLine($"Assistant: {response.Content}");

// Update state with the response
_state.ChatMessages.Add(response);

// emit event: assistantResponse
await context.EmitEventAsync(new KernelProcessEvent { Id = ChatBotEvents.AssistantResponseGenerated, Data = response });
}
Expand Down
51 changes: 24 additions & 27 deletions dotnet/src/InternalUtilities/samples/InternalUtilities/BaseTest.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Reflection;
using System.Text;
using System.Text.Json;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;

public abstract class BaseTest
public abstract class BaseTest : TextWriter
{
/// <summary>
/// Flag to force usage of OpenAI configuration if both <see cref="TestConfiguration.OpenAI"/>
Expand Down Expand Up @@ -59,7 +60,7 @@ protected Kernel CreateKernelWithChatCompletion()
return builder.Build();
}

protected BaseTest(ITestOutputHelper output)
protected BaseTest(ITestOutputHelper output, bool redirectSystemConsoleOutput = false)
{
this.Output = output;
this.LoggerFactory = new XunitLogger(output);
Expand All @@ -71,36 +72,32 @@ protected BaseTest(ITestOutputHelper output)
.Build();

TestConfiguration.Initialize(configRoot);

// Redirect System.Console output to the test output if requested
if (redirectSystemConsoleOutput)
{
System.Console.SetOut(this);
}
}

/// <summary>
/// This method can be substituted by Console.WriteLine when used in Console apps.
/// </summary>
/// <param name="target">Target object to write</param>
public void WriteLine(object? target = null)
=> this.Output.WriteLine(target ?? string.Empty);
/// <inheritdoc/>
public override void WriteLine(object? value = null)
=> this.Output.WriteLine(value ?? string.Empty);

/// <summary>
/// This method can be substituted by Console.WriteLine when used in Console apps.
/// </summary>
/// <param name="format">Format string</param>
/// <param name="args">Arguments</param>
public void WriteLine(string? format, params object?[] args)
=> this.Output.WriteLine(format ?? string.Empty, args);
/// <inheritdoc/>
public override void WriteLine(string? format, params object?[] arg)
=> this.Output.WriteLine(format ?? string.Empty, arg);

/// <summary>
/// This method can be substituted by Console.WriteLine when used in Console apps.
/// </summary>
/// <param name="message">The message</param>
public void WriteLine(string? message)
=> this.Output.WriteLine(message ?? string.Empty);
/// <inheritdoc/>
public override void WriteLine(string? value)
=> this.Output.WriteLine(value ?? string.Empty);

/// <summary>
/// Current interface ITestOutputHelper does not have a Write method. This extension method adds it to make it analogous to Console.Write when used in Console apps.
/// </summary>
/// <param name="target">Target object to write</param>
public void Write(object? target = null)
=> this.Output.WriteLine(target ?? string.Empty);
/// <inheritdoc/>
public override void Write(object? value = null)
=> this.Output.WriteLine(value ?? string.Empty);

/// <inheritdoc/>
public override Encoding Encoding => Encoding.UTF8;

/// <summary>
/// Outputs the last message in the chat history.
Expand Down

0 comments on commit 2724f34

Please sign in to comment.