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 Dispose_DisposesAllReaders(
            string topic,
            IDisposableBlockingRawMessageReader <IPollingOptions> firstReader,
            IDisposableBlockingRawMessageReader <IPollingOptions> secondReader,
            [Frozen] IPollingOptions options,
            IRawMessageHandler firstRawMessageHandler,
            IRawMessageHandler secondRawMessageHandler,
            [Frozen] IBlockingRawMessageReaderFactory <IPollingOptions> factory,
            BlockingReaderRawMessageHandlerSubscriber <IPollingOptions> sut)
        {
            // Arrange
            factory.Create(topic, options).Returns(firstReader, secondReader);

            var firstDisposeEvent = new ManualResetEventSlim();

            firstReader.When(r => r.Dispose()).Do(r => firstDisposeEvent.Set());
            var secondDisposeEvent = new ManualResetEventSlim();

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

            await sut.Subscribe(topic, firstRawMessageHandler, None);

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

            // Act
            sut.Dispose();

            // Assert
            Assert.True(firstDisposeEvent.Wait(1000));
            Assert.True(secondDisposeEvent.Wait(1000));
        }
        public async Task Subscribe_HandlerThrows_DisposesReader(
            string topic,
            byte[] message,
            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());

            reader.TryGetMessage(out var _, options)
            .Returns(r =>
            {
                r[0] = message;
                return(true);
            });

            rawMessageHandler.Handle(topic, message, Arg.Any <CancellationToken>())
            .Throws <ArgumentNullException>();

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

            // Assert
            Assert.True(disposeEvent.Wait(1000));
        }
        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_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 Subscribe_ReaderThrows_DisposesReader(
            string topic,
            IRawMessageHandler rawMessageHandler,
            IDisposableBlockingRawMessageReader <IPollingOptions> reader,
            [Frozen] IPollingOptions options,
            [Frozen] IBlockingRawMessageReaderFactory <IPollingOptions> factory,
            BlockingReaderRawMessageHandlerSubscriber <IPollingOptions> sut)
        {
            factory.Create(topic, options).Returns(reader);

            var disposeEvent = new ManualResetEventSlim();

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

            reader.TryGetMessage(out var _, options)
            .Throws <ArgumentNullException>();

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

            Assert.True(disposeEvent.Wait(1000));
        }
        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));
        }