NavisworksTransport/UnitTests/Integration/ExportImportRoundTripAutomationTests.cs
tian 8e5d9e845f feat: 集成测试补 T11-T15(P0+P1+P2 全部完成,24/24 通过)
- T11 路径编辑(PathEditingAutomationTests):删除点/更新位置/正交化/去环
- T12 路径导出(ExportImportRoundTripAutomationTests):XML/JSON 导出→导入回环
- T13 播放控制(AnimationPlaybackControlAutomationTests):pause 验证帧停止/resume 前进
- T14 批量队列(BatchQueueAutomationTests):队列添加/计数递增
- T15 路径分析(PathAnalysisAutomationTests):评分结构验证
- 服务端新增 5 端点:export-route-file/edit-route/animation-playback-control/batch-queue-add/analyze-path
- 产品 bug 修复:PathDatabase.CollisionResults 表已废弃→GetCollisionCount 改查 CollisionReports、
  SaveCollisions 异常保护;路径编辑真删点走 PathRoute.RemovePoint(RemovePathPoint 仅 3D 标记)

验证:集成测试 24/24 通过,完整集 74.6s(15fps/5s 动画)
2026-08-04 18:39:16 +08:00

133 lines
6.6 KiB
C#
Raw 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 System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json.Linq;
namespace NavisworksTransport.UnitTests.Integration
{
/// <summary>
/// 路径导出→导入回环集成测试(覆盖计划 T12
///
/// 验证路径导出XML/JSON与导入的完整回环
/// - 导出路径文件成功(文件存在、格式正确)
/// - 重新导入后属性一致:名称、路径类型、点数、总长度(米)
/// </summary>
[TestClass]
[TestCategory("NavisworksIntegration")]
public class ExportImportRoundTripAutomationTests
{
private const string RouteName = "导出回环_测试";
[TestMethod]
[Timeout(240000)]
public async Task ExportImportRoundTrip_Xml_PropertiesConsistent()
{
await RunRoundTripAsync("xml").ConfigureAwait(false);
}
[TestMethod]
[Timeout(240000)]
public async Task ExportImportRoundTrip_Json_PropertiesConsistent()
{
await RunRoundTripAsync("json").ConfigureAwait(false);
}
private static async Task RunRoundTripAsync(string format)
{
using (var client = new NavisworksTestAutomationClient())
{
await client.EnsureServiceReadyAsync(TimeSpan.FromSeconds(90)).ConfigureAwait(false);
string tempDir = Path.Combine(Path.GetTempPath(), "NavisworksTransportIntegrationTests", Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(tempDir);
try
{
// 1. 准备一条临时路径2 点 Ground坐标取自测试基准区域
string sourceFile = Path.Combine(tempDir, "source-route.json");
File.WriteAllText(sourceFile, BuildSourceRouteJson(), new UTF8Encoding(false));
JObject importSource = await client.ImportRouteFileAsync(sourceFile, overwrite: true).ConfigureAwait(false);
Assert.IsTrue(importSource.Value<bool>("ok"), "准备源路径失败: " + (string)importSource["error"]);
double metersToModelUnits = importSource["data"].Value<double>("metersToModelUnits");
// 2. 导出
string exportPath = Path.Combine(tempDir, "exported-route." + format);
JObject exportResponse = await client.ExportRouteFileAsync(RouteName, format, exportPath).ConfigureAwait(false);
Assert.IsTrue(exportResponse.Value<bool>("ok"), "导出失败: " + (string)exportResponse["error"]);
Assert.IsTrue(File.Exists(exportPath), "导出文件不存在: " + exportPath);
Assert.IsTrue(new FileInfo(exportPath).Length > 0, "导出文件为空");
int sourcePointCount = (int)exportResponse["data"]["pointCount"];
double sourceLengthMeters = (double)exportResponse["data"]["totalLengthInMeters"];
// 3. 重新导入overwrite 同名路径)
JObject reimportResponse = await client.ImportRouteFileAsync(exportPath, overwrite: true).ConfigureAwait(false);
Assert.IsTrue(reimportResponse.Value<bool>("ok"), "重新导入失败: " + (string)reimportResponse["error"]);
JObject reimported = (JObject)((JArray)reimportResponse["data"]["routes"])[0];
// 4. 回环一致性断言
Assert.AreEqual(RouteName, (string)reimported["name"], "回环后路径名不一致");
Assert.AreEqual("Ground", (string)reimported["pathType"], "回环后路径类型不一致");
Assert.AreEqual(sourcePointCount, (int)reimported["pointCount"], "回环后点数不一致");
Assert.AreEqual(
sourceLengthMeters,
(double)reimported["totalLengthInMeters"],
1e-2,
"回环后总长度不一致(源 " + sourceLengthMeters.ToString("F3") + "m");
// 长度应等于模型单位直线距离换算验证单位链完整YUp 水平面为 XZ
double expectedStraightMeters = Math.Sqrt(
(EndX - StartX) * (EndX - StartX) +
(EndZ - StartZ) * (EndZ - StartZ)) / metersToModelUnits;
Assert.AreEqual(
expectedStraightMeters,
(double)reimported["totalLengthInMeters"],
1e-2,
"回环后长度与起终点直线距离不一致(单位换算)");
}
finally
{
SafeDelete(tempDir);
}
}
}
// 源路径起终点(模型单位,测试基准区域附近)
private const double StartX = -204.608;
private const double StartY = 14.833;
private const double StartZ = 19.250;
private const double EndX = -208.608;
private const double EndY = 14.833;
private const double EndZ = 18.250;
private static string BuildSourceRouteJson()
{
return string.Format(
System.Globalization.CultureInfo.InvariantCulture,
@"{{""PathPlanningData"":{{""version"":""1.0"",""generator"":""integration-test"",""timestamp"":""2026-08-04T21:30:00"",""ProjectInfo"":{{""name"":""test"",""description"":""test"",""units"":""meters"",""coordinateSystem"":""Global""}},""Routes"":[{{""id"":""roundtrip-{0}"",""name"":""{1}"",""description"":"""",""pathType"":""Ground"",""totalLength"":10.0,""objectLimits"":{{""maxLength"":0,""maxWidth"":0,""maxHeight"":0,""safetyMargin"":0}},""gridSize"":1.0,""liftHeight"":0.0,""created"":""2026-08-04T21:30:00"",""points"":[{{""id"":""rt-p1"",""name"":""start"",""type"":""StartPoint"",""index"":0,""x"":{2},""y"":{3},""z"":{4},""created"":""2026-08-04T21:30:00""}},{{""id"":""rt-p2"",""name"":""end"",""type"":""EndPoint"",""index"":1,""x"":{5},""y"":{6},""z"":{7},""created"":""2026-08-04T21:30:00""}}]}}]}}}}",
Guid.NewGuid().ToString("N"),
RouteName,
StartX, StartY, StartZ,
EndX, EndY, EndZ);
}
private static void SafeDelete(string directory)
{
if (!Directory.Exists(directory))
{
return;
}
try
{
Directory.Delete(directory, true);
}
catch
{
}
}
}
}