Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/publish-artifacts-examples-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ jobs:

# Ensure we preserve access to NuGet.org
- name: Configure NuGet.org source
continue-on-error: true
run: |
dotnet nuget add source https://api.nuget.org/v3/index.json --name nuget.org

Expand Down
74 changes: 62 additions & 12 deletions libraries/src/AWS.Lambda.Powertools.Common/Core/ConsoleWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,41 +22,77 @@
public class ConsoleWrapper : IConsoleWrapper
{
private static bool _override;
private static TextWriter _testOutputStream;
private static bool _outputResetPerformed = false;
private static bool _inTestMode = false;

/// <inheritdoc />
public void WriteLine(string message)
{
OverrideLambdaLogger();
Console.WriteLine(message);
if (_inTestMode && _testOutputStream != null)
{
_testOutputStream.WriteLine(message);
}
else
{
EnsureConsoleOutputOnce();
Console.WriteLine(message);
}
}

/// <inheritdoc />
public void Debug(string message)
{
OverrideLambdaLogger();
System.Diagnostics.Debug.WriteLine(message);
if (_inTestMode && _testOutputStream != null)
{
_testOutputStream.WriteLine(message);
}

Check warning on line 49 in libraries/src/AWS.Lambda.Powertools.Common/Core/ConsoleWrapper.cs

View check run for this annotation

Codecov / codecov/patch

libraries/src/AWS.Lambda.Powertools.Common/Core/ConsoleWrapper.cs#L47-L49

Added lines #L47 - L49 were not covered by tests
else
{
EnsureConsoleOutputOnce();
System.Diagnostics.Debug.WriteLine(message);
}

Check warning on line 54 in libraries/src/AWS.Lambda.Powertools.Common/Core/ConsoleWrapper.cs

View check run for this annotation

Codecov / codecov/patch

libraries/src/AWS.Lambda.Powertools.Common/Core/ConsoleWrapper.cs#L51-L54

Added lines #L51 - L54 were not covered by tests
}

/// <inheritdoc />
public void Error(string message)
{
if (!_override)
if (_inTestMode && _testOutputStream != null)
{
var errordOutput = new StreamWriter(Console.OpenStandardError());
errordOutput.AutoFlush = true;
Console.SetError(errordOutput);
_testOutputStream.WriteLine(message);
}
else
{

Check warning on line 65 in libraries/src/AWS.Lambda.Powertools.Common/Core/ConsoleWrapper.cs

View check run for this annotation

Codecov / codecov/patch

libraries/src/AWS.Lambda.Powertools.Common/Core/ConsoleWrapper.cs#L65

Added line #L65 was not covered by tests
if (!_override)
{
var errordOutput = new StreamWriter(Console.OpenStandardError());
errordOutput.AutoFlush = true;
Console.SetError(errordOutput);
}
Console.Error.WriteLine(message);

Check warning on line 72 in libraries/src/AWS.Lambda.Powertools.Common/Core/ConsoleWrapper.cs

View check run for this annotation

Codecov / codecov/patch

libraries/src/AWS.Lambda.Powertools.Common/Core/ConsoleWrapper.cs#L67-L72

Added lines #L67 - L72 were not covered by tests
}

Console.Error.WriteLine(message);
}

internal static void SetOut(StringWriter consoleOut)
/// <summary>
/// Set the ConsoleWrapper to use a different TextWriter
/// This is useful for unit tests where you want to capture the output
/// </summary>
public static void SetOut(TextWriter consoleOut)
{
_testOutputStream = consoleOut;
_inTestMode = true;
_override = true;
Console.SetOut(consoleOut);
}

private void OverrideLambdaLogger()
private static void EnsureConsoleOutputOnce()
{
if (_outputResetPerformed) return;
OverrideLambdaLogger();
_outputResetPerformed = true;
}

private static void OverrideLambdaLogger()
{
if (_override)
{
Expand All @@ -73,8 +109,22 @@
Console.WriteLine($"{DateTime.UtcNow:yyyy-MM-ddTHH:mm:ss.fffZ}\t{logLevel}\t{message}");
}

/// <summary>
/// Reset the ConsoleWrapper to its original state
/// </summary>
public static void ResetForTest()
{
_override = false;
_inTestMode = false;
_testOutputStream = null;
_outputResetPerformed = false;
}

/// <summary>
/// Clear the output reset flag
/// </summary>
public static void ClearOutputResetFlag()
{
_outputResetPerformed = false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public void BatchProcessing_Set_Execution_Environment_Context_SQS()
var sqsBatchProcessor = new SqsBatchProcessor(conf);

// Assert
Assert.Equal($"{Constants.FeatureContextIdentifier}/BatchProcessing/1.0.0",
Assert.Equal($"{Constants.FeatureContextIdentifier}/BatchProcessing/{env.GetAssemblyVersion(this)}",
env.GetEnvironmentVariable("AWS_EXECUTION_ENV"));

Assert.NotNull(sqsBatchProcessor);
Expand All @@ -52,7 +52,7 @@ public void BatchProcessing_Set_Execution_Environment_Context_Kinesis()
var KinesisEventBatchProcessor = new KinesisEventBatchProcessor(conf);

// Assert
Assert.Equal($"{Constants.FeatureContextIdentifier}/BatchProcessing/1.0.0",
Assert.Equal($"{Constants.FeatureContextIdentifier}/BatchProcessing/{env.GetAssemblyVersion(this)}",
env.GetEnvironmentVariable("AWS_EXECUTION_ENV"));

Assert.NotNull(KinesisEventBatchProcessor);
Expand All @@ -69,7 +69,7 @@ public void BatchProcessing_Set_Execution_Environment_Context_DynamoDB()
var dynamoDbStreamBatchProcessor = new DynamoDbStreamBatchProcessor(conf);

// Assert
Assert.Equal($"{Constants.FeatureContextIdentifier}/BatchProcessing/1.0.0",
Assert.Equal($"{Constants.FeatureContextIdentifier}/BatchProcessing/{env.GetAssemblyVersion(this)}",
env.GetEnvironmentVariable("AWS_EXECUTION_ENV"));

Assert.NotNull(dynamoDbStreamBatchProcessor);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,159 +6,136 @@ namespace AWS.Lambda.Powertools.Common.Tests;

public class ConsoleWrapperTests : IDisposable
{
private StringWriter _writer;

public ConsoleWrapperTests()
{
// Setup a new StringWriter for each test
_writer = new StringWriter();
// Reset static state for clean testing
ConsoleWrapper.ResetForTest();
}

[Fact]
public void WriteLine_Should_Write_To_Console()
{
// Arrange
var consoleWrapper = new ConsoleWrapper();
var writer = new StringWriter();
ConsoleWrapper.SetOut(writer);
ConsoleWrapper.SetOut(_writer);

// Act
consoleWrapper.WriteLine("test message");

// Assert
Assert.Equal($"test message{Environment.NewLine}", writer.ToString());
Assert.Equal($"test message{Environment.NewLine}", _writer.ToString());
}

[Fact]
public void Error_Should_Write_To_Error_Console()
{
// Arrange
var consoleWrapper = new ConsoleWrapper();
var writer = new StringWriter();
ConsoleWrapper.SetOut(writer);
Console.SetError(writer);
ConsoleWrapper.SetOut(_writer);
Console.SetError(_writer);

// Act
consoleWrapper.Error("error message");
writer.Flush();
_writer.Flush();

// Assert
Assert.Equal($"error message{Environment.NewLine}", writer.ToString());
Assert.Equal($"error message{Environment.NewLine}", _writer.ToString());
}

[Fact]
public void SetOut_Should_Override_Console_Output()
{
// Arrange
var consoleWrapper = new ConsoleWrapper();
var writer = new StringWriter();
ConsoleWrapper.SetOut(writer);
ConsoleWrapper.SetOut(_writer);

// Act
consoleWrapper.WriteLine("test message");

// Assert
Assert.Equal($"test message{Environment.NewLine}", writer.ToString());
Assert.Equal($"test message{Environment.NewLine}", _writer.ToString());
}

[Fact]
public void OverrideLambdaLogger_Should_Override_Console_Out()
{
// Arrange
var originalOut = Console.Out;
try
{
var consoleWrapper = new ConsoleWrapper();

// Act - create a custom StringWriter and set it after constructor
// but before WriteLine (which triggers OverrideLambdaLogger)
var writer = new StringWriter();
ConsoleWrapper.SetOut(writer);

consoleWrapper.WriteLine("test message");

// Assert
Assert.Equal($"test message{Environment.NewLine}", writer.ToString());
}
finally
{
// Restore original console out
ConsoleWrapper.ResetForTest();
}
// Arrange
var consoleWrapper = new ConsoleWrapper();
ConsoleWrapper.SetOut(_writer);

// Act
consoleWrapper.WriteLine("test message");

// Assert
Assert.Equal($"test message{Environment.NewLine}", _writer.ToString());
}

[Fact]
public void WriteLine_WritesMessageToConsole()
{
// Arrange
var consoleWrapper = new ConsoleWrapper();
ConsoleWrapper.SetOut(_writer);

// Act
consoleWrapper.WriteLine("Test message");

// Assert
var output = _writer.ToString();
Assert.Contains("Test message", output);
}

[Fact]
public void SetOut_OverridesConsoleOutput()
{
// Act
ConsoleWrapper.SetOut(_writer);
Console.WriteLine("Test override");

// Assert
var output = _writer.ToString();
Assert.Contains("Test override", output);
}

[Fact]
public void WriteLine_WritesMessageToConsole()
{
// Arrange
var consoleWrapper = new ConsoleWrapper();
var originalOutput = Console.Out;
using var stringWriter = new StringWriter();
ConsoleWrapper.SetOut(stringWriter);

try
{
// Act
consoleWrapper.WriteLine("Test message");

// Assert
var output = stringWriter.ToString();
Assert.Contains("Test message", output);
}
finally
{
// Restore original output
ConsoleWrapper.ResetForTest();
}
}
public void StaticWriteLine_FormatsLogMessageCorrectly()
{
// Arrange
ConsoleWrapper.SetOut(_writer);

// Act - Using reflection to call internal static method
typeof(ConsoleWrapper)
.GetMethod("WriteLine", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static, null, new[] { typeof(string), typeof(string) }, null)
?.Invoke(null, new object[] { "INFO", "Test log message" });

// Assert
var output = _writer.ToString();
Assert.Matches(@"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z\tINFO\tTest log message", output);
}

[Fact]
public void ClearOutputResetFlag_ResetsFlag()
{
// Arrange
var consoleWrapper = new ConsoleWrapper();
ConsoleWrapper.SetOut(_writer);

[Fact]
public void SetOut_OverridesConsoleOutput()
{
// Arrange
var originalOutput = Console.Out;
using var stringWriter = new StringWriter();

try
{
// Act
typeof(ConsoleWrapper)
.GetMethod("SetOut", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static)
?.Invoke(null, new object[] { stringWriter });

Console.WriteLine("Test override");

// Assert
var output = stringWriter.ToString();
Assert.Contains("Test override", output);
}
finally
{
// Restore original output
ConsoleWrapper.ResetForTest();
}
}
// Act
consoleWrapper.WriteLine("First message"); // Should set the reset flag
ConsoleWrapper.ClearOutputResetFlag();
consoleWrapper.WriteLine("Second message"); // Should set it again

[Fact]
public void StaticWriteLine_FormatsLogMessageCorrectly()
{
// Arrange
var originalOutput = Console.Out;
using var stringWriter = new StringWriter();
ConsoleWrapper.SetOut(stringWriter);

try
{
// Act
typeof(ConsoleWrapper)
.GetMethod("WriteLine", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static, null, new[] { typeof(string), typeof(string) }, null)
?.Invoke(null, new object[] { "INFO", "Test log message" });

// Assert
var output = stringWriter.ToString();
Assert.Matches(@"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z\tINFO\tTest log message", output);
}
finally
{
// Restore original output
ConsoleWrapper.ResetForTest();
}
}

public void Dispose()
{
ConsoleWrapper.ResetForTest();
}
// Assert
Assert.Equal($"First message{Environment.NewLine}Second message{Environment.NewLine}", _writer.ToString());
}

public void Dispose()
{
ConsoleWrapper.ResetForTest();
_writer?.Dispose();
}
}
Loading
Loading