- 新增 IndexPath(COM 树索引路径),复用 ModelItemAnalysisHelper.GetModelItemIndexPaths - 保留 DisplayPath(父链 DisplayName 拼接)作为降级匹配 - 序列化格式:"IndexPath||DisplayPath",向后兼容纯 DisplayPath - FindModelItemByNodeKey: IndexPath 优先定位,DisplayPath 降级 - BuildNode: 新增旧格式兼容查找 - 单元测试全面更新覆盖新/旧格式、双字段解析、前缀匹配
362 lines
12 KiB
C#
362 lines
12 KiB
C#
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<string, string>
|
|
{
|
|
{ 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));
|
|
}
|
|
}
|
|
}
|