Remove infinite loop potential from ArgumentFormatter.Format.

This commit is contained in:
Brad Wilson 2014-04-12 14:18:29 -07:00
Родитель 857e4f4ad6
Коммит 15cf562d6f
2 изменённых файлов: 37 добавлений и 5 удалений

Просмотреть файл

@ -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;
}
}
}