Improve theory parameter display (closes #28)

This commit is contained in:
Brad Wilson 2014-04-12 12:22:16 -07:00
Родитель 277dd4b2a8
Коммит 80fe3ba105
6 изменённых файлов: 165 добавлений и 25 удалений

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

@ -0,0 +1,65 @@
using System;
using System.Collections;
using System.Globalization;
using System.Linq;
using System.Reflection;
namespace Xunit.Sdk
{
public static class ArgumentFormatter
{
public static string Format(object value)
{
if (value == null)
return "null";
if (value is char)
return String.Format("'{0}'", value);
string stringParameter = value as string;
if (stringParameter != null)
{
if (stringParameter.Length > 50)
return String.Format("\"{0}\"...", stringParameter.Substring(0, 50));
return String.Format("\"{0}\"", stringParameter);
}
var enumerable = value as IEnumerable;
if (enumerable != null)
return String.Format("[{0}]", String.Join(", ", enumerable.Cast<object>().Select(x => Format(x))));
var type = value.GetType();
if (type.GetTypeInfo().IsValueType)
return Convert.ToString(value, CultureInfo.CurrentCulture);
var fields = type.GetRuntimeFields()
.Where(f => f.IsPublic && !f.IsStatic)
.Select(f => new { name = f.Name, value = WrapAndGetFormattedValue(() => f.GetValue(value)) })
.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)) })
.ToList();
var formattedParameters = fields.Concat(properties)
.OrderBy(p => p.name)
.Select(p => String.Format("{0} = {1}", p.name, p.value))
.ToList();
var parameterValues = formattedParameters.Count == 0 ? "{ }" : String.Format("{{ {0} }}", String.Join(", ", formattedParameters));
return String.Format("{0} {1}", type.Name, parameterValues);
}
private static string WrapAndGetFormattedValue(Func<object> getter)
{
try
{
return Format(getter());
}
catch (Exception ex)
{
return String.Format("(throws {0})", ex.Unwrap().GetType().Name);
}
}
}
}

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

@ -61,6 +61,7 @@
<Compile Include="ICollectionFixture.cs" />
<Compile Include="InlineDataAttribute.cs" />
<Compile Include="MemberDataAttribute.cs" />
<Compile Include="Sdk\ArgumentFormatter.cs" />
<Compile Include="Sdk\BeforeAfterTestAttribute.cs" />
<Compile Include="Sdk\DataAttribute.cs" />
<Compile Include="Sdk\DataDiscoverer.cs" />

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

@ -276,29 +276,9 @@ namespace Xunit.Sdk
stream.WriteByte(0);
}
static string ParameterToDisplayValue(object parameterValue)
{
if (parameterValue == null)
return "null";
if (parameterValue is char)
return String.Format("'{0}'", parameterValue);
string stringParameter = parameterValue as string;
if (stringParameter != null)
{
if (stringParameter.Length > 50)
return String.Format("\"{0}\"...", stringParameter.Substring(0, 50));
return String.Format("\"{0}\"", stringParameter);
}
return Convert.ToString(parameterValue, CultureInfo.CurrentCulture);
}
static string ParameterToDisplayValue(string parameterName, object parameterValue)
{
return String.Format("{0}: {1}", parameterName, ParameterToDisplayValue(parameterValue));
return String.Format("{0}: {1}", parameterName, ArgumentFormatter.Format(parameterValue));
}
static string ConvertToSimpleTypeName(ITypeInfo type)

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

@ -45,8 +45,7 @@ public class Xunit2TheoryAcceptanceTests
Assert.Collection(results.OrderBy(r => r.TestDisplayName),
result => Assert.Equal(@"Xunit2TheoryAcceptanceTests+TheoryTests+GenericWithSerializableData.GenericTest<Int32, Object>(value1: 42, value2: null)", result.TestDisplayName),
// TODO: The parameter values here should eventually read: '[1, 2, 3]' and '["a", "b", "c"]'
result => Assert.Equal(@"Xunit2TheoryAcceptanceTests+TheoryTests+GenericWithSerializableData.GenericTest<Int32[], List<String>>(value1: System.Int32[], value2: System.Collections.Generic.List`1[System.String])", result.TestDisplayName),
result => Assert.Equal(@"Xunit2TheoryAcceptanceTests+TheoryTests+GenericWithSerializableData.GenericTest<Int32[], List<String>>(value1: [1, 2, 3], value2: [""a"", ""b"", ""c""])", result.TestDisplayName),
result => Assert.Equal(@"Xunit2TheoryAcceptanceTests+TheoryTests+GenericWithSerializableData.GenericTest<String, Double>(value1: ""Hello, world!"", value2: 21.12)", result.TestDisplayName)
);
}
@ -73,7 +72,7 @@ public class Xunit2TheoryAcceptanceTests
var results = Run<ITestPassed>(typeof(GenericWithNonSerializableData));
Assert.Collection(results,
result => Assert.Equal(@"Xunit2TheoryAcceptanceTests+TheoryTests+GenericWithNonSerializableData.GenericTest<Xunit2TheoryAcceptanceTests+TheoryTests+GenericWithNonSerializableData>(value: Xunit2TheoryAcceptanceTests+TheoryTests+GenericWithNonSerializableData)", result.TestDisplayName)
result => Assert.Equal<object>(@"Xunit2TheoryAcceptanceTests+TheoryTests+GenericWithNonSerializableData.GenericTest<Xunit2TheoryAcceptanceTests+TheoryTests+GenericWithNonSerializableData>(value: GenericWithNonSerializableData { })", result.TestDisplayName)
);
}
@ -625,7 +624,7 @@ public class Xunit2TheoryAcceptanceTests
{
var testMessages = Run<ITestFailed>(typeof(ClassUnderTest));
var equalFailure = Assert.Single(testMessages, msg => msg.TestDisplayName == "Xunit2TheoryAcceptanceTests+ErrorAggregation+ClassUnderTest.TestViaInlineData(x: 42, y: 21.12, z: Xunit2TheoryAcceptanceTests+ErrorAggregation+ClassUnderTest)");
var equalFailure = Assert.Single(testMessages, msg => msg.TestDisplayName == "Xunit2TheoryAcceptanceTests+ErrorAggregation+ClassUnderTest.TestViaInlineData(x: 42, y: 21.12, z: ClassUnderTest { })");
Assert.Contains("Assert.Equal() Failure", equalFailure.Messages.Single());
var notNullFailure = Assert.Single(testMessages, msg => msg.TestDisplayName == "Xunit2TheoryAcceptanceTests+ErrorAggregation+ClassUnderTest.TestViaInlineData(x: 0, y: 0, z: null)");

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

@ -0,0 +1,94 @@
using System;
using Xunit;
using Xunit.Sdk;
public class ArgumentFormatterTests
{
[Fact]
public static void NullValue()
{
Assert.Equal("null", ArgumentFormatter.Format(null));
}
[Fact]
public static void StringValue()
{
Assert.Equal("\"Hello, world!\"", ArgumentFormatter.Format("Hello, world!"));
}
[Fact]
public static void StringValueTruncatedPast50Characters()
{
Assert.Equal("\"----|----1----|----2----|----3----|----4----|----5\"...", ArgumentFormatter.Format("----|----1----|----2----|----3----|----4----|----5-"));
}
[Fact]
public static void CharacterValue()
{
Assert.Equal("'a'", ArgumentFormatter.Format('a'));
}
[Fact]
public static void DecimalValue()
{
Assert.Equal("123.45", ArgumentFormatter.Format(123.45M));
}
[Fact]
public static void EnumerableValue()
{
Assert.Equal("[1, 2.3, \"Hello, world!\"]", ArgumentFormatter.Format(new object[] { 1, 2.3M, "Hello, world!" }));
}
[Fact]
public static void ComplexTypeReturnsValuesInAlphabeticalOrder()
{
Assert.Equal("MyComplexType { MyPublicField = 42, MyPublicProperty = 21.12 }", ArgumentFormatter.Format(new MyComplexType()));
}
public class MyComplexType
{
private string MyPrivateField = "Hello, world";
public static int MyPublicStaticField = 2112;
public decimal MyPublicProperty { get; private set; }
public int MyPublicField = 42;
public MyComplexType()
{
MyPublicProperty = 21.12M;
}
}
[Fact]
public static void ComplexTypeInsideComplexType()
{
Assert.Equal("MyComplexTypeWrapper { c = 'A', s = \"Hello, world!\", t = MyComplexType { MyPublicField = 42, MyPublicProperty = 21.12 } }", ArgumentFormatter.Format(new MyComplexTypeWrapper()));
}
public class MyComplexTypeWrapper
{
public MyComplexType t = new MyComplexType();
public char c = 'A';
public string s = "Hello, world!";
}
[Fact]
public static void EmptyComplexType()
{
Assert.Equal("Object { }", ArgumentFormatter.Format(new object()));
}
[Fact]
public static void ComplexTypeWithThrowingPropertyGetter()
{
Assert.Equal("ThrowingGetter { MyThrowingProperty = (throws NotImplementedException) }", ArgumentFormatter.Format(new ThrowingGetter()));
}
public class ThrowingGetter
{
public string MyThrowingProperty { get { throw new NotImplementedException(); } }
}
}

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

@ -88,6 +88,7 @@
<Compile Include="..\GlobalTestAssemblyInfo.cs">
<Link>Properties\GlobalTestAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Sdk\ArgumentFormatterTests.cs" />
<Compile Include="Sdk\DefaultTestCaseOrdererTests.cs" />
<Compile Include="Sdk\Frameworks\CollectionPerAssemblyTestCollectionFactoryTests.cs" />
<Compile Include="Sdk\Frameworks\CollectionPerClassTestCollectionFactoryTests.cs" />