Skip to content

Commit 69f24e8

Browse files
authored
Merge pull request #75 from rsdn/fluent-assertions
[WIP] Fluent assertions
2 parents 482ee36 + 4af3f5f commit 69f24e8

File tree

8 files changed

+267
-10
lines changed

8 files changed

+267
-10
lines changed

Build/Props/CodeJam.Default.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<AssemblyOriginatorKeyFile>..\Build\CodeJam.snk</AssemblyOriginatorKeyFile>
1111

1212
<Version>2.2.0.0</Version>
13-
<PackageVersion>2.2.0-beta1</PackageVersion>
13+
<PackageVersion>2.2.0-beta2</PackageVersion>
1414
<PackageOutputPath>..\_Results</PackageOutputPath>
1515

1616
<Company>RSDN</Company>

CodeJam.Blocks/Readme.txt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
CodeJam.Blocks 2.1.1 Release Notes
1+
CodeJam.Blocks 2.2.0-beta1 Release Notes
22
----------------------------------
33

4+
What's new in 2.2.0-beta1
5+
-------------------------
6+
* Additional code annotation for ReSharper
7+
48
What's new in 2.1.1
5-
-----------------------
9+
-------------------
610
* Fix package dependencies
711
* Fix version
812

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
namespace CodeJam
2+
{
3+
/// <summary>
4+
/// Builder type for argument assertions.
5+
/// </summary>
6+
public struct ArgumentAssertion<T>
7+
{
8+
/// <summary>
9+
/// Initialize instance.
10+
/// </summary>
11+
/// <param name="arg">Argument value.</param>
12+
/// <param name="argName">Argument name.</param>
13+
public ArgumentAssertion(T arg, string argName)
14+
{
15+
Argument = arg;
16+
ArgumentName = argName;
17+
}
18+
19+
/// <summary>
20+
/// Argument value.
21+
/// </summary>
22+
public T Argument { get; }
23+
24+
/// <summary>
25+
/// Argument name.
26+
/// </summary>
27+
public string ArgumentName { get; }
28+
}
29+
}
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using System.Runtime.CompilerServices;
5+
6+
using JetBrains.Annotations;
7+
8+
using static CodeJam.PlatformDependent;
9+
10+
namespace CodeJam
11+
{
12+
/// <summary>
13+
/// <see cref="ArgumentAssertion{T}"/> extension methods.
14+
/// </summary>
15+
[PublicAPI]
16+
public static class ArgumentAssertionExtensions
17+
{
18+
/// <summary>
19+
/// Ensures that <paramref name="arg"/> != <c>null</c>
20+
/// </summary>
21+
/// <typeparam name="T">Type of the value. Auto-inferred in most cases</typeparam>
22+
/// <param name="arg">The argument.</param>
23+
[DebuggerHidden, MethodImpl(AggressiveInlining)]
24+
[AssertionMethod]
25+
public static ArgumentAssertion<T> NotNull<T>([NoEnumeration] this ArgumentAssertion<T> arg) where T : class
26+
{
27+
Code.NotNull(arg.Argument, arg.ArgumentName);
28+
return arg;
29+
}
30+
31+
/// <summary>
32+
/// Ensures that <paramref name="arg"/> != <c>null</c>
33+
/// </summary>
34+
/// <typeparam name="T">Type of the value. Auto-inferred in most cases</typeparam>
35+
/// <param name="arg">The argument.</param>
36+
[DebuggerHidden, MethodImpl(AggressiveInlining)]
37+
[AssertionMethod]
38+
public static ArgumentAssertion<T?> NotNull<T>([NoEnumeration] this ArgumentAssertion<T?> arg) where T : struct
39+
{
40+
Code.NotNull(arg.Argument, arg.ArgumentName);
41+
return arg;
42+
}
43+
44+
/// <summary>Ensures that all items in <paramref name="arg"/> != <c>null</c></summary>
45+
/// <typeparam name="T">Type of the value. Auto-inferred in most cases</typeparam>
46+
/// <param name="arg">The argument.</param>
47+
[DebuggerHidden, MethodImpl(AggressiveInlining)]
48+
[AssertionMethod]
49+
public static ArgumentAssertion<IEnumerable<T>> ItemNotNull<T>(this ArgumentAssertion<IEnumerable<T>> arg) where T : class
50+
{
51+
Code.ItemNotNull(arg.Argument, arg.ArgumentName);
52+
return arg;
53+
}
54+
55+
/// <summary>
56+
/// Ensures that supplied enumerable is not empty.
57+
/// </summary>
58+
/// <typeparam name="T">Type of item.</typeparam>
59+
/// <param name="arg">The argument.</param>
60+
[DebuggerHidden, MethodImpl(AggressiveInlining)]
61+
[AssertionMethod]
62+
public static ArgumentAssertion<IEnumerable<T>> NotEmpty<T>(this ArgumentAssertion<IEnumerable<T>> arg)
63+
{
64+
Code.NotEmpty(arg.Argument, arg.ArgumentName);
65+
return arg;
66+
}
67+
68+
/// <summary>
69+
/// Ensures that supplied collection is not empty.
70+
/// </summary>
71+
/// <typeparam name="T">Type of item.</typeparam>
72+
/// <param name="arg">The argument.</param>
73+
[DebuggerHidden, MethodImpl(AggressiveInlining)]
74+
[AssertionMethod]
75+
public static ArgumentAssertion<ICollection<T>> NotEmpty<T>(this ArgumentAssertion<ICollection<T>> arg)
76+
{
77+
Code.NotEmpty(arg.Argument, arg.ArgumentName);
78+
return arg;
79+
}
80+
81+
/// <summary>
82+
/// Ensures that supplied array is not empty.
83+
/// </summary>
84+
/// <typeparam name="T">Type of item.</typeparam>
85+
/// <param name="arg">The argument.</param>
86+
[DebuggerHidden, MethodImpl(AggressiveInlining)]
87+
[AssertionMethod]
88+
public static ArgumentAssertion<T[]> NotEmpty<T>(this ArgumentAssertion<T[]> arg)
89+
{
90+
Code.NotEmpty(arg.Argument, arg.ArgumentName);
91+
return arg;
92+
}
93+
94+
/// <summary>Ensures that <paramref name="arg"/> is not null nor empty</summary>
95+
/// <param name="arg">The argument.</param>
96+
[DebuggerHidden, MethodImpl(AggressiveInlining)]
97+
[AssertionMethod]
98+
public static ArgumentAssertion<string> NotNullNorEmpty(this ArgumentAssertion<string> arg)
99+
{
100+
Code.NotNullNorEmpty(arg.Argument, arg.ArgumentName);
101+
return arg;
102+
}
103+
104+
/// <summary>Ensures that <paramref name="arg"/> is not null nor white space</summary>
105+
/// <param name="arg">The argument.</param>
106+
[DebuggerHidden, MethodImpl(AggressiveInlining)]
107+
[AssertionMethod]
108+
public static ArgumentAssertion<string> NotNullNorWhiteSpace(this ArgumentAssertion<string> arg)
109+
{
110+
Code.NotNullNorWhiteSpace(arg.Argument, arg.ArgumentName);
111+
return arg;
112+
}
113+
114+
/// <summary>Assertion for the argument value</summary>
115+
/// <param name="arg">The argument.</param>
116+
/// <param name="condition">The condition to check</param>
117+
/// <param name="message">The message.</param>
118+
[DebuggerHidden, MethodImpl(AggressiveInlining)]
119+
[AssertionMethod]
120+
public static ArgumentAssertion<T> Assert<T>(
121+
this ArgumentAssertion<T> arg,
122+
[AssertionCondition(AssertionConditionType.IS_TRUE)] bool condition,
123+
[NotNull] string message)
124+
{
125+
Code.AssertArgument(condition, arg.ArgumentName, message);
126+
return arg;
127+
}
128+
129+
/// <summary>Assertion for the argument value</summary>
130+
/// <param name="arg">Argument.</param>
131+
/// <param name="condition">The condition to check</param>
132+
/// <param name="messageFormat">The message format.</param>
133+
/// <param name="args">Format string arguments.</param>
134+
[DebuggerHidden, MethodImpl(AggressiveInlining)]
135+
[AssertionMethod, StringFormatMethod("messageFormat")]
136+
public static ArgumentAssertion<T> Assert<T>(
137+
this ArgumentAssertion<T> arg,
138+
[AssertionCondition(AssertionConditionType.IS_TRUE)] bool condition,
139+
[NotNull] string messageFormat,
140+
[CanBeNull] params object[] args)
141+
{
142+
Code.AssertArgument(condition, arg.ArgumentName, messageFormat, args);
143+
return arg;
144+
}
145+
}
146+
}

CodeJam.Main/Assertions/Code.cs

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
using System.Collections.Generic;
1+
 using System.Collections.Generic;
22
using System.Diagnostics;
33
using System.Runtime.CompilerServices;
44

5-
using CodeJam.Arithmetic;
6-
using CodeJam.Strings;
5+
using CodeJam.Arithmetic;
6+
using CodeJam.Strings;
77

88
using JetBrains.Annotations;
99

@@ -74,14 +74,57 @@ public static void NotNull<T>(
7474
throw CodeExceptions.ArgumentNull(argName);
7575
}
7676

77+
/// <summary>
78+
/// Ensures that supplied enumerable is not empty.
79+
/// </summary>
80+
/// <typeparam name="T">Type of item.</typeparam>
81+
/// <param name="arg">Enumerable.</param>
82+
/// <param name="argName">Name of the argument.</param>
83+
[DebuggerHidden, MethodImpl(AggressiveInlining)]
84+
[AssertionMethod]
85+
public static void NotEmpty<T>(IEnumerable<T> arg, [NotNull, InvokerParameterName] string argName)
86+
{
87+
using (var en = arg.GetEnumerator())
88+
if (!en.MoveNext())
89+
throw CodeExceptions.ArgumentEmpty(argName);
90+
}
91+
92+
/// <summary>
93+
/// Ensures that supplied collection is not empty.
94+
/// </summary>
95+
/// <typeparam name="T">Type of item.</typeparam>
96+
/// <param name="arg">Collection.</param>
97+
/// <param name="argName">Name of the argument.</param>
98+
[DebuggerHidden, MethodImpl(AggressiveInlining)]
99+
[AssertionMethod]
100+
public static void NotEmpty<T>(ICollection<T> arg, [NotNull, InvokerParameterName] string argName)
101+
{
102+
if (arg.Count == 0)
103+
throw CodeExceptions.ArgumentEmpty(argName);
104+
}
105+
106+
/// <summary>
107+
/// Ensures that supplied array is not empty.
108+
/// </summary>
109+
/// <typeparam name="T">Type of item.</typeparam>
110+
/// <param name="arg">Array.</param>
111+
/// <param name="argName">Name of the argument.</param>
112+
[DebuggerHidden, MethodImpl(AggressiveInlining)]
113+
[AssertionMethod]
114+
public static void NotEmpty<T>(T[] arg, [NotNull, InvokerParameterName] string argName)
115+
{
116+
if (arg.Length == 0)
117+
throw CodeExceptions.ArgumentEmpty(argName);
118+
}
119+
77120
/// <summary>Ensures that <paramref name="arg"/> is not null nor empty</summary>
78121
/// <param name="arg">The argument.</param>
79122
/// <param name="argName">Name of the argument.</param>
80123
[DebuggerHidden, MethodImpl(AggressiveInlining)]
81124
[AssertionMethod]
82125
[ContractAnnotation("arg:null => stop")]
83126
public static void NotNullNorEmpty(
84-
[CanBeNull] string arg,
127+
[CanBeNull, AssertionCondition(AssertionConditionType.IS_NOT_NULL)] string arg,
85128
[NotNull, InvokerParameterName] string argName)
86129
{
87130
if (string.IsNullOrEmpty(arg))
@@ -93,8 +136,9 @@ public static void NotNullNorEmpty(
93136
/// <param name="argName">Name of the argument.</param>
94137
[DebuggerHidden, MethodImpl(AggressiveInlining)]
95138
[AssertionMethod]
139+
[ContractAnnotation("arg:null => stop")]
96140
public static void NotNullNorWhiteSpace(
97-
[CanBeNull] string arg,
141+
[CanBeNull, AssertionCondition(AssertionConditionType.IS_NOT_NULL)] string arg,
98142
[NotNull, InvokerParameterName] string argName)
99143
{
100144
if (arg.IsNullOrWhiteSpace())
@@ -132,6 +176,18 @@ public static void AssertArgument(
132176
if (!condition)
133177
throw CodeExceptions.Argument(argName, messageFormat, args);
134178
}
179+
180+
/// <summary>
181+
/// Creates <see cref="ArgumentAssertion{T}"/> for fluent assertions.
182+
/// </summary>
183+
/// <typeparam name="T">Type of argument</typeparam>
184+
/// <param name="arg">Argument value.</param>
185+
/// <param name="argName">Argument name.</param>
186+
/// <returns><see cref="ArgumentAssertion{T}"/> instance.</returns>
187+
[DebuggerHidden, MethodImpl(AggressiveInlining)]
188+
[AssertionMethod]
189+
public static ArgumentAssertion<T> Arg<T>(T arg, [InvokerParameterName] string argName) =>
190+
new ArgumentAssertion<T>(arg, argName);
135191
#endregion
136192

137193
#region Argument validation - in range

CodeJam.Main/Assertions/CodeExceptions.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,22 @@ public static ArgumentException ArgumentItemNull([NotNull, InvokerParameterName]
136136
.LogToCodeTraceSourceBeforeThrow();
137137
}
138138

139+
/// <summary>
140+
/// Creates <see cref="ArgumentException"/>.
141+
/// </summary>
142+
/// <param name="argumentName">Name of the argument.</param>
143+
/// <returns>Initialized instance of <see cref="ArgumentException"/></returns>
144+
[DebuggerHidden, NotNull, MethodImpl(AggressiveInlining)]
145+
[MustUseReturnValue]
146+
public static ArgumentException ArgumentEmpty([NotNull, InvokerParameterName] string argumentName)
147+
{
148+
BreakIfAttached();
149+
return new ArgumentException(
150+
argumentName,
151+
$"Collection {argumentName} must not be empty.")
152+
.LogToCodeTraceSourceBeforeThrow();
153+
}
154+
139155
/// <summary>Creates <see cref="ArgumentException"/> for empty string.</summary>
140156
/// <param name="argumentName">Name of the argument.</param>
141157
/// <returns>Initialized instance of <see cref="ArgumentException"/>.</returns>

CodeJam.Main/CodeJam.Main.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@
113113
<Compile Update="Assertions\DebugCode.generated.cs">
114114
<AutoGen>True</AutoGen>
115115
<DependentUpon>DebugCode.tt</DependentUpon>
116+
<DesignTime>True</DesignTime>
116117
</Compile>
117118
<None Update="Assertions\DebugCode.tt">
118119
<Generator>TextTemplatingFileGenerator</Generator>
@@ -351,4 +352,8 @@
351352
</Content>
352353
</ItemGroup>
353354

355+
<ItemGroup>
356+
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
357+
</ItemGroup>
358+
354359
</Project>

CodeJam.Main/Readme.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
CodeJam 2.1.1 Release Notes
2-
---------------------------
1+
CodeJam 2.2.0-beta2 Release Notes
2+
---------------------------------
33

44
What's new in 2.2.0-beta2
55
-------------------------
6+
* Limited .NET framework 2.0 support
67
* ExceptionExtensions.ToDiagnosticString[Async] improvements
78
* DictionaryExtensions.GetOrAddAsync/AddOrUpdateAsync
89
* LazyDictionary ctors and Create with initial data supplied

0 commit comments

Comments
 (0)