using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using RobotNet10.FleetManager.Data; using RobotNet10.FleetManager.Services; using RobotNet10.FleetManager.Shared.DTOs.RobotModel; using RobotNet10.FleetManager.Shared.Enums; using RobotNet10.RobotManager.Test.Helpers; namespace RobotNet10.RobotManager.Test.Services; /// /// Unit tests for RobotModelService /// [TestFixture] public class RobotModelServiceTests { private ApplicationDbContext _context = null!; private RobotModelService _service = null!; [SetUp] public void Setup() { var options = new DbContextOptionsBuilder() .UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()) .Options; _context = new ApplicationDbContext(options); var logger = new LoggerFactory().CreateLogger(); var _logger = new FleetManager.Services.Logger(logger); _service = new RobotModelService(_context, _logger); } [TearDown] public void TearDown() { _context.Dispose(); } [Test] public async Task CreateAsync_ValidData_ReturnsCreatedRobotModel() { // Arrange var request = new CreateRobotModelRequest { ModelName = "TestModel", Length = 1.2, Width = 0.8, ImageWidth = 800, ImageHeight = 600, NavigationPointX = 0.0, NavigationPointY = 0.0, NavigationType = NavigationType.Differential }; // Act var result = await _service.CreateAsync(request); // Assert Assert.That(result, Is.Not.Null); Assert.That(result.ModelName, Is.EqualTo(request.ModelName)); Assert.That(result.Length, Is.EqualTo(request.Length)); Assert.That(result.Width, Is.EqualTo(request.Width)); Assert.That(result.NavigationType, Is.EqualTo(request.NavigationType)); Assert.That(result.Id, Is.Not.EqualTo(Guid.Empty)); } [Test] public async Task CreateAsync_DuplicateModelName_ThrowsInvalidOperationException() { // Arrange var existingModel = TestHelpers.CreateTestRobotModel(modelName: "ExistingModel"); _context.RobotModels.Add(existingModel); await _context.SaveChangesAsync(); var request = new CreateRobotModelRequest { ModelName = "ExistingModel", Length = 1.0, Width = 0.5, ImageWidth = 800, ImageHeight = 600, NavigationPointX = 0.0, NavigationPointY = 0.0, NavigationType = NavigationType.Differential }; // Act & Assert var ex = Assert.ThrowsAsync(async () => await _service.CreateAsync(request)); Assert.That(ex!.Message, Does.Contain("already exists")); } [Test] public async Task GetAllAsync_ReturnsAllRobotModels() { // Arrange TestHelpers.SeedTestData(_context); // Act var result = await _service.GetAllAsync(); // Assert Assert.That(result, Is.Not.Null); Assert.That(result.Count, Is.EqualTo(2)); } [Test] public async Task GetByIdAsync_ExistingId_ReturnsRobotModel() { // Arrange var model = TestHelpers.CreateTestRobotModel(); _context.RobotModels.Add(model); await _context.SaveChangesAsync(); // Act var result = await _service.GetByIdAsync(model.Id); // Assert Assert.That(result, Is.Not.Null); Assert.That(result!.Id, Is.EqualTo(model.Id)); Assert.That(result.ModelName, Is.EqualTo(model.ModelName)); } [Test] public async Task GetByIdAsync_NonExistentId_ReturnsNull() { // Arrange var nonExistentId = Guid.NewGuid(); // Act var result = await _service.GetByIdAsync(nonExistentId); // Assert Assert.That(result, Is.Null); } [Test] public async Task UpdateAsync_ValidData_UpdatesRobotModel() { // Arrange var model = TestHelpers.CreateTestRobotModel(); _context.RobotModels.Add(model); await _context.SaveChangesAsync(); var request = new UpdateRobotModelRequest { ModelName = "UpdatedModel", Length = 2.0, Width = 1.0, ImageWidth = 1000, ImageHeight = 800, NavigationPointX = 0.1, NavigationPointY = 0.2, NavigationType = NavigationType.OmniDrive }; // Act var result = await _service.UpdateAsync(model.Id, request); // Assert Assert.That(result, Is.Not.Null); Assert.That(result.ModelName, Is.EqualTo(request.ModelName)); Assert.That(result.Length, Is.EqualTo(request.Length)); Assert.That(result.NavigationType, Is.EqualTo(request.NavigationType)); } [Test] public async Task UpdateAsync_NonExistentId_ThrowsKeyNotFoundException() { // Arrange var nonExistentId = Guid.NewGuid(); var request = new UpdateRobotModelRequest { ModelName = "Test", Length = 1.0, Width = 0.5, ImageWidth = 800, ImageHeight = 600, NavigationPointX = 0.0, NavigationPointY = 0.0, NavigationType = NavigationType.Differential }; // Act & Assert Assert.ThrowsAsync(async () => await _service.UpdateAsync(nonExistentId, request)); } [Test] public async Task DeleteAsync_ExistingId_ReturnsTrue() { // Arrange var model = TestHelpers.CreateTestRobotModel(); _context.RobotModels.Add(model); await _context.SaveChangesAsync(); // Act var result = await _service.DeleteAsync(model.Id); // Assert Assert.That(result, Is.True); var deleted = await _context.RobotModels.FindAsync(model.Id); Assert.That(deleted, Is.Null); } [Test] public async Task DeleteAsync_NonExistentId_ReturnsFalse() { // Arrange var nonExistentId = Guid.NewGuid(); // Act var result = await _service.DeleteAsync(nonExistentId); // Assert Assert.That(result, Is.False); } [Test] public async Task DeleteAsync_ModelWithRobots_ThrowsInvalidOperationException() { // Arrange var model = TestHelpers.CreateTestRobotModel(); _context.RobotModels.Add(model); var robot = TestHelpers.CreateTestRobot(modelId: model.Id); _context.Robots.Add(robot); await _context.SaveChangesAsync(); // Act & Assert var ex = Assert.ThrowsAsync(async () => await _service.DeleteAsync(model.Id)); Assert.That(ex, Is.Not.Null); Assert.That(ex!.Message, Does.Contain("Cannot delete").Or.Contain("cannot be deleted").Or.Contain("being used")); } [Test] public async Task SearchAsync_WithQuery_ReturnsMatchingModels() { // Arrange TestHelpers.SeedTestData(_context); // Act var result = await _service.SearchAsync("AMR-T800"); // Assert Assert.That(result, Is.Not.Null); Assert.That(result.Count, Is.EqualTo(1)); Assert.That(result[0].ModelName, Is.EqualTo("AMR-T800")); } [Test] public async Task SearchAsync_EmptyQuery_ReturnsAllModels() { // Arrange TestHelpers.SeedTestData(_context); // Act var result = await _service.SearchAsync(""); // Assert Assert.That(result, Is.Not.Null); Assert.That(result.Count, Is.EqualTo(2)); } [Test] public async Task ExistsAsync_ExistingModelName_ReturnsTrue() { // Arrange var model = TestHelpers.CreateTestRobotModel(modelName: "ExistingModel"); _context.RobotModels.Add(model); await _context.SaveChangesAsync(); // Act var result = await _service.ExistsAsync("ExistingModel"); // Assert Assert.That(result, Is.True); } [Test] public async Task ExistsAsync_NonExistentModelName_ReturnsFalse() { // Arrange // No models in database // Act var result = await _service.ExistsAsync("NonExistentModel"); // Assert Assert.That(result, Is.False); } [Test] public async Task GetUsageInfoAsync_ModelWithRobots_ReturnsUsageInfo() { // Arrange var model = TestHelpers.CreateTestRobotModel(); _context.RobotModels.Add(model); var robot1 = TestHelpers.CreateTestRobot(modelId: model.Id); var robot2 = TestHelpers.CreateTestRobot(robotId: "ROBOT-002", modelId: model.Id); _context.Robots.AddRange(robot1, robot2); await _context.SaveChangesAsync(); // Act var result = await _service.GetUsageInfoAsync(model.Id); // Assert Assert.That(result, Is.Not.Null); Assert.That(result.RobotCount, Is.EqualTo(2)); Assert.That(result.CanDelete, Is.False); } [Test] public async Task GetUsageInfoAsync_ModelWithoutRobots_ReturnsZeroCount() { // Arrange var model = TestHelpers.CreateTestRobotModel(); _context.RobotModels.Add(model); await _context.SaveChangesAsync(); // Act var result = await _service.GetUsageInfoAsync(model.Id); // Assert Assert.That(result, Is.Not.Null); Assert.That(result.RobotCount, Is.EqualTo(0)); Assert.That(result.CanDelete, Is.True); } }