Skip to content

Commit 053d5b5

Browse files
committed
Merge pull request #30 from Tynamix/ENHANCE_ThrowOnCircularRef
Setup Allows now to specify if an exception will be thrown on circular d...
2 parents 045d8de + 63c7c67 commit 053d5b5

File tree

7 files changed

+109
-11
lines changed

7 files changed

+109
-11
lines changed

ObjectFiller.Test/ObjectFillerRecursiveTests.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ private class TestDuplicate
5050
public void RecursiveFill_RecursiveType_ThrowsException()
5151
{
5252
var filler = new Filler<TestParent>();
53+
filler.Setup().OnCircularReference().ThrowException();
5354
filler.Create();
5455
}
5556

@@ -78,6 +79,7 @@ public void RecursiveFill_WithFunc_Succeeds()
7879
public void RecursiveFill_RecursiveType_Parent_First_Fails()
7980
{
8081
var filler = new Filler<TestParent>();
82+
filler.Setup().OnCircularReference().ThrowException();
8183
filler.Create();
8284
}
8385

@@ -86,6 +88,7 @@ public void RecursiveFill_RecursiveType_Parent_First_Fails()
8688
public void RecursiveFill_RecursiveType_Child_First_Fails()
8789
{
8890
var filler = new Filler<TestChild>();
91+
filler.Setup().OnCircularReference().ThrowException();
8992
filler.Create();
9093
}
9194

@@ -94,14 +97,17 @@ public void RecursiveFill_RecursiveType_Child_First_Fails()
9497
public void RecursiveFill_DeepRecursiveType_Fails()
9598
{
9699
var filler = new Filler<TestGrandParent>();
100+
filler.Setup().OnCircularReference().ThrowException();
97101
filler.Create();
102+
98103
}
99104

100105
[TestMethod]
101106
[ExpectedException(typeof(InvalidOperationException))]
102107
public void RecursiveFill_SelfReferencing_Fails()
103108
{
104109
var filler = new Filler<TestSelf>();
110+
filler.Setup().OnCircularReference().ThrowException();
105111
filler.Create();
106112
}
107113

@@ -115,5 +121,39 @@ public void RecursiveFill_DuplicateProperty_Succeeds()
115121

116122
Assert.IsNotNull(result);
117123
}
124+
125+
[TestMethod]
126+
public void RecursiveFill_RecursiveType_Parent_First_Succeeds()
127+
{
128+
var filler = new Filler<TestParent>();
129+
var r = filler.Create();
130+
Assert.IsNull(r.Child.Parent.Child);
131+
}
132+
133+
[TestMethod]
134+
public void RecursiveFill_RecursiveType_Child_First_Succeeds()
135+
{
136+
var filler = new Filler<TestChild>();
137+
var r = filler.Create();
138+
Assert.IsNull(r.Parent.Child.Parent);
139+
140+
}
141+
142+
[TestMethod]
143+
public void RecursiveFill_DeepRecursiveType_Succeeds()
144+
{
145+
var filler = new Filler<TestGrandParent>();
146+
var r = filler.Create();
147+
Assert.IsNull(r.SubObject.Child.Parent);
148+
}
149+
150+
[TestMethod]
151+
public void RecursiveFill_SelfReferencing_Succeeds()
152+
{
153+
var filler = new Filler<TestSelf>();
154+
var r = filler.Create();
155+
156+
Assert.IsNull(r.Self.Self);
157+
}
118158
}
119159
}

ObjectFiller/Filler.cs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -290,10 +290,15 @@ private object GetFilledPoco(Type type, FillerSetupItem currentSetupItem, HashSt
290290
{
291291
if (typeTracker.Contains(type))
292292
{
293-
throw new InvalidOperationException(
294-
string.Format(
295-
"The type {0} was already encountered before, which probably means you have a circular reference in your model. Either ignore the properties which cause this or specify explicit creation rules for them which do not rely on types.",
296-
type.Name));
293+
if (currentSetupItem.ThrowExceptionOnCircularReference)
294+
{
295+
throw new InvalidOperationException(
296+
string.Format(
297+
"The type {0} was already encountered before, which probably means you have a circular reference in your model. Either ignore the properties which cause this or specify explicit creation rules for them which do not rely on types.",
298+
type.Name));
299+
}
300+
301+
return GetDefaultValueOfType(type);
297302
}
298303

299304
typeTracker.Push(type);
@@ -413,18 +418,23 @@ private object GetRandomValue(Type propertyType, FillerSetupItem setupItem)
413418

414419
if (setupItem.IgnoreAllUnknownTypes)
415420
{
416-
if (propertyType.IsValueType)
417-
{
418-
return Activator.CreateInstance(propertyType);
419-
}
420-
return null;
421+
return GetDefaultValueOfType(propertyType);
421422
}
422423

423424
string message = "The type [" + propertyType.Name + "] was not registered in the randomizer.";
424425
Debug.WriteLine("ObjectFiller: " + message);
425426
throw new TypeInitializationException(propertyType.FullName, new Exception(message));
426427
}
427428

429+
private static object GetDefaultValueOfType(Type propertyType)
430+
{
431+
if (propertyType.IsValueType)
432+
{
433+
return Activator.CreateInstance(propertyType);
434+
}
435+
return null;
436+
}
437+
428438
private static bool TypeIsValidForObjectFiller(Type type, FillerSetupItem currentSetupItem)
429439
{
430440
return HasTypeARandomFunc(type, currentSetupItem)

ObjectFiller/ObjectFiller.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
<Compile Include="Plugins\String\Lipsum.cs" />
4040
<Compile Include="HashStack.cs" />
4141
<Compile Include="Setup\FillerSetup.cs" />
42+
<Compile Include="Setup\FluentCircularApi.cs" />
4243
<Compile Include="Setup\FluentFillerApi.cs" />
4344
<Compile Include="Setup\FluentPropertyApi.cs" />
4445
<Compile Include="Setup\FluentTypeApi.cs" />

ObjectFiller/Setup/FillerSetupItem.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,5 +105,10 @@ private void SetDefaultRandomizer()
105105
/// </summary>
106106
internal bool IgnoreAllUnknownTypes { get; set; }
107107

108+
/// <summary>
109+
/// True if an exception will be thrown if an circular reference occured
110+
/// </summary>
111+
public bool ThrowExceptionOnCircularReference { get; set; }
112+
108113
}
109114
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
6+
namespace Tynamix.ObjectFiller.Setup
7+
{
8+
public class FluentCircularApi<TTargetObject> where TTargetObject : class
9+
{
10+
private readonly FluentFillerApi<TTargetObject> _callback;
11+
private readonly SetupManager _setupManager;
12+
13+
internal FluentCircularApi(FluentFillerApi<TTargetObject> callback, SetupManager setupManager)
14+
{
15+
_callback = callback;
16+
_setupManager = setupManager;
17+
}
18+
19+
/// <summary>
20+
/// Call this when you want to get an exception in case of a circular reference in your filled model.
21+
/// By default the ObjectFiller recognizes circular references and stop filling them without throwing an exception.
22+
/// When you want to get an explicit exception on circular refernce call this method!
23+
/// </summary>
24+
/// <param name="throwException">True (default) when you want to get exception on a circular reference</param>
25+
public FluentFillerApi<TTargetObject> ThrowException(bool throwException = true)
26+
{
27+
_setupManager.GetFor<TTargetObject>().ThrowExceptionOnCircularReference = throwException;
28+
29+
return _callback;
30+
}
31+
}
32+
}

ObjectFiller/Setup/FluentFillerApi.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Diagnostics;
44
using System.Linq.Expressions;
55
using System.Reflection;
6+
using Tynamix.ObjectFiller.Setup;
67

78
namespace Tynamix.ObjectFiller
89
{
@@ -34,6 +35,15 @@ public FluentTypeApi<TTargetObject, TTargetType> OnType<TTargetType>()
3435
return new FluentTypeApi<TTargetObject, TTargetType>(this, _setupManager);
3536
}
3637

38+
39+
/// <summary>
40+
/// Starts to configure the behaviour of the ObjectFiller when a circular reference in your model occurs
41+
/// </summary>
42+
public FluentCircularApi<TTargetObject> OnCircularReference()
43+
{
44+
return new FluentCircularApi<TTargetObject>(this, _setupManager);
45+
}
46+
3747
/// <summary>
3848
/// Starts to configure a property of the <see cref="TTargetObject"/> for objectfiller.
3949
/// So you can setup a custom randomizer to a specific property within a class.
@@ -159,5 +169,6 @@ public FluentFillerApi<TNewType> SetupFor<TNewType>(bool useDefaultSettings = fa
159169
return new FluentFillerApi<TNewType>(_setupManager);
160170
}
161171

172+
162173
}
163174
}

ObjectFiller/Setup/SetupManager.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ namespace Tynamix.ObjectFiller
77
/// Responsible to get the right <see cref="FillerSetupItem"/> for a given type.
88
/// </summary>
99
internal class SetupManager
10-
{
11-
10+
{
1211
internal FillerSetup FillerSetup { get; set; }
1312

1413
/// <summary>

0 commit comments

Comments
 (0)