Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bartelink/4731953 to your computer and use it in GitHub Desktop.
Save bartelink/4731953 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using Xunit.Extensions;
namespace Prototypes.AutoFixture.Xunit.Extensions
{
public class CompositeDataAttribute : DataAttribute
{
private readonly IEnumerable<DataAttribute> attributes;
/// <summary>
/// Initializes a new instance of the <see cref="CompositeDataAttribute"/> class.
/// </summary>
/// <param name="attributes">The attributes representing a data source for a data theory.
/// </param>
public CompositeDataAttribute( IEnumerable<DataAttribute> attributes )
: this( attributes.ToArray() )
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CompositeDataAttribute"/> class.
/// </summary>
/// <param name="attributes">The attributes representing a data source for a data theory.
/// </param>
public CompositeDataAttribute( params DataAttribute[] attributes )
{
if ( attributes == null )
{
throw new ArgumentNullException( "attributes" );
}
this.attributes = attributes;
}
/// <summary>
/// Gets the attributes supplied through one of the constructors.
/// </summary>
public IEnumerable<DataAttribute> Attributes
{
get { return this.attributes; }
}
/// <summary>
/// Returns the composition of data to be used to test the theory. Favors the data returned
/// by DataAttributes in ascending order. Data already returned is ignored on next
/// DataAttribute returned data.
/// </summary>
/// <param name="methodUnderTest">The method that is being tested.</param>
/// <param name="parameterTypes">The types of the parameters for the test method.</param>
/// <returns>
/// Returns the composition of the theory data.
/// </returns>
/// <remarks>
/// The number of test cases is set from the first DataAttribute theory length.
/// </remarks>
public override IEnumerable<object[]> GetData( MethodInfo methodUnderTest, Type[] parameterTypes )
{
int numberOfParameters = parameterTypes.Length;
IEnumerator<object[]>[] dataEnumerators = attributes.Select( x => x
.GetData( methodUnderTest, parameterTypes )
.GetEnumerator() )
.ToArray();
while ( dataEnumerators.First().MoveNext() )
{
var foundData = new List<object>( dataEnumerators.First().Current );
foreach ( var dataEnumerator in dataEnumerators.Skip( 1 ) )
{
foundData.AddRange(
FetchRowOrEmpty( dataEnumerator )
.Skip( foundData.Count )
.Take( numberOfParameters - foundData.Count ) );
}
if ( foundData.Count < numberOfParameters )
{
throw new InvalidOperationException(
string.Format(
CultureInfo.CurrentCulture,
"Expected {0} parameters, got {1} parameters",
numberOfParameters, foundData.Count
)
);
}
yield return foundData.ToArray();
}
}
static IEnumerable<object> FetchRowOrEmpty( IEnumerator<object[]> enumerator )
{
if ( enumerator.MoveNext() )
return enumerator.Current;
return Enumerable.Empty<object>();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment