NavisworksTransport/UnitTests/Core/AliasTreeTests.cs
tian 7f3be8495c fix(tests): 修复 AliasTreeTests 编译错误并更新过时旧格式兼容测试
- SetAlias 调用补全缺失的 alias 参数(DeleteByPathPrefix 测试)
- 移除 4 个旧格式兼容测试,改为期望抛 FormatException
  (FromKey 已按 AGENTS.md "不向后兼容" 原则移除旧格式支持)
2026-06-23 23:12:40 +08:00

358 lines
12 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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), "别名");
}
}
}