using Xunit; using Moq; using FluentAssertions; using Microsoft.Extensions.Logging; using Haoliang.Core.Services; using Haoliang.Models.Device; using Haoliang.Data.Repositories; using DeviceStatus = Haoliang.Models.Device.DeviceCurrentStatus; namespace Haoliang.Tests; public class DeviceCollectionServiceTests { private readonly Mock> _mockLogger; private readonly Mock _mockPingService; private readonly Mock _mockDataParserService; private readonly Mock _mockDeviceRepository; private readonly DeviceCollectionService _deviceCollectionService; public DeviceCollectionServiceTests() { _mockLogger = new Mock>(); _mockPingService = new Mock(); _mockDataParserService = new Mock(); _mockDeviceRepository = new Mock(); _deviceCollectionService = new DeviceCollectionService( _mockLogger.Object, _mockPingService.Object, _mockDataParserService.Object, _mockDeviceRepository.Object); } [Fact] public async Task GetAllDevicesAsync_ReturnsDevicesFromRepository() { var devices = new List { new CNCDevice { Id = 1, DeviceCode = "CNC001", DeviceName = "Device 1" }, new CNCDevice { Id = 2, DeviceCode = "CNC002", DeviceName = "Device 2" } }; _mockDeviceRepository.Setup(r => r.GetAllAsync()).ReturnsAsync(devices); var result = await _deviceCollectionService.GetAllDevicesAsync(); result.Should().HaveCount(2); result.Should().BeEquivalentTo(devices); } [Fact] public async Task GetDeviceByIdAsync_ReturnsDevice_WhenExists() { var device = new CNCDevice { Id = 1, DeviceCode = "CNC001", DeviceName = "Device 1" }; _mockDeviceRepository.Setup(r => r.GetByIdAsync(1)).ReturnsAsync(device); var result = await _deviceCollectionService.GetDeviceByIdAsync(1); result.Should().NotBeNull(); result!.Id.Should().Be(1); } [Fact] public async Task GetDeviceByIdAsync_ReturnsNull_WhenNotExists() { _mockDeviceRepository.Setup(r => r.GetByIdAsync(999)).ReturnsAsync((CNCDevice?)null); var result = await _deviceCollectionService.GetDeviceByIdAsync(999); result.Should().BeNull(); } [Fact] public async Task CreateDeviceAsync_SetsCreatedAtAndUpdatedAt() { var device = new CNCDevice { DeviceCode = "CNC003", DeviceName = "New Device" }; _mockDeviceRepository.Setup(r => r.AddAsync(It.IsAny())).Returns(Task.CompletedTask); _mockDeviceRepository.Setup(r => r.SaveAsync()).ReturnsAsync(1); var beforeCreate = DateTime.UtcNow; var result = await _deviceCollectionService.CreateDeviceAsync(device); var afterCreate = DateTime.UtcNow; result.CreatedAt.Should().BeOnOrAfter(beforeCreate); result.CreatedAt.Should().BeOnOrBefore(afterCreate); result.UpdatedAt.Should().BeOnOrAfter(beforeCreate); result.UpdatedAt.Should().BeOnOrBefore(afterCreate); } [Fact] public async Task UpdateDeviceAsync_UpdatesDevice_WhenExists() { var device = new CNCDevice { Id = 1, DeviceCode = "CNC001", DeviceName = "Updated Device" }; _mockDeviceRepository.Setup(r => r.Update(It.IsAny())).Verifiable(); _mockDeviceRepository.Setup(r => r.SaveAsync()).ReturnsAsync(1); var result = await _deviceCollectionService.UpdateDeviceAsync(device); result.Should().NotBeNull(); result!.DeviceName.Should().Be("Updated Device"); } [Fact] public async Task UpdateDeviceAsync_ReturnsNull_WhenNotExists() { var device = new CNCDevice { Id = 999 }; _mockDeviceRepository.Setup(r => r.SaveAsync()).ReturnsAsync(0); var result = await _deviceCollectionService.UpdateDeviceAsync(device); result.Should().BeNull(); } [Fact] public async Task DeleteDeviceAsync_ReturnsTrue_WhenDeviceExists() { var device = new CNCDevice { Id = 1 }; _mockDeviceRepository.Setup(r => r.GetByIdAsync(1)).ReturnsAsync(device); _mockDeviceRepository.Setup(r => r.Remove(device)).Verifiable(); _mockDeviceRepository.Setup(r => r.SaveAsync()).ReturnsAsync(1); var result = await _deviceCollectionService.DeleteDeviceAsync(1); result.Should().BeTrue(); } [Fact] public async Task DeleteDeviceAsync_ReturnsFalse_WhenDeviceNotExists() { _mockDeviceRepository.Setup(r => r.GetByIdAsync(999)).ReturnsAsync((CNCDevice?)null); var result = await _deviceCollectionService.DeleteDeviceAsync(999); result.Should().BeFalse(); } [Fact] public async Task CollectDeviceAsync_Skips_WhenDeviceNotExists() { _mockDeviceRepository.Setup(r => r.GetByIdAsync(999)).ReturnsAsync((CNCDevice?)null); await _deviceCollectionService.CollectDeviceAsync(999); _mockPingService.Verify(p => p.PingAsync(It.IsAny(), It.IsAny()), Times.Never); } [Fact] public async Task CollectDeviceAsync_Skips_WhenDeviceNotAvailable() { var device = new CNCDevice { Id = 1, IsAvailable = false }; _mockDeviceRepository.Setup(r => r.GetByIdAsync(1)).ReturnsAsync(device); await _deviceCollectionService.CollectDeviceAsync(1); _mockPingService.Verify(p => p.PingAsync(It.IsAny(), It.IsAny()), Times.Never); } [Fact] public async Task GetDeviceStatusAsync_ReturnsDeviceStatus() { var result = await _deviceCollectionService.GetDeviceStatusAsync(1); result.Should().NotBeNull(); result.DeviceId.Should().Be(1); result.Timestamp.Should().BeCloseTo(DateTime.UtcNow, TimeSpan.FromSeconds(1)); } }