diff --git a/src/GenFu/GenFu.cs b/src/GenFu/GenFu.cs index 59a65fc..ba41202 100644 --- a/src/GenFu/GenFu.cs +++ b/src/GenFu/GenFu.cs @@ -108,6 +108,8 @@ private static List BuildList(Type type, int itemCount) private static void SetPropertyValue(object instance, PropertyInfo property) { + if (IgnorePropertyCollection.IsPropertyInIgnoreList(property)) + return; IPropertyFiller filler = _fillerManager.GetFiller(property); property.SetValue(instance, filler.GetValue(instance), null); } diff --git a/src/GenFu/GenFuConfigurator.cs b/src/GenFu/GenFuConfigurator.cs index 3a9f3fc..d7c323a 100644 --- a/src/GenFu/GenFuConfigurator.cs +++ b/src/GenFu/GenFuConfigurator.cs @@ -93,13 +93,13 @@ public GenFuConfigurator(GenFu genfu, FillerManager fillerManager) { } - + private PropertyInfo GetPropertyInfoFromExpression(Expression> expression) { PropertyInfo propertyInfo = (expression.Body as MemberExpression).Member as PropertyInfo; return propertyInfo; } - + private MethodInfo GetMethodInfoFromExpression(Expression> expression) { @@ -263,9 +263,33 @@ public GenFuComplexPropertyConfigurator MethodFill(Expression customFiller = new CustomFiller(methodInfo.Name, typeof(T), () => (T2)filler.GetValue(null)); + PropertyFiller customFiller = new CustomFiller(methodInfo.Name, typeof(T), () => (T2)filler.GetValue(null)); _fillerManager.RegisterFiller(customFiller); return new GenFuComplexPropertyConfigurator(_genfu, _fillerManager, methodInfo); } + + /// + /// Configure which property should be ignored while creating new object + /// + /// Property on which needs to be ignored + /// + public GenFuConfigurator Ignore(Expression> expression) + { + MemberInfo memberInfoOfIgnoredProperty; + if (expression.Body is MemberExpression) + { + MemberExpression memberExpression = expression.Body as MemberExpression; + memberInfoOfIgnoredProperty = memberExpression.Member; + } + else + { + UnaryExpression unaryExpression = expression.Body as UnaryExpression; + MemberExpression memberExpression = unaryExpression.Operand as MemberExpression; + memberInfoOfIgnoredProperty = memberExpression.Member; + } + IgnorePropertyCollection.AddPropertyToIgnoreList(memberInfoOfIgnoredProperty); + + return this; + } } } \ No newline at end of file diff --git a/src/GenFu/GenFuFluent.cs b/src/GenFu/GenFuFluent.cs index 5af46bd..1cc8688 100644 --- a/src/GenFu/GenFuFluent.cs +++ b/src/GenFu/GenFuFluent.cs @@ -76,11 +76,13 @@ public static void Reset() defaults.SetSeedPercentage(GenFu.Defaults.SEED_PERCENTAGE); ResourceLoader.PropertyFillers.Clear(); + IgnorePropertyCollection.Reset(); } public static void Reset() { _fillerManager.ResetFillers(); + IgnorePropertyCollection.Reset(); } diff --git a/src/GenFu/IgnorePropertyCollection.cs b/src/GenFu/IgnorePropertyCollection.cs new file mode 100644 index 0000000..467d145 --- /dev/null +++ b/src/GenFu/IgnorePropertyCollection.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; + +namespace GenFu +{ + /// + /// Helps in managing the properties which we should not be initialized while creating new object, + /// Reference types will be null, and value type properties will have default value unless those are nullable + /// + public static class IgnorePropertyCollection + { + private static Dictionary> _propertiesToIgnore; + private static ReaderWriterLockSlim _readWriteLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); + static IgnorePropertyCollection() + { + _propertiesToIgnore = new Dictionary>(); + } + + /// + /// Property which will be ignored for initialization during new object creation + /// + /// Property to be ignored + public static void AddPropertyToIgnoreList(MemberInfo memberInfo) + { + try + { + _readWriteLock.EnterWriteLock(); + if (!_propertiesToIgnore.ContainsKey(memberInfo.DeclaringType)) + { + var fieldCollection = new List + { + memberInfo.Name + }; + _propertiesToIgnore.Add(memberInfo.DeclaringType, fieldCollection); + } + else + { + if (!_propertiesToIgnore[memberInfo.DeclaringType].Contains(memberInfo.Name)) + _propertiesToIgnore[memberInfo.DeclaringType].Add(memberInfo.Name); + } + } + finally + { + _readWriteLock.ExitWriteLock(); + } + } + + /// + /// Checks whether given needs to be ignored or not + /// + /// + /// + public static bool IsPropertyInIgnoreList(PropertyInfo propertyInfo) + { + try + { + _readWriteLock.EnterReadLock(); + if (!_propertiesToIgnore.ContainsKey(propertyInfo.DeclaringType)) + return false; + + List fieldCollection = _propertiesToIgnore[propertyInfo.DeclaringType]; + return fieldCollection.Contains(propertyInfo.Name); + } + finally + { + _readWriteLock.ExitReadLock(); + } + } + + /// + /// Removes all the properties from Ignore list of all Type + /// + public static void Reset() + { + try + { + _readWriteLock.EnterWriteLock(); + _propertiesToIgnore = new Dictionary>(); + } + finally + { + _readWriteLock.ExitWriteLock(); + } + } + + /// + /// Removes all the properties from Ignore list of the given Type + /// + /// + public static void Reset() + { + try + { + _readWriteLock.EnterWriteLock(); + if (_propertiesToIgnore.ContainsKey(typeof(T))) + { + _propertiesToIgnore.Remove(typeof(T)); + } + } + finally + { + _readWriteLock.ExitWriteLock(); + } + } + } +} diff --git a/tests/GenFu.Tests/IgnorePropertyTests.cs b/tests/GenFu.Tests/IgnorePropertyTests.cs new file mode 100644 index 0000000..3d6dc0e --- /dev/null +++ b/tests/GenFu.Tests/IgnorePropertyTests.cs @@ -0,0 +1,136 @@ +using GenFu.Tests.TestEntities; +using System.Collections.Generic; +using Xunit; + +namespace GenFu.Tests +{ + public class IgnorePropertyTests + { + [Fact] + public void IgnoreStringField() + { + A.Reset(); + A.Configure() + .Ignore(x => x.FirstName); + + var person = A.New(); + Assert.Null(person.FirstName); + } + + [Fact] + public void IgnoreIntField() + { + A.Reset(); + A.Configure() + .Ignore(x => x.Id); + + var person = A.New(); + Assert.Equal(default, person.Id); + } + + [Fact] + public void IgnoreDateTimeField() + { + A.Reset(); + A.Configure() + .Ignore(x => x.BirthDate) + .Ignore(x => x.DateOfDeath); + + var person = A.New(); + Assert.Null(person.DateOfDeath); + Assert.Equal(default, person.BirthDate); + } + + [Fact] + public void IgnoreGuidField() + { + A.Reset(); + A.Configure() + .Ignore(x => x.Id); + + var applicationUser = A.New(); + Assert.Equal(default, applicationUser.Id); + } + + [Fact] + public void IgnoreNullableFields() + { + A.Reset(); + A.Configure() + .Ignore(x => x.NullableBoolean) + .Ignore(x => x.NullableChar) + .Ignore(x => x.NullableDateTime) + .Ignore(x => x.NullableDecimal) + .Ignore(x => x.NullableDouble) + .Ignore(x => x.NullableInt) + .Ignore(x => x.NullableLong) + .Ignore(x => x.NullableShort) + .Ignore(x => x.NullableUInt) + .Ignore(x => x.NullableULong); + + var nullableObject = A.New(); + + Assert.Null(nullableObject.NullableBoolean); + Assert.Null(nullableObject.NullableChar); + Assert.Null(nullableObject.NullableDateTime); + Assert.Null(nullableObject.NullableDecimal); + Assert.Null(nullableObject.NullableDouble); + Assert.Null(nullableObject.NullableInt); + Assert.Null(nullableObject.NullableLong); + Assert.Null(nullableObject.NullableShort); + Assert.Null(nullableObject.NullableUInt); + Assert.Null(nullableObject.NullableULong); + } + + [Fact] + public void IgnoreEnumField() + { + A.Reset(); + A.Configure() + .Ignore(x => x.Type); + + var blogPost = A.New(); + Assert.Equal(default, blogPost.Type); + } + + [Fact] + public void IgnoreConstructorInitializedCollectionField() + { + A.Reset(); + A.Configure() + .Ignore(x => x.Tags); + + var blogPost = A.New(); + Assert.Equal(new HashSet(), blogPost.Tags); + } + + [Fact] + public void IgnoreUnInitializedCollectionField() + { + A.Reset(); + var postcomments = A.ListOf(); + + A.Configure() + .Fill(b => b.Comments, () => postcomments) + .Ignore(x => x.Comments); + var blogPost = A.New(); + + Assert.Equal(default, blogPost.Comments); + } + + [Fact] + public void IgnoreMultipleFields() + { + A.Reset(); + A.Configure() + .Ignore(x=>x.NumberOfToes) + .Ignore(x => x.LastName) + .Ignore(x => x.FirstName); + + var person = A.New(); + Assert.Equal(default, person.NumberOfToes); + Assert.Null(person.LastName); + Assert.Null(person.FirstName); + } + } +} diff --git a/tests/GenFu.Tests/IgnorePropertyWithResetTests.cs b/tests/GenFu.Tests/IgnorePropertyWithResetTests.cs new file mode 100644 index 0000000..dd73aaa --- /dev/null +++ b/tests/GenFu.Tests/IgnorePropertyWithResetTests.cs @@ -0,0 +1,52 @@ +using GenFu.Tests.TestEntities; +using Xunit; + +namespace GenFu.Tests +{ + public class IgnorePropertyWithResetTests + { + public IgnorePropertyWithResetTests() + { + A.Configure() + .Ignore(x => x.FirstName); + } + [Fact] + public void WhenResetNotCalled() + { + var person = A.New(); + Assert.Null(person.FirstName); + } + + [Fact] + public void WhenResetPersonCalled() + { + A.Reset(); + var person = A.New(); + Assert.NotNull(person.FirstName); + } + + [Fact] + public void WhenResetCalled() + { + A.Reset(); + var person = A.New(); + Assert.NotNull(person.FirstName); + } + + [Fact] + public void WhenResetCalledForOneType() + { + A.Configure() + .Ignore(x => x.UserName); + + //It will only reset the ignore properties of Person decalred in constructor + A.Reset(); + + var person = A.New(); + var applicationUser = A.New(); + + Assert.NotNull(person.FirstName); + Assert.Null(applicationUser.UserName); + } + } +}