Skip to content

Instantly share code, notes, and snippets.

@bartelink
Last active September 25, 2015 19:47
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/974641 to your computer and use it in GitHub Desktop.
Save bartelink/974641 to your computer and use it in GitHub Desktop.
My 'teardown in reverse order' fork of AutoFixture.Kernel.DisposableTrackingCustomization (Current version works against v3.x, initial revision against 2.x)
namespace Ploeh.AutoFixture.Forked
{
class HackedDisposableTrackingCustomization : ICustomization, IDisposable
{
private readonly DisposableTrackingBehavior behavior;
public HackedDisposableTrackingCustomization()
{
this.behavior = new DisposableTrackingBehavior();
}
public void Customize( IFixture fixture )
{
if ( fixture == null )
throw new ArgumentNullException( "fixture" );
fixture.Behaviors.Add( this.behavior );
}
public void Dispose()
{
this.Dispose( true );
}
protected virtual void Dispose( bool disposing )
{
if ( disposing )
this.behavior.Dispose();
}
internal class DisposableTrackingBehavior : ISpecimenBuilderTransformation, IDisposable
{
readonly List<IDisposable> disposables;
public DisposableTrackingBehavior()
{
disposables = new List<IDisposable>();
}
public ISpecimenBuilder Transform( ISpecimenBuilder builder )
{
return new DisposableTracker( builder, AddIfNotExists );
}
void AddIfNotExists( IDisposable disposable )
{
// TOREVIEW Leaning on default comparison logic here may not satisfy POLA
//if ( !disposables.Contains( disposable ) )
disposables.Add( disposable );
}
public void Dispose()
{
this.Dispose( true );
}
protected virtual void Dispose( bool disposing )
{
if ( !disposing )
return;
foreach ( var d in Enumerable.Reverse( this.disposables ) )
d.Dispose();
this.disposables.Clear();
}
}
internal class DisposableTracker : ISpecimenBuilderNode
{
readonly ISpecimenBuilder builder;
readonly Action<IDisposable> registerDisposable;
public DisposableTracker( ISpecimenBuilder builder, Action<IDisposable> registerDisposable )
{
if ( builder == null )
throw new ArgumentNullException( "builder" );
if ( registerDisposable == null )
throw new ArgumentNullException( "registerDisposable" );
this.builder = builder;
this.registerDisposable = registerDisposable;
}
object ISpecimenBuilder.Create( object request, ISpecimenContext context )
{
var specimen = this.builder.Create( request, context );
var d = specimen as IDisposable;
if ( d != null )
this.registerDisposable( d );
return specimen;
}
ISpecimenBuilderNode ISpecimenBuilderNode.Compose( IEnumerable<ISpecimenBuilder> builders )
{
var composedBuilder = new CompositeSpecimenBuilder( builders );
var d = new DisposableTracker( composedBuilder,registerDisposable );
return d;
}
IEnumerator<ISpecimenBuilder> IEnumerable<ISpecimenBuilder>.GetEnumerator()
{
yield return builder;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
yield return builder;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment