public async Task Subscribe_AfterUnsubscribing_CreatesNewReader(
            string topic,
            IDisposableBlockingRawMessageReader <IPollingOptions> reader,
            [Frozen] IPollingOptions options,
            [Frozen] IRawMessageHandler rawMessageHandler,
            [Frozen] IBlockingRawMessageReaderFactory <IPollingOptions> factory,
            BlockingReaderRawMessageHandlerSubscriber <IPollingOptions> sut)
        {
            // Arrange
            factory.Create(topic, options).Returns(reader);

            var disposeEvent = new ManualResetEventSlim();

            reader.When(r => r.Dispose()).Do(r => disposeEvent.Set());

            // Act
            await sut.Subscribe(topic, rawMessageHandler, None);

            await sut.Unsubscribe(topic, rawMessageHandler, None);

            Assert.True(disposeEvent.Wait(1000)); // wait task complete
            await sut.Subscribe(topic, rawMessageHandler, None);

            // Assert
            factory.Received(2).Create(topic, options);
        }
        public async Task Unsubscribe_DifferentTopics_DisposesSingleReader(
            string firstTopic,
            string secondTopic,
            IDisposableBlockingRawMessageReader <IPollingOptions> firstReader,
            IDisposableBlockingRawMessageReader <IPollingOptions> secondReader,
            [Frozen] IPollingOptions options,
            IRawMessageHandler firstRawMessageHandler,
            IRawMessageHandler secondRawMessageHandler,
            [Frozen] IBlockingRawMessageReaderFactory <IPollingOptions> factory,
            BlockingReaderRawMessageHandlerSubscriber <IPollingOptions> sut)
        {
            // Arrange
            factory.Create(firstTopic, options).Returns(firstReader);
            factory.Create(secondTopic, options).Returns(secondReader);

            var disposeEvent = new ManualResetEventSlim();

            firstReader.When(r => r.Dispose()).Do(r => disposeEvent.Set());

            // Act
            await sut.Subscribe(firstTopic, firstRawMessageHandler, None);

            await sut.Subscribe(secondTopic, secondRawMessageHandler, None);

            await sut.Unsubscribe(firstTopic, firstRawMessageHandler, None);

            // Assert
            Assert.True(disposeEvent.Wait(1000));
            secondReader.DidNotReceive().Dispose();
        }
        public async Task Subscribe_CallbackRethrows_UnsubscribeDoesNotFailAwait(
            string topic,
            [Frozen] IPollingOptions options,
            [Frozen] IRawMessageHandler rawMessageHandler,
            BlockingReaderRawMessageHandlerSubscriber <IPollingOptions> sut)
        {
            // Arrange
            options.ReaderStoppingCallback = (s, handler, ex) => throw ex;

            // Act
            await sut.Subscribe(topic, rawMessageHandler, None);

            // await doesn't throw on OperationCancelledException
            await sut.Unsubscribe(topic, rawMessageHandler, None);
        }
        public async Task Subscribe_CallbackNull_DoesntThrow(
            string topic,
            IDisposableBlockingRawMessageReader <IPollingOptions> reader,
            [Frozen] IPollingOptions options,
            [Frozen] IRawMessageHandler rawMessageHandler,
            BlockingReaderRawMessageHandlerSubscriber <IPollingOptions> sut)
        {
            // Arrange
            options.ReaderStoppingCallback = null;
            options.ErrorCallback          = null;
            reader.TryGetMessage(out var _, options).Throws <DivideByZeroException>();

            // Act
            await sut.Subscribe(topic, rawMessageHandler, None);

            // await doesn't throw on OperationCancelledException
            await sut.Unsubscribe(topic, rawMessageHandler, None);
        }
        public async Task Unsubscribe_CallbackInvoked(
            string topic,
            IDisposableBlockingRawMessageReader <IPollingOptions> reader,
            [Frozen] IPollingOptions options,
            [Frozen] IRawMessageHandler rawMessageHandler,
            [Frozen] IBlockingRawMessageReaderFactory <IPollingOptions> factory,
            BlockingReaderRawMessageHandlerSubscriber <IPollingOptions> sut)
        {
            // Arrange
            var callbackInvokedEvent = new ManualResetEventSlim();

            options.ReaderStoppingCallback = (t, handler, arg3) => callbackInvokedEvent.Set();
            factory.Create(topic, options).Returns(reader);

            // Act
            await sut.Subscribe(topic, rawMessageHandler, None);

            await sut.Unsubscribe(topic, rawMessageHandler, None);

            // Assert
            Assert.True(callbackInvokedEvent.Wait(1000));
        }