protected static Task TestWithRobot <TResourceNamespace>(
            Func <S101Client, Task> testCallback,
            IS101Logger consumerLogger,
            IS101Logger providerLogger,
            EmberTypeBag types,
            bool sendFirstMessage,
            string logXmlName,
            params object[] args)
        {
            var xml = string.Format(CultureInfo.InvariantCulture, GetContent <TResourceNamespace>(logXmlName), args);

            return(TestNoExceptionsAsync(
                       async(consumerClientTask, providerClient) =>
            {
                using (var reader = new StringReader(xml))
                    using (var xmlReader = XmlReader.Create(reader))
                    {
                        var robotTask = S101Robot.RunAsync(providerClient, types, xmlReader, sendFirstMessage);

                        using (var consumerClient = await consumerClientTask)
                        {
                            var testTask = testCallback(consumerClient);

                            // The following lines ensure that exceptions thrown from either testTask or robotTask are
                            // immediately propagated up the call chain to fail the test. It also makes sure that
                            // both tasks complete when the first completed task did not throw an exception.
                            await await Task.WhenAny(testTask, robotTask);
                            await Task.WhenAll(testTask, robotTask);
                        }
                    }
            },
                       () => ConnectAsync(-1, consumerLogger),
                       () => WaitForConnectionAsync(providerLogger)));
        }
        /// <summary>Asynchronously waits for a S101 connection to port 8099.</summary>
        protected static async Task <S101Client> WaitForConnectionAsync(IS101Logger logger)
        {
            var tcpClient = await WaitForConnectionAsync();

            var stream = tcpClient.GetStream();

            return(new S101Client(tcpClient, stream.ReadAsync, stream.WriteAsync, logger, -1, 8192));
        }
        protected static async Task <S101Client> ConnectAsync(int timeout, IS101Logger logger)
        {
            var tcpClient = new TcpClient();
            await tcpClient.ConnectAsync("localhost", 8099);

            var stream = tcpClient.GetStream();

            return(new S101Client(tcpClient, stream.ReadAsync, stream.WriteAsync, logger, timeout, 8192));
        }
        /// <summary>Gets a <see cref="S101Client"/> object, which receives the message contained in
        /// <paramref name="messageStream"/> as soon as a message has been sent by calling
        /// <see cref="S101Client.SendMessageAsync(S101Message)"/>.</summary>
        protected static S101Client GetFakeClient(Stream messageStream, IS101Logger logger)
        {
            var disposable      = new CompleteOnDispose();
            var requestReceived = new TaskCompletionSource <bool>();

            ReadAsyncCallback read =
                async(b, o, c, t) =>
            {
                await requestReceived.Task;
                return(await Read(messageStream, b, o, c, t, disposable.Task));
            };

            WriteAsyncCallback write =
                (b, o, c, t) =>
            {
                requestReceived.SetResult(true);
                return(Task.FromResult(false));
            };

            return(new S101Client(disposable, read, write, logger, -1, 8192));
        }
        public S101Client(
            IDisposable connection,
            ReadAsyncCallback readAsync,
            WriteAsyncCallback writeAsync,
            IS101Logger logger,
            int timeout,
            int bufferSize)
        {
            ReadAsyncCallback readAsyncWithLog;

            using (var connectionGuard = ScopeGuard.Create(connection))
                using (var loggerGuard = ScopeGuard.Create(logger))
                {
                    if (SynchronizationContext.Current == null)
                    {
                        throw new NotSupportedException(
                                  "S101Client is not supported when SynchronizationContext.Current == null");
                    }

                    if (connection == null)
                    {
                        throw new ArgumentNullException(nameof(connection));
                    }

                    if (readAsync == null)
                    {
                        throw new ArgumentNullException(nameof(readAsync));
                    }

                    if (writeAsync == null)
                    {
                        throw new ArgumentNullException(nameof(writeAsync));
                    }

                    if (timeout < -1)
                    {
                        throw new ArgumentOutOfRangeException(nameof(timeout), "A number >= -1 is required.");
                    }

                    WriteAsyncCallback writeAsyncWithLog;

                    if (logger == null)
                    {
                        readAsyncWithLog  = readAsync;
                        writeAsyncWithLog = writeAsync;
                    }
                    else
                    {
                        const string Type = "RawData";

                        readAsyncWithLog =
                            async(b, o, c, t) =>
                        {
                            var read = await readAsync(b, o, c, t);

                            await this.logQueue.Enqueue(() => this.logger.LogData(Type, LogNames.Receive, b, o, read));

                            return(read);
                        };

                        writeAsyncWithLog =
                            async(b, o, c, t) =>
                        {
                            await this.logQueue.Enqueue(() => this.logger.LogData(Type, LogNames.Send, b, o, c));
                            await writeAsync(b, o, c, t);
                        };
                    }

                    this.threadId = NativeMethods.GetCurrentThreadId();
                    this.writer   = new S101Writer(writeAsyncWithLog, bufferSize);
                    this.logger   = logger;
                    this.timeout  = timeout;
                    connectionGuard.Dismiss();
                    loggerGuard.Dismiss();
                }

            this.ReadLoop(connection, new S101Reader(readAsyncWithLog, bufferSize));
        }
 public S101Client(
     IDisposable connection, ReadAsyncCallback readAsync, WriteAsyncCallback writeAsync, IS101Logger logger)
     : this(connection, readAsync, writeAsync, logger, 3000, 8192)
 {
 }