From 0500b9903e5b7fcdbdc5b3bd0cc9b373779d64d8 Mon Sep 17 00:00:00 2001
From: wanshenmean <cathay_xy@163.com>
Date: 星期五, 13 三月 2026 12:47:10 +0800
Subject: [PATCH] feat: implement DB region (Data Blocks)
---
Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.UnitTests/Memory/DBRegionTests.cs | 263 ++++++++++++++++++++
Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Core/Memory/DBRegion.cs | 490 +++++++++++++++++++++++++++++++++++++
2 files changed, 753 insertions(+), 0 deletions(-)
diff --git a/Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Core/Memory/DBRegion.cs b/Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Core/Memory/DBRegion.cs
new file mode 100644
index 0000000..1b72c06
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Core/Memory/DBRegion.cs
@@ -0,0 +1,490 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using WIDESEAWCS_S7Simulator.Core.Interfaces;
+
+namespace WIDESEAWCS_S7Simulator.Core.Memory
+{
+ /// <summary>
+ /// DB鍖猴紙鏁版嵁鍧楋級- 鏀寔澶氫釜DB鍧�
+ /// </summary>
+ public class DBRegion : IMemoryRegion
+ {
+ /// <summary>
+ /// DB鍧楀瓧鍏革紝閿负DB缂栧彿锛屽�间负瀛楄妭鏁扮粍
+ /// </summary>
+ private readonly Dictionary<ushort, byte[]> _blocks;
+
+ /// <summary>
+ /// 璇诲啓閿侊紙鏀寔骞跺彂璁块棶锛�
+ /// </summary>
+ private readonly ReaderWriterLockSlim _lock;
+
+ /// <summary>
+ /// 閲婃斁鐘舵�佹爣蹇�
+ /// </summary>
+ private bool _disposed = false;
+
+ /// <summary>
+ /// 鍗曚釜DB鍧楃殑澶у皬锛堝瓧鑺傦級
+ /// </summary>
+ private readonly int _blockSize;
+
+ /// <summary>
+ /// 榛樿DB缂栧彿
+ /// </summary>
+ private const ushort DEFAULT_DB_NUMBER = 1;
+
+ /// <summary>
+ /// 鍖哄煙绫诲瀷
+ /// </summary>
+ public string RegionType => "DB";
+
+ /// <summary>
+ /// 鍖哄煙澶у皬锛堝瓧鑺傦級- 杩斿洖榛樿DB鍧楃殑澶у皬
+ /// </summary>
+ public int Size => _blockSize;
+
+ /// <summary>
+ /// 鏋勯�犲嚱鏁�
+ /// </summary>
+ /// <param name="defaultDBNumber">榛樿DB缂栧彿</param>
+ /// <param name="blockSize">鍗曚釜DB鍧楃殑澶у皬</param>
+ public DBRegion(ushort defaultDBNumber, int blockSize)
+ {
+ _blockSize = blockSize;
+ _blocks = new Dictionary<ushort, byte[]>();
+ _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
+
+ // 鍒涘缓榛樿DB鍧�
+ CreateBlock(defaultDBNumber);
+ }
+
+ /// <summary>
+ /// 鍒涘缓DB鍧�
+ /// </summary>
+ /// <param name="dbNumber">DB缂栧彿</param>
+ private void CreateBlock(ushort dbNumber)
+ {
+ if (!_blocks.ContainsKey(dbNumber))
+ {
+ _blocks[dbNumber] = new byte[_blockSize];
+ }
+ }
+
+ /// <summary>
+ /// 鑾峰彇DB鍧�
+ /// </summary>
+ /// <param name="dbNumber">DB缂栧彿</param>
+ /// <returns>DB鍧楀瓧鑺傛暟缁�</returns>
+ private byte[] GetBlock(ushort dbNumber)
+ {
+ if (!_blocks.ContainsKey(dbNumber))
+ {
+ throw new ArgumentException($"DB鍧椾笉瀛樺湪: DB{dbNumber}");
+ }
+ return _blocks[dbNumber];
+ }
+
+ /// <summary>
+ /// 璇诲彇瀛楄妭鏁版嵁锛堜娇鐢ㄩ粯璁B1锛�
+ /// </summary>
+ /// <param name="offset">鍋忕Щ閲�</param>
+ /// <param name="length">闀垮害</param>
+ /// <returns>瀛楄妭鏁扮粍</returns>
+ public byte[] Read(ushort offset, ushort length)
+ {
+ return Read(DEFAULT_DB_NUMBER, offset, length);
+ }
+
+ /// <summary>
+ /// 璇诲彇瀛楄妭鏁版嵁锛堟寚瀹欴B缂栧彿锛�
+ /// </summary>
+ /// <param name="dbNumber">DB缂栧彿</param>
+ /// <param name="offset">鍋忕Щ閲�</param>
+ /// <param name="length">闀垮害</param>
+ /// <returns>瀛楄妭鏁扮粍</returns>
+ public byte[] Read(ushort dbNumber, ushort offset, ushort length)
+ {
+ _lock.EnterReadLock();
+ try
+ {
+ var block = GetBlock(dbNumber);
+ if (offset + length > block.Length)
+ {
+ throw new ArgumentOutOfRangeException(
+ $"璇诲彇瓒呭嚭DB{dbNumber}鍖鸿寖鍥�: offset={offset}, length={length}, size={block.Length}");
+ }
+
+ byte[] result = new byte[length];
+ Array.Copy(block, offset, result, 0, length);
+ return result;
+ }
+ finally
+ {
+ _lock.ExitReadLock();
+ }
+ }
+
+ /// <summary>
+ /// 鍐欏叆瀛楄妭鏁版嵁锛堜娇鐢ㄩ粯璁B1锛�
+ /// </summary>
+ /// <param name="offset">鍋忕Щ閲�</param>
+ /// <param name="data">瀛楄妭鏁扮粍</param>
+ public void Write(ushort offset, byte[] data)
+ {
+ Write(DEFAULT_DB_NUMBER, offset, data);
+ }
+
+ /// <summary>
+ /// 鍐欏叆瀛楄妭鏁版嵁锛堟寚瀹欴B缂栧彿锛�
+ /// </summary>
+ /// <param name="dbNumber">DB缂栧彿</param>
+ /// <param name="offset">鍋忕Щ閲�</param>
+ /// <param name="data">瀛楄妭鏁扮粍</param>
+ public void Write(ushort dbNumber, ushort offset, byte[] data)
+ {
+ if (data == null)
+ {
+ throw new ArgumentNullException(nameof(data));
+ }
+
+ _lock.EnterWriteLock();
+ try
+ {
+ // 濡傛灉DB鍧椾笉瀛樺湪锛岃嚜鍔ㄥ垱寤�
+ if (!_blocks.ContainsKey(dbNumber))
+ {
+ CreateBlock(dbNumber);
+ }
+
+ var block = _blocks[dbNumber];
+ if (offset + data.Length > block.Length)
+ {
+ throw new ArgumentOutOfRangeException(
+ $"鍐欏叆瓒呭嚭DB{dbNumber}鍖鸿寖鍥�: offset={offset}, length={data.Length}, size={block.Length}");
+ }
+
+ Array.Copy(data, 0, block, offset, data.Length);
+ }
+ finally
+ {
+ _lock.ExitWriteLock();
+ }
+ }
+
+ /// <summary>
+ /// 璇诲彇甯冨皵鍊�
+ /// </summary>
+ /// <param name="dbNumber">DB缂栧彿</param>
+ /// <param name="byteOffset">瀛楄妭鍋忕Щ閲�</param>
+ /// <param name="bitOffset">浣嶅亸绉婚噺锛�0-7锛�</param>
+ /// <returns>甯冨皵鍊�</returns>
+ public bool ReadBool(ushort dbNumber, ushort byteOffset, byte bitOffset)
+ {
+ if (bitOffset > 7)
+ {
+ throw new ArgumentOutOfRangeException(nameof(bitOffset), "浣嶅亸绉婚噺蹇呴』鍦�0-7涔嬮棿");
+ }
+
+ _lock.EnterReadLock();
+ try
+ {
+ var block = GetBlock(dbNumber);
+ if (byteOffset >= block.Length)
+ {
+ throw new ArgumentOutOfRangeException(
+ $"璇诲彇瓒呭嚭DB{dbNumber}鍖鸿寖鍥�: byteOffset={byteOffset}, size={block.Length}");
+ }
+
+ return (block[byteOffset] & (1 << bitOffset)) != 0;
+ }
+ finally
+ {
+ _lock.ExitReadLock();
+ }
+ }
+
+ /// <summary>
+ /// 鍐欏叆甯冨皵鍊�
+ /// </summary>
+ /// <param name="dbNumber">DB缂栧彿</param>
+ /// <param name="byteOffset">瀛楄妭鍋忕Щ閲�</param>
+ /// <param name="bitOffset">浣嶅亸绉婚噺锛�0-7锛�</param>
+ /// <param name="value">甯冨皵鍊�</param>
+ public void WriteBool(ushort dbNumber, ushort byteOffset, byte bitOffset, bool value)
+ {
+ if (bitOffset > 7)
+ {
+ throw new ArgumentOutOfRangeException(nameof(bitOffset), "浣嶅亸绉婚噺蹇呴』鍦�0-7涔嬮棿");
+ }
+
+ _lock.EnterWriteLock();
+ try
+ {
+ // 濡傛灉DB鍧椾笉瀛樺湪锛岃嚜鍔ㄥ垱寤�
+ if (!_blocks.ContainsKey(dbNumber))
+ {
+ CreateBlock(dbNumber);
+ }
+
+ var block = _blocks[dbNumber];
+ if (byteOffset >= block.Length)
+ {
+ throw new ArgumentOutOfRangeException(
+ $"鍐欏叆瓒呭嚭DB{dbNumber}鍖鸿寖鍥�: byteOffset={byteOffset}, size={block.Length}");
+ }
+
+ if (value)
+ {
+ block[byteOffset] |= (byte)(1 << bitOffset);
+ }
+ else
+ {
+ block[byteOffset] &= (byte)~(1 << bitOffset);
+ }
+ }
+ finally
+ {
+ _lock.ExitWriteLock();
+ }
+ }
+
+ /// <summary>
+ /// 璇诲彇16浣嶆暣鏁帮紙Int锛屽ぇ绔簭锛�
+ /// </summary>
+ /// <param name="dbNumber">DB缂栧彿</param>
+ /// <param name="offset">鍋忕Щ閲�</param>
+ /// <returns>16浣嶆暣鏁�</returns>
+ public short ReadInt(ushort dbNumber, ushort offset)
+ {
+ var data = Read(dbNumber, offset, 2);
+ return (short)((data[0] << 8) | data[1]);
+ }
+
+ /// <summary>
+ /// 鍐欏叆16浣嶆暣鏁帮紙Int锛屽ぇ绔簭锛�
+ /// </summary>
+ /// <param name="dbNumber">DB缂栧彿</param>
+ /// <param name="offset">鍋忕Щ閲�</param>
+ /// <param name="value">16浣嶆暣鏁�</param>
+ public void WriteInt(ushort dbNumber, ushort offset, short value)
+ {
+ var data = new byte[2];
+ data[0] = (byte)((value >> 8) & 0xFF);
+ data[1] = (byte)(value & 0xFF);
+ Write(dbNumber, offset, data);
+ }
+
+ /// <summary>
+ /// 璇诲彇32浣嶆暣鏁帮紙DInt锛屽ぇ绔簭锛�
+ /// </summary>
+ /// <param name="dbNumber">DB缂栧彿</param>
+ /// <param name="offset">鍋忕Щ閲�</param>
+ /// <returns>32浣嶆暣鏁�</returns>
+ public int ReadDInt(ushort dbNumber, ushort offset)
+ {
+ var data = Read(dbNumber, offset, 4);
+ return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
+ }
+
+ /// <summary>
+ /// 鍐欏叆32浣嶆暣鏁帮紙DInt锛屽ぇ绔簭锛�
+ /// </summary>
+ /// <param name="dbNumber">DB缂栧彿</param>
+ /// <param name="offset">鍋忕Щ閲�</param>
+ /// <param name="value">32浣嶆暣鏁�</param>
+ public void WriteDInt(ushort dbNumber, ushort offset, int value)
+ {
+ var data = new byte[4];
+ data[0] = (byte)((value >> 24) & 0xFF);
+ data[1] = (byte)((value >> 16) & 0xFF);
+ data[2] = (byte)((value >> 8) & 0xFF);
+ data[3] = (byte)(value & 0xFF);
+ Write(dbNumber, offset, data);
+ }
+
+ /// <summary>
+ /// 璇诲彇32浣嶆诞鐐规暟锛圧eal锛孖EEE 754锛�
+ /// </summary>
+ /// <param name="dbNumber">DB缂栧彿</param>
+ /// <param name="offset">鍋忕Щ閲�</param>
+ /// <returns>32浣嶆诞鐐规暟</returns>
+ public float ReadReal(ushort dbNumber, ushort offset)
+ {
+ var data = Read(dbNumber, offset, 4);
+ // 闇�瑕佽浆鎹㈠瓧鑺傚簭锛堝ぇ绔簭杞皬绔簭锛�
+ if (BitConverter.IsLittleEndian)
+ {
+ Array.Reverse(data);
+ }
+ return BitConverter.ToSingle(data, 0);
+ }
+
+ /// <summary>
+ /// 鍐欏叆32浣嶆诞鐐规暟锛圧eal锛孖EEE 754锛�
+ /// </summary>
+ /// <param name="dbNumber">DB缂栧彿</param>
+ /// <param name="offset">鍋忕Щ閲�</param>
+ /// <param name="value">32浣嶆诞鐐规暟</param>
+ public void WriteReal(ushort dbNumber, ushort offset, float value)
+ {
+ var data = BitConverter.GetBytes(value);
+ // 闇�瑕佽浆鎹㈠瓧鑺傚簭锛堝皬绔簭杞ぇ绔簭锛�
+ if (BitConverter.IsLittleEndian)
+ {
+ Array.Reverse(data);
+ }
+ Write(dbNumber, offset, data);
+ }
+
+ /// <summary>
+ /// 璇诲彇瀛楃涓诧紙S7瀛楃涓叉牸寮忥級
+ /// S7瀛楃涓叉牸寮忥細[鏈�澶ч暱搴�(1瀛楄妭)][瀹為檯闀垮害(1瀛楄妭)][瀛楃鏁版嵁]
+ /// </summary>
+ /// <param name="dbNumber">DB缂栧彿</param>
+ /// <param name="offset">鍋忕Щ閲�</param>
+ /// <param name="maxLength">鏈�澶ч暱搴�</param>
+ /// <returns>瀛楃涓�</returns>
+ public string ReadString(ushort dbNumber, ushort offset, byte maxLength)
+ {
+ _lock.EnterReadLock();
+ try
+ {
+ var block = GetBlock(dbNumber);
+ if (offset + 2 + maxLength > block.Length)
+ {
+ throw new ArgumentOutOfRangeException(
+ $"璇诲彇瀛楃涓茶秴鍑篋B{dbNumber}鍖鸿寖鍥�: offset={offset}, maxLength={maxLength}, size={block.Length}");
+ }
+
+ // 璇诲彇瀹為檯闀垮害
+ byte actualLength = block[offset + 1];
+
+ // 璇诲彇瀛楃鏁版嵁
+ if (actualLength == 0)
+ {
+ return string.Empty;
+ }
+
+ var chars = new char[actualLength];
+ for (int i = 0; i < actualLength; i++)
+ {
+ chars[i] = (char)block[offset + 2 + i];
+ }
+
+ return new string(chars);
+ }
+ finally
+ {
+ _lock.ExitReadLock();
+ }
+ }
+
+ /// <summary>
+ /// 鍐欏叆瀛楃涓诧紙S7瀛楃涓叉牸寮忥級
+ /// S7瀛楃涓叉牸寮忥細[鏈�澶ч暱搴�(1瀛楄妭)][瀹為檯闀垮害(1瀛楄妭)][瀛楃鏁版嵁]
+ /// </summary>
+ /// <param name="dbNumber">DB缂栧彿</param>
+ /// <param name="offset">鍋忕Щ閲�</param>
+ /// <param name="value">瀛楃涓插��</param>
+ /// <param name="maxLength">鏈�澶ч暱搴�</param>
+ public void WriteString(ushort dbNumber, ushort offset, string value, byte maxLength)
+ {
+ if (value == null)
+ {
+ throw new ArgumentNullException(nameof(value));
+ }
+
+ if (value.Length > maxLength)
+ {
+ throw new ArgumentException(
+ $"瀛楃涓查暱搴value.Length}瓒呰繃鏈�澶ч暱搴maxLength}");
+ }
+
+ _lock.EnterWriteLock();
+ try
+ {
+ // 濡傛灉DB鍧椾笉瀛樺湪锛岃嚜鍔ㄥ垱寤�
+ if (!_blocks.ContainsKey(dbNumber))
+ {
+ CreateBlock(dbNumber);
+ }
+
+ var block = _blocks[dbNumber];
+ if (offset + 2 + maxLength > block.Length)
+ {
+ throw new ArgumentOutOfRangeException(
+ $"鍐欏叆瀛楃涓茶秴鍑篋B{dbNumber}鍖鸿寖鍥�: offset={offset}, maxLength={maxLength}, size={block.Length}");
+ }
+
+ // 鍐欏叆鏈�澶ч暱搴�
+ block[offset] = maxLength;
+
+ // 鍐欏叆瀹為檯闀垮害
+ block[offset + 1] = (byte)value.Length;
+
+ // 鍐欏叆瀛楃鏁版嵁
+ for (int i = 0; i < value.Length; i++)
+ {
+ block[offset + 2 + i] = (byte)value[i];
+ }
+
+ // 濉厖鍓╀綑绌洪棿涓�0
+ for (int i = value.Length; i < maxLength; i++)
+ {
+ block[offset + 2 + i] = 0;
+ }
+ }
+ finally
+ {
+ _lock.ExitWriteLock();
+ }
+ }
+
+ /// <summary>
+ /// 娓呯┖鎵�鏈塂B鍧�
+ /// </summary>
+ public void Clear()
+ {
+ _lock.EnterWriteLock();
+ try
+ {
+ foreach (var block in _blocks.Values)
+ {
+ Array.Clear(block, 0, block.Length);
+ }
+ }
+ finally
+ {
+ _lock.ExitWriteLock();
+ }
+ }
+
+ /// <summary>
+ /// 閲婃斁璧勬簮
+ /// </summary>
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ /// <summary>
+ /// 閲婃斁璧勬簮
+ /// </summary>
+ /// <param name="disposing">鏄惁姝e湪閲婃斁鎵樼璧勬簮</param>
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!_disposed)
+ {
+ if (disposing)
+ {
+ _lock?.Dispose();
+ _blocks.Clear();
+ }
+ _disposed = true;
+ }
+ }
+ }
+}
diff --git a/Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.UnitTests/Memory/DBRegionTests.cs b/Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.UnitTests/Memory/DBRegionTests.cs
new file mode 100644
index 0000000..6285390
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.UnitTests/Memory/DBRegionTests.cs
@@ -0,0 +1,263 @@
+using Xunit;
+using WIDESEAWCS_S7Simulator.Core.Memory;
+
+namespace WIDESEAWCS_S7Simulator.UnitTests.Memory
+{
+ public class DBRegionTests
+ {
+ [Fact]
+ public void Constructor_WithValidParameters_CreatesRegion()
+ {
+ // Arrange & Act
+ var region = new DBRegion(1, 1024);
+
+ // Assert
+ Assert.Equal("DB", region.RegionType);
+ Assert.Equal(1024, region.Size);
+ }
+
+ [Fact]
+ public void Read_ValidDBNumberAndOffset_ReturnsData()
+ {
+ // Arrange
+ var region = new DBRegion(1, 1024);
+ var testData = new byte[] { 0x12, 0x34, 0x56, 0x78 };
+ region.Write(1, 0, testData);
+
+ // Act
+ var result = region.Read(1, 0, 4);
+
+ // Assert
+ Assert.Equal(testData, result);
+ }
+
+ [Fact]
+ public void Read_InvalidDBNumber_ThrowsArgumentException()
+ {
+ // Arrange
+ var region = new DBRegion(1, 1024);
+
+ // Act & Assert
+ Assert.Throws<ArgumentException>(() => region.Read(999, 0, 4));
+ }
+
+ [Fact]
+ public void Read_OutOfBounds_ThrowsArgumentOutOfRange()
+ {
+ // Arrange
+ var region = new DBRegion(1, 100);
+
+ // Act & Assert
+ Assert.Throws<ArgumentOutOfRangeException>(() => region.Read(1, 0, 101));
+ }
+
+ [Fact]
+ public void Write_MultipleDBs_StoresSeparately()
+ {
+ // Arrange
+ var region = new DBRegion(1, 1024);
+ var data1 = new byte[] { 0x11, 0x22, 0x33, 0x44 };
+ var data2 = new byte[] { 0xAA, 0xBB, 0xCC, 0xDD };
+
+ // Act
+ region.Write(1, 0, data1);
+ region.Write(2, 0, data2);
+ var result1 = region.Read(1, 0, 4);
+ var result2 = region.Read(2, 0, 4);
+
+ // Assert
+ Assert.Equal(data1, result1);
+ Assert.Equal(data2, result2);
+ }
+
+ [Fact]
+ public void Clear_AllBlocks_ZerosAllMemory()
+ {
+ // Arrange
+ var region = new DBRegion(1, 1024);
+ region.Write(1, 0, new byte[] { 0xFF, 0xFF, 0xFF });
+ region.Write(2, 0, new byte[] { 0xAA, 0xBB, 0xCC });
+
+ // Act
+ region.Clear();
+ var result1 = region.Read(1, 0, 3);
+ var result2 = region.Read(2, 0, 3);
+
+ // Assert
+ Assert.Equal(new byte[] { 0, 0, 0 }, result1);
+ Assert.Equal(new byte[] { 0, 0, 0 }, result2);
+ }
+
+ [Fact]
+ public void ReadInt_ValidOffset_ReturnsCorrectValue()
+ {
+ // Arrange
+ var region = new DBRegion(1, 1024);
+ region.Write(1, 0, new byte[] { 0x12, 0x34 }); // S7 Int: 0x1234 = 4660
+
+ // Act
+ var result = region.ReadInt(1, 0);
+
+ // Assert
+ Assert.Equal(4660, result);
+ }
+
+ [Fact]
+ public void WriteInt_ValidOffset_WritesCorrectValue()
+ {
+ // Arrange
+ var region = new DBRegion(1, 1024);
+
+ // Act
+ region.WriteInt(1, 0, 4660); // 0x1234
+ var result = region.Read(1, 0, 2);
+
+ // Assert
+ Assert.Equal(new byte[] { 0x12, 0x34 }, result);
+ }
+
+ [Fact]
+ public void ReadDInt_ValidOffset_ReturnsCorrectValue()
+ {
+ // Arrange
+ var region = new DBRegion(1, 1024);
+ region.Write(1, 0, new byte[] { 0x00, 0x01, 0x00, 0x00 }); // S7 DInt: 65536
+
+ // Act
+ var result = region.ReadDInt(1, 0);
+
+ // Assert
+ Assert.Equal(65536, result);
+ }
+
+ [Fact]
+ public void WriteDInt_ValidOffset_WritesCorrectValue()
+ {
+ // Arrange
+ var region = new DBRegion(1, 1024);
+
+ // Act
+ region.WriteDInt(1, 0, 65536); // 0x00010000
+ var result = region.Read(1, 0, 4);
+
+ // Assert
+ Assert.Equal(new byte[] { 0x00, 0x01, 0x00, 0x00 }, result);
+ }
+
+ [Fact]
+ public void ReadReal_ValidOffset_ReturnsCorrectValue()
+ {
+ // Arrange
+ var region = new DBRegion(1, 1024);
+ region.Write(1, 0, new byte[] { 0x41, 0x20, 0x00, 0x00 }); // IEEE 754: 10.0f
+
+ // Act
+ var result = region.ReadReal(1, 0);
+
+ // Assert
+ Assert.Equal(10.0f, result);
+ }
+
+ [Fact]
+ public void WriteReal_ValidOffset_WritesCorrectValue()
+ {
+ // Arrange
+ var region = new DBRegion(1, 1024);
+
+ // Act
+ region.WriteReal(1, 0, 10.0f);
+ var result = region.Read(1, 0, 4);
+
+ // Assert
+ Assert.Equal(new byte[] { 0x41, 0x20, 0x00, 0x00 }, result);
+ }
+
+ [Fact]
+ public void ReadBool_ValidOffset_ReturnsCorrectValue()
+ {
+ // Arrange
+ var region = new DBRegion(1, 1024);
+ region.Write(1, 0, new byte[] { 0xFF }); // 鎵�鏈変綅涓�1
+
+ // Act
+ var result = region.ReadBool(1, 0, 3);
+
+ // Assert
+ Assert.True(result);
+ }
+
+ [Fact]
+ public void WriteBool_ValidOffset_SetsCorrectValue()
+ {
+ // Arrange
+ var region = new DBRegion(1, 1024);
+
+ // Act
+ region.WriteBool(1, 0, 3, true);
+ var result = region.ReadBool(1, 0, 3);
+
+ // Assert
+ Assert.True(result);
+ }
+
+ [Fact]
+ public void ReadString_WriteAndReadString_ReturnsOriginalString()
+ {
+ // Arrange
+ var region = new DBRegion(1, 1024);
+ var testString = "Hello";
+
+ // Act
+ region.WriteString(1, 0, testString, 10);
+ var result = region.ReadString(1, 0, 10);
+
+ // Assert
+ Assert.Equal(testString, result);
+ }
+
+ [Fact]
+ public void ReadString_EmptyString_ReturnsEmptyString()
+ {
+ // Arrange
+ var region = new DBRegion(1, 1024);
+
+ // Act
+ region.WriteString(1, 0, "", 10);
+ var result = region.ReadString(1, 0, 10);
+
+ // Assert
+ Assert.Equal("", result);
+ }
+
+ [Fact]
+ public void ReadString_StringWithMaxLength_RespectsMaxLength()
+ {
+ // Arrange
+ var region = new DBRegion(1, 1024);
+ var testString = "ABC";
+
+ // Act
+ region.WriteString(1, 0, testString, 5);
+ var result = region.ReadString(1, 0, 5);
+
+ // Assert
+ Assert.Equal(testString, result);
+ }
+
+ [Fact]
+ public void Dispose_ClearsBlocksDictionary()
+ {
+ // Arrange
+ var region = new DBRegion(1, 1024);
+ region.Write(1, 0, new byte[] { 0x12, 0x34 });
+ region.Write(2, 0, new byte[] { 0x56, 0x78 });
+
+ // Act
+ region.Dispose();
+
+ // Assert - trying to access after dispose should handle gracefully
+ // The implementation should clear the dictionary
+ Assert.True(true); // If no exception thrown, test passes
+ }
+ }
+}
--
Gitblit v1.9.3