Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -214,3 +214,6 @@ ModelManifest.xml

# Jetbrains
.idea

# GitHub Actions environment files
:GITHUB_ENV
106 changes: 106 additions & 0 deletions IntelliTect.TestTools.Console.Tests/ConsoleAssertTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -232,4 +232,110 @@ public void ExecuteAsync_GivenVariableCRLFWithNLComparedToCRNL_Success()
System.Console.WriteLine(output);
});
}

[TestMethod]
public void ExpectThrows_WhenExceptionIsThrown_CapturesException()
{
const string view = @"Enter a number: <<invalid
>>Error: Invalid input";

FormatException exception = ConsoleAssert.ExpectThrows<FormatException>(view, () =>
{
System.Console.Write("Enter a number: ");
string input = System.Console.ReadLine();
System.Console.Write("Error: Invalid input");
int.Parse(input); // This will throw FormatException
});

Assert.IsNotNull(exception);
Assert.IsInstanceOfType<FormatException>(exception);
}

[TestMethod]
public async Task ExpectThrowsAsync_WhenExceptionIsThrown_CapturesException()
{
const string view = @"Enter a number: <<invalid
>>Error: Invalid input";

FormatException exception = await ConsoleAssert.ExpectThrowsAsync<FormatException>(view, async () =>
{
await Task.Yield();
System.Console.Write("Enter a number: ");
string input = System.Console.ReadLine();
System.Console.Write("Error: Invalid input");
int.Parse(input); // This will throw FormatException
});

Assert.IsNotNull(exception);
Assert.IsInstanceOfType<FormatException>(exception);
}

[TestMethod]
public void ExpectThrows_WhenNoExceptionIsThrown_ThrowsException()
{
const string view = @"Hello World";

Exception exception = Assert.ThrowsExactly<Exception>(() =>
{
ConsoleAssert.ExpectThrows<FormatException>(view, () =>
{
System.Console.Write("Hello World");
// No exception thrown
});
});

StringAssert.Contains(exception.Message, "Expected exception of type FormatException was not thrown");
}

[TestMethod]
public async Task ExpectThrowsAsync_WhenNoExceptionIsThrown_ThrowsException()
{
const string view = @"Hello World";

Exception exception = await Assert.ThrowsExactlyAsync<Exception>(async () =>
{
await ConsoleAssert.ExpectThrowsAsync<FormatException>(view, async () =>
{
await Task.Yield();
System.Console.Write("Hello World");
// No exception thrown
});
});

StringAssert.Contains(exception.Message, "Expected exception of type FormatException was not thrown");
}

[TestMethod]
public void ExpectThrows_WithDifferentExceptionType_ThrowsOriginalException()
{
const string view = @"Enter a number: <<invalid
>>Error: Invalid input";

// Expecting ArgumentException but FormatException is thrown
Assert.ThrowsExactly<FormatException>(() =>
{
ConsoleAssert.ExpectThrows<ArgumentException>(view, () =>
{
System.Console.Write("Enter a number: ");
string input = System.Console.ReadLine();
System.Console.Write("Error: Invalid input");
int.Parse(input); // This throws FormatException, not ArgumentException
});
});
}

[TestMethod]
public void ExpectThrows_WithNormalizeOptions_AppliesNormalization()
{
const string view = "Hello World\n";

ArgumentException exception = ConsoleAssert.ExpectThrows<ArgumentException>(view, () =>
{
System.Console.WriteLine("Hello World");
throw new ArgumentException("Test exception");
}, NormalizeOptions.NormalizeLineEndings);

Assert.IsNotNull(exception);
StringAssert.Contains(exception.Message, "Test exception");
}
}
58 changes: 58 additions & 0 deletions IntelliTect.TestTools.Console/ConsoleAssert.cs
Original file line number Diff line number Diff line change
Expand Up @@ -721,4 +721,62 @@ public static Process ExecuteProcess(string expected, string fileName, string ar
AssertExpectation(expected, standardOutput, (left, right) => LikeOperator(left, right), "The values are not like (using wildcards) each other");
return process;
}

/// <summary>
/// Performs a unit test on a console-based method that is expected to throw an exception.
/// A "view" of what a user would see in their console is provided as a string,
/// where their input (including line-breaks) is surrounded by double
/// less-than/greater-than signs, like so: "Input please: &lt;&lt;Input&gt;&gt;"
/// </summary>
/// <typeparam name="TException">The type of exception expected to be thrown</typeparam>
/// <param name="expected">Expected "view" to be seen on the console,
/// including both input and output</param>
/// <param name="action">Method to be run that is expected to throw an exception</param>
/// <param name="normalizeOptions">Options to normalize input and expected output</param>
/// <returns>The exception that was thrown</returns>
public static TException ExpectThrows<TException>(string expected,
Action action,
NormalizeOptions normalizeOptions = NormalizeOptions.Default)
where TException : Exception
{
try
{
Expect(expected, action, normalizeOptions);
}
catch (TException ex)
{
return ex;
}

throw new Exception($"Expected exception of type {typeof(TException).Name} was not thrown.");
}

/// <summary>
/// Performs a unit test on a console-based async method that is expected to throw an exception.
/// A "view" of what a user would see in their console is provided as a string,
/// where their input (including line-breaks) is surrounded by double
/// less-than/greater-than signs, like so: "Input please: &lt;&lt;Input&gt;&gt;"
/// </summary>
/// <typeparam name="TException">The type of exception expected to be thrown</typeparam>
/// <param name="expected">Expected "view" to be seen on the console,
/// including both input and output</param>
/// <param name="action">Async method to be run that is expected to throw an exception</param>
/// <param name="normalizeOptions">Options to normalize input and expected output</param>
/// <returns>The exception that was thrown</returns>
public static async Task<TException> ExpectThrowsAsync<TException>(string expected,
Func<Task> action,
NormalizeOptions normalizeOptions = NormalizeOptions.Default)
where TException : Exception
{
try
{
await ExpectAsync(expected, action, normalizeOptions);
}
catch (TException ex)
{
return ex;
}

throw new Exception($"Expected exception of type {typeof(TException).Name} was not thrown.");
}
}
Loading