Skip to content

Commit 44096ff

Browse files
committed
Add convenience and lazy message require functions
1 parent cd1ad75 commit 44096ff

File tree

5 files changed

+146
-11
lines changed

5 files changed

+146
-11
lines changed

.github/workflows/build.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,6 @@ jobs:
2424
- name: Build
2525
run: dotnet build --no-restore
2626
- name: Test
27-
run: dotnet test --no-build --verbosity normal
27+
run: dotnet test --no-build --verbosity normal --collect:"XPlat Code Coverage"
28+
- name: Codecov
29+
uses: codecov/codecov-action@v2
Lines changed: 95 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,116 @@
11
using NUnit.Framework;
2+
using NUnit.Framework.Internal;
23

34
namespace DotNet.Extensions.Require.Test;
45

5-
public sealed class PreconditionsTests
6+
public abstract class PreconditionsTests
67
{
8+
protected abstract T Require<T>(T subject, bool condition, string expectation = "");
9+
710
[Test]
811
public void Require_ThrowsArgumentException_WhenConditionIsFalse() =>
912
Assert.Throws<ArgumentException>(
10-
() => 1.Require(condition: false, "message")
13+
() => Require(subject: 1, condition: false, "message")
1114
)?.WithMessage("message");
1215

1316
[Test]
1417
public void Require_DoesNotThrow_WhenConditionIsTrue() =>
1518
Assert.DoesNotThrow(
16-
() => 1.Require(condition: true, string.Empty)
19+
() => Require(subject: 1, condition: true)
1720
);
1821

1922
[Test]
2023
public void Require_Returns_TheValueOnWhichItIsCalled_WhenConditionIsTrue() =>
2124
Assert.AreEqual(
2225
expected: 1,
23-
actual: 1.Require(condition: true, string.Empty)
26+
actual: Require(subject: 1, condition: true)
27+
);
28+
}
29+
30+
[TestFixture]
31+
public sealed class BasicRequire : PreconditionsTests
32+
{
33+
protected override T Require<T>(T subject, bool condition, string expectation = "") =>
34+
subject.Require(condition, expectation);
35+
}
36+
37+
public sealed class RequireWithLazyMessage : PreconditionsTests
38+
{
39+
protected override T Require<T>(T subject, bool condition, string expectation = "") =>
40+
subject.Require(condition, expectation: () => expectation);
41+
42+
[Test]
43+
public void Require_DoesNotCreateExpectationMessage_WhenConditionIsTrue() =>
44+
Assert.DoesNotThrow(
45+
() => 1.Require(condition: true, () => throw new NUnitException("must not be called"))
46+
);
47+
}
48+
49+
public sealed class RequireWithLazilyConstructedMessage : PreconditionsTests
50+
{
51+
protected override T Require<T>(T subject, bool condition, string expectation = "") =>
52+
subject.Require(condition, expectation: _ => expectation);
53+
54+
[Test]
55+
public void Require_CanUseTheValue_ToConstructTheExpectation() =>
56+
Assert.Throws<ArgumentException>(
57+
() => 1.Require(condition: false, value => $"message with {value}")
58+
)?.WithMessage("message with 1");
59+
60+
[Test]
61+
public void Require_DoesNotBuildExpectationMessage_WhenConditionIsTrue() =>
62+
Assert.DoesNotThrow(
63+
() => 1.Require(condition: true, value => throw new NUnitException($"must not be called for {value}"))
64+
);
65+
}
66+
67+
public abstract class RequireWithPredicate : PreconditionsTests
68+
{
69+
protected abstract T Require<T>(T subject, Predicate<T> requirement, string expectation = "");
70+
71+
protected override T Require<T>(T subject, bool condition, string expectation = "") =>
72+
Require(subject, requirement: _ => condition, expectation);
73+
74+
[Test]
75+
public void RequirePredicate_WillBeGivenTheValue() =>
76+
Assert.DoesNotThrow(
77+
() => 1.Require(requirement: value => value == 1, string.Empty)
78+
);
79+
}
80+
81+
[TestFixture]
82+
public sealed class RequireWithPredicateAndConstantMessage : RequireWithPredicate
83+
{
84+
protected override T Require<T>(T subject, Predicate<T> requirement, string expectation = "") =>
85+
subject.Require(requirement, expectation);
86+
}
87+
88+
public sealed class RequireWithPredicateAndLazyMessage : RequireWithPredicate
89+
{
90+
protected override T Require<T>(T subject, Predicate<T> requirement, string expectation = "") =>
91+
subject.Require(requirement, expectation: () => expectation);
92+
93+
[Test]
94+
public void Require_DoesNotCreateExpectationMessage_WhenRequirementYieldsTrue() =>
95+
Assert.DoesNotThrow(
96+
() => 1.Require(requirement: _ => true, () => throw new NUnitException("must not be called"))
97+
);
98+
}
99+
100+
public sealed class RequireWithPredicateAndLazilyConstructedMessage : RequireWithPredicate
101+
{
102+
protected override T Require<T>(T subject, Predicate<T> requirement, string expectation = "") =>
103+
subject.Require(requirement, expectation: _ => expectation);
104+
105+
[Test]
106+
public void Require_CanUseTheValue_ToConstructTheExpectation() =>
107+
Assert.Throws<ArgumentException>(
108+
() => 1.Require(requirement: _ => false, value => $"message with {value}")
109+
)?.WithMessage("message with 1");
110+
111+
[Test]
112+
public void Require_DoesNotBuildExpectationMessage_WhenConditionIsTrue() =>
113+
Assert.DoesNotThrow(
114+
() => 1.Require(requirement: _ => true, value => throw new NUnitException($"must not be called for {value}"))
24115
);
25116
}

DotNet.Extensions.Require/DotNet.Extensions.Require.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<Description>☑ Require Expressions - A precondition checks library for .Net 📦 via extensions methods on types.</Description>
66
<PackageTags>preconditions;require;guard;code-contracts;argument-checks;extension-methods</PackageTags>
77

8-
<Version>1.0.1-alpha</Version>
8+
<Version>1.0.0</Version>
99
<Authors>Andrej Dyck</Authors>
1010

1111
<PackageReadmeFile>README.md</PackageReadmeFile>

DotNet.Extensions.Require/Preconditions.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,19 @@ public static class Preconditions
44
{
55
public static T Require<T>(this T @this, bool condition, string expectation) =>
66
condition ? @this : throw new ArgumentException(expectation);
7+
8+
public static T Require<T>(this T @this, bool condition, Func<string> expectation) =>
9+
condition ? @this : throw new ArgumentException(expectation());
10+
11+
public static T Require<T>(this T @this, bool condition, Func<T, string> expectation) =>
12+
condition ? @this : throw new ArgumentException(expectation(@this));
13+
14+
public static T Require<T>(this T @this, Predicate<T> requirement, string expectation) =>
15+
requirement(@this) ? @this : throw new ArgumentException(expectation);
16+
17+
public static T Require<T>(this T @this, Predicate<T> requirement, Func<string> expectation) =>
18+
requirement(@this) ? @this : throw new ArgumentException(expectation());
19+
20+
public static T Require<T>(this T @this, Predicate<T> requirement, Func<T, string> expectation) =>
21+
requirement(@this) ? @this : throw new ArgumentException(expectation(@this));
722
}

README.md

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
# Require Expressions for .Net
22

33
![build](https://github.com/andrej-dyck/template-gradle-kotlin/actions/workflows/gradle-ci.yml/badge.svg?branch=main)
4+
[![codecov](https://codecov.io/gh/andrej-dyck/dotnet-extensions-require/branch/main/graph/badge.svg?token=9IL6K5CX37)](https://codecov.io/gh/andrej-dyck/dotnet-extensions-require)
45
[![NuGet](https://badgen.net/nuget/v/Require-Expressions)](https://www.nuget.org/packages/Require-Expressions/)
56

67
A small library that provides _pre-condition_ checks as an extension method on types.
78
This allows the client code to check a condition on arguments and use the value directly if no exception is thrown.
89

910
```csharp
1011
Reservation Request(DateTime now, DateTime reservationDate, int seats) =>
11-
new Reservation(
12-
reservationDate.Require(d => d > now, d => $"Reservation date {d} must be in the future"),
13-
seats.Require(seats > 0, () => "Expected positive number of seats")
14-
);
12+
new Reservation(
13+
reservationDate.Require(d => d > now, d => $"Reservation date {d} must be in the future"),
14+
seats.Require(seats > 0, () => "Expected positive number of seats")
15+
);
1516
```
1617

1718
## NuGet Package
@@ -22,14 +23,40 @@ dotnet add package Require-Expressions
2223

2324
## Examples
2425

25-
**Basic `Require` Function**
26+
**Basic `Require` function**
2627
```csharp
2728
var requestedSeats = seats.Require(
2829
condition: seats > 0,
2930
expectation: "expected: seats > 0"
3031
);
3132
```
3233

34+
**`Require` functions with lazily constructed expectation messages**
35+
```csharp
36+
var requestedSeats = seats.Require(
37+
condition: seats > 0,
38+
expectation: () => "expected: seats > 0"
39+
);
40+
41+
var requestedDate = reservationDate.Require(
42+
condition: reservationDate > now,
43+
expectation: d => $"Reservation date {d} must be in the future"
44+
);
45+
```
46+
47+
**`Require` functions with predicate for convenience**
48+
```csharp
49+
var requestedSeats = seats.Require(
50+
condition: s => s > 0,
51+
expectation: "expected: seats > 0"
52+
);
53+
54+
var requestedDate = reservationDate.Require(
55+
requirement: d => d > now,
56+
expectation: d => $"Reservation date {d} must be in the future"
57+
);
58+
```
59+
3360
## Q&A
3461

3562
**Why yet another preconditions library?**

0 commit comments

Comments
 (0)