Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Merge branch 'array-support'

  • Loading branch information...
commit a889791a6a5ad8259920e9b92698f27a3be46883 2 parents 99ad992 + 18f805e
Aaron Stannard authored
1  Faker.Tests/Faker.Tests.csproj
@@ -57,6 +57,7 @@
57 57 <Compile Include="GeneratorTests\NameGeneratorTests.cs" />
58 58 <Compile Include="GeneratorTests\NumberGeneratorTests.cs" />
59 59 <Compile Include="GeneratorTests\StringsGeneratorTests.cs" />
  60 + <Compile Include="MatcherTests\ListMatcherTests.cs" />
60 61 <Compile Include="MatcherTests\NestedPocoMatcherTests.cs" />
61 62 <Compile Include="MatcherTests\SimplePocoMatcherTests.cs" />
62 63 <Compile Include="Properties\AssemblyInfo.cs" />
110 Faker.Tests/MatcherTests/ListMatcherTests.cs
... ... @@ -0,0 +1,110 @@
  1 +using System;
  2 +using System.Collections.Generic;
  3 +using System.Linq;
  4 +using System.Text;
  5 +using System.Text.RegularExpressions;
  6 +using NUnit.Framework;
  7 +
  8 +namespace Faker.Tests.MatcherTests
  9 +{
  10 + [TestFixture(Description = "Tests for validating that our matcher is able to ")]
  11 + public class ListMatcherTests
  12 + {
  13 + public const string ValidEmailRegex = @"(\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b)";
  14 +
  15 + public Regex _valid_email_regex = new Regex(ValidEmailRegex, RegexOptions.IgnoreCase);
  16 +
  17 + private Matcher _matcher;
  18 +
  19 + #region List test classes
  20 +
  21 + public class SpecialFieldsTestClass
  22 + {
  23 + public int UserID { get; set; }
  24 + public string Name { get; set; }
  25 + public string Email { get; set; }
  26 + public long Timestamp { get; set; }
  27 + public DateTime DateRegistered { get; set; }
  28 + }
  29 +
  30 + public class SimpleListClass
  31 + {
  32 + public List<string> strings { get; set; }
  33 + public List<DateTime> dates { get; set; }
  34 + }
  35 +
  36 + public class PocoListsClass
  37 + {
  38 + public List<SpecialFieldsTestClass> Users { get; set; }
  39 + }
  40 +
  41 + #endregion
  42 +
  43 + #region Setup / Teardown
  44 +
  45 + [SetUp]
  46 + public void SetUp()
  47 + {
  48 + _matcher = new Matcher();
  49 + }
  50 +
  51 + #endregion
  52 +
  53 + #region Tests
  54 +
  55 + [Test(Description = "Should be able to inject and inject values for lists of primitive elements, even with the lists currently set to null")]
  56 + public void Should_Bind_Primitive_Lists_With_Uninstantiated_Target_Objects()
  57 + {
  58 + var simpleListClass = new SimpleListClass();
  59 +
  60 + _matcher.Match(simpleListClass);
  61 +
  62 + Assert.IsNotNull(simpleListClass.dates);
  63 + Assert.IsNotNull(simpleListClass.strings);
  64 + Assert.IsTrue(simpleListClass.dates.Count > 0);
  65 + Assert.IsTrue(simpleListClass.strings.Count > 0);
  66 + Assert.IsTrue(simpleListClass.dates.All(x => x != default(DateTime)));
  67 + Assert.IsTrue(simpleListClass.strings.All(x => x != default(string)));
  68 + }
  69 +
  70 + [Test(Description = "Should be able to inject and inject values for lists of primitive elements, even with the lists currently set to null")]
  71 + public void Should_Bind_Primitive_Lists_With_Instantiated_Target_Objects()
  72 + {
  73 + var simpleListClass = new SimpleListClass {dates = new List<DateTime>(), strings = new List<string>()};
  74 +
  75 + _matcher.Match(simpleListClass);
  76 +
  77 + Assert.IsNotNull(simpleListClass.dates);
  78 + Assert.IsNotNull(simpleListClass.strings);
  79 + Assert.IsTrue(simpleListClass.dates.Count > 0);
  80 + Assert.IsTrue(simpleListClass.strings.Count > 0);
  81 + Assert.IsTrue(simpleListClass.dates.All(x => x != default(DateTime)));
  82 + Assert.IsTrue(simpleListClass.strings.All(x => x != default(string)));
  83 + }
  84 +
  85 + [Test(Description = "Should be able to inject and map values for lists that contain other POCO objects")]
  86 + public void Should_Bind_Lists_With_Poco_Objects()
  87 + {
  88 + var richListClass = new PocoListsClass();
  89 +
  90 + _matcher.Match(richListClass);
  91 +
  92 + Assert.IsNotNull(richListClass.Users);
  93 + Assert.IsTrue(richListClass.Users.Count > 0);
  94 +
  95 + foreach(var user in richListClass.Users)
  96 + {
  97 + /* Assert to see that we have populated all of the fields on our test instance */
  98 + Assert.AreNotEqual(user.UserID, default(int));
  99 + Assert.AreNotEqual(user.Timestamp, default(long));
  100 + Assert.AreNotEqual(user.DateRegistered, default(DateTime));
  101 +
  102 + Assert.IsNotNullOrEmpty(user.Name);
  103 + Assert.IsNotNullOrEmpty(user.Email);
  104 + Assert.IsTrue(_valid_email_regex.IsMatch(user.Email));
  105 + }
  106 + }
  107 +
  108 + #endregion
  109 + }
  110 +}
28 Faker/Fake.cs
@@ -12,11 +12,14 @@ namespace Faker
12 12 /// </summary>
13 13 public class Fake<T> where T : new()
14 14 {
15   - private IList<ITypeSelector> _selectors;
  15 + /// <summary>
  16 + /// Engine used to power our fakes
  17 + /// </summary>
  18 + private readonly Matcher _matcher;
16 19
17 20 public Fake()
18 21 {
19   - _selectors = new List<ITypeSelector>();
  22 + _matcher = new Matcher();
20 23 }
21 24
22 25 /// <summary>
@@ -25,7 +28,14 @@ public Fake()
25 28 /// <returns>A populated instance of a given class</returns>
26 29 T Generate()
27 30 {
28   - throw new NotImplementedException();
  31 + //create a new instance of the type we want to Fake
  32 + var instance = (T)Matcher.SafeObjectCreate(typeof(T));
  33 +
  34 + //Match all of the properties of the object and come up with the most reasonable guess we can as to the type of data needed
  35 + _matcher.Match(instance);
  36 +
  37 + //Return the instance once matching is complete
  38 + return instance;
29 39 }
30 40
31 41 /// <summary>
@@ -34,7 +44,17 @@ T Generate()
34 44 /// <returns>A list of populated instances with length [count] of a given class</returns>
35 45 IList<T> Generate(int count)
36 46 {
37   - throw new NotImplementedException();
  47 + //Create a list to hold all of the fakes we want to return back to the caller
  48 + var items = new List<T>();
  49 +
  50 + //Build the list of objects
  51 + for(var i = 0; i < count; i++)
  52 + {
  53 + items.Add(this.Generate());
  54 + }
  55 +
  56 + //Return the list to the caller
  57 + return items;
38 58 }
39 59 }
40 60 }
78 Faker/Matcher.cs
@@ -20,7 +20,7 @@ public class Matcher
20 20 /// <summary>
21 21 /// Default constructor - uses the default TypeTable
22 22 /// </summary>
23   - public Matcher():this(new TypeTable()){}
  23 + public Matcher() : this(new TypeTable()) { }
24 24
25 25 /// <summary>
26 26 /// Constructor which accepts a TypeTable as an argument
@@ -39,7 +39,7 @@ public Matcher(TypeTable table)
39 39 public virtual void Match<T>(T targetObject) where T : new()
40 40 {
41 41 //Get all of the properties of the class
42   - var properties = typeof (T).GetProperties();
  42 + var properties = typeof(T).GetProperties();
43 43
44 44 ProcessProperties(properties, targetObject);
45 45 }
@@ -75,13 +75,13 @@ protected virtual void ProcessProperty(PropertyInfo property, object targetObjec
75 75 var selectorCount = TypeMap.CountSelectors(propertyType);
76 76
77 77 //We have some matching selectors, so we'll evaluate and return the best match
78   - if(selectorCount > 0)
  78 + if (selectorCount > 0)
79 79 {
80 80 //Evaluate all of the possible selectors and find the first available match
81 81 var selector = EvaluateSelectors(property, TypeMap.GetSelectors(propertyType));
82 82
83 83 //We found a matching selector
84   - if(!(selector is MissingSelector))
  84 + if (!(selector is MissingSelector))
85 85 {
86 86 selector.Generate(targetObject, property); //Bind the property
87 87 return; //Exit
@@ -89,7 +89,7 @@ protected virtual void ProcessProperty(PropertyInfo property, object targetObjec
89 89 }
90 90
91 91 //Check to see if the type is a class and has a default constructor
92   - if (propertyType.IsClass && propertyType.GetConstructor(Type.EmptyTypes) != null)
  92 + if (propertyType.IsClass && propertyType.GetConstructor(Type.EmptyTypes) != null && !IsArray(propertyType))
93 93 {
94 94 var subProperties = propertyType.GetProperties();
95 95
@@ -106,51 +106,51 @@ protected virtual void ProcessProperty(PropertyInfo property, object targetObjec
106 106 }
107 107
108 108 //Check to see if the type is an array or any other sort of collection
109   - if(typeof(IList).IsAssignableFrom(propertyType))
  109 + if (IsArray(propertyType))
110 110 {
111 111 //Get the underlying type used int he array
112   - var elementType = propertyType.GetElementType();
  112 + //var elementType = propertyType.GetElementType(); //Works only for arrays
  113 + var elementType = propertyType.GetGenericArguments()[0]; //Works for IList<T> / IEnumerable<T>
113 114
114 115 //Get a number of elements we want to create
115   - //Note: (between 0 and 10 for now)
116   - var elementCount = Numbers.Int(0, 10);
117   -
  116 + //Note: (between 1 and 10 for now)
  117 + var elementCount = Numbers.Int(1, 10);
  118 +
118 119 //Create an instance of our target array
119 120 IList arrayInstance = null;
120 121
121 122 //If we're working with a generic list or any other sort of collection
122   - if(propertyType.IsGenericType)
  123 + if (propertyType.IsGenericTypeDefinition)
123 124 {
124 125 arrayInstance = (IList)GenericHelper.CreateGeneric(propertyType, elementType);
125 126 }
126 127 else
127 128 {
128   - arrayInstance = (IList) GenericHelper.CreateGeneric(typeof (List<>), elementType);
  129 + arrayInstance = (IList)GenericHelper.CreateGeneric(typeof(List<>), elementType);
129 130 }
130 131
131 132 //Determine if there's a selector available for this type
132 133 var hasSelector = TypeMap.CountSelectors(elementType) > 0;
133 134 ITypeSelector selector = null;
134 135
135   - if(hasSelector)
  136 + //So we have a type available for this selector..
  137 + if (hasSelector)
136 138 {
137   - //selector = EvaluateSelectors(ele)
  139 + selector = TypeMap.GetBaseSelector(elementType);
138 140 }
139 141
140   - for(var i =0; i < elementCount; i++)
  142 + for (var i = 0; i < elementCount; i++)
141 143 {
142 144 //Create a new element instance
143   - var element = Activator.CreateInstance(elementType);
  145 + var element = SafeObjectCreate(elementType);
144 146
145   - if(hasSelector)
  147 + if (hasSelector)
146 148 {
147   -
  149 + selector.Generate(ref element);
148 150 }
149   -
150   - //If the element type is a sub-class, then populate it recursively
151   - if(elementType.IsClass)
  151 + else if (elementType.IsClass) //If the element type is a sub-class, then populate it recursively
152 152 {
153   - var subProperties = propertyType.GetProperties();
  153 + var subProperties = elementType.GetProperties();
154 154
155 155 //Populate all of the properties on this object
156 156 ProcessProperties(subProperties, element);
@@ -158,8 +158,38 @@ protected virtual void ProcessProperty(PropertyInfo property, object targetObjec
158 158
159 159 arrayInstance.Add(element);
160 160 }
  161 +
  162 + //Bind the sub-class back onto the original target object
  163 + property.SetValue(targetObject, arrayInstance, null);
  164 + }
  165 +
  166 + }
  167 +
  168 + /// <summary>
  169 + /// Returns true if the targeted type is an array of some sort
  170 + /// </summary>
  171 + /// <param name="targetType">the type we want to test</param>
  172 + /// <returns>true if it's an array, false otherwise</returns>
  173 + protected virtual bool IsArray(Type targetType)
  174 + {
  175 + return typeof(IList).IsAssignableFrom(targetType);
  176 + }
  177 +
  178 + /// <summary>
  179 + /// Method used for safely creating new instances of type objects; handles a few special cases
  180 + /// where activation has to be done carefully.
  181 + /// </summary>
  182 + /// <param name="t">The target type we want to instantiate</param>
  183 + /// <returns>an instance of the specified type</returns>
  184 + public static object SafeObjectCreate(Type t)
  185 + {
  186 + //If the object is a string (tricky)
  187 + if (t == typeof(string))
  188 + {
  189 + return string.Empty;
161 190 }
162 191
  192 + return Activator.CreateInstance(t);
163 193 }
164 194
165 195 /// <summary>
@@ -170,10 +200,10 @@ protected virtual void ProcessProperty(PropertyInfo property, object targetObjec
170 200 /// <returns>the first matching ITypeSelector instance we could find</returns>
171 201 protected virtual ITypeSelector EvaluateSelectors(PropertyInfo propertyType, IEnumerable<ITypeSelector> selectors)
172 202 {
173   - foreach(var selector in selectors)
  203 + foreach (var selector in selectors)
174 204 {
175 205 //If the selector can bind
176   - if(selector.CanBind(propertyType))
  206 + if (selector.CanBind(propertyType))
177 207 {
178 208 //Return it
179 209 return selector;

0 comments on commit a889791

Please sign in to comment.
Something went wrong with that request. Please try again.