Beispiel #1
0
        public async Task Check_Logging_When_Reading()
        {
            // Arrange
            var logger = Mock.Of <ILogger>();

            LogManager.LoggerFactory = () => logger;
            LogManager.LogAllReadAndWriteOperations = true;
            var byteItem = new BytePlcItem(dataBlock: 0, position: 0, initialValue: Byte.MaxValue);
            ICollection <IPlcItem> items = new IPlcItem[] { byteItem, byteItem.Clone(), byteItem.Clone() };
            var plcMock = new Mock <Plc>(Guid.NewGuid().ToString());

            plcMock
            .Setup(p => p.ReadItemsAsync(It.IsAny <IList <IPlcItem> >(), CancellationToken.None))
#if NET45
            .Returns(CompletedTask)
#else
            .Returns(Task.CompletedTask)
#endif
            ;
            var plc = plcMock.Object;

            // Act
            await plc.ReadItemsAsync(items);

            // Assert
            Mock.Get(logger).Verify(l => l.Trace(It.IsAny <string>(), It.IsAny <object[]>()), Times.Exactly(items.Count));
        }
Beispiel #2
0
        public async Task Check_If_Writing_Is_Paused_If_Not_Connected()
        {
            // Arrange
            var byteItem = new BytePlcItem(dataBlock: 0, position: 0, initialValue: byte.MaxValue);
            var plcMock  = new Mock <Plc>("MockPlc")
            {
                CallBase = true
            };

            plcMock
            .Setup(p => p.OpenConnection())
            .Returns(true)
            .Verifiable()
            ;
            plcMock
            .Setup(p => p.CloseConnection())
            .Returns(true)
            .Verifiable()
            ;
            plcMock
            .Setup(p => p.PerformReadWriteAsync(It.IsAny <ICollection <IPlcItem> >(), It.IsAny <Plc.PlcItemUsageType>(), CancellationToken.None))
#if NET45
            .Returns(CompletedTask)
#else
            .Returns(Task.CompletedTask)
#endif
            .Verifiable()
            ;
            var plc = (IPlc)plcMock.Object;

            // Disconnect before reading.
            var success = plc.Disconnect();
            Assert.True(success);

            // Execute the write function.
            var writeTask = plc.WriteItemAsync(byteItem);

            // Create a new task that automatically ends after some time.
            var waitTask = Task.Delay(3000);

            // Wait until one of the tasks finishes.
            await Task.WhenAny(new[] { writeTask, waitTask });

            // The write task should still be running.
            Assert.False(writeTask.Status == TaskStatus.RanToCompletion);

            // Connect to the plc.
            success = plc.Connect();
            Assert.True(success);

            // Now await the write task and check the result.
            var result = await writeTask;
            Assert.True(result);
            Assert.True(byteItem.Value == byte.MaxValue);
        }
        public void Check_Initial_Data()
        {
            // Arrange
            var targetValue = TargetValue;
            var targetData  = new byte[] { TargetValue };

            // Act
            var item = new BytePlcItem(0, 0, targetValue);

            // Assert: Number → Data
            Assert.That(item.Value, Is.EqualTo(targetValue));
            Assert.That((byte[])((IPlcItem)item).Value, Is.EqualTo(targetData));
        }
        public void WriteByte()
        {
            var writeItem = new BytePlcItem(dataBlock: this.Data.Datablock, position: 4, initialValue: this.Data.WriteBytes[0]);

            base.ExecuteTest
            (
                async(plc) =>
            {
                var result = await plc.WriteItemWithValidationAsync(writeItem);
                Assert.True(result);
            }
            );
        }
        public void Check_FromData()
        {
            // Arrange
            var targetValue = TargetValue;
            var targetData  = new byte[] { TargetValue };
            var item        = new BytePlcItem(0, 0, (ushort)targetData.Length);

            // Act: Data → Number
            ((IPlcItem)item).Value.TransferValuesFrom(targetData);

            // Assert
            Assert.That(item.Value, Is.EqualTo(targetValue));
            Assert.That((byte[])((IPlcItem)item).Value, Is.EqualTo(targetData));
        }
        public void Check_ToData()
        {
            // Arrange
            var targetValue = TargetValue;
            var targetData  = new byte[] { TargetValue };
            var item        = new BytePlcItem(0, 0, (ushort)targetData.Length);

            // Act: Number → Data
            item.Value = targetValue;

            // Assert
            Assert.That(item.Value, Is.EqualTo(targetValue));
            Assert.That((byte[])((IPlcItem)item).Value, Is.EqualTo(targetData));
        }
        public void Check_Clone()
        {
            var item  = new BytePlcItem(0, 0, TargetValue);
            var clone = item.Clone();

            // Check equality (Equals is overriden).
            Assert.AreEqual(item, clone);

            // Check the value.
            Assert.AreEqual(item.Value, clone.Value);

            // Check if both items are different references.
            Assert.False(Object.ReferenceEquals(item, clone));
        }
Beispiel #8
0
        public void ReadByte()
        {
            var byteItem = new BytePlcItem(dataBlock: this.Data.Datablock, position: 0);

            base.ExecuteTest
            (
                async(plc) =>
            {
                var result = await plc.ReadItemAsync(byteItem);
                //var result = await PlcExtensions.ReadItemAsync(plc, byteItem);
                Assert.True(byteItem.Value == result);
                Assert.True(byteItem.Value == this.Data.TargetBytes[0]);
            }
            );
        }
        [TestCase(new byte[] { 0 }, 1, new byte[] { 0 })]                         // This can be written in total.
        public void Check_If_Limit_Is_Respected_When_Writing(byte[] value, byte targetLength, byte[] targetData)
        {
            // Arrange
            var limit       = (uint)2;
            var numericItem = new BytePlcItem(0, 0);
            Func <string, IPlcItem <byte[]> > flexiblePlcItemFactory = name => new BytesPlcItem(0, 1, true, new byte[0], name);
            var dynamicPlcItem = new DynamicPlcItem <byte[]>(numericItem, flexiblePlcItemFactory, 1, limit);

            // Act
            dynamicPlcItem.FlexiblePlcItem.Value = value;

            // Assert
            Assert.That(numericItem.Value, Is.EqualTo(targetLength));
            Assert.True(targetData.SequenceEqual(dynamicPlcItem.FlexiblePlcItem.Value));
        }
Beispiel #10
0
        public async Task Check_That_The_Internal_CancellationTokenSource_Is_Disposed_After_Reading_Or_Writing()
        {
            // Arrange
            using var externalTokenSource = new CancellationTokenSource();
            var externalToken = externalTokenSource.Token;
            var byteItem      = new BytePlcItem(dataBlock: 0, position: 0, initialValue: byte.MaxValue);
            var plcMock       = new Mock <Plc>("MockPlc")
            {
                CallBase = true
            };

            plcMock
            .Setup(p => p.OpenConnection())
            .Returns(true)
            .Verifiable()
            ;
            plcMock
            .Setup(p => p.CloseConnection())
            .Returns(true)
            .Verifiable()
            ;
            plcMock
            .Setup(p => p.PerformReadWriteAsync(It.IsAny <ICollection <IPlcItem> >(), It.IsAny <Plc.PlcItemUsageType>(), CancellationToken.None))
#if NET45
            .Returns(CompletedTask)
#else
            .Returns(Task.CompletedTask)
#endif
            .Verifiable()
            ;
            plcMock
            .Setup(p => p.LinkedTokenWasCanceled())
            .Verifiable()
            ;
            using var plc = plcMock.Object;
            plc.Connect();

            // Act
            await plc.ReadItemAsync(byteItem, CancellationToken.None);

            // Assert
            plcMock.Verify(p => p.LinkedTokenWasCanceled(), Times.Once);
            Assert.False(externalTokenSource.IsCancellationRequested);
            Assert.False(externalToken.IsCancellationRequested);
        }
Beispiel #11
0
        public void Check_If_Disposing_A_Plc_With_Waiting_Items_For_Writing_Throws()
        {
            // Arrange
            var byteItem = new BytePlcItem(dataBlock: 0, position: 0, initialValue: byte.MaxValue);
            var plcMock  = new Mock <Plc>("MockPlc")
            {
                CallBase = true
            };

            plcMock
            .Setup(p => p.OpenConnection())
            .Returns(true)
            .Verifiable()
            ;
            plcMock
            .Setup(p => p.CloseConnection())
            .Returns(true)
            .Verifiable()
            ;
            plcMock
            .Setup(p => p.PerformReadWriteAsync(It.IsAny <ICollection <IPlcItem> >(), It.IsAny <Plc.PlcItemUsageType>(), CancellationToken.None))
#if NET45
            .Returns(CompletedTask)
#else
            .Returns(Task.CompletedTask)
#endif
            .Verifiable()
            ;
            var plc       = (IPlc)plcMock.Object;
            var writeTask = plc.WriteItemsAsync(new IPlcItem[] { byteItem });

            // Act
            Task.Run
            (
                async() =>
            {
                await Task.Delay(1000);
                plc.Dispose();
            }
            );

            // Assert
            Assert.ThrowsAsync <DisposedWritePlcException>(() => writeTask);
        }
Beispiel #12
0
        public async Task Check_If_Writing_Is_Canceled_If_Plc_Is_Disposed()
        {
            // Arrange
            var byteItem = new BytePlcItem(dataBlock: 0, position: 0, initialValue: byte.MaxValue);
            var plcMock  = new Mock <Plc>("MockPlc")
            {
                CallBase = true
            };

            plcMock
            .Setup(p => p.OpenConnection())
            .Returns(true)
            .Verifiable()
            ;
            plcMock
            .Setup(p => p.CloseConnection())
            .Returns(true)
            .Verifiable()
            ;
            plcMock
            .Setup(p => p.PerformReadWriteAsync(It.IsAny <ICollection <IPlcItem> >(), It.IsAny <Plc.PlcItemUsageType>(), CancellationToken.None))
#if NET45
            .Returns(CompletedTask)
#else
            .Returns(Task.CompletedTask)
#endif
            .Verifiable()
            ;
            var plc = (IPlc)plcMock.Object;

            // Disconnect before writing and then wait a little bit.
            plc.Disconnect();
            var writeTask = plc.WriteItemsAsync(new IPlcItem[] { byteItem });
            await Task.Delay(1000);

            // Act
            plc.Dispose();

            // Assert
            Assert.ThrowsAsync <DisposedWritePlcException>(() => writeTask);
            Assert.That(writeTask.Status, Is.EqualTo(TaskStatus.Faulted));
        }
Beispiel #13
0
        public void CheckItemIdentifierAndPlcString()
        {
            IPlcItem plcItem;

            plcItem = new BitPlcItem(dataBlock: 0, position: 0, bitPosition: BitPosition.X1, identifier: "Bit");
            Assert.AreEqual("Bit", plcItem.Identifier);
            Assert.AreEqual("DB0,X0.1,1", plcItem.PlcString);

            plcItem = new BytePlcItem(dataBlock: 1234, position: 0, identifier: "Byte");
            Assert.AreEqual("Byte", plcItem.Identifier);
            Assert.AreEqual("DB1234,B0,1", plcItem.PlcString);

            plcItem = new BitsPlcItem(type: PlcItemType.Input, dataBlock: 0, position: 0, bitPosition: BitPosition.X1, bitAmount: 2, identifier: "Bits");
            Assert.AreEqual("Bits", plcItem.Identifier);
            Assert.AreEqual("Input,X0.1,2", plcItem.PlcString);

            plcItem = new BytePlcItem(type: PlcItemType.Output, dataBlock: 0, position: 0);
            Assert.AreEqual("Output,B0,1", plcItem.Identifier);
            Assert.AreEqual(plcItem.Identifier, plcItem.PlcString);
        }
        public DynamicUtf8PlcItem BuildDynamic()
        {
            this.Validate();

            // ReSharper disable PossibleInvalidOperationException
            //! The validation method takes care of no value being null.
            INumericPlcItem numericPlcItem;

            if (_numericPlcItemType == typeof(BytePlcItem))
            {
                numericPlcItem = new BytePlcItem(base.DataBlock.Value, base.Position.Value, initialValue: (byte)base.ByteAmount);
            }
            else if (_numericPlcItemType == typeof(UInt16PlcItem))
            {
                numericPlcItem = new UInt16PlcItem(base.DataBlock.Value, base.Position.Value, initialValue: (UInt16)base.ByteAmount);
            }
            else if (_numericPlcItemType == typeof(UInt32PlcItem))
            {
                numericPlcItem = new UInt32PlcItem(base.DataBlock.Value, base.Position.Value, initialValue: (UInt32)base.ByteAmount);
            }
            else if (_numericPlcItemType == typeof(WordPlcItem))
            {
                numericPlcItem = new WordPlcItem(base.DataBlock.Value, base.Position.Value, initialValue: (UInt16)base.ByteAmount);
            }
            else if (_numericPlcItemType == typeof(DWordPlcItem))
            {
                numericPlcItem = new DWordPlcItem(base.DataBlock.Value, base.Position.Value, initialValue: (UInt32)base.ByteAmount);
            }
            else
            {
                throw new NotSupportedException($"The numeric part of any dynamic plc item must be an {nameof(INumericPlcItem)}. Currently supported are the following concrete items: {nameof(BytePlcItem)}, {nameof(UInt16PlcItem)}, {nameof(UInt32PlcItem)}, {nameof(WordPlcItem)}, {nameof(DWordPlcItem)}");
            }

            return(new DynamicUtf8PlcItem(numericPlcItem, _lengthFactor, _lengthLimit, base.InitialValue, base.Identifier));
            // ReSharper restore PossibleInvalidOperationException
        }
        public async Task MonitorDifferentIntervals()
        {
            var monitoredChangesOfFirstItem  = 0;
            var monitoredChangesOfSecondItem = 0;

            var  firstMonitorItemIdentifier  = "Monitored item #01";
            uint firstMonitorItemInterval    = 50;
            var  secondMonitorItemIdentifier = "Monitored item #02";
            uint secondMonitorItemInterval   = 200;

            var changes       = 100;
            var secondChanges = changes / ((secondMonitorItemInterval / firstMonitorItemInterval) / 2);

            var monitoredPlc = new MockPlc().MakeMonitorable
                               (
                new Dictionary <string, uint>
            {
                { firstMonitorItemIdentifier, firstMonitorItemInterval }
                , { secondMonitorItemIdentifier, secondMonitorItemInterval }
            }
                               );

            // Create items that must be monitored.
            var firstMonitoredItem  = new BytePlcItem(dataBlock: Data.Datablock, position: Data.StartOfModifiableBytes, identifier: firstMonitorItemIdentifier);
            var secondMonitoredItem = firstMonitoredItem.Clone(secondMonitorItemIdentifier);

            // Create the item that is used to manipulate the value.
            IPlcItem writeItem = firstMonitoredItem.Clone("ChangeItem");

            // Set a callback for changes to the items.
            firstMonitoredItem.ValueChanged += (sender, args) =>
            {
                monitoredChangesOfFirstItem++;
            };
            secondMonitoredItem.ValueChanged += (sender, args) =>
            {
                monitoredChangesOfSecondItem++;
            };

            try
            {
                // Connect to the plc.
                monitoredPlc.Connect();

                // Start monitoring those items.
                monitoredPlc.MonitorItem(firstMonitoredItem);
                monitoredPlc.MonitorItem(secondMonitoredItem);
                monitoredPlc.Start();

                // Manipulate the monitored value.
                for (byte i = 1; i <= changes; i++)
                {
                    writeItem.Value.TransferValuesFrom(new[] { i });
                    await monitoredPlc.WriteItemAsync(writeItem);

                    await Task.Delay((int)firstMonitorItemInterval * 2);                     // This must be at least the double amount of the polling interval.
                }

                // Stop monitoring.
                monitoredPlc.Stop();

                // Check if all changes where registered.
                Assert.AreEqual(changes, monitoredChangesOfFirstItem);
                Assert.True(monitoredChangesOfSecondItem >= secondChanges);
            }
            finally
            {
                monitoredPlc.Dispose();
            }
        }
        public async Task MonitorChanges()
        {
            var changes          = 100;
            var target           = (changes * (changes + 1)) / 2;   // Gaußsche Summenformel
            var monitoredChanges = 0;
            var collectedValue   = 0;

            var  monitorItemIdentifier = "MonitoredItem";
            uint monitorItemInterval   = 50;

            var monitoredPlc = new MockPlc().MakeMonitorable
                               (
                new Dictionary <string, uint>
            {
                { monitorItemIdentifier, monitorItemInterval }
            }
                               );

            // Create the item that must be monitored.
            var monitorItem = new BytePlcItem(dataBlock: Data.Datablock, position: Data.StartOfModifiableBytes, identifier: monitorItemIdentifier);

            // Create the item that is used to manipulate the value.
            IPlcItem writeItem = monitorItem.Clone("ChangeItem");

            // Set a callback for changes to the items.
            monitorItem.ValueChanged += (sender, args) =>
            {
                monitoredChanges++;
                collectedValue += args.NewValue;
            };

            try
            {
                // Connect to the plc.
                monitoredPlc.Connect();

                // Start monitoring those items.
                monitoredPlc.MonitorItem(monitorItem);
                monitoredPlc.Start();

                // Manipulate the monitored value.
                for (byte i = 1; i <= changes; i++)
                {
                    writeItem.Value.TransferValuesFrom(new[] { i });
                    await monitoredPlc.WriteItemAsync(writeItem);

                    await Task.Delay((int)monitorItemInterval * 2);                     // This must be at least the double amount of the polling interval.
                }

                // Stop monitoring.
                monitoredPlc.Stop();

                // Further manipulate the value to check if this is not monitored.
                writeItem.Value.TransferValuesFrom(new[] { byte.MinValue });
                writeItem.Value.TransferValuesFrom(new[] { byte.MaxValue });

                // Check if all changes where registered.
                Assert.AreEqual(changes, monitoredChanges);
                Assert.AreEqual(target, collectedValue);
                Assert.AreEqual(changes, monitorItem.Value);
            }
            finally
            {
                monitoredPlc.Dispose();
            }
        }
        /// <summary>
        /// Checks that the <see cref="CancellationTokenSource"/> that is created while reading/writing is properly disposed.
        /// </summary>
        protected async Task CheckMemoryUsage(int iterations = 100000)
        {
            // Arrange
            var byteItem = new BytePlcItem(dataBlock: 0, position: 0, initialValue: byte.MaxValue);
            var plc      = this.Plc;

            plc.Connect();

            // Perform some warm-up
            for (var iteration = 1; iteration <= 500; iteration++)
            {
                await plc.ReadItemAsync(byteItem, CancellationToken.None);

                if (iteration % 100 == 0)
                {
                    await Task.Delay(250, CancellationToken.None);
                }
            }

            GC.Collect();
            GC.WaitForPendingFinalizers();

            var initialMemoryUsage = 0d;
            var finalMemoryUsage   = 0d;

            using (var process = Process.GetCurrentProcess())
            {
                initialMemoryUsage = process.PrivateMemorySize64 / (double)(1024 * 1024);
                Console.WriteLine($"Initial memory usage: {initialMemoryUsage} MByte");
            }

            // Act
            for (var iteration = 1; iteration <= iterations; iteration++)
            {
                await plc.ReadItemAsync(byteItem, CancellationToken.None);

                if (iteration % 500 == 0)
                {
                    await Task.Delay(250, CancellationToken.None);
                }
            }

            GC.Collect();
            GC.WaitForPendingFinalizers();

            using (var process = Process.GetCurrentProcess())
            {
                finalMemoryUsage = process.PrivateMemorySize64 / (double)(1024 * 1024);
                Console.WriteLine($"Final memory usage: {finalMemoryUsage} MByte");
            }

            // Assert
            var difference = finalMemoryUsage - initialMemoryUsage;

            Console.WriteLine($"Memory increased by: {difference} MByte");

#if NET45
            if (difference <= 15)
            {
                Assert.Pass();
            }
            else
            {
                Assert.Inconclusive("When running in .NET Framework 4.5 environment, the memory usage seems not predictable. Tests with 100.000 iterations repetitively showed, that the memory consumption spikes from 180 MByte after warmup to 620 MByte in a linear fashion but then immediately slows down. The final value is then around 635 MByte. Manual memory snapshots showed no significant increase in allocated objects however.");
            }
#else
            Assert.That(difference, Is.Not.GreaterThan(15));             //! Both 100.000 and 1.000.000 iterations proofed to not allocate more than 13 MByte.
#endif
        }
Beispiel #18
0
        public void CheckItemBuilder()
        {
            var itemBuilder = new PlcItemBuilder();

            var plcItem = itemBuilder
                          .Construct("Generic")
                          .ForData()
                          .AtDatablock(0)
                          .AtPosition(0, BitPosition.X2)
                          .ForBitAmount(3)
                          .Build()
            ;

            Assert.AreEqual((uint)3, plcItem.Value.Length);

            BitsPlcItem bitsItem = itemBuilder
                                   .ConstructBitsPlcItem()
                                   .ForFlags()
                                   .AtPosition(20, BitPosition.X5)
                                   .ForBitAmount(5)
                                   .Build()
            ;

            Assert.AreEqual((uint)5, ((IPlcItem)bitsItem).Value.Length);

            BitPlcItem bitItem = itemBuilder
                                 .ConstructBitPlcItem("Bit")
                                 .ForData()
                                 .AtDatablock(0)
                                 .AtPosition(5)
                                 .AsSet()
                                 .Build()
            ;

            Assert.AreEqual((uint)1, ((IPlcItem)bitItem).Value.Length);

            BytesPlcItem bytesItem = itemBuilder
                                     .ConstructBytesPlcItem(identifier: "Bytes")
                                     .ForOutput()
                                     .AtPosition(0)
                                     .WithInitialValue(new[] { byte.MinValue, byte.MaxValue })
                                     .Build()
            ;

            Assert.AreEqual((uint)2, ((IPlcItem)bytesItem).Value.ByteLength);

            BytePlcItem byteItem = itemBuilder
                                   .ConstructBytePlcItem("Byte")
                                   .ForInput()
                                   .AtPosition(10)
                                   .WithInitialValue(Byte.MaxValue)
                                   .Build()
            ;

            Assert.AreEqual((uint)sizeof(Byte), ((IPlcItem)byteItem).Value.ByteLength);

            Int16PlcItem int16Item = itemBuilder
                                     .ConstructInt16PlcItem("Int16")
                                     .AtDatablock(0)
                                     .AtPosition(1)
                                     .WithoutInitialValue()
                                     .Build()
            ;

            Assert.AreEqual((uint)sizeof(Int16), ((IPlcItem)int16Item).Value.ByteLength);

            Int32PlcItem int32Item = itemBuilder
                                     .ConstructInt32PlcItem("Int32")
                                     .AtDatablock(0)
                                     .AtPosition(1)
                                     .WithInitialValue(int.MinValue)
                                     .Build()
            ;

            Assert.AreEqual((uint)sizeof(Int32), ((IPlcItem)int32Item).Value.ByteLength);

            Int64PlcItem int64Item = itemBuilder
                                     .ConstructInt64PlcItem("Int64")
                                     .AtDatablock(0)
                                     .AtPosition(1)
                                     .WithInitialValue(long.MinValue)
                                     .Build()
            ;

            Assert.AreEqual((uint)sizeof(Int64), ((IPlcItem)int64Item).Value.ByteLength);

            UInt16PlcItem uInt16Item = itemBuilder
                                       .ConstructUInt16PlcItem("UInt16")
                                       .AtDatablock(0)
                                       .AtPosition(1)
                                       .WithoutInitialValue()
                                       .Build()
            ;

            Assert.AreEqual((uint)sizeof(UInt16), ((IPlcItem)uInt16Item).Value.ByteLength);

            UInt32PlcItem uInt32PlcItem = itemBuilder
                                          .ConstructUInt32PlcItem("UInt32")
                                          .AtDatablock(0)
                                          .AtPosition(1)
                                          .WithInitialValue(uint.MaxValue)
                                          .Build()
            ;

            Assert.AreEqual((uint)sizeof(UInt32), ((IPlcItem)uInt32PlcItem).Value.ByteLength);

            UInt64PlcItem uInt64PlcItem = itemBuilder
                                          .ConstructUInt64PlcItem("UInt64")
                                          .AtDatablock(0)
                                          .AtPosition(1)
                                          .WithInitialValue(ulong.MaxValue)
                                          .Build()
            ;

            Assert.AreEqual((uint)sizeof(UInt64), ((IPlcItem)uInt64PlcItem).Value.ByteLength);

            WordPlcItem wordItem = itemBuilder
                                   .ConstructWordPlcItem("Word")
                                   .AtDatablock(0)
                                   .AtPosition(2)
                                   .WithInitialValue(32458)
                                   .Build()
            ;

            Assert.AreEqual((uint)2, ((IPlcItem)wordItem).Value.ByteLength);

            DWordPlcItem dwordItem = itemBuilder
                                     .ConstructDWordPlcItem("DWord")
                                     .AtDatablock(0)
                                     .AtPosition(2)
                                     .WithInitialValue(uint.MaxValue)
                                     .Build()
            ;

            Assert.AreEqual((uint)4, ((IPlcItem)dwordItem).Value.ByteLength);

            LWordPlcItem lwordItem = itemBuilder
                                     .ConstructLWordPlcItem("LWord")
                                     .AtDatablock(0)
                                     .AtPosition(2)
                                     .WithInitialValue(ulong.MaxValue)
                                     .Build()
            ;

            Assert.AreEqual((uint)8, ((IPlcItem)lwordItem).Value.ByteLength);

            TextPlcItem textItem = itemBuilder
                                   .ConstructTextPlcItem("Text")
                                   .WithEncoding(Encoding.UTF7)
                                   .AtDatablock(0)
                                   .AtPosition(3)
                                   .WithInitialValue("Some String")
                                   .Build()
            ;

            Assert.AreEqual((uint)Encoding.UTF7.GetBytes("Some String").Length, ((IPlcItem)textItem).Value.ByteLength);

            Utf8PlcItem utf8Item = itemBuilder
                                   .ConstructUtf8PlcItem("UTF-8")
                                   .AtDatablock(0)
                                   .AtPosition(4)
                                   .WithLength(10)
                                   .Build()
            ;

            Assert.AreEqual((uint)10, ((IPlcItem)utf8Item).Value.ByteLength);

            var initialText = "String whose length fits into a single byte.";
            DynamicUtf8PlcItem secondDynamicUtf8Item = itemBuilder
                                                       .ConstructUtf8PlcItem("UTF-8")
                                                       .AtDatablock(0)
                                                       .AtPosition(4)
                                                       .WithDynamicItemFromInitialValue(initialText)
                                                       .BuildDynamic()
            ;

            Assert.That(secondDynamicUtf8Item.LengthPlcItem.Value, Is.EqualTo((uint)Encoding.UTF8.GetBytes(initialText).Length));
            Assert.AreEqual(initialText, secondDynamicUtf8Item.Value);

            var items = new []
            {
                plcItem,
                bitsItem,
                bitItem,
                bytesItem,
                byteItem,
                int16Item,
                int32Item,
                int64Item,
                uInt16Item,
                uInt32PlcItem,
                uInt64PlcItem,
                wordItem,
                dwordItem,
                lwordItem,
                textItem,
                utf8Item,
                secondDynamicUtf8Item,
            };

            foreach (var item in items)
            {
                Debug.WriteLine($" -> {item}");
            }
        }