Remove infinite loop potential from ArgumentFormatter.Format.
This commit is contained in:
Родитель
857e4f4ad6
Коммит
15cf562d6f
|
@ -6,9 +6,22 @@ using System.Reflection;
|
|||
|
||||
namespace Xunit.Sdk
|
||||
{
|
||||
/// <summary>
|
||||
/// Formats arguments for display in theories.
|
||||
/// </summary>
|
||||
public static class ArgumentFormatter
|
||||
{
|
||||
/// <summary>
|
||||
/// Format the value for presentation.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to be formatted.</param>
|
||||
/// <returns>The formatted value.</returns>
|
||||
public static string Format(object value)
|
||||
{
|
||||
return Format(value, 1);
|
||||
}
|
||||
|
||||
private static string Format(object value, int depth)
|
||||
{
|
||||
if (value == null)
|
||||
return "null";
|
||||
|
@ -27,19 +40,22 @@ namespace Xunit.Sdk
|
|||
|
||||
var enumerable = value as IEnumerable;
|
||||
if (enumerable != null)
|
||||
return String.Format("[{0}]", String.Join(", ", enumerable.Cast<object>().Select(x => Format(x))));
|
||||
return String.Format("[{0}]", String.Join(", ", enumerable.Cast<object>().Select(x => Format(x, depth + 1))));
|
||||
|
||||
var type = value.GetType();
|
||||
if (type.GetTypeInfo().IsValueType)
|
||||
return Convert.ToString(value, CultureInfo.CurrentCulture);
|
||||
|
||||
if (depth == 3)
|
||||
return String.Format("{0} {{ ... }}", type.Name);
|
||||
|
||||
var fields = type.GetRuntimeFields()
|
||||
.Where(f => f.IsPublic && !f.IsStatic)
|
||||
.Select(f => new { name = f.Name, value = WrapAndGetFormattedValue(() => f.GetValue(value)) })
|
||||
.Select(f => new { name = f.Name, value = WrapAndGetFormattedValue(() => f.GetValue(value), depth) })
|
||||
.ToList();
|
||||
var properties = type.GetRuntimeProperties()
|
||||
.Where(p => p.GetMethod != null && p.GetMethod.IsPublic && !p.GetMethod.IsStatic)
|
||||
.Select(p => new { name = p.Name, value = WrapAndGetFormattedValue(() => p.GetValue(value)) })
|
||||
.Select(p => new { name = p.Name, value = WrapAndGetFormattedValue(() => p.GetValue(value), depth) })
|
||||
.ToList();
|
||||
var formattedParameters = fields.Concat(properties)
|
||||
.OrderBy(p => p.name)
|
||||
|
@ -50,11 +66,11 @@ namespace Xunit.Sdk
|
|||
return String.Format("{0} {1}", type.Name, parameterValues);
|
||||
}
|
||||
|
||||
private static string WrapAndGetFormattedValue(Func<object> getter)
|
||||
private static string WrapAndGetFormattedValue(Func<object> getter, int depth)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Format(getter());
|
||||
return Format(getter(), depth + 1);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
@ -93,4 +93,20 @@ public class ArgumentFormatterTests
|
|||
{
|
||||
public string MyThrowingProperty { get { throw new NotImplementedException(); } }
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void TypesAreRenderedWithMaximumDepthToPreventInfiniteRecursion()
|
||||
{
|
||||
Assert.Equal("Looping { Me = Looping { Me = Looping { ... } } }", ArgumentFormatter.Format(new Looping()));
|
||||
}
|
||||
|
||||
public class Looping
|
||||
{
|
||||
public Looping Me;
|
||||
|
||||
public Looping()
|
||||
{
|
||||
Me = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче