/// <summary>
        /// Decode the <see cref="Tes.Net.ServerInfoMessage" /> packet.
        /// </summary>
        /// <param name="packet">The packet containing a <c>ServerInfoMessage</c></param>
        private void HandleServerInfo(PacketBuffer packet)
        {
            NetworkReader     packetReader = new NetworkReader(packet.CreateReadStream(true));
            ServerInfoMessage serverInfo   = new ServerInfoMessage();

            if (serverInfo.Read(packetReader))
            {
                _defaultFrameTime = serverInfo.DefaultFrameTime;
                _timeUnit         = serverInfo.TimeUnit;
            }
        }
        static void ValidateClient(TcpClient socket, Shape reference, ServerInfoMessage serverInfo, CreateShapeFunction createShape, ShapeValidationFunction validate, uint timeoutSec = 10u)
        {
            Stopwatch                    timer          = new Stopwatch();
            ServerInfoMessage            readServerInfo = new ServerInfoMessage();
            Dictionary <ulong, Resource> resources      = new Dictionary <ulong, Resource>();
            PacketBuffer                 packetBuffer   = new PacketBuffer(64 * 1024);
            Shape shape          = createShape();
            bool  endMsgReceived = false;
            bool  serverInfoRead = false;
            bool  shapeMsgRead   = false;

            timer.Start();

            // Keep looping until we get a CIdEnd ControlMessage or timeoutSec elapses.
            // Timeout ignored when debugger is attached.
            while (!endMsgReceived && (Debugger.IsAttached || timer.ElapsedMilliseconds / 1000u < timeoutSec))
            {
                if (socket.Available <= 0)
                {
                    Thread.Yield();
                    continue;
                }

                // Data available. Read from the network stream into a buffer and attempt to
                // read a valid message.
                packetBuffer.Append(socket.GetStream(), socket.Available);

                PacketBuffer completedPacket;
                bool         crcOk = true;
                while ((completedPacket = packetBuffer.PopPacket(out crcOk)) != null || !crcOk)
                {
                    Assert.True(crcOk);
                    if (crcOk)
                    {
                        if (packetBuffer.DroppedByteCount != 0)
                        {
                            Console.Error.WriteLine("Dropped {0} bad bytes", packetBuffer.DroppedByteCount);
                            packetBuffer.DroppedByteCount = 0;
                        }

                        Assert.Equal(PacketHeader.PacketMarker, completedPacket.Header.Marker);
                        Assert.Equal(PacketHeader.PacketVersionMajor, completedPacket.Header.VersionMajor);
                        Assert.Equal(PacketHeader.PacketVersionMinor, completedPacket.Header.VersionMinor);

                        NetworkReader packetReader = new NetworkReader(completedPacket.CreateReadStream(true));

                        switch (completedPacket.Header.RoutingID)
                        {
                        case (int)RoutingID.ServerInfo:
                            serverInfoRead = true;
                            Assert.True(readServerInfo.Read(packetReader));

                            // Validate server info.
                            Assert.Equal(serverInfo.TimeUnit, readServerInfo.TimeUnit);
                            Assert.Equal(serverInfo.DefaultFrameTime, readServerInfo.DefaultFrameTime);
                            Assert.Equal(serverInfo.CoordinateFrame, readServerInfo.CoordinateFrame);

                            unsafe
                            {
                                for (int i = 0; i < ServerInfoMessage.ReservedBytes; ++i)
                                {
                                    Assert.Equal(serverInfo.Reserved[i], readServerInfo.Reserved[i]);
                                }
                            }
                            break;

                        case (int)RoutingID.Control:
                        {
                            // Only interested in the CIdEnd message to mark the end of the stream.
                            ControlMessage msg = new ControlMessage();
                            Assert.True(msg.Read(packetReader));

                            if (completedPacket.Header.MessageID == (int)ControlMessageID.End)
                            {
                                endMsgReceived = true;
                            }
                            break;
                        }

                        case (int)RoutingID.Mesh:
                            HandleMeshMessage(completedPacket, packetReader, resources);
                            break;

                        default:
                            if (completedPacket.Header.RoutingID == reference.RoutingID)
                            {
                                shapeMsgRead = true;
                                HandleShapeMessage(completedPacket, packetReader, shape, reference);
                            }
                            break;
                        }
                    }
                }
                // else fail?
            }

            Assert.True(serverInfoRead);
            Assert.True(shapeMsgRead);
            Assert.True(endMsgReceived);

            // Validate the shape state.
            if (shapeMsgRead)
            {
                validate(shape, reference, resources);
            }
        }