Skip to content

Commit

Permalink
#172 Add ContainAny verification extension methods; Update `DataVer…
Browse files Browse the repository at this point in the history
…ificationProviderExtensionMethodTests` functionality and tests
  • Loading branch information
YevgeniyShunevych committed Dec 1, 2022
1 parent 1fc425a commit 9198835
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 31 deletions.
66 changes: 66 additions & 0 deletions src/Atata/Verification/IObjectVerificationProviderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,72 @@ public static TOwner Contain<TOwner>(
$"contain having value that {match.ToString(TermCase.MidSentence)} {Stringifier.ToStringInFormOfOneOrMany(expected)}");
}

/// <summary>
/// Verifies that collection contains any of the expected items.
/// </summary>
/// <typeparam name="TItem">The type of the collection item.</typeparam>
/// <typeparam name="TOwner">The type of the owner.</typeparam>
/// <param name="verifier">The verification provider.</param>
/// <param name="expected">An expected item values.</param>
/// <returns>The owner instance.</returns>
public static TOwner ContainAny<TItem, TOwner>(
this IObjectVerificationProvider<IEnumerable<TItem>, TOwner> verifier,
params TItem[] expected)
=>
verifier.ContainAny(expected?.AsEnumerable());

/// <summary>
/// Verifies that collection contains any of the expected items.
/// </summary>
/// <typeparam name="TItem">The type of the collection item.</typeparam>
/// <typeparam name="TOwner">The type of the owner.</typeparam>
/// <param name="verifier">The verification provider.</param>
/// <param name="expected">An expected item values.</param>
/// <returns>The owner instance.</returns>
public static TOwner ContainAny<TItem, TOwner>(
this IObjectVerificationProvider<IEnumerable<TItem>, TOwner> verifier,
IEnumerable<TItem> expected)
{
expected.CheckNotNullOrEmpty(nameof(expected));

return verifier.Satisfy(
actual => actual != null && actual.Intersect(expected).Any(),
$"contain any of {Stringifier.ToString(expected)}");
}

/// <summary>
/// Verifies that collection contains any of the expected items.
/// </summary>
/// <typeparam name="TObject">The type of the collection item object.</typeparam>
/// <typeparam name="TOwner">The type of the owner.</typeparam>
/// <param name="verifier">The verification provider.</param>
/// <param name="expected">An expected object values.</param>
/// <returns>The owner instance.</returns>
public static TOwner ContainAny<TObject, TOwner>(
this IObjectVerificationProvider<IEnumerable<IObjectProvider<TObject>>, TOwner> verifier,
params TObject[] expected)
=>
verifier.ContainAny(expected?.AsEnumerable());

/// <summary>
/// Verifies that collection contains any of the expected items.
/// </summary>
/// <typeparam name="TObject">The type of the collection item object.</typeparam>
/// <typeparam name="TOwner">The type of the owner.</typeparam>
/// <param name="verifier">The verification provider.</param>
/// <param name="expected">An expected object values.</param>
/// <returns>The owner instance.</returns>
public static TOwner ContainAny<TObject, TOwner>(
this IObjectVerificationProvider<IEnumerable<IObjectProvider<TObject>>, TOwner> verifier,
IEnumerable<TObject> expected)
{
expected.CheckNotNullOrEmpty(nameof(expected));

return verifier.Satisfy(
actual => actual != null && actual.Intersect(expected).Any(),
$"contain any of {Stringifier.ToString(expected)}");
}

public static TOwner ContainHavingContent<TControl, TOwner>(
this IObjectVerificationProvider<IEnumerable<TControl>, TOwner> verifier,
TermMatch match,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Runtime.CompilerServices;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;

namespace Atata.UnitTests.DataProvision;

Expand All @@ -8,6 +9,7 @@ public class Satisfy_Expression : ExtensionMethodTestFixture<string, Satisfy_Exp
{
static Satisfy_Expression() =>
For("abc123")
.ThrowsArgumentNullException(x => x.Satisfy(null))
.Pass(x => x.Satisfy(x => x.Contains("abc") && x.Contains("123")))
.Fail(x => x.Satisfy(x => x == "xyz"));
}
Expand All @@ -16,6 +18,7 @@ public class Satisfy_Function : ExtensionMethodTestFixture<int, Satisfy_Function
{
static Satisfy_Function() =>
For(5)
.ThrowsArgumentNullException(x => x.Satisfy(null, "..."))
.Pass(x => x.Satisfy(x => x > 1 && x < 10, "..."))
.Fail(x => x.Satisfy(x => x == 7, "..."));
}
Expand All @@ -24,20 +27,35 @@ public class Satisfy_IEnumerable_Expression : ExtensionMethodTestFixture<Subject
{
static Satisfy_IEnumerable_Expression() =>
For(new[] { "a".ToSubject(), "b".ToSubject(), "c".ToSubject() })
.ThrowsArgumentNullException(x => x.Satisfy(null as Expression<Func<IEnumerable<string>, bool>>))
.Pass(x => x.Satisfy(x => x.Contains("a") && x.Contains("c")))
.Fail(x => x.Satisfy(x => x.Any(y => y.Contains('z'))));
.Fail(x => x.Satisfy((IEnumerable<string> x) => x.Any(y => y.Contains('z'))));
}

public class Contain_IEnumerable : ExtensionMethodTestFixture<int[], Contain_IEnumerable>
{
static Contain_IEnumerable() =>
For(new[] { 1, 2, 3, 5 })
.ThrowsArgumentNullException(x => x.Contain(null as IEnumerable<int>))
.ThrowsArgumentException(x => x.Contain())
.Pass(x => x.Contain(2, 3))
.Pass(x => x.Contain(5))
.Pass(x => x.Contain(5, 5))
.Fail(x => x.Contain(4, 6));
}

public class ContainAny_IEnumerable : ExtensionMethodTestFixture<int[], ContainAny_IEnumerable>
{
static ContainAny_IEnumerable() =>
For(new[] { 1, 2, 3, 5 })
.ThrowsArgumentNullException(x => x.ContainAny(null as IEnumerable<int>))
.ThrowsArgumentException(x => x.ContainAny())
.Pass(x => x.ContainAny(4, 5))
.Pass(x => x.ContainAny(5))
.Pass(x => x.ContainAny(5, 5))
.Fail(x => x.ContainAny(4, 6));
}

public abstract class ExtensionMethodTestFixture<TObject, TFixture>
where TFixture : ExtensionMethodTestFixture<TObject, TFixture>
{
Expand All @@ -51,46 +69,64 @@ protected static TestSuiteBuilder For(TObject testObject)
return new TestSuiteBuilder(s_testSuiteData);
}

public static IEnumerable<TestCaseData> GetPassFunctionsTestCases(string testName) =>
GetTestCases(s_testSuiteData.PassFunctions, testName);
public static IEnumerable<TestCaseData> GetTestActions() =>
GetTestActionGroups().SelectMany(x => x);

public static IEnumerable<TestCaseData> GetFailFunctionsTestCases(string testName) =>
GetTestCases(s_testSuiteData.FailFunctions, testName);
private static IEnumerable<IEnumerable<TestCaseData>> GetTestActionGroups()
{
yield return GenerateTestCaseData(
"Should passes",
s_testSuiteData.PassFunctions,
(sut, function) => Assert.DoesNotThrow(() => function(sut.Should)));

yield return GenerateTestCaseData(
"Should fails",
s_testSuiteData.FailFunctions,
(sut, function) => Assert.Throws<AssertionException>(() => function(sut.Should)));

yield return GenerateTestCaseData(
"Should.Not passes",
s_testSuiteData.FailFunctions,
(sut, function) => Assert.DoesNotThrow(() => function(sut.Should.Not)));

yield return GenerateTestCaseData(
"Should.Not fails",
s_testSuiteData.PassFunctions,
(sut, function) => Assert.Throws<AssertionException>(() => function(sut.Should.Not)));

yield return GenerateTestCaseData(
"Should throws ArgumentException",
s_testSuiteData.ThrowingArgumentExceptionFunctions,
(sut, function) => Assert.Throws<ArgumentException>(() => function(sut.Should)));

yield return GenerateTestCaseData(
"Should throws ArgumentNullException",
s_testSuiteData.ThrowingArgumentNullExceptionFunctions,
(sut, function) => Assert.Throws<ArgumentNullException>(() => function(sut.Should)));
}

private static IEnumerable<TestCaseData> GetTestCases(
private static IEnumerable<TestCaseData> GenerateTestCaseData(
string testName,
List<Func<IObjectVerificationProvider<TObject, Subject<TObject>>, Subject<TObject>>> functions,
string testName)
Action<Subject<TObject>, Func<IObjectVerificationProvider<TObject, Subject<TObject>>, Subject<TObject>>> assertionFunction)
{
RuntimeHelpers.RunClassConstructor(typeof(TFixture).TypeHandle);

Action<Subject<TObject>> BuildTestAction(Func<IObjectVerificationProvider<TObject, Subject<TObject>>, Subject<TObject>> function) =>
sut => assertionFunction(sut, function);

return functions.Count == 1
? new[] { new TestCaseData(functions[0]).SetName(testName) }
: functions.Select((x, i) => new TestCaseData(x).SetArgDisplayNames($"#{i + 1}"));
? new[] { new TestCaseData(BuildTestAction(functions[0])).SetArgDisplayNames(testName) }
: functions.Select((x, i) => new TestCaseData(BuildTestAction(x)).SetArgDisplayNames($"{testName} #{i + 1}"));
}

[OneTimeSetUp]
public void SetUpFixture() =>
_sut = s_testSuiteData.TestObject.ToSutSubject();

[TestCaseSource(nameof(GetPassFunctionsTestCases), new object[] { nameof(Passes) })]
public void Passes(Func<IObjectVerificationProvider<TObject, Subject<TObject>>, Subject<TObject>> function) =>
Assert.DoesNotThrow(() =>
function(_sut.Should));

[TestCaseSource(nameof(GetFailFunctionsTestCases), new object[] { nameof(Fails) })]
public void Fails(Func<IObjectVerificationProvider<TObject, Subject<TObject>>, Subject<TObject>> function) =>
Assert.Throws<AssertionException>(() =>
function(_sut.Should));

[TestCaseSource(nameof(GetFailFunctionsTestCases), new object[] { nameof(Not_Passes) })]
public void Not_Passes(Func<IObjectVerificationProvider<TObject, Subject<TObject>>, Subject<TObject>> function) =>
Assert.DoesNotThrow(() =>
function(_sut.Should.Not));

[TestCaseSource(nameof(GetPassFunctionsTestCases), new object[] { nameof(Not_Fails) })]
public void Not_Fails(Func<IObjectVerificationProvider<TObject, Subject<TObject>>, Subject<TObject>> function) =>
Assert.Throws<AssertionException>(() =>
function(_sut.Should.Not));
[TestCaseSource(nameof(GetTestActions))]
public void When(Action<Subject<TObject>> testAction) =>
testAction.Invoke(_sut);

public class TestSuiteData
{
Expand All @@ -101,6 +137,12 @@ public class TestSuiteData

public List<Func<IObjectVerificationProvider<TObject, Subject<TObject>>, Subject<TObject>>> FailFunctions { get; } =
new List<Func<IObjectVerificationProvider<TObject, Subject<TObject>>, Subject<TObject>>>();

public List<Func<IObjectVerificationProvider<TObject, Subject<TObject>>, Subject<TObject>>> ThrowingArgumentExceptionFunctions { get; } =
new List<Func<IObjectVerificationProvider<TObject, Subject<TObject>>, Subject<TObject>>>();

public List<Func<IObjectVerificationProvider<TObject, Subject<TObject>>, Subject<TObject>>> ThrowingArgumentNullExceptionFunctions { get; } =
new List<Func<IObjectVerificationProvider<TObject, Subject<TObject>>, Subject<TObject>>>();
}

public class TestSuiteBuilder
Expand All @@ -121,6 +163,18 @@ public TestSuiteBuilder Fail(Func<IObjectVerificationProvider<TObject, Subject<T
_context.FailFunctions.Add(failFunction);
return this;
}

public TestSuiteBuilder ThrowsArgumentException(Func<IObjectVerificationProvider<TObject, Subject<TObject>>, Subject<TObject>> throwingFunction)
{
_context.ThrowingArgumentExceptionFunctions.Add(throwingFunction);
return this;
}

public TestSuiteBuilder ThrowsArgumentNullException(Func<IObjectVerificationProvider<TObject, Subject<TObject>>, Subject<TObject>> throwingFunction)
{
_context.ThrowingArgumentNullExceptionFunctions.Add(throwingFunction);
return this;
}
}
}
}
3 changes: 1 addition & 2 deletions test/Atata.UnitTests/GlobalSuppressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
#pragma warning disable S103 // Lines should not be too long

[assembly: SuppressMessage("Major Code Smell", "S2743:Static fields should not be used in generic types", Justification = "<Pending>", Scope = "member", Target = "~F:Atata.UnitTests.DataProvision.DataVerificationProviderExtensionMethodTests.ExtensionMethodTestFixture`2.s_testSuiteData")]
[assembly: SuppressMessage("Design", "CA1000:Do not declare static members on generic types", Justification = "<Pending>", Scope = "member", Target = "~M:Atata.UnitTests.DataProvision.DataVerificationProviderExtensionMethodTests.ExtensionMethodTestFixture`2.GetPassFunctionsTestCases(System.String)~System.Collections.Generic.IEnumerable{NUnit.Framework.TestCaseData}")]
[assembly: SuppressMessage("Design", "CA1000:Do not declare static members on generic types", Justification = "<Pending>", Scope = "member", Target = "~M:Atata.UnitTests.DataProvision.DataVerificationProviderExtensionMethodTests.ExtensionMethodTestFixture`2.GetFailFunctionsTestCases(System.String)~System.Collections.Generic.IEnumerable{NUnit.Framework.TestCaseData}")]
[assembly: SuppressMessage("Naming", "CA1720:Identifier contains type name", Justification = "<Pending>", Scope = "member", Target = "~P:Atata.UnitTests.DataProvision.EnumerableProviderTests.TestOwner.Object")]
[assembly: SuppressMessage("Minor Code Smell", "S1125:Boolean literals should not be redundant", Justification = "<Pending>", Scope = "member", Target = "~M:Atata.UnitTests.Expressions.ObjectExpressionStringBuilderTests.GetExpressionTestCases~System.Collections.Generic.IEnumerable{NUnit.Framework.TestCaseData}")]
[assembly: SuppressMessage("Performance", "CA1802:Use literals where appropriate", Justification = "<Pending>", Scope = "member", Target = "~F:Atata.UnitTests.Expressions.ImprovedExpressionStringBuilderTests.s_testFieldValue")]
Expand All @@ -14,5 +12,6 @@
[assembly: SuppressMessage("Design", "CA1024:Use properties where appropriate", Justification = "<Pending>", Scope = "member", Target = "~M:Atata.UnitTests.Expressions.ImprovedExpressionStringBuilderTests.StaticClass.GetInt~System.Int32")]
[assembly: SuppressMessage("Major Code Smell", "S2326:Unused type parameters should be removed", Justification = "<Pending>", Scope = "type", Target = "~T:Atata.UnitTests.Utils.TypeFinderTests.StaticSubClass.GenericSubClass`1")]
[assembly: SuppressMessage("Design", "CA1000:Do not declare static members on generic types", Justification = "<Pending>", Scope = "member", Target = "~P:Atata.UnitTests.GenericCollectionAssertionsExtensions.ReferenceEqualityComparer`1.Default")]
[assembly: SuppressMessage("Design", "CA1000:Do not declare static members on generic types", Justification = "<Pending>", Scope = "member", Target = "~M:Atata.UnitTests.DataProvision.DataVerificationProviderExtensionMethodTests.ExtensionMethodTestFixture`2.GetTestActions~System.Collections.Generic.IEnumerable{NUnit.Framework.TestCaseData}")]

#pragma warning restore S103 // Lines should not be too long

0 comments on commit 9198835

Please sign in to comment.