CounterDroneBackend/test/unit/CounterDrone.Core.Tests/ScenarioServiceTests.cs

484 lines
17 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.Collections.Generic;
using System.IO;
using CounterDrone.Core;
using CounterDrone.Core.Models;
using CounterDrone.Core.Repository;
using CounterDrone.Core.Services;
using SQLite;
using Xunit;
using TaskStatus = CounterDrone.Core.Models.TaskStatus;
namespace CounterDrone.Core.Tests
{
public class ScenarioServiceTests : IDisposable
{
private readonly string _testDir;
private readonly SQLiteConnection _db;
private readonly IScenarioService _service;
public ScenarioServiceTests()
{
_testDir = Path.Combine(Path.GetTempPath(), $"cd_test_{Guid.NewGuid():N}");
var paths = new TestPathProvider(_testDir);
var dbManager = new DatabaseManager(paths);
_db = dbManager.OpenMainDb();
_service = new ScenarioService(
new SimTaskRepository(_db),
new CombatSceneRepository(_db),
new ControlZoneRepository(_db),
new TargetConfigRepository(_db),
new EquipmentDeploymentRepository(_db),
new CloudDispersalRepository(_db),
new RoutePlanRepository(_db),
new WaypointRepository(_db));
}
public void Dispose()
{
_db?.Close();
if (Directory.Exists(_testDir))
Directory.Delete(_testDir, true);
}
// ========== Task CRUD ==========
[Fact]
public void CreateTask_Valid_ReturnsTask()
{
var task = _service.CreateTask("测试任务", "SIM-20260611-001");
Assert.NotNull(task);
Assert.Equal("测试任务", task.Name);
Assert.Equal("SIM-20260611-001", task.TaskNumber);
Assert.Equal((int)TaskStatus.Configuring, task.Status);
Assert.Equal(1, task.CurrentStep);
Assert.NotEmpty(task.Id);
}
[Fact]
public void CreateTask_AutoGeneratesTaskNumber()
{
var task = _service.CreateTask("自动编号", "");
Assert.StartsWith("SIM-", task.TaskNumber);
}
[Fact]
public void CreateTask_EmptyName_Throws()
{
Assert.Throws<ArgumentException>(() =>
_service.CreateTask("", "SIM-001"));
}
[Fact]
public void CreateTask_DuplicateNumber_Throws()
{
_service.CreateTask("Task A", "SIM-001");
Assert.Throws<ArgumentException>(() =>
_service.CreateTask("Task B", "SIM-001"));
}
[Fact]
public void DeleteTask_RemovesTask()
{
var task = _service.CreateTask("ToDelete", "");
_service.DeleteTask(task.Id);
var detail = _service.GetTaskDetail(task.Id);
Assert.Null(detail);
}
[Fact]
public void GetTaskDetail_ReturnsFullConfig()
{
var task = _service.CreateTask("Full Config", "");
// 保存各步骤配置
_service.SaveScene(task.Id, new CombatScene
{
SceneType = (int)SceneType.Mountain,
WindSpeed = 10.0,
Temperature = 25.0,
});
_service.SaveTarget(task.Id, new TargetConfig
{
TargetType = (int)TargetType.FixedWing,
Quantity = 3,
});
_service.SaveCloudDispersal(task.Id, new CloudDispersal
{
AerosolType = (int)AerosolType.ActiveMaterial,
Duration = 45.0,
});
_service.UpdateStep(task.Id, 4);
// 读取完整配置
var detail = _service.GetTaskDetail(task.Id);
Assert.Equal("Full Config", detail.Task.Name);
Assert.Equal(4, detail.Task.CurrentStep);
Assert.Equal((int)SceneType.Mountain, detail.Scene.SceneType);
Assert.Equal(10.0, detail.Scene.WindSpeed);
Assert.Equal(3, detail.Targets[0].Quantity);
Assert.Equal((int)AerosolType.ActiveMaterial, detail.Cloud.AerosolType);
}
// ========== Step Save ==========
[Fact]
public void SaveScene_FirstTime_Inserts()
{
var task = _service.CreateTask("Scene Test", "");
_service.SaveScene(task.Id, new CombatScene
{
WeatherType = (int)WeatherType.Fog,
Visibility = 2000.0,
TimeOfDay = "03:00",
});
var detail = _service.GetTaskDetail(task.Id);
Assert.Equal((int)WeatherType.Fog, detail.Scene.WeatherType);
Assert.Equal(2000.0, detail.Scene.Visibility);
Assert.Equal("03:00", detail.Scene.TimeOfDay);
}
[Fact]
public void SaveScene_SecondTime_Updates()
{
var task = _service.CreateTask("Update Scene", "");
_service.SaveScene(task.Id, new CombatScene { WindSpeed = 5.0 });
_service.SaveScene(task.Id, new CombatScene { WindSpeed = 15.0 });
var detail = _service.GetTaskDetail(task.Id);
Assert.Equal(15.0, detail.Scene.WindSpeed);
}
[Fact]
public void SaveControlZones_SavesAndRetrieves()
{
var task = _service.CreateTask("Zone Test", "");
var zones = new List<ControlZone>
{
new ControlZone { Name = "禁区A", VerticesJson = "[{\"x\":0,\"y\":0,\"z\":0},{\"x\":100,\"y\":0,\"z\":0},{\"x\":100,\"y\":100,\"z\":0}]", MinAltitude = 0, MaxAltitude = 500 },
new ControlZone { Name = "禁区B", VerticesJson = "[{\"x\":200,\"y\":200,\"z\":0}]", MinAltitude = 100, MaxAltitude = 300 },
};
_service.SaveControlZones(task.Id, zones);
var detail = _service.GetTaskDetail(task.Id);
Assert.Equal(2, detail.ControlZones.Count);
Assert.Equal("禁区A", detail.ControlZones[0].Name);
Assert.Equal(0, detail.ControlZones[0].OrderIndex);
Assert.Equal("禁区B", detail.ControlZones[1].Name);
Assert.Equal(1, detail.ControlZones[1].OrderIndex);
}
[Fact]
public void SaveControlZones_ReplaceExisting()
{
var task = _service.CreateTask("Zone Replace", "");
_service.SaveControlZones(task.Id, new List<ControlZone>
{
new ControlZone { Name = "Old" }
});
_service.SaveControlZones(task.Id, new List<ControlZone>
{
new ControlZone { Name = "New1" },
new ControlZone { Name = "New2" },
});
var detail = _service.GetTaskDetail(task.Id);
Assert.Equal(2, detail.ControlZones.Count);
}
[Fact]
public void SaveTarget_SavesCorrectly()
{
var task = _service.CreateTask("Target Test", "");
_service.SaveTarget(task.Id, new TargetConfig
{
TargetType = (int)TargetType.Piston,
Quantity = 5,
PowerType = (int)PowerType.Piston,
Wingspan = 2.5,
TypicalSpeed = 120.0,
TypicalAltitude = 800.0,
});
var detail = _service.GetTaskDetail(task.Id);
var target = detail.Targets[0];
Assert.Equal((int)TargetType.Piston, target.TargetType);
Assert.Equal(5, target.Quantity);
Assert.Equal(120.0, target.TypicalSpeed);
}
[Fact]
public void SaveDeployment_SavesMultiple()
{
var task = _service.CreateTask("Equip Test", "");
var equips = new List<EquipmentDeployment>
{
new EquipmentDeployment
{
EquipmentRole = (int)EquipmentRole.LaunchPlatform,
PlatformType = (int)PlatformType.GroundBased,
Quantity = 2,
PositionX = 1000, PositionY = 0, PositionZ = 50,
MuzzleVelocity = 800.0,
MunitionCount = 3,
},
new EquipmentDeployment
{
EquipmentRole = (int)EquipmentRole.Detection,
Quantity = 1,
DetectionRadius = 5000.0,
},
};
_service.SaveDeployment(task.Id, equips);
var detail = _service.GetTaskDetail(task.Id);
Assert.Equal(2, detail.Equipment.Count);
var platform = detail.Equipment.Find(e => e.EquipmentRole == (int)EquipmentRole.LaunchPlatform);
Assert.NotNull(platform);
Assert.Equal(2, platform.Quantity);
Assert.Equal(800.0, platform.MuzzleVelocity);
}
[Fact]
public void SaveRoute_SavesWaypoints()
{
var task = _service.CreateTask("Route Test", "");
var route = new RoutePlan
{
FormationMode = (int)FormationMode.Formation,
FormationSpacing = 60.0,
};
var waypoints = new List<Waypoint>
{
new Waypoint { PosX = 0, PosY = 0, PosZ = 100, Altitude = 500, Speed = 100 },
new Waypoint { PosX = 5000, PosY = 0, PosZ = 100, Altitude = 500, Speed = 100 },
new Waypoint { PosX = 10000, PosY = 0, PosZ = 100, Altitude = 300, Speed = 80 },
};
_service.SaveRoute(task.Id, route, waypoints);
var detail = _service.GetTaskDetail(task.Id);
Assert.Equal((int)FormationMode.Formation, detail.Route.FormationMode);
Assert.Equal(3, detail.Waypoints.Count);
Assert.Equal(0, detail.Waypoints[0].OrderIndex);
Assert.Equal(2, detail.Waypoints[2].OrderIndex);
Assert.Equal(5000.0, detail.Waypoints[1].PosX);
}
// ========== Search & Pagination ==========
[Fact]
public void SearchTasks_KeywordFilter()
{
_service.CreateTask("城市防御演习", "");
_service.CreateTask("平原拦截测试", "");
_service.CreateTask("海岸边防演练", "");
var result = _service.SearchTasks("城市", null, null, 1, 10);
Assert.Equal(1, result.TotalCount);
Assert.Equal("城市防御演习", result.Items[0].Name);
}
[Fact]
public void SearchTasks_NoResults()
{
_service.CreateTask("Task A", "");
var result = _service.SearchTasks("不存在的任务", null, null, 1, 10);
Assert.Equal(0, result.TotalCount);
}
[Fact]
public void SearchTasks_Pagination()
{
for (int i = 0; i < 15; i++)
_service.CreateTask($"Task {i:D2}", "");
var page1 = _service.SearchTasks(null, null, null, 1, 5);
Assert.Equal(15, page1.TotalCount);
Assert.Equal(5, page1.Items.Count);
Assert.Equal(3, page1.TotalPages);
var page3 = _service.SearchTasks(null, null, null, 3, 5);
Assert.Equal(5, page3.Items.Count);
}
[Fact]
public void SearchTasks_DateRangeFilter()
{
// All tasks created today, so date filter should include them
_service.CreateTask("Recent Task", "");
var yesterday = DateTime.UtcNow.AddDays(-1).ToString("yyyy-MM-dd");
var tomorrow = DateTime.UtcNow.AddDays(1).ToString("yyyy-MM-dd");
var result = _service.SearchTasks(null, yesterday, tomorrow, 1, 10);
Assert.Equal(1, result.TotalCount);
var oldResult = _service.SearchTasks(null, "2020-01-01", "2020-12-31", 1, 10);
Assert.Equal(0, oldResult.TotalCount);
}
// ========== UpdateStep ==========
[Fact]
public void UpdateStep_ValidSteps()
{
var task = _service.CreateTask("Step Test", "");
Assert.Equal(1, task.CurrentStep);
_service.UpdateStep(task.Id, 3);
var detail = _service.GetTaskDetail(task.Id);
Assert.Equal(3, detail.Task.CurrentStep);
_service.UpdateStep(task.Id, 5);
detail = _service.GetTaskDetail(task.Id);
Assert.Equal(5, detail.Task.CurrentStep);
}
[Fact]
public void UpdateStep_ClampedToRange()
{
var task = _service.CreateTask("Clamp Test", "");
_service.UpdateStep(task.Id, 0);
Assert.Equal(1, _service.GetTaskDetail(task.Id).Task.CurrentStep);
_service.UpdateStep(task.Id, 10);
Assert.Equal(5, _service.GetTaskDetail(task.Id).Task.CurrentStep);
}
// ========== Full Workflow ==========
[Fact]
public void FullWorkflow_CreateConfigureSearch()
{
// 1. 创建任务
var task = _service.CreateTask("完整流程测试", "");
Assert.NotNull(task);
// 2. 步骤1作战场景
_service.SaveScene(task.Id, new CombatScene
{
SceneType = (int)SceneType.Urban,
WeatherType = (int)WeatherType.Rain,
WindSpeed = 8.0,
WindDirection = (int)WindDirection.SE,
Temperature = 18.0,
TimeOfDay = "14:00",
});
_service.UpdateStep(task.Id, 1);
// 3. 步骤1扩展管控区域
_service.SaveControlZones(task.Id, new List<ControlZone>
{
new ControlZone
{
Name = "核心区",
VerticesJson = "[{\"x\":0,\"y\":0,\"z\":0},{\"x\":500,\"y\":0,\"z\":0},{\"x\":500,\"y\":500,\"z\":0},{\"x\":0,\"y\":500,\"z\":0}]",
MinAltitude = 0, MaxAltitude = 1000,
}
});
// 4. 步骤2目标配置
_service.SaveTarget(task.Id, new TargetConfig
{
TargetType = (int)TargetType.HighSpeed,
Quantity = 2,
PowerType = (int)PowerType.Jet,
TypicalSpeed = 300.0,
});
_service.UpdateStep(task.Id, 2);
// 5. 步骤3装备部署
_service.SaveDeployment(task.Id, new List<EquipmentDeployment>
{
new EquipmentDeployment
{
EquipmentRole = (int)EquipmentRole.Detection,
Quantity = 1,
DetectionRadius = 6000.0,
},
new EquipmentDeployment
{
EquipmentRole = (int)EquipmentRole.LaunchPlatform,
PlatformType = (int)PlatformType.GroundBased,
Quantity = 3,
PositionX = 800, PositionY = 0, PositionZ = 50,
MuzzleVelocity = 850.0,
MunitionCount = 2,
},
});
_service.UpdateStep(task.Id, 3);
// 6. 步骤4云团抛撒
_service.SaveCloudDispersal(task.Id, new CloudDispersal
{
AerosolType = (int)AerosolType.ActiveMaterial,
TriggerMode = (int)TriggerMode.Area,
Duration = 50.0,
PositionX = 3000, PositionY = 0, PositionZ = 300,
});
_service.UpdateStep(task.Id, 4);
// 7. 步骤5航路规划
_service.SaveRoute(task.Id, new RoutePlan
{
FormationMode = (int)FormationMode.Swarm,
FormationSpacing = 30.0,
}, new List<Waypoint>
{
new Waypoint { PosX = 0, PosY = 100, PosZ = 200, Altitude = 600, Speed = 250 },
new Waypoint { PosX = 10000, PosY = 100, PosZ = 200, Altitude = 600, Speed = 250 },
});
_service.UpdateStep(task.Id, 5);
// 8. 验证完整配置
var detail = _service.GetTaskDetail(task.Id);
Assert.Equal("完整流程测试", detail.Task.Name);
Assert.Equal(5, detail.Task.CurrentStep);
Assert.Equal((int)TaskStatus.Configuring, detail.Task.Status);
// 场景
Assert.Equal((int)SceneType.Urban, detail.Scene.SceneType);
Assert.Equal((int)WeatherType.Rain, detail.Scene.WeatherType);
Assert.Equal("14:00", detail.Scene.TimeOfDay);
// 管控区域
Assert.Single(detail.ControlZones);
Assert.Equal("核心区", detail.ControlZones[0].Name);
// 目标
Assert.Single(detail.Targets);
Assert.Equal(2, detail.Targets[0].Quantity);
Assert.Equal(300.0, detail.Targets[0].TypicalSpeed);
// 装备
Assert.Equal(2, detail.Equipment.Count);
// 云团
Assert.Equal((int)AerosolType.ActiveMaterial, detail.Cloud.AerosolType);
Assert.Equal(50.0, detail.Cloud.Duration);
// 航路
Assert.Equal((int)FormationMode.Swarm, detail.Route.FormationMode);
Assert.Equal(2, detail.Waypoints.Count);
Assert.Equal(250.0, detail.Waypoints[0].Speed);
// 9. 搜索验证
var searchResult = _service.SearchTasks("完整流程", null, null, 1, 10);
Assert.Equal(1, searchResult.TotalCount);
}
}
}