diff --git a/Source/Mockolate/It.IsOneOf.cs b/Source/Mockolate/It.IsOneOf.cs
new file mode 100644
index 00000000..24aadcdb
--- /dev/null
+++ b/Source/Mockolate/It.IsOneOf.cs
@@ -0,0 +1,32 @@
+using System.Collections.Generic;
+using System.Linq;
+using Mockolate.Parameters;
+
+namespace Mockolate;
+
+#pragma warning disable S3453 // This class can't be instantiated; make its constructor 'public'.
+#pragma warning disable S3218 // Inner class members should not shadow outer class "static" or type members
+public partial class It
+{
+ ///
+ /// Matches a parameter that is equal to one of the .
+ ///
+ public static IParameter IsOneOf(params T[] values)
+ => new ParameterIsOneOfMatch(values);
+
+ private sealed class ParameterIsOneOfMatch(T[] values) : TypedMatch
+ {
+ ///
+ protected override bool Matches(T value)
+ {
+ EqualityComparer comparer = EqualityComparer.Default;
+ return values.Any(v => comparer.Equals(value, v));
+ }
+
+ ///
+ public override string ToString()
+ => $"It.IsOneOf({string.Join(", ", values.Select(v => v is string ? $"\"{v}\"" : v?.ToString() ?? "null"))})";
+ }
+}
+#pragma warning restore S3218 // Inner class members should not shadow outer class "static" or type members
+#pragma warning restore S3453 // This class can't be instantiated; make its constructor 'public'.
diff --git a/Tests/Mockolate.Api.Tests/Expected/Mockolate_net10.0.txt b/Tests/Mockolate.Api.Tests/Expected/Mockolate_net10.0.txt
index 99d71074..c26f0c44 100644
--- a/Tests/Mockolate.Api.Tests/Expected/Mockolate_net10.0.txt
+++ b/Tests/Mockolate.Api.Tests/Expected/Mockolate_net10.0.txt
@@ -40,6 +40,7 @@ namespace Mockolate
public static Mockolate.It.IInRangeParameter IsInRange(T minimum, T maximum, [System.Runtime.CompilerServices.CallerArgumentExpression("minimum")] string doNotPopulateThisValue1 = "", [System.Runtime.CompilerServices.CallerArgumentExpression("maximum")] string doNotPopulateThisValue2 = "")
where T : System.IComparable { }
public static Mockolate.Parameters.IParameter IsNull() { }
+ public static Mockolate.Parameters.IParameter IsOneOf(params T[] values) { }
public static Mockolate.Parameters.IVerifyOutParameter IsOut() { }
public static Mockolate.Parameters.IOutParameter IsOut(System.Func setter, [System.Runtime.CompilerServices.CallerArgumentExpression("setter")] string doNotPopulateThisValue = "") { }
public static Mockolate.Parameters.IVerifyReadOnlySpanParameter IsReadOnlySpan(System.Func predicate) { }
diff --git a/Tests/Mockolate.Api.Tests/Expected/Mockolate_net8.0.txt b/Tests/Mockolate.Api.Tests/Expected/Mockolate_net8.0.txt
index 760c254d..ec7b2fb0 100644
--- a/Tests/Mockolate.Api.Tests/Expected/Mockolate_net8.0.txt
+++ b/Tests/Mockolate.Api.Tests/Expected/Mockolate_net8.0.txt
@@ -39,6 +39,7 @@ namespace Mockolate
public static Mockolate.It.IInRangeParameter IsInRange(T minimum, T maximum, [System.Runtime.CompilerServices.CallerArgumentExpression("minimum")] string doNotPopulateThisValue1 = "", [System.Runtime.CompilerServices.CallerArgumentExpression("maximum")] string doNotPopulateThisValue2 = "")
where T : System.IComparable { }
public static Mockolate.Parameters.IParameter IsNull() { }
+ public static Mockolate.Parameters.IParameter IsOneOf(params T[] values) { }
public static Mockolate.Parameters.IVerifyOutParameter IsOut() { }
public static Mockolate.Parameters.IOutParameter IsOut(System.Func setter, [System.Runtime.CompilerServices.CallerArgumentExpression("setter")] string doNotPopulateThisValue = "") { }
public static Mockolate.Parameters.IVerifyReadOnlySpanParameter IsReadOnlySpan(System.Func predicate) { }
diff --git a/Tests/Mockolate.Api.Tests/Expected/Mockolate_netstandard2.0.txt b/Tests/Mockolate.Api.Tests/Expected/Mockolate_netstandard2.0.txt
index 30d01e37..6ed02460 100644
--- a/Tests/Mockolate.Api.Tests/Expected/Mockolate_netstandard2.0.txt
+++ b/Tests/Mockolate.Api.Tests/Expected/Mockolate_netstandard2.0.txt
@@ -36,6 +36,7 @@ namespace Mockolate
public static Mockolate.It.IInRangeParameter IsInRange(T minimum, T maximum, [System.Runtime.CompilerServices.CallerArgumentExpression("minimum")] string doNotPopulateThisValue1 = "", [System.Runtime.CompilerServices.CallerArgumentExpression("maximum")] string doNotPopulateThisValue2 = "")
where T : System.IComparable { }
public static Mockolate.Parameters.IParameter IsNull() { }
+ public static Mockolate.Parameters.IParameter IsOneOf(params T[] values) { }
public static Mockolate.Parameters.IVerifyOutParameter IsOut() { }
public static Mockolate.Parameters.IOutParameter IsOut(System.Func setter, [System.Runtime.CompilerServices.CallerArgumentExpression("setter")] string doNotPopulateThisValue = "") { }
public static Mockolate.Parameters.IVerifyRefParameter IsRef() { }
diff --git a/Tests/Mockolate.Tests/MatchTests.AnyOutTests.cs b/Tests/Mockolate.Tests/ItTests.IsAnyOutTests.cs
similarity index 90%
rename from Tests/Mockolate.Tests/MatchTests.AnyOutTests.cs
rename to Tests/Mockolate.Tests/ItTests.IsAnyOutTests.cs
index 7d659ff9..0639a06a 100644
--- a/Tests/Mockolate.Tests/MatchTests.AnyOutTests.cs
+++ b/Tests/Mockolate.Tests/ItTests.IsAnyOutTests.cs
@@ -2,9 +2,9 @@
namespace Mockolate.Tests;
-public sealed partial class MatchTests
+public sealed partial class ItTests
{
- public sealed class AnyOutTests
+ public sealed class IsAnyOutTests
{
[Theory]
[InlineData(42L, false)]
diff --git a/Tests/Mockolate.Tests/MatchTests.AnyParametersTests.cs b/Tests/Mockolate.Tests/ItTests.IsAnyParametersTests.cs
similarity index 88%
rename from Tests/Mockolate.Tests/MatchTests.AnyParametersTests.cs
rename to Tests/Mockolate.Tests/ItTests.IsAnyParametersTests.cs
index 0574ef67..24675234 100644
--- a/Tests/Mockolate.Tests/MatchTests.AnyParametersTests.cs
+++ b/Tests/Mockolate.Tests/ItTests.IsAnyParametersTests.cs
@@ -2,9 +2,9 @@
namespace Mockolate.Tests;
-public sealed partial class MatchTests
+public sealed partial class ItTests
{
- public sealed class AnyParametersTests
+ public sealed class IsAnyParametersTests
{
[Theory]
[InlineData(null, null)]
diff --git a/Tests/Mockolate.Tests/MatchTests.AnyRefTests.cs b/Tests/Mockolate.Tests/ItTests.IsAnyRefTests.cs
similarity index 90%
rename from Tests/Mockolate.Tests/MatchTests.AnyRefTests.cs
rename to Tests/Mockolate.Tests/ItTests.IsAnyRefTests.cs
index 14563a4d..5db059a1 100644
--- a/Tests/Mockolate.Tests/MatchTests.AnyRefTests.cs
+++ b/Tests/Mockolate.Tests/ItTests.IsAnyRefTests.cs
@@ -2,9 +2,9 @@
namespace Mockolate.Tests;
-public sealed partial class MatchTests
+public sealed partial class ItTests
{
- public sealed class AnyRefTests
+ public sealed class IsAnyRefTests
{
[Theory]
[InlineData(42L, false)]
diff --git a/Tests/Mockolate.Tests/MatchTests.AnyTests.cs b/Tests/Mockolate.Tests/ItTests.IsAnyTests.cs
similarity index 89%
rename from Tests/Mockolate.Tests/MatchTests.AnyTests.cs
rename to Tests/Mockolate.Tests/ItTests.IsAnyTests.cs
index 3e343bff..a6c773e0 100644
--- a/Tests/Mockolate.Tests/MatchTests.AnyTests.cs
+++ b/Tests/Mockolate.Tests/ItTests.IsAnyTests.cs
@@ -2,9 +2,9 @@
namespace Mockolate.Tests;
-public sealed partial class MatchTests
+public sealed partial class ItTests
{
- public sealed class AnyTests
+ public sealed class IsAnyTests
{
[Theory]
[InlineData(null)]
diff --git a/Tests/Mockolate.Tests/MatchTests.FalseTests.cs b/Tests/Mockolate.Tests/ItTests.IsFalseTests.cs
similarity index 90%
rename from Tests/Mockolate.Tests/MatchTests.FalseTests.cs
rename to Tests/Mockolate.Tests/ItTests.IsFalseTests.cs
index e86f552e..953a1738 100644
--- a/Tests/Mockolate.Tests/MatchTests.FalseTests.cs
+++ b/Tests/Mockolate.Tests/ItTests.IsFalseTests.cs
@@ -2,9 +2,9 @@
namespace Mockolate.Tests;
-public sealed partial class MatchTests
+public sealed partial class ItTests
{
- public sealed class FalseTests
+ public sealed class IsFalseTests
{
[Theory]
[InlineData(false, 1)]
diff --git a/Tests/Mockolate.Tests/MatchTests.InRangeTests.cs b/Tests/Mockolate.Tests/ItTests.IsInRangeTests.cs
similarity index 96%
rename from Tests/Mockolate.Tests/MatchTests.InRangeTests.cs
rename to Tests/Mockolate.Tests/ItTests.IsInRangeTests.cs
index d66f1b74..f445e895 100644
--- a/Tests/Mockolate.Tests/MatchTests.InRangeTests.cs
+++ b/Tests/Mockolate.Tests/ItTests.IsInRangeTests.cs
@@ -2,9 +2,9 @@
namespace Mockolate.Tests;
-public sealed partial class MatchTests
+public sealed partial class ItTests
{
- public sealed class InRangeTests
+ public sealed class IsInRangeTests
{
[Theory]
[InlineData(3, 5, false)]
diff --git a/Tests/Mockolate.Tests/MatchTests.NullTests.cs b/Tests/Mockolate.Tests/ItTests.IsNullTests.cs
similarity index 63%
rename from Tests/Mockolate.Tests/MatchTests.NullTests.cs
rename to Tests/Mockolate.Tests/ItTests.IsNullTests.cs
index d55f5873..04f0c51b 100644
--- a/Tests/Mockolate.Tests/MatchTests.NullTests.cs
+++ b/Tests/Mockolate.Tests/ItTests.IsNullTests.cs
@@ -2,9 +2,9 @@
namespace Mockolate.Tests;
-public sealed partial class MatchTests
+public sealed partial class ItTests
{
- public sealed class NullTests
+ public sealed class IsNullTests
{
[Theory]
[InlineData(null, 1)]
@@ -29,5 +29,18 @@ public async Task ToString_ShouldReturnExpectedValue()
await That(result).IsEqualTo(expectedValue);
}
+
+ [Theory]
+ [InlineData(null, true)]
+ [InlineData("", false)]
+ [InlineData("foo", false)]
+ public async Task WithValue_Nullable_ShouldMatchWhenEqual(string? value, bool expectMatch)
+ {
+ IParameter sut = It.IsNull();
+
+ bool result = ((IParameter)sut).Matches(value);
+
+ await That(result).IsEqualTo(expectMatch);
+ }
}
}
diff --git a/Tests/Mockolate.Tests/ItTests.IsOneOfTests.cs b/Tests/Mockolate.Tests/ItTests.IsOneOfTests.cs
new file mode 100644
index 00000000..f571fedc
--- /dev/null
+++ b/Tests/Mockolate.Tests/ItTests.IsOneOfTests.cs
@@ -0,0 +1,118 @@
+using Mockolate.Parameters;
+
+namespace Mockolate.Tests;
+
+public sealed partial class ItTests
+{
+ public sealed class IsOneOfTests
+ {
+ [Fact]
+ public async Task ToString_WithNullableIntValues_ShouldReturnExpectedValue()
+ {
+ IParameter sut = It.IsOneOf(3, null, 5);
+ string expectedValue = "It.IsOneOf(3, null, 5)";
+
+ string? result = sut.ToString();
+
+ await That(result).IsEqualTo(expectedValue);
+ }
+
+ [Fact]
+ public async Task ToString_WithStringValues_ShouldReturnExpectedValue()
+ {
+ IParameter sut = It.IsOneOf("foo", "bar");
+ string expectedValue = "It.IsOneOf(\"foo\", \"bar\")";
+
+ string? result = sut.ToString();
+
+ await That(result).IsEqualTo(expectedValue);
+ }
+
+ [Theory]
+ [InlineData(1, false)]
+ [InlineData(4, false)]
+ [InlineData(5, true)]
+ [InlineData(6, true)]
+ [InlineData(7, true)]
+ [InlineData(8, false)]
+ [InlineData(-5, false)]
+ [InlineData(42, false)]
+ public async Task WithValue_ShouldMatchWhenEqualToAny(int value, bool expectMatch)
+ {
+ IParameter sut = It.IsOneOf(5, 6, 7);
+
+ bool result = ((IParameter)sut).Matches(value);
+
+ await That(result).IsEqualTo(expectMatch);
+ }
+
+ [Fact]
+ public async Task WithValue_ShouldSupportCovarianceInSetup()
+ {
+ IMyService mock = Mock.Create();
+ MyImplementation value1 = new();
+ MyImplementation value2 = new();
+ MyOtherImplementation other1 = new();
+ mock.SetupMock.Method.DoSomething(It.IsOneOf(value1, value2))
+ .Returns(3);
+
+ int result1 = mock.DoSomething(value1);
+ int result2 = mock.DoSomething(other1);
+
+ await That(result1).IsEqualTo(3);
+ await That(result2).IsEqualTo(0);
+ }
+
+ [Fact]
+ public async Task WithValue_ShouldSupportCovarianceInVerify()
+ {
+ IMyService mock = Mock.Create();
+ mock.SetupMock.Method.DoSomething(It.Is(_ => true))
+ .Do(d => d.DoWork())
+ .Returns(3);
+ MyImplementation value1 = new();
+ MyImplementation value2 = new();
+ MyOtherImplementation other1 = new();
+ MyOtherImplementation other2 = new();
+
+ int result1 = mock.DoSomething(value1);
+
+ await That(mock.VerifyMock.Invoked.DoSomething(It.IsOneOf(value1, value2))).Once();
+ await That(value1.Progress).IsEqualTo(1);
+ await That(result1).IsEqualTo(3);
+ await That(mock.VerifyMock.Invoked.DoSomething(It.IsOneOf(other1, other2))).Never();
+ }
+
+ public interface IMyBase
+ {
+ int DoWork();
+ }
+
+ public class MyImplementation : IMyBase
+ {
+ public int Progress { get; private set; }
+
+ public int DoWork()
+ {
+ Progress++;
+ return Progress;
+ }
+ }
+
+ public class MyOtherImplementation : IMyBase
+ {
+ public string Output { get; private set; } = "";
+
+ public int DoWork()
+ {
+ Output += "did something\n";
+ return 1;
+ }
+ }
+
+ public interface IMyService
+ {
+ int DoSomething(IMyBase value);
+ }
+ }
+}
diff --git a/Tests/Mockolate.Tests/MatchTests.OutTests.cs b/Tests/Mockolate.Tests/ItTests.IsOutTests.cs
similarity index 94%
rename from Tests/Mockolate.Tests/MatchTests.OutTests.cs
rename to Tests/Mockolate.Tests/ItTests.IsOutTests.cs
index f4b5a9d5..237b6bd3 100644
--- a/Tests/Mockolate.Tests/MatchTests.OutTests.cs
+++ b/Tests/Mockolate.Tests/ItTests.IsOutTests.cs
@@ -2,9 +2,9 @@
namespace Mockolate.Tests;
-public sealed partial class MatchTests
+public sealed partial class ItTests
{
- public sealed class OutTests
+ public sealed class IsOutTests
{
[Fact]
public async Task ToString_ShouldReturnExpectedValue()
diff --git a/Tests/Mockolate.Tests/MatchTests.RefTests.cs b/Tests/Mockolate.Tests/ItTests.IsRefTests.cs
similarity index 97%
rename from Tests/Mockolate.Tests/MatchTests.RefTests.cs
rename to Tests/Mockolate.Tests/ItTests.IsRefTests.cs
index d55327d5..44de174d 100644
--- a/Tests/Mockolate.Tests/MatchTests.RefTests.cs
+++ b/Tests/Mockolate.Tests/ItTests.IsRefTests.cs
@@ -2,9 +2,9 @@
namespace Mockolate.Tests;
-public sealed partial class MatchTests
+public sealed partial class ItTests
{
- public sealed class RefTests
+ public sealed class IsRefTests
{
[Fact]
public async Task ToString_ShouldReturnExpectedValue()
diff --git a/Tests/Mockolate.Tests/MatchTests.WithTests.cs b/Tests/Mockolate.Tests/ItTests.IsTests.cs
similarity index 92%
rename from Tests/Mockolate.Tests/MatchTests.WithTests.cs
rename to Tests/Mockolate.Tests/ItTests.IsTests.cs
index 52930624..637f8693 100644
--- a/Tests/Mockolate.Tests/MatchTests.WithTests.cs
+++ b/Tests/Mockolate.Tests/ItTests.IsTests.cs
@@ -2,9 +2,9 @@
namespace Mockolate.Tests;
-public sealed partial class MatchTests
+public sealed partial class ItTests
{
- public sealed class WithTests
+ public sealed class IsTests
{
[Fact]
public async Task ToString_WithPredicate_ShouldReturnExpectedValue()
@@ -109,19 +109,6 @@ public async Task WithPredicate_ShouldSupportCovarianceInVerify()
await That(mock.VerifyMock.Invoked.DoSomething(It.Is(_ => true))).Never();
}
- [Theory]
- [InlineData(null, true)]
- [InlineData("", false)]
- [InlineData("foo", false)]
- public async Task WithValue_Nullable_ShouldMatchWhenEqual(string? value, bool expectMatch)
- {
- IParameter sut = It.IsNull();
-
- bool result = ((IParameter)sut).Matches(value);
-
- await That(result).IsEqualTo(expectMatch);
- }
-
[Theory]
[InlineData(1, false)]
[InlineData(5, true)]
diff --git a/Tests/Mockolate.Tests/MatchTests.TrueTests.cs b/Tests/Mockolate.Tests/ItTests.IsTrueTests.cs
similarity index 91%
rename from Tests/Mockolate.Tests/MatchTests.TrueTests.cs
rename to Tests/Mockolate.Tests/ItTests.IsTrueTests.cs
index 5e1fe3c8..fc62d03d 100644
--- a/Tests/Mockolate.Tests/MatchTests.TrueTests.cs
+++ b/Tests/Mockolate.Tests/ItTests.IsTrueTests.cs
@@ -2,9 +2,9 @@
namespace Mockolate.Tests;
-public sealed partial class MatchTests
+public sealed partial class ItTests
{
- public sealed class TrueTests
+ public sealed class IsTrueTests
{
[Fact]
public async Task ToString_ShouldReturnExpectedValue()
diff --git a/Tests/Mockolate.Tests/MatchTests.MatchesTests.cs b/Tests/Mockolate.Tests/ItTests.MatchesTests.cs
similarity index 98%
rename from Tests/Mockolate.Tests/MatchTests.MatchesTests.cs
rename to Tests/Mockolate.Tests/ItTests.MatchesTests.cs
index ef78f71b..c3fbf302 100644
--- a/Tests/Mockolate.Tests/MatchTests.MatchesTests.cs
+++ b/Tests/Mockolate.Tests/ItTests.MatchesTests.cs
@@ -3,7 +3,7 @@
namespace Mockolate.Tests;
-public sealed partial class MatchTests
+public sealed partial class ItTests
{
public sealed class MatchesTests
{
diff --git a/Tests/Mockolate.Tests/MatchTests.cs b/Tests/Mockolate.Tests/ItTests.cs
similarity index 98%
rename from Tests/Mockolate.Tests/MatchTests.cs
rename to Tests/Mockolate.Tests/ItTests.cs
index 3d661242..76b8bc3b 100644
--- a/Tests/Mockolate.Tests/MatchTests.cs
+++ b/Tests/Mockolate.Tests/ItTests.cs
@@ -5,7 +5,7 @@
namespace Mockolate.Tests;
-public sealed partial class MatchTests
+public sealed partial class ItTests
{
[Fact]
public async Task InvokeCallbacks_WithCorrectType_ShouldInvokeCallback()