using Flyshot.ControllerClientCompat; using Flyshot.Core.Config; namespace Flyshot.Core.Tests; /// /// 验证 ControllerClient 兼容层默认围绕运行目录 Config 读写配置和轨迹文件。 /// public sealed class ControllerClientCompatConfigRootTests { /// /// 验证路径兼容层优先命中运行目录 Config 下的 RobotConfig.json,而不是旧仓库根目录候选。 /// [Fact] public void PathCompatibility_ResolvesRuntimeConfigBeforeLegacyCandidates() { var runtimeRoot = CreateTempDirectory(); try { var configPath = Path.Combine(runtimeRoot, "Config", "RobotConfig.json"); var legacyPath = Path.Combine(runtimeRoot, "RobotConfig.json"); Directory.CreateDirectory(Path.GetDirectoryName(configPath)!); File.WriteAllText(configPath, "{}"); File.WriteAllText(legacyPath, "{}"); var resolved = PathCompatibility.ResolveConfigPath("RobotConfig.json", runtimeRoot); Assert.Equal(configPath, resolved); } finally { Directory.Delete(runtimeRoot, recursive: true); } } /// /// 验证机器人目录优先从显式 ConfigRoot/Models 加载 .robot 文件。 /// [Fact] public void ControllerClientCompatRobotCatalog_LoadsModelFromConfigRootModels() { var configRoot = CreateTempConfigRoot(); try { CopySampleRobotModel(configRoot); var options = new ControllerClientCompatOptions { ConfigRoot = configRoot }; var catalog = new ControllerClientCompatRobotCatalog(options, new RobotModelLoader()); var profile = catalog.LoadProfile("FANUC_LR_Mate_200iD"); Assert.Equal(Path.Combine(configRoot, "Models", "LR_Mate_200iD_7L.robot"), profile.ModelPath); } finally { Directory.Delete(configRoot, recursive: true); } } /// /// 验证 JSON 轨迹存储保存、加载和删除都落在 ConfigRoot/RobotConfig.json。 /// [Fact] public void JsonFlyshotTrajectoryStore_PersistsTrajectoriesInRobotConfigJson() { var configRoot = CreateTempConfigRoot(); try { var options = new ControllerClientCompatOptions { ConfigRoot = configRoot }; var store = new JsonFlyshotTrajectoryStore(options, new RobotConfigLoader()); var settings = new CompatibilityRobotSettings( useDo: true, ioAddresses: [7, 8], ioKeepCycles: 2, accLimitScale: 1.0, jerkLimitScale: 1.0, adaptIcspTryNum: 5); var trajectory = TestRobotFactory.CreateUploadedTrajectoryWithSingleShot(); store.Save("FANUC_LR_Mate_200iD", settings, trajectory); var expectedPath = Path.Combine(configRoot, "RobotConfig.json"); Assert.True(File.Exists(expectedPath), $"应在运行目录 Config 下创建统一配置文件: {expectedPath}"); Assert.False(Directory.Exists(Path.Combine(configRoot, "TrajectoryStore")), "不应再创建独立轨迹存储目录。"); var loaded = store.LoadAll("FANUC_LR_Mate_200iD", out var loadedSettings); Assert.NotNull(loadedSettings); Assert.Contains(trajectory.Name, loaded); store.Delete("FANUC_LR_Mate_200iD", trajectory.Name); var afterDelete = store.LoadAll("FANUC_LR_Mate_200iD", out _); Assert.Empty(afterDelete); } finally { Directory.Delete(configRoot, recursive: true); } } /// /// 创建测试专用的运行目录 Config 根,避免污染真实输出目录。 /// private static string CreateTempConfigRoot() { var root = Path.Combine(Path.GetTempPath(), "flyshot-config-root-tests", Guid.NewGuid().ToString("N"), "Config"); Directory.CreateDirectory(root); return root; } /// /// 创建测试专用的临时目录。 /// private static string CreateTempDirectory() { var root = Path.Combine(Path.GetTempPath(), "flyshot-config-root-tests", Guid.NewGuid().ToString("N")); Directory.CreateDirectory(root); return root; } /// /// 复制仓库内已固化的现场机器人模型到临时 Config/Models 目录。 /// private static void CopySampleRobotModel(string configRoot) { var modelDir = Path.Combine(configRoot, "Models"); Directory.CreateDirectory(modelDir); File.Copy( Path.Combine(GetReplacementRoot(), "Config", "Models", "LR_Mate_200iD_7L.robot"), Path.Combine(modelDir, "LR_Mate_200iD_7L.robot")); } /// /// 定位 replacement 仓库根目录,供测试读取仓库内固化样本。 /// private static string GetReplacementRoot() { var current = new DirectoryInfo(AppContext.BaseDirectory); while (current is not null) { if (File.Exists(Path.Combine(current.FullName, "FlyshotReplacement.sln"))) { return current.FullName; } current = current.Parent; } throw new DirectoryNotFoundException("Unable to locate the flyshot replacement root."); } }