Skip to content
This repository has been archived by the owner on Jan 24, 2021. It is now read-only.

Commit

Permalink
Updated model binding to support fields as well as properties.
Browse files Browse the repository at this point in the history
Replaced references to PropertyInfo in the binding code with a new class BindingMemberInfo, which can refer to either PropertyInfo or FieldInfo objects. Turned the reflection code into a utility method Collect() on the new class. Updated existing unit tests and added new ones.
  • Loading branch information
logiclrd committed Aug 26, 2014
1 parent 8ceabb6 commit 353598d
Show file tree
Hide file tree
Showing 9 changed files with 607 additions and 127 deletions.
1 change: 1 addition & 0 deletions src/Nancy.Tests/Nancy.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@
<Compile Include="Unit\Json\TestPrimitiveConverter.cs" />
<Compile Include="Unit\Json\TestPrimitiveConverterType.cs" />
<Compile Include="Unit\MimeTypesFixture.cs" />
<Compile Include="Unit\ModelBinding\BindingMemberInfoFixture.cs" />
<Compile Include="Unit\ModelBinding\ModelBindingExceptionFixture.cs" />
<Compile Include="Unit\ModelBinding\PropertyBindingExceptionFixture.cs" />
<Compile Include="Unit\NamedPipelineBaseFixture.cs" />
Expand Down
235 changes: 235 additions & 0 deletions src/Nancy.Tests/Unit/ModelBinding/BindingMemberInfoFixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
namespace Nancy.Tests.Unit.ModelBinding
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;
using Nancy.ModelBinding;
using Xunit;
using Xunit.Sdk;

public class BindingMemberInfoFixture
{
[Fact]
public void Should_return_MemberInfo_for_properties_or_fields()
{
// Given
var type = typeof(TestModel);
var underlyingFieldInfo = type.GetFields().First();
var underlyingPropertyInfo = type.GetProperties().First();

// When
var fieldInfo = new BindingMemberInfo(underlyingFieldInfo);
var propertyInfo = new BindingMemberInfo(underlyingPropertyInfo);

// Then
fieldInfo.MemberInfo.ShouldEqual(underlyingFieldInfo);
propertyInfo.MemberInfo.ShouldEqual(underlyingPropertyInfo);
}

[Fact]
public void Should_return_Name_for_properties_or_fields()
{
// Given
var type = typeof(TestModel);
var underlyingFieldInfo = type.GetFields().First();
var underlyingPropertyInfo = type.GetProperties().First();

// When
var fieldInfo = new BindingMemberInfo(underlyingFieldInfo);
var propertyInfo = new BindingMemberInfo(underlyingPropertyInfo);

// Then
fieldInfo.Name.ShouldEqual(underlyingFieldInfo.Name);
propertyInfo.Name.ShouldEqual(underlyingPropertyInfo.Name);
}

[Fact]
public void Should_return_PropertyType_for_properties_or_fields()
{
// Given
var properties = BindingMemberInfo.Collect<TestModel>();

// When

// Then
properties.ShouldHaveCount(4);

foreach (var propInfo in properties)
{
if (propInfo.Name.StartsWith("Int"))
{
propInfo.PropertyType.ShouldEqual(typeof(int));
}
else if (propInfo.Name.StartsWith("String"))
{
propInfo.PropertyType.ShouldEqual(typeof(string));
}
else
{
throw new AssertException("Internal error in unit test: Test model property/field name does not follow the expected convention: " + propInfo.Name);
}
}
}

[Fact]
public void Should_get_fields()
{
// Given
var propInfo = BindingMemberInfo.Collect<TestModel>().Where(prop => prop.Name.EndsWith("Field"));
var model = new TestModel();

// When
model.IntField = 669;
model.StringField = "testing";

// Then
propInfo.Single(prop => prop.PropertyType == typeof(int))
.GetValue(model)
.ShouldEqual(669);

propInfo.Single(prop => prop.PropertyType == typeof(string))
.GetValue(model)
.ShouldEqual("testing");
}

[Fact]
public void Should_set_fields()
{
// Given
var propInfo = BindingMemberInfo.Collect<TestModel>().Where(prop => prop.Name.EndsWith("Field"));
var model = new TestModel();

// When
propInfo.Single(prop => prop.PropertyType == typeof(int))
.SetValue(model, 42);

propInfo.Single(prop => prop.PropertyType == typeof(string))
.SetValue(model, "nineteen");

// Then
model.IntField.ShouldEqual(42);
model.StringField.ShouldEqual("nineteen");
}

[Fact]
public void Should_get_properties()
{
// Given
var propInfo = BindingMemberInfo.Collect<TestModel>().Where(prop => prop.Name.EndsWith("Property"));
var model = new TestModel();

// When
model.IntProperty = 1701;
model.StringProperty = "NancyFX Unit Testing";

// Then
propInfo.Single(prop => prop.PropertyType == typeof(int))
.GetValue(model)
.ShouldEqual(1701);

propInfo.Single(prop => prop.PropertyType == typeof(string))
.GetValue(model)
.ShouldEqual("NancyFX Unit Testing");
}

[Fact]
public void Should_set_properties()
{
// Given
var propInfo = BindingMemberInfo.Collect<TestModel>().Where(prop => prop.Name.EndsWith("Property"));
var model = new TestModel();

// When
propInfo.Single(prop => prop.PropertyType == typeof(int))
.SetValue(model, 2600);

propInfo.Single(prop => prop.PropertyType == typeof(string))
.SetValue(model, "R2D2");

// Then
model.IntProperty.ShouldEqual(2600);
model.StringProperty.ShouldEqual("R2D2");
}

[Fact]
public void Should_collect_all_bindable_members_and_skip_all_others()
{
// Given

// When
var properties = BindingMemberInfo.Collect<BiggerTestModel>();

// Then
properties.ShouldHaveCount(16);

foreach (var property in properties)
property.Name.ShouldStartWith("Bindable");
}

public class TestModel
{
public int IntField;
public string StringField;

public int IntProperty { get; set; }
public string StringProperty { get; set; }
}

public class BiggerTestModel
{
public int BindableIntField;
public int BindableIntProperty { get; set; }
public string BindableStringField;
public string BindableStringProperty { get; set; }
public TestModel BindableTestModelField;
public TestModel BindableTestModelProperty { get; set; }
public BiggerTestModel BindableBiggerTestModelField;
public BiggerTestModel BindableBiggerTestModelProperty { get; set; }
[XmlIgnore]
public IEnumerable<int> BindableEnumerableField;
[XmlIgnore]
public IEnumerable<int> BindableEnumerableProperty { get; set; }
public List<string> BindableListField;
public List<string> BindableListProperty { get; set; }
public double[] BindableArrayField;
public double[] BindableArrayProperty { get; set; }
public TestModel[] BindableArrayOfObjectsField;
public TestModel[] BindableArrayOfObjectsProperty { get; set; }

public int this[int index]
{
get { return 0; }
set { }
}

public int this[string index, int index2]
{
get { return 0; }
set { }
}

public readonly int UnbindableReadOnlyField = 74205;

public string UnbindableReadOnlyProperty
{
get { return "hi"; }
}

public string UnbindableWriteOnlyProperty
{
set { }
}

private int UnbindablePrivateField;

public static int UnbindableStaticField;

public static int UnbindableStaticProperty
{
get { return 0; }
set { }
}
}
}
}
Loading

0 comments on commit 353598d

Please sign in to comment.