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 { /// /// 路径导出→导入回环集成测试(覆盖计划 T12)。 /// /// 验证路径导出(XML/JSON)与导入的完整回环: /// - 导出路径文件成功(文件存在、格式正确) /// - 重新导入后属性一致:名称、路径类型、点数、总长度(米) /// [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("ok"), "准备源路径失败: " + (string)importSource["error"]); double metersToModelUnits = importSource["data"].Value("metersToModelUnits"); // 2. 导出 string exportPath = Path.Combine(tempDir, "exported-route." + format); JObject exportResponse = await client.ExportRouteFileAsync(RouteName, format, exportPath).ConfigureAwait(false); Assert.IsTrue(exportResponse.Value("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("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 { } } } }