Improve theory parameter display (closes #28)
This commit is contained in:
Родитель
277dd4b2a8
Коммит
80fe3ba105
|
@ -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" />
|
||||
|
|
Загрузка…
Ссылка в новой задаче