Skip to content

Commit 6831f66

Browse files
authored
Merge pull request nunit#4882 from manfred-brands/typeSpecificEqualConstraints
Type specific equal constraints
2 parents 0c1ef7f + 879c489 commit 6831f66

27 files changed

+1484
-27
lines changed

src/NUnitFramework/framework/Constraints/ConstraintBuilder.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,17 @@ public void Append(Constraint constraint)
175175
constraint.Builder = this;
176176
}
177177

178+
/// <summary>
179+
/// Replaces the last pushed constraint with the specified constraint.
180+
/// </summary>
181+
/// <param name="constraint">The constraint to replace the lastPushed with.</param>
182+
public void Replace(Constraint constraint)
183+
{
184+
_constraints.Pop();
185+
_lastPushed = _ops.Top;
186+
Append(constraint);
187+
}
188+
178189
/// <summary>
179190
/// Sets the top operator right context.
180191
/// </summary>

src/NUnitFramework/framework/Constraints/ConstraintExpression.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,49 @@ public EqualConstraint EqualTo(object? expected)
427427
return Append(new EqualConstraint(expected));
428428
}
429429

430+
/// <summary>
431+
/// Returns a constraint that tests two strings for equality
432+
/// </summary>
433+
public EqualStringConstraint EqualTo(string? expected)
434+
{
435+
return Append(new EqualStringConstraint(expected));
436+
}
437+
438+
/// <summary>
439+
/// Returns a constraint that tests two date time offset instances for equality
440+
/// </summary>
441+
public EqualDateTimeOffsetConstraint EqualTo(DateTimeOffset expected)
442+
{
443+
return Append(new EqualDateTimeOffsetConstraint(expected));
444+
}
445+
446+
/// <summary>
447+
/// Returns a constraint that tests two date time instances for equality
448+
/// </summary>
449+
public EqualTimeBaseConstraint<DateTime> EqualTo(DateTime expected)
450+
{
451+
return Append(new EqualTimeBaseConstraint<DateTime>(expected, x => x.Ticks));
452+
}
453+
454+
/// <summary>
455+
/// Returns a constraint that tests two timespan instances for equality
456+
/// </summary>
457+
public EqualTimeBaseConstraint<TimeSpan> EqualTo(TimeSpan expected)
458+
{
459+
return Append(new EqualTimeBaseConstraint<TimeSpan>(expected, x => x.Ticks));
460+
}
461+
462+
/// <summary>
463+
/// Returns a constraint that tests two numbers for equality
464+
/// </summary>
465+
#pragma warning disable CS3024 // Constraint type is not CLS-compliant
466+
public EqualNumericConstraint<T> EqualTo<T>(T expected)
467+
where T : unmanaged, IConvertible, IEquatable<T>
468+
{
469+
return Append(new EqualNumericConstraint<T>(expected));
470+
}
471+
#pragma warning restore CS3024 // Constraint type is not CLS-compliant
472+
430473
#endregion
431474

432475
#region SameAs

src/NUnitFramework/framework/Constraints/EqualConstraintResult.cs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,51 @@ public EqualConstraintResult(EqualConstraint constraint, object? actual, bool ha
5757
_failurePoints = constraint.HasFailurePoints ? constraint.FailurePoints : Array.Empty<NUnitEqualityComparer.FailurePoint>();
5858
}
5959

60+
/// <summary>
61+
/// Construct an EqualConstraintResult
62+
/// </summary>
63+
public EqualConstraintResult(Constraint constraint, object? actual, Tolerance tolerance, bool hasSucceeded)
64+
: base(constraint, actual, hasSucceeded)
65+
{
66+
_expectedValue = constraint.Arguments[0];
67+
_tolerance = tolerance;
68+
_comparingProperties = false;
69+
_caseInsensitive = false;
70+
_ignoringWhiteSpace = false;
71+
_clipStrings = false;
72+
_failurePoints = Array.Empty<NUnitEqualityComparer.FailurePoint>();
73+
}
74+
75+
/// <summary>
76+
/// Construct an EqualConstraintResult
77+
/// </summary>
78+
public EqualConstraintResult(Constraint constraint, object? actual, bool hasSucceeded)
79+
: base(constraint, actual, hasSucceeded)
80+
{
81+
_expectedValue = constraint.Arguments[0];
82+
_tolerance = Tolerance.Default;
83+
_comparingProperties = false;
84+
_caseInsensitive = false;
85+
_ignoringWhiteSpace = false;
86+
_clipStrings = false;
87+
_failurePoints = Array.Empty<NUnitEqualityComparer.FailurePoint>();
88+
}
89+
90+
/// <summary>
91+
/// Construct an EqualConstraintResult
92+
/// </summary>
93+
public EqualConstraintResult(EqualStringWithoutUsingConstraint constraint, object? actual, bool caseInsensitive, bool ignoringWhiteSpace, bool clipStrings, bool hasSucceeded)
94+
: base(constraint, actual, hasSucceeded)
95+
{
96+
_expectedValue = constraint.Arguments[0];
97+
_tolerance = Tolerance.Exact;
98+
_comparingProperties = false;
99+
_caseInsensitive = caseInsensitive;
100+
_ignoringWhiteSpace = ignoringWhiteSpace;
101+
_clipStrings = clipStrings;
102+
_failurePoints = Array.Empty<NUnitEqualityComparer.FailurePoint>();
103+
}
104+
60105
/// <summary>
61106
/// Write a failure message. Overridden to provide custom
62107
/// failure messages for EqualConstraint.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt
2+
3+
using System;
4+
5+
namespace NUnit.Framework.Constraints
6+
{
7+
/// <summary>
8+
/// EqualConstraint is able to compare an actual value with the
9+
/// expected value provided in its constructor. Two objects are
10+
/// considered equal if both are null, or if both have the same
11+
/// value. NUnit has special semantics for some object types.
12+
/// </summary>
13+
public class EqualDateTimeOffsetConstraint : EqualTimeBaseConstraint<DateTimeOffset>
14+
{
15+
#region Constructor
16+
17+
/// <summary>
18+
/// Initializes a new instance of the <see cref="EqualConstraint"/> class.
19+
/// </summary>
20+
/// <param name="expected">The expected value.</param>
21+
public EqualDateTimeOffsetConstraint(DateTimeOffset expected)
22+
: base(expected, x => x.UtcTicks)
23+
{
24+
}
25+
26+
#endregion
27+
28+
#region Constraint Modifiers
29+
30+
/// <summary>
31+
/// Flags the constraint to include <see cref="DateTimeOffset.Offset"/>
32+
/// property in comparison of two <see cref="DateTimeOffset"/> values.
33+
/// </summary>
34+
/// <remarks>
35+
/// Using this modifier does not allow to use the <see cref="EqualConstraint.Within"/>
36+
/// constraint modifier.
37+
/// </remarks>
38+
public EqualDateTimeOffsetConstraintWithSameOffset WithSameOffset
39+
{
40+
get
41+
{
42+
var constraint = new EqualDateTimeOffsetConstraintWithSameOffset(Expected);
43+
Builder?.Replace(constraint);
44+
return constraint;
45+
}
46+
}
47+
48+
#endregion
49+
}
50+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt
2+
3+
using System;
4+
using System.Text;
5+
6+
namespace NUnit.Framework.Constraints
7+
{
8+
/// <summary>
9+
/// EqualConstraint is able to compare an actual value with the
10+
/// expected value provided in its constructor. Two objects are
11+
/// considered equal if both are null, or if both have the same
12+
/// value. NUnit has special semantics for some object types.
13+
/// </summary>
14+
public class EqualDateTimeOffsetConstraintWithSameOffset : Constraint
15+
{
16+
private readonly DateTimeOffset _expected;
17+
18+
#region Constructor
19+
20+
/// <summary>
21+
/// Initializes a new instance of the <see cref="EqualConstraint"/> class.
22+
/// </summary>
23+
/// <param name="expected">The expected value.</param>
24+
public EqualDateTimeOffsetConstraintWithSameOffset(DateTimeOffset expected)
25+
: base(expected)
26+
{
27+
_expected = expected;
28+
}
29+
30+
#endregion
31+
32+
#region Public Methods
33+
34+
/// <summary>
35+
/// Test whether the constraint is satisfied by a given value
36+
/// </summary>
37+
/// <param name="actual">The value to be tested</param>
38+
/// <returns>True for success, false for failure</returns>
39+
public ConstraintResult ApplyTo(DateTimeOffset actual)
40+
{
41+
bool hasSucceeded = _expected.Equals(actual) && _expected.Offset == actual.Offset;
42+
43+
return new ConstraintResult(this, actual, hasSucceeded);
44+
}
45+
46+
/// <summary>
47+
/// Test whether the constraint is satisfied by a given value
48+
/// </summary>
49+
/// <param name="actual">The value to be tested</param>
50+
/// <returns>True for success, false for failure</returns>
51+
public override ConstraintResult ApplyTo<TActual>(TActual actual)
52+
{
53+
if (actual is DateTimeOffset dateTimeOffset)
54+
{
55+
return ApplyTo(dateTimeOffset);
56+
}
57+
58+
return new ConstraintResult(this, actual, false);
59+
}
60+
61+
/// <summary>
62+
/// The Description of what this constraint tests, for
63+
/// use in messages and in the ConstraintResult.
64+
/// </summary>
65+
public override string Description
66+
{
67+
get
68+
{
69+
var sb = new StringBuilder(MsgUtils.FormatValue(_expected));
70+
71+
sb.Append(" with the same offset");
72+
73+
return sb.ToString();
74+
}
75+
}
76+
77+
#endregion
78+
}
79+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt
2+
3+
using System;
4+
5+
namespace NUnit.Framework.Constraints
6+
{
7+
/// <summary>
8+
/// EqualNumericConstraint is able to compare an actual value with the
9+
/// expected value provided in its constructor. Two objects are
10+
/// considered equal if both are null, or if both have the same
11+
/// value. NUnit has special semantics for some object types.
12+
/// </summary>
13+
#pragma warning disable CS3024 // Constraint type is not CLS-compliant
14+
public class EqualNumericConstraint<T> : EqualNumericWithoutUsingConstraint<T>, IEqualWithUsingConstraint<T>
15+
where T : unmanaged, IConvertible, IEquatable<T>
16+
#pragma warning restore CS3024 // Constraint type is not CLS-compliant
17+
{
18+
#region Constructor
19+
20+
/// <summary>
21+
/// Initializes a new instance of the <see cref="EqualConstraint"/> class.
22+
/// </summary>
23+
/// <param name="expected">The expected value.</param>
24+
public EqualNumericConstraint(T expected)
25+
: base(expected)
26+
{
27+
}
28+
29+
#endregion
30+
}
31+
}

0 commit comments

Comments
 (0)