Skip to content

Commit 963b628

Browse files
authored
Merge pull request #122 from feO2x/issue-116-must-not-contain-for-immutable-array
MustNotContain for immutable array
2 parents e1484b4 + ac60b22 commit 963b628

File tree

3 files changed

+134
-1
lines changed

3 files changed

+134
-1
lines changed

Code/Light.GuardClauses.Tests/CollectionAssertions/MustNotContainTests.cs

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
3+
using System.Collections.Immutable;
34
using System.Collections.ObjectModel;
45
using FluentAssertions;
56
using Light.GuardClauses.Exceptions;
@@ -75,4 +76,68 @@ public static void CallerArgumentExpression()
7576
act.Should().Throw<ExistingItemException>()
7677
.WithParameterName(nameof(array));
7778
}
79+
80+
[Theory]
81+
[InlineData(new[] { "Foo", "Bar" }, "Foo")]
82+
[InlineData(new[] { "Baz", "Qux", "Quux" }, "Qux")]
83+
[InlineData(new[] { "Corge", "Grault", null }, null)]
84+
public static void ImmutableArrayItemExists(string[] items, string item)
85+
{
86+
var array = ImmutableArray.Create(items);
87+
88+
Action act = () => array.MustNotContain(item, nameof(array));
89+
90+
var assertions = act.Should().Throw<ExistingItemException>().Which;
91+
assertions.Message.Should()
92+
.Contain($"{nameof(array)} must not contain {item.ToStringOrNull()}, but it actually does.");
93+
assertions.ParamName.Should().BeSameAs(nameof(array));
94+
}
95+
96+
[Theory]
97+
[InlineData(new[] { 100, 101, 102 }, 42)]
98+
[InlineData(new[] { 11 }, -5000)]
99+
public static void ImmutableArrayItemExistsNot(int[] items, int item)
100+
{
101+
var array = ImmutableArray.Create(items);
102+
array.MustNotContain(item).Should().Equal(array);
103+
}
104+
105+
[Fact]
106+
public static void ImmutableArrayEmptyDoesNotContainItem()
107+
{
108+
var emptyArray = ImmutableArray<int>.Empty;
109+
emptyArray.MustNotContain(42).Should().Equal(emptyArray);
110+
}
111+
112+
[Fact]
113+
public static void ImmutableArrayCustomException() =>
114+
Test.CustomException(
115+
ImmutableArray.Create("Foo"),
116+
"Foo",
117+
(array, value, exceptionFactory) => array.MustNotContain(value, exceptionFactory)
118+
);
119+
120+
[Fact]
121+
public static void ImmutableArrayNoCustomExceptionThrown()
122+
{
123+
var array = ImmutableArray.Create(1, 2);
124+
array.MustNotContain(3, (_, _) => new ()).Should().Equal(array);
125+
}
126+
127+
[Fact]
128+
public static void ImmutableArrayCustomMessage() =>
129+
Test.CustomMessage<ExistingItemException>(
130+
message => ImmutableArray.Create(42).MustNotContain(42, message: message)
131+
);
132+
133+
[Fact]
134+
public static void ImmutableArrayCallerArgumentExpression()
135+
{
136+
var array = ImmutableArray.Create(1, 2, 3);
137+
138+
Action act = () => array.MustNotContain(3);
139+
140+
act.Should().Throw<ExistingItemException>()
141+
.WithParameterName(nameof(array));
142+
}
78143
}

Code/Light.GuardClauses/Check.MustNotContain.cs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Collections.Immutable;
34
using System.Linq;
45
using System.Runtime.CompilerServices;
56
using JetBrains.Annotations;
@@ -197,4 +198,51 @@ public static string MustNotContain(
197198

198199
return parameter;
199200
}
201+
202+
/// <summary>
203+
/// Ensures that the <see cref="ImmutableArray{T}" /> does not contain the specified item, or otherwise throws an <see cref="ExistingItemException" />.
204+
/// </summary>
205+
/// <param name="parameter">The <see cref="ImmutableArray{T}" /> to be checked.</param>
206+
/// <param name="item">The item that must not be part of the <see cref="ImmutableArray{T}" />.</param>
207+
/// <param name="parameterName">The name of the parameter (optional).</param>
208+
/// <param name="message">The message that will be passed to the resulting exception (optional).</param>
209+
/// <exception cref="ExistingItemException">Thrown when <paramref name="parameter" /> contains <paramref name="item" />.</exception>
210+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
211+
public static ImmutableArray<T> MustNotContain<T>(
212+
this ImmutableArray<T> parameter,
213+
T item,
214+
[CallerArgumentExpression("parameter")] string? parameterName = null,
215+
string? message = null
216+
)
217+
{
218+
if (parameter.Contains(item))
219+
{
220+
Throw.ExistingItem(parameter, item, parameterName, message);
221+
}
222+
223+
return parameter;
224+
}
225+
226+
/// <summary>
227+
/// Ensures that the <see cref="ImmutableArray{T}" /> does not contain the specified item, or otherwise throws your custom exception.
228+
/// </summary>
229+
/// <param name="parameter">The <see cref="ImmutableArray{T}" /> to be checked.</param>
230+
/// <param name="item">The item that must not be part of the <see cref="ImmutableArray{T}" />.</param>
231+
/// <param name="exceptionFactory">The delegate that creates your custom exception. <paramref name="parameter" /> and <paramref name="item" /> are passed to this delegate.</param>
232+
/// <exception cref="Exception">Your custom exception thrown when <paramref name="parameter" /> contains <paramref name="item" />.</exception>
233+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
234+
[ContractAnnotation("exceptionFactory:null => halt")]
235+
public static ImmutableArray<T> MustNotContain<T>(
236+
this ImmutableArray<T> parameter,
237+
T item,
238+
Func<ImmutableArray<T>, T, Exception> exceptionFactory
239+
)
240+
{
241+
if (parameter.Contains(item))
242+
{
243+
Throw.CustomException(exceptionFactory, parameter, item);
244+
}
245+
246+
return parameter;
247+
}
200248
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Issue 116 - MustNotContain for ImmutableArray
2+
3+
## Context
4+
5+
The .NET library Light.GuardClauses already has several assertions for collections. They often rely on `IEnumerable<T>` or `IEnumerable`. However, these assertions would result in `ImmutableArray<T>` being boxed - we want to avoid that by providing dedicated assertions for this type which avoids boxing. For this issue, we implement the `MustNotContain` assertion for `ImmutableArray<T>`.
6+
7+
## Tasks for this issue
8+
9+
- [ ] The production code should be placed in the Light.GuardClauses project. The file `Check.MustNotContain.cs` already exists in the root folder of the project - extend this existing file.
10+
- [ ] In this file, create two extension method overloads called `MustNotContain` for `ImmutableArray<T>`. It should be placed in the class `Check` which is marked as `partial`.
11+
- [ ] Each assertion in Light.GuardClauses has two overloads - the first one takes the optional `parameterName` and `message` arguments and throw the default exception. The actual exception is thrown in the `Throw` class - use the existing `Throw.ExistingItem` method which is located in `ExceptionFactory/Throw.ExistingItem.cs`.
12+
- [ ] The other overload takes a delegate which allows the caller to provide their own custom exceptions. Use the existing `Throw.CustomException` method and pass the delegate, the erroneous `ImmutableArray<T>` instance and the unwanted item.
13+
- [ ] Create unit tests for both overloads. The corresponding tests should be placed in Light.GuardClauses.Tests project, in the existing file 'CollectionAssertions/MustNotContainTests.cs'. Please follow conventions of the existing tests (e.g. use FluentAssertions' `Should()` for assertions).
14+
15+
## Notes
16+
17+
- There are already plenty of other assertions and tests in this library. All overloads are placed in the same file in the production code project. The test projects has top-level folders for different groups of assertions, like `CollectionAssertions`, `StringAssertions`, `DateTimeAssertions` and so on. Please take a look at them to follow a similar structure and code style.
18+
- This assertion specifically targets `ImmutableArray<T>` to avoid boxing that would occur with generic `IEnumerable<T>` extensions.
19+
- The assertion should verify that the `ImmutableArray<T>` does not contain the specified item.
20+
- If you have any questions or suggestions, please ask me about them.

0 commit comments

Comments
 (0)