Completed v0.1 of CompilerAssert.
MODIFY
src/Chapter09.Tests/Listing09.ReadOnlyMembers.cs
src/Chapter09.Tests/Listing09.ReadOnlyMembers.cs
@@ -11,7 +11,7 @@ namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09.Tests
[TestClass]
public class MyTestClass
{
- [TestMethod][Ignore("WIP: Currently an error is not reported when one is expected.")]
+ [TestMethod]// [Ignore("WIP: Currently an error is not reported when one is expected.")]
async public Task ReadOnlyMethod_ModifyObject_ErrorReported()
{
string thingCode = @"
@@ -37,7 +37,7 @@ namespace AddisonWesley.Michaelis.EssentialCSharp.Chapter09.Listing09.Tests
}";
await CompilerAssert.ExpectErrorsAsync(thingCode,
- new CompileError("CS1606", "Cannot assign to 'Number' because it is read-only")
+ new CompileError("CS1604", "Cannot assign to 'Number' because it is read-only")
);
}
}

MODIFY
src/Shared/CompilerAssert.cs
src/Shared/CompilerAssert.cs
-using Microsoft.CSharp;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
-using Microsoft.CodeAnalysis;
using System.Linq;
-using System.Collections.Generic;
using System.Threading.Tasks;
+using System.Collections.Generic;
+using System;
#nullable enable
namespace AddisonWesley.Michaelis.EssentialCSharp.Shared
@@ -15,6 +14,17 @@ namespace AddisonWesley.Michaelis.EssentialCSharp.Shared
public string Id { get; }
public string Message { get; }
+ public CompileError(string fullMessage)
+ {
+ string[] parts = fullMessage.Split(": ");
+ if(parts.Length != 2)
+ {
+ throw new ArgumentException(
+ "Message is not of the form Id: Message", nameof(fullMessage));
+ }
+ Id = parts[0];
+ Message = parts[1];
+ }
public CompileError(string id, string message)
{
Id = id;
@@ -24,10 +34,43 @@ namespace AddisonWesley.Michaelis.EssentialCSharp.Shared
{
(id, message) = (Id, Message);
}
+ public override string ToString()
+ {
+ return $"{Id}: {Message}";
+ }
+
+ // override object.Equals
+ public override bool Equals(object? obj)
+ {
+ return (obj is CompileError)
+ && Equals((CompileError)obj);
+ }
+
+ // Implemented IEquitable<T>
+ public bool Equals(CompileError rhs)
+ {
+ return (Id, Message).Equals(
+ (rhs.Id, rhs.Message));
+ }
+
+
+ // override object.GetHashCode
+ public override int GetHashCode() =>
+ (Id, Message).GetHashCode();
+
+
+ public static bool operator ==(
+ CompileError lhs, CompileError rhs) =>
+ lhs.Equals(rhs);
+
+ public static bool operator !=(
+ CompileError lhs, CompileError rhs) =>
+ !lhs.Equals(rhs);
}
static public class CompilerAssert
{
- async static public Task ExpectErrorsAsync(string sourceCode, params CompileError[] diagnostics)
+ async static public Task<CompileError[]> ExpectErrorsAsync(
+ string sourceCode, params CompileError[] diagnostics)
{
try
{
@@ -36,29 +79,34 @@ namespace AddisonWesley.Michaelis.EssentialCSharp.Shared
catch(CompilationErrorException exception)
{
Assert.IsTrue(exception.Diagnostics.Length > 0);
- if(diagnostics is { } && diagnostics.Length >0)
- {
- CompileError[] actualCompileErrors = exception.Diagnostics.Select(item =>
+
+ CompileError[] actualCompileErrors;
+ actualCompileErrors = exception.Diagnostics.Select(item =>
new CompileError(item.Id, item.GetMessage())).ToArray();
+ if (diagnostics is { } && diagnostics.Length > 0)
+ {
Assert.AreEqual<int>(diagnostics.Length, actualCompileErrors.Length,
"The number of errors returned does not match what was expected.");
for (int i = 0; i < actualCompileErrors.Length; i++)
{
- Assert.AreEqual<string>(diagnostics[i].Id, diagnostics[i].Id,
- $"The expected Ids do not match for item {i}: " +
- $"{diagnostics[i].Id} <> {diagnostics[i].Id}");
+ // Compare Id's first as that is more meaningful.
Assert.AreEqual<string>(diagnostics[i].Message, actualCompileErrors[i].Message,
$"The expected Messages do not match for item {i}: " +
$"{diagnostics[i].Message} <> {diagnostics[i].Message}");
+ Assert.AreEqual<string>(diagnostics[i].Id, actualCompileErrors[i].Id,
+ $"The expected Ids do not match for item {i}: " +
+ $"{diagnostics[i].Id} <> {actualCompileErrors[i].Id}");
}
//CollectionAssert.AreEquivalent(
// diagnostics,
// actualCompileErrors.ToList());
}
+ return actualCompileErrors;
}
Assert.Fail("The expected compilation errors did not occur.");
+ return null!; // This code will never execute due to the Fail line above.
}
}
}

Completed v0.1 of CompilerAssert.