Skip to content

Commit

Permalink
Adding Specifications, Builders and Customizations to target issue:
Browse files Browse the repository at this point in the history
  • Loading branch information
WojcikMike committed May 27, 2013
1 parent 9df6684 commit ebda500
Show file tree
Hide file tree
Showing 17 changed files with 483 additions and 3 deletions.
5 changes: 5 additions & 0 deletions Src/AutoFixture/AutoFixture.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@
<ItemGroup>
<Compile Include="AutoPropertiesTarget.cs" />
<Compile Include="BehaviorRoot.cs" />
<Compile Include="Kernel\NoConstructorSpecification.cs" />
<Compile Include="Kernel\StructureSpecification.cs" />
<Compile Include="Kernel\StructureWithoutConstructorSpecimenBuilder.cs" />
<Compile Include="RandomBooleanSequenceGenerator.cs" />
<Compile Include="CharSequenceGenerator.cs" />
<Compile Include="CollectionFiller.cs" />
Expand Down Expand Up @@ -240,6 +243,8 @@
<Compile Include="StableFiniteSequenceCustomization.cs" />
<Compile Include="NumericSequenceGenerator.cs" />
<Compile Include="NumericSequencePerTypeCustomization.cs" />
<Compile Include="SupportStructureDefaultConstructorsCustomization.cs" />
<Compile Include="SupportStructureDefaultConstructorsGenerator.cs" />
<Compile Include="ThrowingRecursionBehavior.cs" />
<Compile Include="Kernel\TraceWriter.cs" />
<Compile Include="GuidGenerator.cs" />
Expand Down
11 changes: 8 additions & 3 deletions Src/AutoFixture/Fixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@ public Fixture(ISpecimenBuilder engine, MultipleRelay multiple)
this),
new OrRequestSpecification(
new ExactTypeSpecification(
typeof(Fixture)),
typeof (Fixture)),
new ExactTypeSpecification(
typeof(IFixture)),
typeof (IFixture)),
new ExactTypeSpecification(
typeof(ISpecimenBuilder)))),
typeof (ISpecimenBuilder)))),
new StableFiniteSequenceRelay(),
new FilteringSpecimenBuilder(
new Postprocessor(
Expand Down Expand Up @@ -111,6 +111,11 @@ public Fixture(ISpecimenBuilder engine, MultipleRelay multiple)
new CollectionRelay(),
new ListRelay(),
new EnumerableRelay())),
new FilteringSpecimenBuilder(
new StructureWithoutConstructorSpecimenBuilder(),
new AndRequestSpecification(
new StructureSpecification(),
new NoConstructorSpecification())),
new TerminatingSpecimenBuilder()));

this.UpdateCustomizer();
Expand Down
37 changes: 37 additions & 0 deletions Src/AutoFixture/Kernel/NoConstructorSpecification.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System;
using System.Linq;

namespace Ploeh.AutoFixture.Kernel
{
/// <summary>
/// A specification that evaluates whether a request is a request for a type without public constructors.
/// </summary>
public class NoConstructorSpecification : IRequestSpecification
{
private readonly IMethodQuery modestConstructorQuery;

public NoConstructorSpecification()
{
modestConstructorQuery = new ModestConstructorQuery();
}

/// <summary>
/// Evaluates a request for a specimen.
/// </summary>
/// <param name="request">The specimen request.</param>
/// <returns>
/// <see langword="true"/> if <paramref name="request"/> is a <see cref="Type"/> that represents a type without public constructors;
/// otherwise, <see langword="false"/>.
/// </returns>
public bool IsSatisfiedBy(object request)
{
if (request == null)
{
throw new ArgumentNullException("request");
}

var type = request as Type;
return type != null && !modestConstructorQuery.SelectMethods(type).Any();
}
}
}
35 changes: 35 additions & 0 deletions Src/AutoFixture/Kernel/StructureSpecification.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System;

namespace Ploeh.AutoFixture.Kernel
{
/// <summary>
/// A specification that evaluates whether a request is a request for a value type such as a custom structure.
/// </summary>
public class StructureSpecification : IRequestSpecification
{

/// <summary>
/// Evaluates a request for a specimen.
/// </summary>
/// <param name="request">The specimen request.</param>
/// <returns>
/// <see langword="true"/> if <paramref name="request"/> is a <see cref="Type"/> that represents a custom structure;
/// otherwise, <see langword="false"/>.
/// </returns>
public bool IsSatisfiedBy(object request)
{
if (request == null)
{
throw new ArgumentNullException("request");
}

var type = request as Type;
return type != null && IsStruct(type);
}

private bool IsStruct(Type type)
{
return type.IsValueType && !type.IsEnum && !type.IsPrimitive;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System.Globalization;

namespace Ploeh.AutoFixture.Kernel
{
/// <summary>
/// Throws an <see cref="ObjectCreationException"/> when one tries to create Structure without explicit parametrized constructor.
/// Possibly notifying about bad design (mutable value type).
/// </summary>
/// <remarks>
/// <para>
/// This <see cref="ISpecimenBuilder"/> can be used with proper filtering <see cref="IRequestSpecification"/> to throw exceptions only on
/// structures without constructors. Will throw an exception instead of letting the
/// containing builder return a <see cref="NoSpecimen"/> instance when it can't satisfy a
/// request or generic exception being thrown.
/// </para>
/// </remarks>
public class StructureWithoutConstructorSpecimenBuilder : ISpecimenBuilder
{
/// <summary>
/// Throws an <see cref="ObjectCreationException"/>.
/// </summary>
/// <param name="request">The request that describes what to create.</param>
/// <param name="context">
/// A context that can be used to create other specimens. Not used.
/// </param>
/// <returns>
/// This method never returns. It always throws an <see cref="ObjectCreationException"/>.
/// </returns>
public object Create(object request, ISpecimenContext context)
{
throw new ObjectCreationException(
string.Format(
CultureInfo.CurrentCulture,
@"AutoFixture was unable to create an instance from {0}, since it's a value type with no explicit, parameterized constructors. Are you attempting to create an instance of a mutable value type? If so, you should strongly consider changing the design of the value type. However, if you are unable to do so, you can add the SupportValueTypeDefaultConstructors customizations to your Fixture instance:
var fixture = new Fixture();
var customization = new {1}();
customization.Customize(fixture);",
request, typeof(SupportStructureDefaultConstructorsCustomization).Name
)
);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;

namespace Ploeh.AutoFixture

{
/// <summary>
/// A customization that changes how custom <see langword="struct"/> are generated. Uses <see cref="SupportStructureDefaultConstructorsGenerator"/>.
/// </summary>
public class SupportStructureDefaultConstructorsCustomization : ICustomization
{
/// <summary>
/// Customizes specified fixture by adding <see cref="SupportStructureDefaultConstructorsGenerator"/> as a default stragety for
/// creating new custom <see langword="struct"/> that has only default constructor.
/// </summary>
/// <param name="fixture">The fixture to customize.</param>
public void Customize(IFixture fixture)
{
if (fixture == null)
{
throw new ArgumentNullException("fixture");
}

fixture.Customizations.Add(new SupportStructureDefaultConstructorsGenerator());
}
}
}
35 changes: 35 additions & 0 deletions Src/AutoFixture/SupportStructureDefaultConstructorsGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System;
using Ploeh.AutoFixture.Kernel;

namespace Ploeh.AutoFixture
{
/// <summary>
/// Creates new <see langword="struct"/>.
/// </summary>
public class SupportStructureDefaultConstructorsGenerator : ISpecimenBuilder
{
/// <summary>
/// Creates a new <see langword="struct"/>.
/// </summary>
/// <param name="request">The request that describes what to create.</param>
/// <param name="context">A context that can be used to create other specimens. Not used</param>
/// <returns>
/// The requested struct if possible; otherwise a <see cref="NoSpecimen"/> instance.
/// </returns>
public object Create(object request, ISpecimenContext context)
{
Type type = request as Type;
if (type == null || !IsCustomStructure(type))
{
return new NoSpecimen(request);
}

return Activator.CreateInstance(type);
}

private bool IsCustomStructure(Type type)
{
return type.IsValueType && !type.IsEnum && !type.IsPrimitive;
}
}
}
5 changes: 5 additions & 0 deletions Src/AutoFixtureUnitTest/AutoFixtureUnitTest.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@
<Compile Include="AbstractRecursionIssue\ItemBase.cs" />
<Compile Include="AbstractRecursionIssue\ItemLocation.cs" />
<Compile Include="AbstractRecursionIssue\Repro.cs" />
<Compile Include="Kernel\NoConstructorSpecificationTest.cs" />
<Compile Include="Kernel\StructureSpecificationTest.cs" />
<Compile Include="Kernel\StructureWithoutConstructorSpecimenBuilderTest.cs" />
<Compile Include="RandomBooleanSequenceGeneratorTest.cs" />
<Compile Include="FixtureResolvingItselfTests.cs" />
<Compile Include="IncrementingDateTimeCustomizationTest.cs" />
Expand Down Expand Up @@ -230,6 +233,8 @@
<Compile Include="StableFiniteSequenceCustomizationTest.cs" />
<Compile Include="NumericSequenceGeneratorTest.cs" />
<Compile Include="NumericSequencePerTypeCustomizationTest.cs" />
<Compile Include="SupportStructureDefaultConstructorsCustomizationTest.cs" />
<Compile Include="SupportStructureDefaultConstructorsGeneratorTest.cs" />
<Compile Include="TaggedNode.cs" />
<Compile Include="TaggedNodeComparer.cs" />
<Compile Include="TestConsole.cs" />
Expand Down
41 changes: 41 additions & 0 deletions Src/AutoFixtureUnitTest/FixtureTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4894,6 +4894,47 @@ public void SutYieldsSomething()
Assert.NotEmpty(sut);
}

[Fact]
public void CreateAnonymousStructWithConstructorReturnsInstance()
{
// Fixture setup
var fixture = new Fixture();
// Exercise system
var result = fixture.Create<StructType>();
// Verify outcome
Assert.NotNull(result);
Assert.NotNull(result.Property1);
Assert.NotNull(result.Property2);
Assert.NotNull(result.Property3);
// Teardown
}

[Fact]
public void CreateAnonymousStructWithoutConstructorThrowsExpcetion()
{
// Fixture setup
var fixture = new Fixture();
// Exercise system and verify outcome
Assert.Throws<ObjectCreationException>(() => fixture.Create<StructTypeWithoutConstructor>());
// Teardown
}

[Fact]
public void CreateAnonymousStructWithoutConstructorUsingCustomizationReturnsInstance()
{
// Fixture setup
var fixture = new Fixture();
var sut = new SupportStructureDefaultConstructorsCustomization();
sut.Customize(fixture);
// Exercise system and verify outcome
var result = fixture.Create<StructTypeWithoutConstructor>();
// Verify outcome
Assert.NotNull(result);
Assert.NotNull(result.Property1);
Assert.NotNull(result.Property2);
// Teardown
}

private class RecursionTestObjectWithReferenceOutA
{
public RecursionTestObjectWithReferenceOutB ReferenceToB
Expand Down
53 changes: 53 additions & 0 deletions Src/AutoFixtureUnitTest/Kernel/NoConstructorSpecificationTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System;
using Ploeh.AutoFixture.Kernel;
using Ploeh.TestTypeFoundation;
using Xunit;
using Xunit.Extensions;

namespace Ploeh.AutoFixtureUnitTest.Kernel
{
public class NoConstructorSpecificationTest
{
[Fact]
public void SutIsRequestSpecification()
{
// Fixture setup
// Exercise system
var sut = new NoConstructorSpecification();
// Verify outcome
Assert.IsAssignableFrom<IRequestSpecification>(sut);
// Teardown
}

[Fact]
public void IsSatisfiedByNullThrows()
{
// Fixture setup
var sut = new NoConstructorSpecification();
// Exercise system and verify outcome
Assert.Throws<ArgumentNullException>(() => sut.IsSatisfiedBy(null));
// Teardown
}

[Theory]
[InlineData("Ploeh", false)]
[InlineData(1, false)]
[InlineData(typeof(object), false)]
[InlineData(typeof(string), false)]
[InlineData(typeof(AbstractType), true)]
[InlineData(typeof(IInterface), true)]
[InlineData(typeof(StructType), false)]
[InlineData(typeof(char), true)]
[InlineData(typeof(ActivityScope), true)]
public void IsSatisfiedByReturnsCorrectResult(object request, bool expectedResult)
{
// Fixture setup
var sut = new NoConstructorSpecification();
// Exercise system
var result = sut.IsSatisfiedBy(request);
// Verify outcome
Assert.Equal(expectedResult, result);
// Teardown
}
}
}
Loading

0 comments on commit ebda500

Please sign in to comment.