MsgUtils
Static methods used in creating messages
using NUnit.Framework.Internal;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Text;
namespace NUnit.Framework.Constraints
{
[NullableContext(1)]
[Nullable(0)]
internal static class MsgUtils
{
internal const int DefaultMaxItems = 10;
private const string ELLIPSIS = "...";
private static readonly string Fmt_Null;
private static readonly string Fmt_EmptyString;
private static readonly string Fmt_EmptyCollection;
private static readonly string Fmt_String;
private static readonly string Fmt_Char;
private static readonly string Fmt_DateTime;
private static readonly string Fmt_DateTimeOffset;
private static readonly string Fmt_ValueType;
private static readonly string Fmt_Default;
private static readonly string Fmt_ExceptionThrown;
public static ValueFormatter DefaultValueFormatter { get; set; }
static MsgUtils()
{
Fmt_Null = "null";
Fmt_EmptyString = "<string.Empty>";
Fmt_EmptyCollection = "<empty>";
Fmt_String = "\"{0}\"";
Fmt_Char = "'{0}'";
Fmt_DateTime = "yyyy-MM-dd HH:mm:ss.FFFFFFF";
Fmt_DateTimeOffset = "yyyy-MM-dd HH:mm:ss.FFFFFFFzzz";
Fmt_ValueType = "{0}";
Fmt_Default = "<{0}>";
Fmt_ExceptionThrown = "<! {0} !>";
DefaultValueFormatter = FormatValueWithoutThrowing;
AddFormatter((ValueFormatter next) => (object val) => TryFormatTuple(val, TypeHelper.IsTuple, GetValueFromTuple) ?? next(val));
AddFormatter((ValueFormatter next) => delegate(object val) {
if (!(val is ValueType))
return next(val);
return string.Format(Fmt_ValueType, val);
});
AddFormatter((ValueFormatter next) => (object val) => TryFormatKeyValuePair(val) ?? next(val));
AddFormatter((ValueFormatter next) => (object val) => TryFormatTuple(val, TypeHelper.IsValueTuple, GetValueFromValueTuple) ?? next(val));
AddFormatter((ValueFormatter next) => delegate(object val) {
if (!(val is DateTime))
return next(val);
DateTime dt = (DateTime)val;
return FormatDateTime(dt);
});
AddFormatter((ValueFormatter next) => delegate(object val) {
if (!(val is DateTimeOffset))
return next(val);
DateTimeOffset dto = (DateTimeOffset)val;
return FormatDateTimeOffset(dto);
});
AddFormatter((ValueFormatter next) => delegate(object val) {
if (!(val is decimal))
return next(val);
decimal d2 = (decimal)val;
return FormatDecimal(d2);
});
AddFormatter((ValueFormatter next) => delegate(object val) {
if (!(val is float))
return next(val);
float f = (float)val;
return FormatFloat(f);
});
AddFormatter((ValueFormatter next) => delegate(object val) {
if (!(val is double))
return next(val);
double d = (double)val;
return FormatDouble(d);
});
AddFormatter((ValueFormatter next) => delegate(object val) {
if (!(val is char))
return next(val);
return string.Format(Fmt_Char, val);
});
AddFormatter((ValueFormatter next) => delegate(object val) {
IEnumerable enumerable = val as IEnumerable;
if (enumerable == null)
return next(val);
return FormatCollection(enumerable, 0, 10);
});
AddFormatter((ValueFormatter next) => delegate(object val) {
string text = val as string;
if (text == null)
return next(val);
return FormatString(text);
});
AddFormatter((ValueFormatter next) => delegate(object val) {
if (!(val is DictionaryEntry))
return next(val);
DictionaryEntry dictionaryEntry = (DictionaryEntry)val;
return FormatKeyValuePair(dictionaryEntry.Key, dictionaryEntry.Value);
});
AddFormatter((ValueFormatter next) => delegate(object val) {
Array array = val as Array;
if (array == null)
return next(val);
return FormatArray(array);
});
}
private static string FormatValueWithoutThrowing([Nullable(2)] object val)
{
string arg;
try {
arg = val?.ToString();
} catch (Exception ex) {
return string.Format(Fmt_ExceptionThrown, ex.GetType().Name + " was thrown by " + val.GetType().Name + ".ToString()");
}
return string.Format(Fmt_Default, arg);
}
public static void AddFormatter(ValueFormatterFactory formatterFactory)
{
DefaultValueFormatter = formatterFactory(DefaultValueFormatter);
}
public static string FormatValue([Nullable(2)] object val)
{
if (val == null)
return Fmt_Null;
TestExecutionContext currentContext = TestExecutionContext.CurrentContext;
if (currentContext != null)
return currentContext.CurrentValueFormatter(val);
return DefaultValueFormatter(val);
}
public static string FormatCollection(IEnumerable collection, long start = 0, int max = 10)
{
int num = 0;
int num2 = 0;
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("< ");
if (start > 0)
stringBuilder.Append("...");
foreach (object item in collection) {
if (num2++ >= start) {
if (++num > max)
break;
if (num > 1)
stringBuilder.Append(", ");
stringBuilder.Append(FormatValue(item));
}
}
if (num == 0)
return Fmt_EmptyCollection;
if (num > max)
stringBuilder.Append("...");
stringBuilder.Append(" >");
return stringBuilder.ToString();
}
private static string FormatArray(Array array)
{
if (array.Length == 0)
return Fmt_EmptyCollection;
int rank = array.Rank;
int[] array2 = new int[rank];
int num = 1;
int num2 = rank;
while (--num2 >= 0) {
num = (array2[num2] = num * array.GetLength(num2));
}
int num3 = 0;
StringBuilder stringBuilder = new StringBuilder();
foreach (object item in array) {
if (num3 > 0)
stringBuilder.Append(", ");
bool flag = false;
for (int i = 0; i < rank; i++) {
flag = (flag || num3 % array2[i] == 0);
if (flag)
stringBuilder.Append("< ");
}
stringBuilder.Append(FormatValue(item));
num3++;
bool flag2 = false;
for (int j = 0; j < rank; j++) {
flag2 = (flag2 || num3 % array2[j] == 0);
if (flag2)
stringBuilder.Append(" >");
}
}
return stringBuilder.ToString();
}
[NullableContext(2)]
private static string TryFormatKeyValuePair(object value)
{
if (value == null)
return null;
Type type = value.GetType();
if (!type.IsGenericType)
return null;
Type genericTypeDefinition = type.GetGenericTypeDefinition();
if (genericTypeDefinition != typeof(KeyValuePair<, >))
return null;
object key = type.GetProperty("Key")?.GetValue(value, null);
object value2 = type.GetProperty("Value")?.GetValue(value, null);
return FormatKeyValuePair(key, value2);
}
[NullableContext(2)]
[return: Nullable(1)]
private static string FormatKeyValuePair(object key, object value)
{
DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(4, 2);
defaultInterpolatedStringHandler.AppendLiteral("[");
defaultInterpolatedStringHandler.AppendFormatted(FormatValue(key));
defaultInterpolatedStringHandler.AppendLiteral(", ");
defaultInterpolatedStringHandler.AppendFormatted(FormatValue(value));
defaultInterpolatedStringHandler.AppendLiteral("]");
return defaultInterpolatedStringHandler.ToStringAndClear();
}
[return: Nullable(2)]
private static object GetValueFromTuple(Type type, string propertyName, object obj)
{
return type.GetProperty(propertyName)?.GetValue(obj, null);
}
[return: Nullable(2)]
private static object GetValueFromValueTuple(Type type, string propertyName, object obj)
{
return type.GetField(propertyName)?.GetValue(obj);
}
[NullableContext(2)]
private static string TryFormatTuple(object value, [Nullable(1)] Func<Type, bool> isTuple, [Nullable(new byte[] {
1,
1,
1,
1,
2
})] Func<Type, string, object, object> getValue)
{
if (value == null)
return null;
Type type = value.GetType();
if (!isTuple(type))
return null;
return FormatTuple(value, true, getValue);
}
private static string FormatTuple(object value, bool printParentheses, [Nullable(new byte[] {
1,
1,
1,
1,
2
})] Func<Type, string, object, object> getValue)
{
Type type = value.GetType();
int num = type.GetGenericArguments().Length;
StringBuilder stringBuilder = new StringBuilder();
if (printParentheses)
stringBuilder.Append("(");
for (int i = 0; i < num; i++) {
if (i > 0)
stringBuilder.Append(", ");
bool flag = i < 7;
string arg = flag ? ("Item" + (i + 1).ToString()) : "Rest";
object obj = getValue(type, arg, value);
string value2 = flag ? FormatValue(obj) : FormatTuple(obj, false, getValue);
stringBuilder.Append(value2);
}
if (printParentheses)
stringBuilder.Append(")");
return stringBuilder.ToString();
}
private static string FormatString(string s)
{
if (!(s == string.Empty))
return string.Format(Fmt_String, s);
return Fmt_EmptyString;
}
private static string FormatDouble(double d)
{
if (double.IsNaN(d) || double.IsInfinity(d))
return d.ToString();
string text = d.ToString("G17", CultureInfo.InvariantCulture);
if (text.IndexOf('.') > 0)
return text + "d";
return text + ".0d";
}
private static string FormatFloat(float f)
{
if (float.IsNaN(f) || float.IsInfinity(f))
return f.ToString();
string text = f.ToString("G9", CultureInfo.InvariantCulture);
if (text.IndexOf('.') > 0)
return text + "f";
return text + ".0f";
}
private static string FormatDecimal(decimal d)
{
return d.ToString("G29", CultureInfo.InvariantCulture) + "m";
}
private static string FormatDateTime(DateTime dt)
{
return dt.ToString(Fmt_DateTime, CultureInfo.InvariantCulture);
}
private static string FormatDateTimeOffset(DateTimeOffset dto)
{
return dto.ToString(Fmt_DateTimeOffset, CultureInfo.InvariantCulture);
}
public static string GetTypeRepresentation(object obj)
{
Array array = obj as Array;
DefaultInterpolatedStringHandler defaultInterpolatedStringHandler;
if (array == null) {
defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(2, 1);
defaultInterpolatedStringHandler.AppendLiteral("<");
defaultInterpolatedStringHandler.AppendFormatted(obj.GetType());
defaultInterpolatedStringHandler.AppendLiteral(">");
return defaultInterpolatedStringHandler.ToStringAndClear();
}
StringBuilder stringBuilder = new StringBuilder();
Type type = array.GetType();
int num = 0;
while (type.IsArray) {
type = type.GetElementType();
num++;
}
stringBuilder.Append(type);
stringBuilder.Append('[');
for (int i = 0; i < array.Rank; i++) {
if (i > 0)
stringBuilder.Append(',');
stringBuilder.Append(array.GetLength(i));
}
stringBuilder.Append(']');
while (--num > 0) {
stringBuilder.Append("[]");
}
defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(2, 1);
defaultInterpolatedStringHandler.AppendLiteral("<");
defaultInterpolatedStringHandler.AppendFormatted(stringBuilder);
defaultInterpolatedStringHandler.AppendLiteral(">");
return defaultInterpolatedStringHandler.ToStringAndClear();
}
[NullableContext(2)]
[return: NotNullIfNotNull("s")]
public static string EscapeControlChars(string s)
{
int index = 0;
return EscapeControlChars(s, ref index);
}
[NullableContext(2)]
[return: NotNullIfNotNull("s")]
public static string EscapeControlChars(string s, ref int index)
{
if (s == null)
return null;
int num = index;
StringBuilder stringBuilder = new StringBuilder(s.Length + 42);
for (int i = 0; i < s.Length; i++) {
char c = s[i];
string text = EscapeControlChars(c);
if (text == null)
stringBuilder.Append(c);
else {
stringBuilder.Append(text);
if (num > i)
index += text.Length - 1;
}
}
return stringBuilder.ToString();
}
[NullableContext(2)]
private static string EscapeControlChars(char c)
{
switch (c) {
case '\\':
return "\\\\";
case ' ':
return "\\0";
case '':
return "\\a";
case '\b':
return "\\b";
case '':
return "\\f";
case '\n':
return "\\n";
case '\r':
return "\\r";
case '\t':
return "\\t";
case '':
return "\\v";
case '
':
case '
':
case '
': {
DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(2, 1);
defaultInterpolatedStringHandler.AppendLiteral("\\x");
defaultInterpolatedStringHandler.AppendFormatted((int)c, "X4");
return defaultInterpolatedStringHandler.ToStringAndClear();
}
default:
return null;
}
}
[NullableContext(2)]
[return: NotNullIfNotNull("s")]
public static string EscapeNullCharacters(string s)
{
if (s != null) {
StringBuilder stringBuilder = new StringBuilder(s.Length + 42);
string text = s;
foreach (char c in text) {
if (c == ' ')
stringBuilder.Append("\\0");
else
stringBuilder.Append(c);
}
s = stringBuilder.ToString();
}
return s;
}
public static string GetArrayIndicesAsString(int[] indices)
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append('[');
for (int i = 0; i < indices.Length; i++) {
if (i > 0)
stringBuilder.Append(',');
stringBuilder.Append(indices[i].ToString());
}
stringBuilder.Append(']');
return stringBuilder.ToString();
}
public static int[] GetArrayIndicesFromCollectionIndex(IEnumerable collection, long index)
{
Array array = collection as Array;
int num = array?.Rank ?? 1;
int[] array2 = new int[num];
int num2 = num;
while (--num2 > 0) {
int length = array.GetLength(num2);
array2[num2] = (int)index % length;
index /= length;
}
array2[0] = (int)index;
return array2;
}
public static string ClipString(string s, int clipLength, int clipStart)
{
StringBuilder stringBuilder = new StringBuilder(s.Length + 2 * "...".Length);
if (clipStart > 0)
stringBuilder.Append("...");
int num = s.Length - clipStart;
int count = Math.Min(num, clipLength);
stringBuilder.Append(s, clipStart, count);
if (num > clipLength)
stringBuilder.Append("...");
return stringBuilder.ToString();
}
public static string ClipWhenNeeded(string s, int length, int maxDisplayLength, ref int mismatchLocation)
{
if (length <= maxDisplayLength)
return s;
maxDisplayLength -= "...".Length;
int num;
if (mismatchLocation + 5 < maxDisplayLength)
num = 0;
else if (length - mismatchLocation + 5 < maxDisplayLength) {
num = length - maxDisplayLength;
} else {
maxDisplayLength -= "...".Length;
num = mismatchLocation - maxDisplayLength / 2;
}
if (num > 0)
mismatchLocation -= num - "...".Length;
return ClipString(s, maxDisplayLength, num);
}
public static void ClipExpectedAndActual(ref string expected, ref string actual, int maxDisplayLength, ref int mismatchExpected, ref int mismatchActual)
{
if (mismatchExpected != mismatchActual)
throw new ArgumentException("The values for mismatchExpected and mismatchActual should be the same.");
int num = Math.Max(expected.Length, actual.Length);
if (num > maxDisplayLength) {
expected = ClipWhenNeeded(expected, num, maxDisplayLength, ref mismatchExpected);
actual = ClipWhenNeeded(actual, num, maxDisplayLength, ref mismatchActual);
}
}
[return: Nullable(0)]
public static (int, int) FindMismatchPosition(string expected, string actual, bool ignoreCase, bool ignoreWhiteSpace)
{
string text = ignoreCase ? expected.ToLower() : expected;
string text2 = ignoreCase ? actual.ToLower() : actual;
int num = 0;
int num2 = 0;
while (true) {
if (ignoreWhiteSpace) {
num = FindNonWhiteSpace(text, num);
num2 = FindNonWhiteSpace(text2, num2);
}
if (num >= text.Length || num2 >= text2.Length)
break;
if (text[num] != text2[num2])
return (num, num2);
num++;
num2++;
}
if (num < text.Length || num2 < text2.Length)
return (num, num2);
return (-1, -1);
}
private static int FindNonWhiteSpace(string s, int i)
{
while (i < s.Length && char.IsWhiteSpace(s[i])) {
i++;
}
return i;
}
}
}