Skip to content

Commit

Permalink
Added struct support (#94)
Browse files Browse the repository at this point in the history
* Added StructTypeCreator
* Updated DefaultConstructorResolver.Resolve to return null for structs
* Fixed DefaultPropertyResolver.IsIgnored which returned the inverse value
  • Loading branch information
roryprimrose authored May 6, 2020
1 parent 340a9f5 commit 93484dd
Show file tree
Hide file tree
Showing 16 changed files with 612 additions and 175 deletions.
31 changes: 31 additions & 0 deletions ModelBuilder.UnitTests/DefaultConstructorResolverTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,17 @@ public void ResolveMatchesConstructorWithMatchingParametersTypes()
constructor.GetParameters().Length.Should().Be(6);
}

[Fact]
public void ResolveReturnsConstructorForStructThatHasConstructors()
{
var sut = new DefaultConstructorResolver();

var constructor = sut.Resolve(typeof(KeyValuePair<Guid, Person>));

constructor.Should().NotBeNull();
constructor.GetParameters().Should().HaveCount(2);
}

[Fact]
public void ResolveReturnsConstructorThatMatchesAgainstNullParameters()
{
Expand Down Expand Up @@ -265,6 +276,16 @@ public void ResolveReturnsDefaultConstructorWhenManyConstructorsAvailable()
constructor.GetParameters().Should().BeEmpty();
}

[Fact]
public void ResolveReturnsNullForStructThatHasNoConstructors()
{
var sut = new DefaultConstructorResolver();

var constructor = sut.Resolve(typeof(StructModel));

constructor.Should().BeNull();
}

[Fact]
public void ResolveReturnsParameterConstructor()
{
Expand All @@ -275,6 +296,16 @@ public void ResolveReturnsParameterConstructor()
constructor.GetParameters().Should().NotBeEmpty();
}

[Fact]
public void ResolveThrowsExceptionForEnum()
{
var sut = new DefaultConstructorResolver();

Action action = () => sut.Resolve(typeof(Gender));

_output.WriteLine(action.Should().Throw<MissingMemberException>().And.Message);
}

[Fact]
public void ResolveThrowsExceptionWhenArgsContainsNullAndArgCountLessThanOptionalParam()
{
Expand Down
5 changes: 0 additions & 5 deletions ModelBuilder.UnitTests/DefaultExecuteStrategyTTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,11 +204,6 @@ public void PopulateAssignsPropertyValuesToExistingInstance()
buildConfiguration.PropertyResolver.Returns(propertyResolver);
propertyResolver.GetOrderedProperties(buildConfiguration, typeof(SlimModel))
.Returns(typeof(SlimModel).GetProperties());
propertyResolver.IsIgnored(
buildConfiguration,
model,
Arg.Is<PropertyInfo>(x => x.Name == nameof(SlimModel.Value)),
Arg.Any<object[]>()).Returns(true);
processor.GetBuildCapability(buildConfiguration, buildHistory, BuildRequirement.Create,
Arg.Is<PropertyInfo>(x => x.Name == nameof(SlimModel.Value)))
.Returns(valueCapability);
Expand Down
101 changes: 66 additions & 35 deletions ModelBuilder.UnitTests/DefaultExecuteStrategyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,11 +189,6 @@ public void CreateDeterminesPropertiesToCreateByProvidingConstructorArgsForNeste
buildConfiguration.PropertyResolver.Returns(propertyResolver);
propertyResolver.GetOrderedProperties(buildConfiguration, typeof(SimpleConstructor))
.Returns(typeof(SimpleConstructor).GetProperties());
propertyResolver.IsIgnored(
Arg.Any<IBuildConfiguration>(),
expected,
Arg.Is<PropertyInfo>(x => x.Name == nameof(SimpleConstructor.Age)),
Arg.Any<object[]>()).Returns(true);

sut.Initialize(buildConfiguration);

Expand All @@ -202,12 +197,6 @@ public void CreateDeterminesPropertiesToCreateByProvidingConstructorArgsForNeste
actual.Should().Be(expected);
actual.Model.Should().Be(model);
actual.Age.Should().Be(age);

propertyResolver.Received(1).IsIgnored(
buildConfiguration,
Arg.Is<object>(x => x.GetType() == typeof(SimpleConstructor)),
Arg.Is<PropertyInfo>(x => x.Name == nameof(SimpleConstructor.Age)),
Arg.Is<object[]>(x => x[0] == model));
}

[Fact]
Expand Down Expand Up @@ -448,11 +437,6 @@ public void CreatePushesInstanceIntoBuildChain()
buildConfiguration.PropertyResolver.Returns(propertyResolver);
propertyResolver.GetOrderedProperties(buildConfiguration, typeof(SlimModel))
.Returns(typeof(SlimModel).GetProperties());
propertyResolver.IsIgnored(
Arg.Any<IBuildConfiguration>(),
Arg.Any<object>(),
Arg.Any<PropertyInfo>(),
Arg.Any<object[]>()).Returns(true);

sut.Initialize(buildConfiguration);

Expand Down Expand Up @@ -580,11 +564,6 @@ public void CreateReturnsValueFromProcessorWithPropertyPopulation()
buildConfiguration.PropertyResolver.Returns(propertyResolver);
propertyResolver.GetOrderedProperties(buildConfiguration, typeof(SlimModel))
.Returns(typeof(SlimModel).GetProperties());
propertyResolver.IsIgnored(
Arg.Any<IBuildConfiguration>(),
Arg.Any<object>(),
Arg.Any<PropertyInfo>(),
Arg.Any<object[]>()).Returns(true);

sut.Initialize(buildConfiguration);

Expand Down Expand Up @@ -643,7 +622,8 @@ public void CreateReturnsValueFromResolvedConstructorAndBuiltParameters()
buildConfiguration.TypeResolver.Returns(typeResolver);
typeResolver.GetBuildType(buildConfiguration, Arg.Any<Type>()).Returns(x => x.Arg<Type>());
constructorResolver.Resolve(typeof(ReadOnlyModel)).Returns(constructorInfo);
constructorResolver.GetOrderedParameters(buildConfiguration, constructorInfo).Returns(constructorInfo.GetParameters());
constructorResolver.GetOrderedParameters(buildConfiguration, constructorInfo)
.Returns(constructorInfo.GetParameters());

sut.Initialize(buildConfiguration);

Expand Down Expand Up @@ -683,7 +663,8 @@ public void CreateReturnsValueWithNoArgumentsAndDetectConstructorEnabledCreatedU
typeof(Person))
.Returns(typeCapability);
constructorResolver.Resolve(typeof(Person)).Returns(constructorInfo);
constructorResolver.GetOrderedParameters(buildConfiguration, constructorInfo).Returns(constructorInfo.GetParameters());
constructorResolver.GetOrderedParameters(buildConfiguration, constructorInfo)
.Returns(constructorInfo.GetParameters());
processor.Build(sut, typeof(Person), null).Returns(expected);
processor.Populate(sut, expected).Returns(expected);

Expand Down Expand Up @@ -734,6 +715,7 @@ public void CreateThrowsExceptionWhenNoCapabilityFoundForParameter()
AutoPopulate = false,
SupportsCreate = true
};
var constructor = typeof(ReadOnlyModel).GetConstructors().Single();

var processor = Substitute.For<IBuildProcessor>();
var buildConfiguration = Substitute.For<IBuildConfiguration>();
Expand All @@ -747,8 +729,10 @@ public void CreateThrowsExceptionWhenNoCapabilityFoundForParameter()
.Returns(typeCapability);
buildConfiguration.TypeResolver.Returns(typeResolver);
typeResolver.GetBuildType(buildConfiguration, Arg.Any<Type>()).Returns(x => x.Arg<Type>());
constructorResolver.Resolve(typeof(ReadOnlyModel), null)
.Returns(typeof(ReadOnlyModel).GetConstructors().Single());
constructorResolver.Resolve(typeof(ReadOnlyModel))
.Returns(constructor);
constructorResolver.GetOrderedParameters(buildConfiguration, constructor)
.Returns(constructor.GetParameters());
buildConfiguration.ConstructorResolver.Returns(constructorResolver);

sut.Initialize(buildConfiguration);
Expand Down Expand Up @@ -793,11 +777,6 @@ public void CreateThrowsExceptionWhenNoCapabilityFoundForProperty()
buildConfiguration.PropertyResolver.Returns(propertyResolver);
propertyResolver.GetOrderedProperties(buildConfiguration, typeof(SlimModel))
.Returns(typeof(SlimModel).GetProperties());
propertyResolver.IsIgnored(
Arg.Any<IBuildConfiguration>(),
expected,
Arg.Is<PropertyInfo>(x => x.Name == nameof(SlimModel.Value)),
Arg.Any<object[]>()).Returns(true);

sut.Initialize(buildConfiguration);

Expand Down Expand Up @@ -922,11 +901,6 @@ public void PopulateAssignsPropertyValuesToExistingInstance()
buildConfiguration.PropertyResolver.Returns(propertyResolver);
propertyResolver.GetOrderedProperties(buildConfiguration, typeof(SlimModel))
.Returns(typeof(SlimModel).GetProperties());
propertyResolver.IsIgnored(
buildConfiguration,
model,
Arg.Is<PropertyInfo>(x => x.Name == nameof(SlimModel.Value)),
Arg.Any<object[]>()).Returns(true);
processor.GetBuildCapability(buildConfiguration, buildHistory, BuildRequirement.Create,
Arg.Is<PropertyInfo>(x => x.Name == nameof(SlimModel.Value)))
.Returns(valueCapability);
Expand All @@ -944,6 +918,63 @@ public void PopulateAssignsPropertyValuesToExistingInstance()
actual.Value.Should().Be(expected);
}

[Fact]
public void PopulateDoesNotAssignIgnoredProperty()
{
var buildHistory = new BuildHistory();
var model = new SlimModel();
var expected = Guid.NewGuid();
var typeCapability = new BuildCapability
{
SupportsPopulate = true,
ImplementedByType = GetType(),
AutoDetectConstructor = false,
AutoPopulate = true,
SupportsCreate = true
};
var valueCapability = new BuildCapability
{
SupportsPopulate = false,
ImplementedByType = GetType(),
AutoDetectConstructor = false,
AutoPopulate = false,
SupportsCreate = true
};

var processor = Substitute.For<IBuildProcessor>();
var buildConfiguration = Substitute.For<IBuildConfiguration>();
var propertyResolver = Substitute.For<IPropertyResolver>();

var sut = new DefaultExecuteStrategy(buildHistory, _buildLog, processor);

processor.GetBuildCapability(buildConfiguration, buildHistory, BuildRequirement.Populate,
typeof(SlimModel))
.Returns(typeCapability);
buildConfiguration.PropertyResolver.Returns(propertyResolver);
propertyResolver.GetOrderedProperties(buildConfiguration, typeof(SlimModel))
.Returns(typeof(SlimModel).GetProperties());
processor.GetBuildCapability(buildConfiguration, buildHistory, BuildRequirement.Create,
Arg.Is<PropertyInfo>(x => x.Name == nameof(SlimModel.Value)))
.Returns(valueCapability);
processor.GetBuildCapability(buildConfiguration, buildHistory, BuildRequirement.Populate,
typeof(Guid))
.Returns(valueCapability);
processor.Populate(sut, model).Returns(model);
propertyResolver.IsIgnored(
Arg.Any<IBuildConfiguration>(),
Arg.Any<object>(),
Arg.Any<PropertyInfo>(),
Arg.Any<object[]>()).Returns(true);

sut.Initialize(buildConfiguration);

var actual = (SlimModel) sut.Populate(model);

actual.Value.Should().BeEmpty();

processor.DidNotReceive().Build(sut, Arg.Is<PropertyInfo>(x => x.Name == nameof(SlimModel.Value)), null);
}

[Fact]
public void PopulatePropertyThrowsExceptionWithNullInstance()
{
Expand Down
Loading

0 comments on commit 93484dd

Please sign in to comment.