public void WhenSendMultipleMessages_MustQueueItAndSendOneAfterAnother()
        {
            // PLC sends valid handshake
            _tagListener
            .Setup(t => t.ReadTagSynchronously(It.IsAny <Tag>()))
            .Callback <Tag>(tag => { tag.Value = DataStateEnum.DataChannelFree; });
            int writeCalls = 0;

            _tagController
            .Setup(t => t.WriteTag(It.IsAny <Tag>(), It.IsAny <object>()))
            .Callback(() => writeCalls++);

            Action act = () =>
            {
                var udt = new ValidDataUdtTest();

                _testee.AddAsyncWriteTask(_tag, udt);
                _testee.AddAsyncWriteTask(_tag, udt);
                _testee.AddAsyncWriteTask(_tag, udt);
                _testee.AddAsyncWriteTask(_tag, udt);
                _testee.AddAsyncWriteTask(_tag, udt);
                _testee.WaitWriteComplete();
            };

            act.ShouldNotThrow("DataChannelManager must never throw an exception, but only error events");
            writeCalls.Should().Be(5, "LineControl sent 5 valid messages");
        }
        public void GivenOneMessageIsInvalid_WhenSendMultipleMessages_MustSendAtLeastTheValidMessages()
        {
            _testee.MonitorEvents();

            // PLC sends valid handshake
            _tagListener
            .Setup(t => t.ReadTagSynchronously(It.IsAny <Tag>()))
            .Callback <Tag>(tag => { tag.Value = DataStateEnum.DataChannelFree; });
            int writeCalls = 0;

            _tagController
            .Setup(t => t.WriteTag(It.IsAny <Tag>(), It.IsAny <object>()))
            .Callback(() => writeCalls++);

            Action act = () =>
            {
                var udt        = new ValidDataUdtTest();
                var invalidUdt = new InvalidDataUdtTest();

                _testee.AddAsyncWriteTask(_tag, udt);
                _testee.AddAsyncWriteTask(_tag, invalidUdt);
                _testee.AddAsyncWriteTask(_tag, udt);
                _testee.WaitWriteComplete();
            };

            act.ShouldNotThrow("DataChannelManager must never throw an exception, but only error events");
            _testee.ShouldRaise("CommunicationProblemOccured");
            writeCalls.Should().Be(2, "2 messages are valid and 1 is invalid (should be skipped)");
        }
        public void WhenValidDataUdtToChannel_MustNotThrowException()
        {
            // PLC sends valid handshake
            _tagListener
            .Setup(t => t.ReadTagSynchronously(It.IsAny <Tag>()))
            .Callback <Tag>(tag => { tag.Value = DataStateEnum.DataChannelFree; });

            Action act = () =>
            {
                var udt = new ValidDataUdtTest();

                _testee.AddAsyncWriteTask(_tag, udt);
                _testee.WaitWriteComplete();
            };

            act.ShouldNotThrow("DataChannelManager must never throw an exception, but only error events");
        }
        public void GivenPlcSendsFatalResponse_WhenWriteValidData_MustThrowException()
        {
            _testee.MonitorEvents();
            // PLC sends fatal error response
            _tagListener
            .Setup(t => t.ReadTagSynchronously(It.IsAny <Tag>()))
            .Callback <Tag>(tag => { tag.Value = DataStateEnum.InvalidDataReceivedError; });

            Action act = () =>
            {
                var udt = new ValidDataUdtTest();

                _testee.AddAsyncWriteTask(_tag, udt);
                _testee.WaitWriteComplete();
            };

            act.ShouldNotThrow("DataChannelManager must never throw an exception, but only error events");
            _testee.ShouldRaise("CommunicationProblemOccured");
        }
        public void GivenPlcSendsInvalidData_WhenWriteValidData_TryItSeveralTimes()
        {
            // PLC sends invalid data
            _tagListener
            .Setup(t => t.ReadTagSynchronously(It.IsAny <Tag>()))
            .Callback <Tag>(tag => { tag.Value = DataStateEnum.InvalidDataReceived; });
            int writeCalls = 0;

            _tagController
            .Setup(t => t.WriteTag(It.IsAny <Tag>(), It.IsAny <object>()))
            .Callback(() => writeCalls++);

            Action act = () =>
            {
                var udt = new ValidDataUdtTest();

                _testee.AddAsyncWriteTask(_tag, udt);
                _testee.WaitWriteComplete();
            };

            act.ShouldNotThrow("DataChannelManager must never throw an exception, but only error events");
            writeCalls.Should().BeGreaterThan(1, "LineControl should try to repeat send data over DataChannel in case of negative feedback from PLC");
        }