public async Task GivenSequencesWithAPreviousAndTargetSequenceThenTheReconcilerIsInvokedOnceForEachAggregateAboveThePreviousAndBelowTheTargetSequenceAsync()
        {
            const int ExpectedInvocations = 1;
            int       eventsReconciling   = 0;
            int       eventsReconciled    = 0;

            SequencedEvents[] sequences = new[]
            {
                new SequencedEvents(1, CreateEvents()),
                new SequencedEvents(2, CreateEvents()),
                new SequencedEvents(3, CreateEvents()),
                new SequencedEvents(4, CreateEvents()),
                new SequencedEvents(5, CreateEvents()),
            };

            ulong previous = 1;
            ulong target   = 4;

            SequencedEvents[] expected = sequences
                                         .Where(aggregate => aggregate.Sequence > previous && aggregate.Sequence <= target)
                                         .ToArray();

            var aggregates = expected.ToDictionary(sequence => sequence.Aggregate, sequence => 0);

            _ = EventStore
                .Setup(store => store.ReadAsync(
                           It.Is <ulong>(value => value == previous),
                           It.IsAny <CancellationToken?>(),
                           It.IsAny <ushort>()))
                .ReturnsAsync(expected);

            _ = EventStore
                .Setup(store => store.ReadAsync(
                           It.Is <ulong>(value => value > previous),
                           It.IsAny <CancellationToken?>(),
                           It.IsAny <ushort>()))
                .ReturnsAsync(Enumerable.Empty <SequencedEvents>());

            _ = Reconciler
                .Setup(reconciler => reconciler.ReconcileAsync(
                           It.IsAny <IEnumerable <DomainEvent> >(),
                           It.IsAny <CancellationToken?>()))
                .Callback <IEnumerable <DomainEvent>, CancellationToken?>((value, _) => aggregates[value.First().Aggregate]++);

            instance.EventsReconciling += (sender, e) => Task.FromResult(eventsReconciling++);
            instance.EventsReconciled  += (sender, e) => Task.FromResult(eventsReconciled++);

            _ = await instance.ReconcileAsync(previous : previous, target : target);

            int invocations = expected.Length;
            int skips       = sequences.Length - invocations;

            Assert.Equal(invocations, eventsReconciling);
            Assert.Equal(invocations, eventsReconciled);
            Assert.All(aggregates.Values, value => Assert.Equal(ExpectedInvocations, value));
        }
        public async Task GivenSequencesThenTheReconcilerIsInvokedOnceForEachAggregate()
        {
            const int ExpectedInvocations = 1;
            int       eventsReconciling   = 0;
            int       eventsReconciled    = 0;

            SequencedEvents[] sequences = new[]
            {
                new SequencedEvents(1, CreateEvents()),
                new SequencedEvents(2, CreateEvents()),
                new SequencedEvents(3, CreateEvents()),
            };

            var aggregates = sequences.ToDictionary(sequence => sequence.Aggregate, sequence => 0);

            _ = EventStore
                .Setup(store => store.ReadAsync(
                           It.Is <ulong>(value => value == ulong.MinValue),
                           It.IsAny <CancellationToken?>(),
                           It.IsAny <ushort>()))
                .ReturnsAsync(sequences);

            _ = EventStore
                .Setup(store => store.ReadAsync(
                           It.Is <ulong>(value => value > ulong.MinValue),
                           It.IsAny <CancellationToken?>(),
                           It.IsAny <ushort>()))
                .ReturnsAsync(Enumerable.Empty <SequencedEvents>());

            _ = Reconciler
                .Setup(reconciler => reconciler.ReconcileAsync(
                           It.IsAny <IEnumerable <DomainEvent> >(),
                           It.IsAny <CancellationToken?>()))
                .Callback <IEnumerable <DomainEvent>, CancellationToken?>((value, _) => aggregates[value.First().Aggregate]++);

            instance.EventsReconciling += (sender, e) => Task.FromResult(eventsReconciling++);
            instance.EventsReconciled  += (sender, e) => Task.FromResult(eventsReconciled++);

            _ = await instance.ReconcileAsync();

            Assert.Equal(sequences.Length, eventsReconciling);
            Assert.Equal(sequences.Length, eventsReconciled);
            Assert.All(aggregates.Values, value => Assert.Equal(ExpectedInvocations, value));
        }