using Microsoft.VisualStudio.TestTools.UnitTesting; using NavisworksTransport.Core.AliasTree; using System; using System.Data.SQLite; using System.IO; namespace NavisworksTransport.UnitTests.Core { [TestClass] public class AliasNodeIdentityTests { // ── 构造 ── [TestMethod] public void Constructor_ShouldSetBothFields() { var id = new AliasNodeIdentity("0,2,5", "building/floor/wall#1"); Assert.AreEqual("0,2,5", id.IndexPath); Assert.AreEqual("building/floor/wall#1", id.DisplayPath); } [TestMethod] public void Constructor_WithEmptyIndexPath_IsValid() { var id = new AliasNodeIdentity("", "building/floor"); Assert.AreEqual("", id.IndexPath); Assert.AreEqual("building/floor", id.DisplayPath); } [TestMethod] [ExpectedException(typeof(ArgumentNullException))] public void Constructor_NullDisplayPath_ShouldThrow() { new AliasNodeIdentity("0,0", null); } // ── 序列化 ── [TestMethod] public void ToKey_WithBothFields_ShouldFormatCorrectly() { var id = new AliasNodeIdentity("0,2,5", "模型/楼层/墙#0"); Assert.AreEqual("0,2,5||模型/楼层/墙#0", id.ToKey()); } [TestMethod] public void ToKey_WithEmptyIndexPath_ShouldReturnDisplayPathOnly() { var id = new AliasNodeIdentity("", "模型/楼层/墙#0"); Assert.AreEqual("模型/楼层/墙#0", id.ToKey()); } [TestMethod] public void FromKey_NewFormat_ShouldParseCorrectly() { var id = AliasNodeIdentity.FromKey("0,2,5||模型/楼层/墙#0"); Assert.AreEqual("0,2,5", id.IndexPath); Assert.AreEqual("模型/楼层/墙#0", id.DisplayPath); } [TestMethod] public void FromKey_OldFormat_ShouldRetroCompatible() { var id = AliasNodeIdentity.FromKey("building/floor/wall#2"); Assert.AreEqual("", id.IndexPath); Assert.AreEqual("building/floor/wall#2", id.DisplayPath); } [TestMethod] public void FromKey_OldFormatNoIndex_ShouldParse() { var id = AliasNodeIdentity.FromKey("building/floor"); Assert.AreEqual("", id.IndexPath); Assert.AreEqual("building/floor", id.DisplayPath); } [TestMethod] [ExpectedException(typeof(ArgumentException))] public void FromKey_EmptyString_ShouldThrow() { AliasNodeIdentity.FromKey(""); } [TestMethod] [ExpectedException(typeof(FormatException))] public void FromKey_EmptyDisplayAfterSeparator_ShouldThrow() { AliasNodeIdentity.FromKey("0,0||"); } // ── TryParse ── [TestMethod] public void TryParseKey_NewFormat_ShouldSucceed() { Assert.IsTrue(AliasNodeIdentity.TryParseKey("0,0||path#0", out var id)); Assert.AreEqual("0,0", id.IndexPath); Assert.AreEqual("path#0", id.DisplayPath); } [TestMethod] public void TryParseKey_OldFormat_ShouldSucceed() { Assert.IsTrue(AliasNodeIdentity.TryParseKey("path#0", out var id)); Assert.AreEqual("", id.IndexPath); } [TestMethod] public void TryParseKey_Empty_ShouldReturnFalse() { Assert.IsFalse(AliasNodeIdentity.TryParseKey("", out _)); } // ── 查询辅助 ── [TestMethod] public void GetHierarchicalPath_WithIndex_ShouldStripSuffix() { var id = new AliasNodeIdentity("0,0", "a/b/c#2"); Assert.AreEqual("a/b/c", id.GetHierarchicalPath()); } [TestMethod] public void GetHierarchicalPath_WithoutIndex_ShouldReturnFull() { var id = new AliasNodeIdentity("0,0", "a/b/c"); Assert.AreEqual("a/b/c", id.GetHierarchicalPath()); } [TestMethod] public void GetSiblingIndex_WithIndex_ShouldReturn() { var id = new AliasNodeIdentity("0,0", "a/b#3"); Assert.AreEqual(3, id.GetSiblingIndex()); } [TestMethod] public void GetSiblingIndex_WithoutIndex_ShouldReturnZero() { var id = new AliasNodeIdentity("0,0", "a/b"); Assert.AreEqual(0, id.GetSiblingIndex()); } [TestMethod] public void HasPathPrefix_Matching_ShouldReturnTrue() { var id = new AliasNodeIdentity("0,0", "building/floor/wall#0"); Assert.IsTrue(id.HasPathPrefix("building/floor")); Assert.IsTrue(id.HasPathPrefix("building")); Assert.IsTrue(id.HasPathPrefix("building/floor/wall")); } [TestMethod] public void HasPathPrefix_NonMatching_ShouldReturnFalse() { var id = new AliasNodeIdentity("0,0", "building/floor/wall#0"); Assert.IsFalse(id.HasPathPrefix("building/roof")); Assert.IsFalse(id.HasPathPrefix("Build")); } // ── 值语义 ── [TestMethod] public void Equals_Identical_ShouldMatch() { var a = new AliasNodeIdentity("0,1", "path#0"); var b = new AliasNodeIdentity("0,1", "path#0"); Assert.AreEqual(a, b); Assert.IsTrue(a == b); Assert.AreEqual(a.GetHashCode(), b.GetHashCode()); } [TestMethod] public void Equals_DifferentIndexPath_ShouldNotMatch() { var a = new AliasNodeIdentity("0,1", "path"); var b = new AliasNodeIdentity("0,2", "path"); Assert.AreNotEqual(a, b); } [TestMethod] public void Equals_DifferentDisplayPath_ShouldNotMatch() { var a = new AliasNodeIdentity("0,1", "path/a"); var b = new AliasNodeIdentity("0,1", "path/b"); Assert.AreNotEqual(a, b); } [TestMethod] public void ToString_ShouldMatchToKey() { var id = new AliasNodeIdentity("0,1", "path#0"); Assert.AreEqual(id.ToKey(), id.ToString()); } } [TestClass] public class AliasDataStoreTests { private string _dbPath; private SQLiteConnection _connection; [TestInitialize] public void Setup() { _dbPath = Path.Combine(Path.GetTempPath(), $"AliasDataStoreTest_{Guid.NewGuid():N}.db"); _connection = new SQLiteConnection($"Data Source={_dbPath};Version=3;"); _connection.Open(); } [TestCleanup] public void Cleanup() { _connection?.Close(); _connection?.Dispose(); try { File.Delete(_dbPath); } catch { } } private AliasDataStore CreateStore() { var store = new AliasDataStore(_connection); store.EnsureTableExists(); return store; } private AliasNodeIdentity Id(string displayPath, string indexPath = "") => new AliasNodeIdentity(indexPath, displayPath); // ── CRUD ── [TestMethod] public void SetAndGetAlias_ShouldReturnSavedValue() { var store = CreateStore(); store.SetAlias(Id("building/floor", "0,1"), "1F-办公层"); Assert.AreEqual("1F-办公层", store.GetAlias(Id("building/floor", "0,1"))); } [TestMethod] public void GetAlias_Nonexistent_ShouldReturnNull() { var store = CreateStore(); Assert.IsNull(store.GetAlias(Id("nonexistent"))); } [TestMethod] public void SetAlias_Overwrite_ShouldUpdateValue() { var store = CreateStore(); store.SetAlias(Id("wall", "0,0"), "旧名称"); store.SetAlias(Id("wall", "0,0"), "新名称"); Assert.AreEqual("新名称", store.GetAlias(Id("wall", "0,0"))); } [TestMethod] public void SetAlias_EmptyString_ShouldDelete() { var store = CreateStore(); store.SetAlias(Id("x", "0,0"), "原本"); Assert.AreEqual(1, store.Count); store.SetAlias(Id("x", "0,0"), " "); Assert.IsNull(store.GetAlias(Id("x", "0,0"))); Assert.AreEqual(0, store.Count); } [TestMethod] public void DeleteAlias_ShouldRemoveEntry() { var store = CreateStore(); store.SetAlias(Id("x"), "别名"); Assert.AreEqual(1, store.Count); store.DeleteAlias(Id("x")); Assert.AreEqual(0, store.Count); } // ── 批量 ── [TestMethod] public void DeleteByPathPrefix_ShouldRemoveAllUnderPath() { var store = CreateStore(); store.SetAlias(Id("building/floor/1")); store.SetAlias(Id("building/floor/2")); store.SetAlias(Id("building/roof/3")); store.DeleteAliasesByPathPrefix("building/floor"); Assert.IsNull(store.GetAlias(Id("building/floor/1"))); Assert.IsNull(store.GetAlias(Id("building/floor/2"))); Assert.IsNotNull(store.GetAlias(Id("building/roof/3"))); } [TestMethod] public void LoadAll_ShouldReturnAll() { var store = CreateStore(); store.SetAlias(Id("a", "0,0"), "别名A"); store.SetAlias(Id("b", "1,0"), "别名B"); var all = store.LoadAll(); Assert.AreEqual(2, all.Count); Assert.AreEqual("别名A", all[Id("a", "0,0").ToKey()]); Assert.AreEqual("别名B", all[Id("b", "1,0").ToKey()]); } [TestMethod] public void Count_ShouldReflectInserts() { var store = CreateStore(); Assert.AreEqual(0, store.Count); store.SetAlias(Id("a"), "alias1"); store.SetAlias(Id("b"), "alias2"); Assert.AreEqual(2, store.Count); } // ── ImportBatch ── [TestMethod] public void ImportBatch_ShouldMergeAndOverwrite() { var store = CreateStore(); store.SetAlias(Id("existing", "0,0"), "保留值"); var entries = new System.Collections.Generic.Dictionary { { Id("existing", "0,0").ToKey(), "覆盖值" }, { Id("new", "1,0").ToKey(), "新值" } }; store.ImportBatch(entries); Assert.AreEqual("覆盖值", store.GetAlias(Id("existing", "0,0"))); Assert.AreEqual("新值", store.GetAlias(Id("new", "1,0"))); Assert.AreEqual(2, store.Count); } [TestMethod] public void ClearAll_ShouldRemoveEverything() { var store = CreateStore(); store.SetAlias(Id("a"), "别名1"); store.SetAlias(Id("b"), "别名2"); store.ClearAll(); Assert.AreEqual(0, store.Count); } // ── 新格式 → 旧格式 兼容 ── [TestMethod] public void OldFormatKey_StillWorks() { var store = CreateStore(); string oldKey = "building/floor/wall#0"; store.SetAlias(AliasNodeIdentity.FromKey(oldKey), "别名"); Assert.AreEqual("别名", store.GetAlias(AliasNodeIdentity.FromKey(oldKey))); // 同一个节点用新格式读取 var newId = new AliasNodeIdentity("", "building/floor/wall#0"); Assert.AreEqual("别名", store.GetAlias(newId)); } } }