Table of Contents

Class HasLoggedSequenceAssertion

Namespace
LogAssertions.TUnit
Assembly
LogAssertions.TUnit.dll

TUnit assertion that verifies a Microsoft.Extensions.Logging.Testing.FakeLogCollector contains a sequence of matching log records, in order. Each step is built from the same filter chain as HasLoggedAssertion (AtLevel, Containing, etc.); call Then() to commit the current step and start the next strictly-ordered step, or ThenAnyOrder(params Action<HasLoggedSequenceAssertion>[]) to commit a concurrent group whose sub-steps must all occur but in any order.

[AssertionExtension("HasLoggedSequence")]
public sealed class HasLoggedSequenceAssertion : LogAssertionBase<HasLoggedSequenceAssertion>, IAssertion
Inheritance
Assertion<FakeLogCollector>
HasLoggedSequenceAssertion
Implements
IAssertion
Inherited Members
Assertion<FakeLogCollector>.AssertAsync()
Assertion<FakeLogCollector>.GetAwaiter()
Assertion<FakeLogCollector>.And
Assertion<FakeLogCollector>.Or

Examples

await Assert.That(collector).HasLoggedSequence()
    .AtLevel(LogLevel.Information).Containing("Started")
    .Then().AtLevel(LogLevel.Warning).Containing("validation failed")
    .Then().AtLevel(LogLevel.Information).Containing("Stopped");

Each step matches the first subsequent record satisfying its filters; records between matches are skipped (sequence is order-preserving but not contiguous).

Constructors

HasLoggedSequenceAssertion(AssertionContext<FakeLogCollector>)

Initialises a sequence assertion. Called by the TUnit source generator.

public HasLoggedSequenceAssertion(AssertionContext<FakeLogCollector> context)

Parameters

context AssertionContext<FakeLogCollector>

The assertion context supplied by TUnit.

Methods

AddFilter(ILogRecordFilter)

Records a filter. Default implementation appends to the shared filter chain used by single-match assertions; HasLoggedSequenceAssertion overrides this to route filters into the current sequence step.

protected override void AddFilter(ILogRecordFilter filter)

Parameters

filter ILogRecordFilter

The filter to add.

Exceptions

ArgumentNullException

filter is null.

CheckAsync(EvaluationMetadata<FakeLogCollector>)

Implements the specific check logic for this assertion. Called after the context has been evaluated. Override this method if your assertion uses the default AssertAsync() flow. If you override AssertAsync() with custom logic (like AndAssertion/OrAssertion), you don't need to implement this.

protected override Task<AssertionResult> CheckAsync(EvaluationMetadata<FakeLogCollector> metadata)

Parameters

metadata EvaluationMetadata<FakeLogCollector>

Metadata about the evaluation including value, exception, and timing information

Returns

Task<AssertionResult>

The result of the assertion check

GetExpectation()

Gets a human-readable description of what this assertion expects. Used in error messages.

protected override string GetExpectation()

Returns

string

Then()

Commits the current step's filters and starts a new strictly-ordered step. The next filter call adds to the new step. An empty step (a Then() call with no subsequent filter calls before the next Then() or terminator) is a no-op during evaluation: it neither matches nor consumes a record. This keeps multi-step chains like .AtLevel(Info).Then().Then().AtLevel(Warning) matching exactly the records the filters describe, with the empty steps acting as inert separators.

public HasLoggedSequenceAssertion Then()

Returns

HasLoggedSequenceAssertion

This assertion for chaining.

Exceptions

InvalidOperationException

Called inside a ThenAnyOrder(params Action<HasLoggedSequenceAssertion>[]) sub-step configurator. Sub-step configurators describe filters for one concurrent group; structure the outer sequence at the top level instead.

ThenAnyOrder(params Action<HasLoggedSequenceAssertion>[])

Commits the current step and adds a concurrent group: all subSteps must match somewhere in the remaining records, but the order among them does not matter. Records that match no sub-step are skipped. Sub-steps are matched via backtracking, so any order-independent valid assignment is found if one exists: even when sub-step filters overlap (a broad filter never starves a more specific filter).

public HasLoggedSequenceAssertion ThenAnyOrder(params Action<HasLoggedSequenceAssertion>[] subSteps)

Parameters

subSteps Action<HasLoggedSequenceAssertion>[]

Configurators for each concurrent sub-step. Each receives the assertion and adds filter calls; the filters added during the configurator's invocation are captured as that sub-step's filters.

Returns

HasLoggedSequenceAssertion

This assertion for chaining.

Exceptions

ArgumentNullException

A required argument is null.

InvalidOperationException

Called inside another sub-step configurator, or a sub-step configurator calls Then() or ThenAnyOrder(params Action<HasLoggedSequenceAssertion>[]). Sub-step configurators must add filters only: outer sequence structure must be expressed at the top level, not inside a configurator.