/
GivenSelector.cs
141 lines (127 loc) · 7.18 KB
/
GivenSelector.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
using System;
using System.Linq;
namespace FluentAssertions.Execution
{
/// <summary>
/// Represents a chaining object returned from <see cref="AssertionScope.Given{T}"/> to continue the assertion using
/// an object returned by a selector.
/// </summary>
public class GivenSelector<T>
{
#region Private Definitions
private readonly T subject;
private readonly bool evaluateCondition;
private readonly AssertionScope parentScope;
#endregion
public GivenSelector(Func<T> selector, bool evaluateCondition, AssertionScope parentScope)
{
this.evaluateCondition = evaluateCondition;
this.parentScope = parentScope;
subject = evaluateCondition ? selector() : default(T);
}
/// <summary>
/// Specify the condition that must be satisfied upon the subject selected through a prior selector.
/// </summary>
/// <param name="predicate">
/// If <c>true</c> the assertion will be treated as successful and no exceptions will be thrown.
/// </param>
/// <remarks>
/// The condition will not be evaluated if the prior assertion failed,
/// nor will <see cref="FailWith(string, System.Func{T, object}[])"/> throw any exceptions.
/// </remarks>
public GivenSelector<T> ForCondition(Func<T, bool> predicate)
{
if (evaluateCondition)
{
parentScope.ForCondition(predicate(subject));
}
return this;
}
/// <summary>
/// Allows to safely refine the subject for successive assertions, even when the prior assertion has failed.
/// </summary>
/// <paramref name="selector">
/// Selector which result is passed to successive calls to <see cref="ForCondition"/>.
/// </paramref>
/// <remarks>
/// The selector will not be invoked if the prior assertion failed,
/// nor will <see cref="FailWith(string,System.Func{T,object}[])"/> throw any exceptions.
/// </remarks>
public GivenSelector<TOut> Given<TOut>(Func<T, TOut> selector)
{
return new GivenSelector<TOut>(() => selector(subject), evaluateCondition, parentScope);
}
/// <summary>
/// Sets the failure message when the assertion is not met, or completes the failure message set to a
/// prior call to <see cref="FluentAssertions.Execution.AssertionScope.WithExpectation"/>.
/// </summary>
/// <remarks>
/// If an expectation was set through a prior call to <see cref="FluentAssertions.Execution.AssertionScope.WithExpectation"/>,
/// then the failure message is appended to that expectation.
/// </remarks>
/// <param name="message">The format string that represents the failure message.</param>
public ContinuationOfGiven<T> FailWith(string message)
{
return FailWith(message, new object[0]);
}
/// <summary>
/// Sets the failure message when the assertion is not met, or completes the failure message set to a
/// prior call to <see cref="FluentAssertions.Execution.AssertionScope.WithExpectation"/>.
/// </summary>
/// <remarks>
/// In addition to the numbered <see cref="string.Format(string,object[])"/>-style placeholders, messages may contain a few
/// specialized placeholders as well. For instance, {reason} will be replaced with the reason of the assertion as passed
/// to <see cref="FluentAssertions.Execution.AssertionScope.BecauseOf"/>. Other named placeholders will be replaced with
/// the <see cref="FluentAssertions.Execution.AssertionScope.Current"/> scope data passed through
/// <see cref="FluentAssertions.Execution.AssertionScope.AddNonReportable"/> and
/// <see cref="FluentAssertions.Execution.AssertionScope.AddReportable"/>. Finally, a description of the current subject
/// can be passed through the {context:description} placeholder. This is used in the message if no explicit context
/// is specified through the <see cref="AssertionScope"/> constructor.
/// Note that only 10 <paramref name="args"/> are supported in combination with a {reason}.
/// If an expectation was set through a prior call to <see cref="FluentAssertions.Execution.AssertionScope.WithExpectation"/>,
/// then the failure message is appended to that expectation.
/// </remarks>
/// <param name="message">The format string that represents the failure message.</param>
/// <param name="args">Optional arguments to any numbered placeholders.</param>
public ContinuationOfGiven<T> FailWith(string message, params Func<T, object>[] args)
{
object[] mappedArguments = args.Select(a => a(subject)).ToArray();
return FailWith(message, mappedArguments);
}
/// <summary>
/// Sets the failure message when the assertion is not met, or completes the failure message set to a
/// prior call to <see cref="FluentAssertions.Execution.AssertionScope.WithExpectation"/>.
/// </summary>
/// <remarks>
/// In addition to the numbered <see cref="string.Format(string, object[])"/>-style placeholders, messages may contain
/// a few specialized placeholders as well. For instance, {reason} will be replaced with the reason of the assertion as
/// passed to <see cref="FluentAssertions.Execution.AssertionScope.BecauseOf"/>. Other named placeholders will be
/// replaced with the <see cref="FluentAssertions.Execution.AssertionScope.Current"/> scope data passed through
/// <see cref="FluentAssertions.Execution.AssertionScope.AddNonReportable"/> and
/// <see cref="FluentAssertions.Execution.AssertionScope.AddReportable"/>. Finally, a description of the
/// current subject can be passed through the {context:description} placeholder. This is used in the message if no
/// explicit context is specified through the <see cref="AssertionScope"/> constructor.
/// Note that only 10 <paramref name="args"/> are supported in combination with a {reason}.
/// If an expectation was set through a prior call to
/// <see cref="FluentAssertions.Execution.AssertionScope.WithExpectation"/>, then the failure message is appended
/// to that expectation.
/// </remarks>
/// <param name="message">The format string that represents the failure message.</param>
/// <param name="args">Optional arguments to any numbered placeholders.</param>
public ContinuationOfGiven<T> FailWith(string message, params object[] args)
{
bool succeeded = parentScope.Succeeded;
if (evaluateCondition)
{
Continuation continuation = parentScope.FailWith(message, args);
succeeded = continuation.SourceSucceeded;
}
return new ContinuationOfGiven<T>(this, succeeded);
}
public ContinuationOfGiven<T> ClearExpectation()
{
parentScope.ClearExpectation();
return new ContinuationOfGiven<T>(this, parentScope.Succeeded);
}
}
}