TextMessageWriter
TextMessageWriter writes constraint descriptions and messages
in displayable form as a text stream. It tailors the display
of individual message components to form the standard message
format of NUnit assertion failure messages.
using NUnit.Framework.Constraints;
using System;
using System.Collections;
using System.Runtime.CompilerServices;
namespace NUnit.Framework.Internal
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public class TextMessageWriter : MessageWriter
{
private static readonly int DEFAULT_LINE_LENGTH = 78;
public static readonly string Pfx_Expected = " Expected: ";
public static readonly string Pfx_Actual = " But was: ";
public static readonly string Pfx_Difference = " Off by: ";
public static readonly int PrefixLength = Pfx_Expected.Length;
private int _maxLineLength = DEFAULT_LINE_LENGTH;
private bool _sameValDiffTypes;
[System.Runtime.CompilerServices.Nullable(2)]
private string _expectedType;
[System.Runtime.CompilerServices.Nullable(2)]
private string _actualType;
public override int MaxLineLength {
get {
return _maxLineLength;
}
set {
_maxLineLength = value;
}
}
public TextMessageWriter()
{
}
[System.Runtime.CompilerServices.NullableContext(2)]
public TextMessageWriter(string userMessage, params object[] args)
{
if (!string.IsNullOrEmpty(userMessage))
WriteMessageLine(userMessage, args);
}
public override void WriteMessageLine(int level, string message, [System.Runtime.CompilerServices.Nullable(2)] params object[] args)
{
if (message != null) {
while (level-- >= 0) {
Write(" ");
}
if (args != null && args.Length != 0)
message = string.Format(message, args);
WriteLine(MsgUtils.EscapeNullCharacters(message));
}
}
public override void DisplayDifferences(ConstraintResult result)
{
WriteExpectedLine(result);
WriteActualLine(result);
WriteAdditionalLine(result);
}
private void ResolveTypeNameDifference(object expected, object actual, out string expectedType, out string actualType)
{
TypeNameDifferenceResolver typeNameDifferenceResolver = new TypeNameDifferenceResolver();
typeNameDifferenceResolver.ResolveTypeNameDifference(expected, actual, out expectedType, out actualType);
expectedType = " (" + expectedType + ")";
actualType = " (" + actualType + ")";
}
[System.Runtime.CompilerServices.NullableContext(2)]
public override void DisplayDifferences(object expected, object actual)
{
DisplayDifferences(expected, actual, null);
}
[System.Runtime.CompilerServices.NullableContext(2)]
public override void DisplayDifferences(object expected, object actual, Tolerance tolerance)
{
if (expected != null && actual != null && expected.GetType() != actual.GetType() && MsgUtils.FormatValue(expected) == MsgUtils.FormatValue(actual)) {
_sameValDiffTypes = true;
ResolveTypeNameDifference(expected, actual, out _expectedType, out _actualType);
}
WriteExpectedLine(expected, tolerance);
WriteActualLine(actual);
if (tolerance != null && expected != null && actual != null)
WriteDifferenceLine(expected, actual, tolerance);
}
public override void DisplayStringDifferences(string expected, string actual, int mismatch, bool ignoreCase, bool clipping)
{
DisplayStringDifferences(expected, actual, mismatch, mismatch, ignoreCase, false, clipping);
}
public override void DisplayStringDifferences(string expected, string actual, int mismatchExpected, int mismatchActual, bool ignoreCase, bool ignoreWhiteSpace, bool clipping)
{
int maxDisplayLength = MaxLineLength - PrefixLength - 2;
if (clipping) {
if (ignoreWhiteSpace) {
expected = MsgUtils.ClipWhenNeeded(expected, expected.Length, maxDisplayLength, ref mismatchExpected);
actual = MsgUtils.ClipWhenNeeded(actual, actual.Length, maxDisplayLength, ref mismatchActual);
} else
MsgUtils.ClipExpectedAndActual(ref expected, ref actual, maxDisplayLength, ref mismatchExpected, ref mismatchActual);
}
expected = MsgUtils.EscapeControlChars(expected, ref mismatchExpected);
actual = MsgUtils.EscapeControlChars(actual, ref mismatchActual);
Write(Pfx_Expected);
Write(MsgUtils.FormatValue(expected));
if (ignoreCase)
Write(", ignoring case");
if (ignoreWhiteSpace)
Write(", ignoring white-space");
WriteLine();
if (mismatchExpected >= 0 && mismatchExpected != mismatchActual)
WriteCaretLine(mismatchExpected);
WriteActualLine(actual);
if (mismatchActual >= 0)
WriteCaretLine(mismatchActual);
}
[System.Runtime.CompilerServices.NullableContext(2)]
public override void WriteActualValue(object actual)
{
WriteValue(actual);
}
[System.Runtime.CompilerServices.NullableContext(2)]
public override void WriteValue(object val)
{
Write(MsgUtils.FormatValue(val));
}
public override void WriteCollectionElements(IEnumerable collection, long start, int max)
{
Write(MsgUtils.FormatCollection(collection, start, max));
}
private void WriteExpectedLine(ConstraintResult result)
{
Write(Pfx_Expected);
WriteLine(result.Description);
}
[System.Runtime.CompilerServices.NullableContext(2)]
private void WriteExpectedLine(object expected, Tolerance tolerance)
{
Write(Pfx_Expected);
Write(MsgUtils.FormatValue(expected));
if (_sameValDiffTypes)
Write(_expectedType);
if (tolerance != null && tolerance.HasVariance) {
Write(" +/- ");
Write(MsgUtils.FormatValue(tolerance.Amount));
if (tolerance.Mode != ToleranceMode.Linear)
Write(" {0}", tolerance.Mode);
}
WriteLine();
}
private void WriteActualLine(ConstraintResult result)
{
Write(Pfx_Actual);
result.WriteActualValueTo(this);
WriteLine();
}
private void WriteAdditionalLine(ConstraintResult result)
{
result.WriteAdditionalLinesTo(this);
}
[System.Runtime.CompilerServices.NullableContext(2)]
private void WriteActualLine(object actual)
{
Write(Pfx_Actual);
WriteActualValue(actual);
if (_sameValDiffTypes)
Write(_actualType);
WriteLine();
}
[System.Runtime.CompilerServices.NullableContext(2)]
private void WriteDifferenceLine(object expected, object actual, [System.Runtime.CompilerServices.Nullable(1)] Tolerance tolerance)
{
if (tolerance.Mode == ToleranceMode.Linear || tolerance.Mode == ToleranceMode.Percent) {
string text = (tolerance.Amount is TimeSpan) ? MsgUtils.FormatValue(DateTimes.Difference(expected, actual)) : MsgUtils.FormatValue(Numerics.Difference(expected, actual, tolerance.Mode));
if (text != NaN.ToString()) {
Write(Pfx_Difference);
Write(text);
if (tolerance.Mode != ToleranceMode.Linear)
Write(" {0}", tolerance.Mode);
WriteLine();
}
}
}
private void WriteCaretLine(int mismatch)
{
WriteLine(" {0}^", new string('-', PrefixLength + mismatch - 2 + 1));
}
}
}