Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions Docs/pages/02-filters.md
Original file line number Diff line number Diff line change
Expand Up @@ -468,14 +468,17 @@ In addition to [access modifiers](#access-modifiers),
| handler of exact type | `.OfExactType<T>()` | `.IsOfExactType<T>()` | `.AreOfExactType<T>()` |
| abstract / sealed | `.WhichAreAbstract()` / `.WhichAreSealed()` | `.IsAbstract()` / `.IsSealed()` | `.AreAbstract()` / `.AreSealed()` |
| static | `.WhichAreStatic()` | `.IsStatic()` | `.AreStatic()` |
| virtual | `.WhichAreVirtual()` | `.IsVirtual()` | `.AreVirtual()` |
| override | `.WhichOverride()` | `.Overrides()` | `.Override()` |

The `OfType` / `IsOfType` / `AreOfType` filters and assertions match the event's handler type (its
`EventHandlerType`, e.g. `EventHandler<T>`); the `…ExactType` variants match only the exact handler type.
Use `OrOfType<T>()` / `OrOfExactType<T>()` to allow several handler types.

:::note[Negation]
The `abstract`, `sealed` and `static` rows have a negated form: `WhichAreNot…` on filters and
`IsNot…` / `AreNot…` on assertions (e.g. `WhichAreNotSealed()`, `IsNotSealed()`, `AreNotSealed()`).
The `abstract`, `sealed`, `static` and `virtual` rows have a negated form: `WhichAreNot…` on filters and
`IsNot…` / `AreNot…` on assertions (e.g. `WhichAreNotSealed()`, `IsNotSealed()`, `AreNotSealed()`);
`override` uses `WhichDoNotOverride()` / `DoesNotOverride()` / `DoNotOverride()`.
:::

```csharp
Expand Down
24 changes: 24 additions & 0 deletions Source/aweXpect.Reflection/Filters/EventFilters.WhichAreVirtual.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System.Reflection;
using aweXpect.Reflection.Collections;
using aweXpect.Reflection.Helpers;

namespace aweXpect.Reflection;

public static partial class EventFilters
{
/// <summary>
/// Filters for events that are virtual.
/// </summary>
public static Filtered.Events WhichAreVirtual(this Filtered.Events @this)
=> @this.Which(Filter.Prefix<EventInfo>(
eventInfo => eventInfo.IsReallyVirtual(),
"virtual "));

/// <summary>
/// Filters for events that are not virtual.
/// </summary>
public static Filtered.Events WhichAreNotVirtual(this Filtered.Events @this)
=> @this.Which(Filter.Prefix<EventInfo>(
eventInfo => !eventInfo.IsReallyVirtual(),
"non-virtual "));
}
24 changes: 24 additions & 0 deletions Source/aweXpect.Reflection/Filters/EventFilters.WhichOverride.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System.Reflection;
using aweXpect.Reflection.Collections;
using aweXpect.Reflection.Helpers;

namespace aweXpect.Reflection;

public static partial class EventFilters
{
/// <summary>
/// Filters for events that override a base class event.
/// </summary>
public static Filtered.Events WhichOverride(this Filtered.Events @this)
=> @this.Which(Filter.Suffix<EventInfo>(
eventInfo => eventInfo.IsOverride(),
"which override a base event "));

/// <summary>
/// Filters for events that do not override a base class event.
/// </summary>
public static Filtered.Events WhichDoNotOverride(this Filtered.Events @this)
=> @this.Which(Filter.Suffix<EventInfo>(
eventInfo => !eventInfo.IsOverride(),
"which do not override a base event "));
}
16 changes: 16 additions & 0 deletions Source/aweXpect.Reflection/Helpers/EventInfoHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,22 @@ public static bool IsReallyAbstract(this EventInfo? eventInfo)
public static bool IsReallySealed(this EventInfo? eventInfo)
=> eventInfo?.AddMethod?.IsFinal == true;

/// <summary>
/// Checks if the <paramref name="eventInfo" /> is virtual (based on its accessor methods).
/// </summary>
/// <param name="eventInfo">The <see cref="EventInfo" /> to check.</param>
/// <returns><see langword="true" /> if the event is virtual; otherwise, <see langword="false" />.</returns>
public static bool IsReallyVirtual(this EventInfo? eventInfo)
=> eventInfo?.AddMethod?.IsVirtual == true;

/// <summary>
/// Checks if the <paramref name="eventInfo" /> overrides a base class event (based on its accessor methods).
/// </summary>
/// <param name="eventInfo">The <see cref="EventInfo" /> to check.</param>
/// <returns><see langword="true" /> if the event overrides a base class event; otherwise, <see langword="false" />.</returns>
public static bool IsOverride(this EventInfo? eventInfo)
=> eventInfo?.AddMethod.IsOverride() == true;

/// <summary>
/// Checks if the <paramref name="eventInfo" /> is static (based on its accessor methods).
/// </summary>
Expand Down
59 changes: 59 additions & 0 deletions Source/aweXpect.Reflection/ThatEvent.IsVirtual.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System.Reflection;
using System.Text;
using aweXpect.Core;
using aweXpect.Core.Constraints;
using aweXpect.Reflection.Helpers;
using aweXpect.Results;

namespace aweXpect.Reflection;

public static partial class ThatEvent
{
/// <summary>
/// Verifies that the <see cref="EventInfo" /> is virtual.
/// </summary>
public static AndOrResult<EventInfo?, IThat<EventInfo?>> IsVirtual(
this IThat<EventInfo?> subject)
=> new(subject.Get().ExpectationBuilder.AddConstraint((it, grammars)
=> new IsVirtualConstraint(it, grammars)),
subject);

/// <summary>
/// Verifies that the <see cref="EventInfo" /> is not virtual.
/// </summary>
public static AndOrResult<EventInfo?, IThat<EventInfo?>> IsNotVirtual(
this IThat<EventInfo?> subject)
=> new(subject.Get().ExpectationBuilder.AddConstraint((it, grammars)
=> new IsVirtualConstraint(it, grammars).Invert()),
subject);

private sealed class IsVirtualConstraint(string it, ExpectationGrammars grammars)
: ConstraintResult.WithNotNullValue<EventInfo?>(it, grammars),
IValueConstraint<EventInfo?>
{
public ConstraintResult IsMetBy(EventInfo? actual)
{
Actual = actual;
Outcome = actual.IsReallyVirtual() ? Outcome.Success : Outcome.Failure;
return this;
}

protected override void AppendNormalExpectation(StringBuilder stringBuilder, string? indentation = null)
=> stringBuilder.Append("is virtual");

protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(It).Append(" was non-virtual ");
Formatter.Format(stringBuilder, Actual);
}

protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
=> stringBuilder.Append("is not virtual");

protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(It).Append(" was virtual ");
Formatter.Format(stringBuilder, Actual);
}
}
}
59 changes: 59 additions & 0 deletions Source/aweXpect.Reflection/ThatEvent.Overrides.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System.Reflection;
using System.Text;
using aweXpect.Core;
using aweXpect.Core.Constraints;
using aweXpect.Reflection.Helpers;
using aweXpect.Results;

namespace aweXpect.Reflection;

public static partial class ThatEvent
{
/// <summary>
/// Verifies that the <see cref="EventInfo" /> overrides a base class event.
/// </summary>
public static AndOrResult<EventInfo?, IThat<EventInfo?>> Overrides(
this IThat<EventInfo?> subject)
=> new(subject.Get().ExpectationBuilder.AddConstraint((it, grammars)
=> new OverridesConstraint(it, grammars)),
subject);

/// <summary>
/// Verifies that the <see cref="EventInfo" /> does not override a base class event.
/// </summary>
public static AndOrResult<EventInfo?, IThat<EventInfo?>> DoesNotOverride(
this IThat<EventInfo?> subject)
=> new(subject.Get().ExpectationBuilder.AddConstraint((it, grammars)
=> new OverridesConstraint(it, grammars).Invert()),
subject);

private sealed class OverridesConstraint(string it, ExpectationGrammars grammars)
: ConstraintResult.WithNotNullValue<EventInfo?>(it, grammars),
IValueConstraint<EventInfo?>
{
public ConstraintResult IsMetBy(EventInfo? actual)
{
Actual = actual;
Outcome = actual.IsOverride() ? Outcome.Success : Outcome.Failure;
return this;
}

protected override void AppendNormalExpectation(StringBuilder stringBuilder, string? indentation = null)
=> stringBuilder.Append("overrides a base event");

protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(It).Append(" did not override a base event ");
Formatter.Format(stringBuilder, Actual);
}

protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
=> stringBuilder.Append("does not override a base event");

protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(It).Append(" did override a base event ");
Formatter.Format(stringBuilder, Actual);
}
}
}
128 changes: 128 additions & 0 deletions Source/aweXpect.Reflection/ThatEvents.AreVirtual.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using aweXpect.Core;
using aweXpect.Core.Constraints;
using aweXpect.Reflection.Helpers;
using aweXpect.Results;
#if NET8_0_OR_GREATER
using System.Threading;
using System.Threading.Tasks;
#endif

// ReSharper disable PossibleMultipleEnumeration

namespace aweXpect.Reflection;

public static partial class ThatEvents
{
/// <summary>
/// Verifies that all items in the filtered collection of <see cref="EventInfo" /> are virtual.
/// </summary>
public static AndOrResult<IEnumerable<EventInfo?>, IThat<IEnumerable<EventInfo?>>> AreVirtual(
this IThat<IEnumerable<EventInfo?>> subject)
=> new(subject.Get().ExpectationBuilder.AddConstraint<IEnumerable<EventInfo?>>((it, grammars)
=> new AreVirtualConstraint(it, grammars)),
subject);

#if NET8_0_OR_GREATER
/// <summary>
/// Verifies that all items in the filtered collection of <see cref="EventInfo" /> are virtual.
/// </summary>
public static AndOrResult<IAsyncEnumerable<EventInfo?>, IThat<IAsyncEnumerable<EventInfo?>>> AreVirtual(
this IThat<IAsyncEnumerable<EventInfo?>> subject)
=> new(subject.Get().ExpectationBuilder.AddConstraint<IAsyncEnumerable<EventInfo?>>((it, grammars)
=> new AreVirtualConstraint(it, grammars)),
subject);
#endif

/// <summary>
/// Verifies that all items in the filtered collection of <see cref="EventInfo" /> are not virtual.
/// </summary>
public static AndOrResult<IEnumerable<EventInfo?>, IThat<IEnumerable<EventInfo?>>> AreNotVirtual(
this IThat<IEnumerable<EventInfo?>> subject)
=> new(subject.Get().ExpectationBuilder.AddConstraint<IEnumerable<EventInfo?>>((it, grammars)
=> new AreNotVirtualConstraint(it, grammars)),
subject);

#if NET8_0_OR_GREATER
/// <summary>
/// Verifies that all items in the filtered collection of <see cref="EventInfo" /> are not virtual.
/// </summary>
public static AndOrResult<IAsyncEnumerable<EventInfo?>, IThat<IAsyncEnumerable<EventInfo?>>> AreNotVirtual(
this IThat<IAsyncEnumerable<EventInfo?>> subject)
=> new(subject.Get().ExpectationBuilder.AddConstraint<IAsyncEnumerable<EventInfo?>>((it, grammars)
=> new AreNotVirtualConstraint(it, grammars)),
subject);
#endif

private sealed class AreVirtualConstraint(string it, ExpectationGrammars grammars)
: CollectionConstraintResult<EventInfo?>(grammars),
IValueConstraint<IEnumerable<EventInfo?>>
#if NET8_0_OR_GREATER
, IAsyncConstraint<IAsyncEnumerable<EventInfo?>>
#endif
{
#if NET8_0_OR_GREATER
public async Task<ConstraintResult> IsMetBy(IAsyncEnumerable<EventInfo?> actual,
CancellationToken cancellationToken)
=> await SetAsyncValue(actual, @event => @event.IsReallyVirtual());
#endif

public ConstraintResult IsMetBy(IEnumerable<EventInfo?> actual)
=> SetValue(actual, @event => @event.IsReallyVirtual());

protected override void AppendNormalExpectation(StringBuilder stringBuilder, string? indentation = null)
=> stringBuilder.Append("are all virtual");

protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(it).Append(" contained non-virtual events ");
Formatter.Format(stringBuilder, NotMatching, FormattingOptions.Indented(indentation));
}

protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
=> stringBuilder.Append("are not all virtual");

protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(it).Append(" only contained virtual events ");
Formatter.Format(stringBuilder, Matching, FormattingOptions.Indented(indentation));
}
}

private sealed class AreNotVirtualConstraint(string it, ExpectationGrammars grammars)
: CollectionConstraintResult<EventInfo?>(grammars),
IValueConstraint<IEnumerable<EventInfo?>>
#if NET8_0_OR_GREATER
, IAsyncConstraint<IAsyncEnumerable<EventInfo?>>
#endif
{
#if NET8_0_OR_GREATER
public async Task<ConstraintResult> IsMetBy(IAsyncEnumerable<EventInfo?> actual,
CancellationToken cancellationToken)
=> await SetAsyncValue(actual, @event => !@event.IsReallyVirtual());
#endif

public ConstraintResult IsMetBy(IEnumerable<EventInfo?> actual)
=> SetValue(actual, @event => !@event.IsReallyVirtual());

protected override void AppendNormalExpectation(StringBuilder stringBuilder, string? indentation = null)
=> stringBuilder.Append("are all not virtual");

protected override void AppendNormalResult(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(it).Append(" contained virtual events ");
Formatter.Format(stringBuilder, NotMatching, FormattingOptions.Indented(indentation));
}

protected override void AppendNegatedExpectation(StringBuilder stringBuilder, string? indentation = null)
=> stringBuilder.Append("also contain a virtual event");

protected override void AppendNegatedResult(StringBuilder stringBuilder, string? indentation = null)
{
stringBuilder.Append(it).Append(" only contained non-virtual events ");
Formatter.Format(stringBuilder, Matching, FormattingOptions.Indented(indentation));
}
}
}
Loading
Loading