public async Task StartShouldCreateWebSocketClient(
                [Frozen, Substitute] IGatewayUtilsFactory gatewayUtilsFactory,
                [Target] DefaultGatewayService gateway
                )
            {
                await gateway.StartAsync();

                gatewayUtilsFactory.Received().CreateWebSocketClient();
            }
            public async Task ShouldThrowIfCancelled(
                [Target] DefaultGatewayService gateway
                )
            {
                var         cancellationToken = new CancellationToken(true);
                Func <Task> func = () => gateway.Heartbeat(cancellationToken);

                await func.Should().ThrowAsync <OperationCanceledException>();
            }
            public async Task StartShouldCreateWorker(
                [Frozen, Substitute] ITimerFactory timerFactory,
                [Target] DefaultGatewayService gateway
                )
            {
                await gateway.StartAsync();

                timerFactory.Received().CreateTimer(Is((AsyncTimerCallback)gateway.Run), Is(0), Is("Gateway Master"));
            }
            public async Task ShouldThrowIfGatewayHasntBeenStarted(
                uint interval,
                [Target] DefaultGatewayService gateway
                )
            {
                Func <Task> func = () => gateway.StartHeartbeat(interval);

                await func.Should().ThrowAsync <OperationCanceledException>();
            }
            public async Task ShouldNotThrowIfNotCancelled(
                [Target] DefaultGatewayService gateway,
                CancellationToken cancellationToken
                )
            {
                Func <Task> func = () => gateway.Heartbeat(cancellationToken);

                await func.Should().NotThrowAsync <OperationCanceledException>();
            }
            public async Task StartShouldStartTheMasterWorker(
                [Frozen, Substitute] ITimer timer,
                [Target] DefaultGatewayService gateway
                )
            {
                await gateway.StartAsync();

                await timer.Received().Start();
            }
            public async Task StartShouldStartTheRxWorker(
                [Frozen, Substitute] IGatewayRxWorker rxWorker,
                [Target] DefaultGatewayService gateway
                )
            {
                await gateway.StartAsync();

                await rxWorker.Received().Start(Is(gateway));
            }
            public async Task StartShouldStartTheTxWorker(
                [Frozen, Substitute] IClientWebSocket clientWebSocket,
                [Frozen, Substitute] IGatewayTxWorker txWorker,
                [Target] DefaultGatewayService gateway
                )
            {
                await gateway.StartAsync();

                await txWorker.Received().Start(Is(gateway), Is(clientWebSocket));
            }
            public async Task StopShouldStopTheTxWorker(
                [Frozen, Substitute] IGatewayTxWorker txWorker,
                [Target] DefaultGatewayService gateway
                )
            {
                await gateway.StartAsync();

                await gateway.StopAsync();

                await txWorker.Received().Stop();
            }
            public async Task StopShouldAbortTheWebSocket(
                [Frozen, Substitute] IClientWebSocket clientWebSocket,
                [Target] DefaultGatewayService gateway
                )
            {
                await gateway.StartAsync();

                await gateway.StopAsync();

                clientWebSocket.Received().Abort();
            }
            public async Task ShouldCallTheRestartService(
                bool resume,
                [Frozen, Substitute] IGatewayRestartService restartService,
                [Target] DefaultGatewayService gateway
                )
            {
                var cancellationToken = new CancellationToken(false);

                await gateway.Restart(resume, cancellationToken);

                await restartService.Received().Restart(Is(gateway), Is(resume), Is(cancellationToken));
            }
            public async Task StopShouldSetIsReadyToFalse(
                [Frozen, Substitute] IGatewayTxWorker txWorker,
                [Frozen, Substitute] IGatewayUtilsFactory factory,
                [Target] DefaultGatewayService gateway
                )
            {
                gateway.IsReady = true;
                await gateway.StartAsync();

                await gateway.StopAsync();

                gateway.IsReady.Should().BeFalse();
            }
            public async Task RunShouldThrowIfTheGatewayWasStopped(
                [Target] DefaultGatewayService gateway
                )
            {
                var cancellationToken = new CancellationToken(false);

                await gateway.StartAsync();

                await gateway.StopAsync();

                Func <Task> func = () => gateway.Run();
                await func.Should().ThrowAsync <OperationCanceledException>();
            }
            public async Task ShouldThrowIfGatewayWasStopped(
                uint interval,
                [Target] DefaultGatewayService gateway
                )
            {
                var cancellationToken = new CancellationToken(false);

                await gateway.StartAsync();

                await gateway.StopAsync();

                Func <Task> func = () => gateway.StartHeartbeat(interval);

                await func.Should().ThrowAsync <OperationCanceledException>();
            }
            public async Task SendShouldEmitTheMessageToTheTxWorker(
                int sequenceNumber,
                [Frozen, Substitute] IGatewayTxWorker txWorker,
                [Target] DefaultGatewayService gateway
                )
            {
                var message = new GatewayMessage {
                    SequenceNumber = sequenceNumber
                };
                var cancellationToken = new CancellationToken(false);

                await gateway.StartAsync();

                await gateway.Send(message, cancellationToken);

                await txWorker.Received().Emit(Is(message), Is(cancellationToken));
            }
            public async Task RunShouldReceiveChunksFromTheWebSocket(
                [Frozen, Options] IOptions <GatewayOptions> options,
                [Frozen, Substitute] IClientWebSocket webSocket,
                [Frozen, Substitute] IGatewayRxWorker rxWorker,
                [Target] DefaultGatewayService gateway
                )
            {
                var cancellationToken = new CancellationToken(false);

                webSocket.Receive(Any <Memory <byte> >(), Any <CancellationToken>()).Returns(x => new ValueWebSocketReceiveResult(0, WebSocketMessageType.Text, true));

                await gateway.StartAsync();

                await gateway.Run(cancellationToken);

                await webSocket.Received().Receive(Any <Memory <byte> >(), Is(cancellationToken));
            }
            public async Task SendShouldThrowIfTheOperationWasCanceled(
                int sequenceNumber,
                [Frozen, Substitute] IGatewayTxWorker txWorker,
                [Target] DefaultGatewayService gateway
                )
            {
                var message = new GatewayMessage {
                    SequenceNumber = sequenceNumber
                };
                var cancellationToken = new CancellationToken(false);

                await gateway.StartAsync();

                var         operationCancellationToken = new CancellationToken(true);
                Func <Task> func = () => gateway.Send(message, operationCancellationToken);

                await func.Should().ThrowAsync <OperationCanceledException>();
            }
            public async Task ShouldSendAHeartbeatToTheTxWorker(
                int sequenceNumber,
                [Frozen, Substitute] IGatewayTxWorker txWorker,
                [Target] DefaultGatewayService gateway,
                CancellationToken cancellationToken
                )
            {
                gateway.SequenceNumber = sequenceNumber;
                await gateway.Heartbeat(cancellationToken);

                await txWorker.Received().Emit(
                    Is <GatewayMessage>(message =>
                                        message.OpCode == GatewayOpCode.Heartbeat &&
                                        (HeartbeatEvent?)message.Data == sequenceNumber
                                        ),
                    Any <CancellationToken>()
                    );
            }
            public async Task RunShouldNotConnectToTheWebSocketServerIfAlreadyConnected(
                [Frozen, Options] IOptions <GatewayOptions> options,
                [Frozen, Substitute] IClientWebSocket webSocket,
                [Frozen, Substitute] IGatewayRxWorker rxWorker,
                [Target] DefaultGatewayService gateway
                )
            {
                var cancellationToken = new CancellationToken(false);

                webSocket.State.Returns(WebSocketState.Open);
                webSocket.Receive(Any <Memory <byte> >(), Any <CancellationToken>()).Returns(x => new ValueWebSocketReceiveResult(0, WebSocketMessageType.Text, true));

                await gateway.StartAsync();

                await gateway.Run(cancellationToken);

                await webSocket.DidNotReceive().Connect(Is(options.Value.Uri), Is(cancellationToken));
            }
            public async Task StartShouldSetupGatewayToRestartOnUnexpectedStops(
                [Frozen, Substitute] IGatewayRestartService restartService,
                [Frozen, Substitute] ITimer worker,
                [Target] DefaultGatewayService gateway
                )
            {
                var cancellationToken = new CancellationToken(false);
                await gateway.StartAsync();

                worker.Received().StopOnException  = Is(true);
                worker.Received().OnUnexpectedStop = Any <OnUnexpectedTimerStop>();
                var arg = (from call in worker.ReceivedCalls()
                           where call.GetMethodInfo().Name.Contains(nameof(worker.OnUnexpectedStop))
                           select(OnUnexpectedTimerStop) call.GetArguments()[0]).First();

                await arg();

                await restartService.Received().Restart(Is(gateway), Is(true), Any <CancellationToken>());
            }
            public async Task ShouldStopSendingHeartbeatsToTheTxWorker(
                uint interval,
                int sequenceNumber,
                [Frozen] ITimer heartbeat,
                [Frozen, Substitute] IGatewayUtilsFactory factory,
                [Frozen, Substitute] IGatewayTxWorker txWorker,
                [Frozen, Substitute] ITimerFactory timerFactory,
                [Target] DefaultGatewayService gateway
                )
            {
                gateway.SequenceNumber = sequenceNumber;
                await gateway.StartAsync();

                await gateway.StartHeartbeat(interval);

                await gateway.StopHeartbeat();

                await heartbeat.Received().Stop();
            }
            public async Task StopShouldStopTheHeartbeat(
                ITimer heartbeat,
                [Frozen, Substitute] ITimerFactory timerFactory,
                [Frozen, Substitute] IGatewayTxWorker txWorker,
                [Frozen, Substitute] IGatewayUtilsFactory factory,
                [Target] DefaultGatewayService gateway
                )
            {
                var cancellationToken = new CancellationToken(false);

                timerFactory.CreateTimer(Any <AsyncTimerCallback>(), Any <int>(), Is("Heartbeat")).Returns(heartbeat);

                await gateway.StartAsync();

                await gateway.StartHeartbeat(10);

                await gateway.StopAsync();

                await heartbeat.Received().Stop();
            }
            public async Task ShouldStartSendingAHeartbeatToTheTxWorker(
                uint interval,
                int sequenceNumber,
                [Frozen] ITimer timer,
                [Frozen, Substitute] IGatewayUtilsFactory factory,
                [Frozen, Substitute] IGatewayTxWorker txWorker,
                [Frozen, Substitute] ITimerFactory timerFactory,
                [Target] DefaultGatewayService gateway
                )
            {
                var cancellationToken = new CancellationToken(false);

                gateway.SequenceNumber = sequenceNumber;
                await gateway.StartAsync();

                await gateway.StartHeartbeat(interval);

                timerFactory.Received().CreateTimer(Is <AsyncTimerCallback>(gateway.Heartbeat), Is((int)interval), Is("Heartbeat"));
                await timer.Received().Start();
            }
            public async Task RunShouldEmitMessageChunksToTheRxWorker(
                string messageChunk,
                [Frozen] CancellationTokenSource cancellationTokenSource,
                [Frozen, Options] IOptions <GatewayOptions> options,
                [Frozen, Substitute] IClientWebSocket webSocket,
                [Frozen, Substitute] IGatewayRxWorker rxWorker,
                [Target] DefaultGatewayService gateway
                )
            {
                var buffer            = new byte[messageChunk.Length];
                var memoryBuffer      = new Memory <byte>(buffer);
                var cancellationToken = new CancellationToken(false);

                gateway.SetPrivateField("buffer", buffer);
                gateway.SetPrivateField("memoryBuffer", memoryBuffer);

                webSocket.Receive(Any <Memory <byte> >(), Any <CancellationToken>()).Returns(x =>
                {
                    var buffer = x.ArgAt <Memory <byte> >(0);
                    ((Memory <byte>)Encoding.UTF8.GetBytes(messageChunk)).CopyTo(buffer);
                    return(new ValueWebSocketReceiveResult(messageChunk.Length, WebSocketMessageType.Text, true));
                });

                await gateway.StartAsync();

                await gateway.Run(cancellationToken);

                await rxWorker.Received().Emit(
                    Is <GatewayMessageChunk>(chunk =>
                                             Encoding.UTF8.GetString(chunk.Bytes.ToArray()) == messageChunk &&
                                             chunk.Count == messageChunk.Length &&
                                             chunk.EndOfMessage
                                             ),
                    Is(cancellationToken)
                    );
            }