- SetAlias 调用补全缺失的 alias 参数(DeleteByPathPrefix 测试) - 移除 4 个旧格式兼容测试,改为期望抛 FormatException (FromKey 已按 AGENTS.md "不向后兼容" 原则移除旧格式支持)
358 lines
12 KiB
C#
358 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]
|
||
[ExpectedException(typeof(FormatException))]
|
||
public void FromKey_OldFormat_ShouldThrow()
|
||
{
|
||
// 旧格式(无 || 分隔符)已不再支持,按 AGENTS.md "不向后兼容" 原则抛 FormatException
|
||
AliasNodeIdentity.FromKey("building/floor/wall#2");
|
||
}
|
||
|
||
[TestMethod]
|
||
[ExpectedException(typeof(FormatException))]
|
||
public void FromKey_OldFormatNoIndex_ShouldThrow()
|
||
{
|
||
AliasNodeIdentity.FromKey("building/floor");
|
||
}
|
||
|
||
[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_ShouldReturnFalse()
|
||
{
|
||
// 旧格式(无 || 分隔符)已不再支持
|
||
Assert.IsFalse(AliasNodeIdentity.TryParseKey("path#0", out _));
|
||
}
|
||
|
||
[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"), "别名1");
|
||
store.SetAlias(Id("building/floor/2"), "别名2");
|
||
store.SetAlias(Id("building/roof/3"), "别名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);
|
||
}
|
||
|
||
// ── 旧格式已不支持(AGENTS.md "不向后兼容" 原则)──
|
||
|
||
[TestMethod]
|
||
[ExpectedException(typeof(FormatException))]
|
||
public void OldFormatKey_ShouldThrow()
|
||
{
|
||
var store = CreateStore();
|
||
string oldKey = "building/floor/wall#0";
|
||
// 旧格式 key 无 || 分隔符,FromKey 应抛 FormatException
|
||
store.SetAlias(AliasNodeIdentity.FromKey(oldKey), "别名");
|
||
}
|
||
}
|
||
}
|