using System.Security.Claims; using adas_core.Application.Exceptions; using adas_core.Application.Repositories.Interfaces; using adas_core.Application.Services; using adas_core.Application.Services.Interfaces; using adas_core.Domain.Enums; using adas_core.Domain.Models.AppSettings; using adas_core.Domain.Models.MongoModels; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using MongoDB.Bson; using Moq; using Options = Microsoft.Extensions.Options.Options; namespace adas_core.Test.Services; [TestFixture] public class PointOfCareServiceTests { [SetUp] public void SetUp() { _pointOfCareRepositoryMock = new Mock(); _unitServiceMock = new Mock(); _admissionServiceMock = new Mock(); _cacheServiceMock = new Mock(); _cacheServiceMock .Setup(c => c.GetOrSetObjectAsync( It.IsAny(), It.IsAny>>(), It.IsAny(), It.IsAny())) .Returns((string _, Func> factory, TimeSpan? _, CancellationToken _) => factory()); var loggerMock = new Mock>(); var userClaims = new ClaimsPrincipal(new ClaimsIdentity([ new Claim(ClaimTypes.Name, "TestUser") ], "mock")); var httpContextMock = new DefaultHttpContext { User = userClaims }; _httpContextAccessorMock.Setup(accessor => accessor.HttpContext) .Returns(httpContextMock); _pointOfCareService = new PointOfCareService( loggerMock.Object, _pointOfCareRepositoryMock.Object, new Lazy(Mock.Of), new Lazy(() => _unitServiceMock.Object), Mock.Of(), Mock.Of>(), new Lazy(() => _admissionServiceMock.Object), _httpContextAccessorMock.Object, _auditServiceMock.Object, _cacheServiceMock.Object, Options.Create(new CacheSettings()) ); } private PointOfCareService _pointOfCareService = null!; private Mock _pointOfCareRepositoryMock = null!; private Mock _unitServiceMock = null!; private Mock _cacheServiceMock = null!; private Mock _admissionServiceMock = null!; private readonly Mock _httpContextAccessorMock = new(); private readonly Mock _auditServiceMock = new(); [Test] public async Task Delete_ValidObjectId_DeletesPointOfCare() { // Arrange var id = ObjectId.GenerateNewId(); _pointOfCareRepositoryMock.Setup(m => m.FindByIdAllConfig(id)) .ReturnsAsync(new PointOfCare { Id = id, AdmissionId = null }); _pointOfCareRepositoryMock.Setup(m => m.Delete(id)).Verifiable(); // Act await _pointOfCareService.Delete(id); // Assert _pointOfCareRepositoryMock.Verify(); } [Test] public async Task Update_ValidPointOfCare_UpdatesPointOfCare() { // Arrange var pointOfCare = new PointOfCare { Id = ObjectId.GenerateNewId(), UnitName = "TestUnit" }; _pointOfCareRepositoryMock.Setup(m => m.Update(pointOfCare)).Verifiable(); // Act await _pointOfCareService.Update(pointOfCare); // Assert _pointOfCareRepositoryMock.Verify(); } [Test] public async Task GetAll_NoArguments_ReturnsListOfPointOfCare() { // Arrange var pointOfCareList = new List { new(), new() }; _pointOfCareRepositoryMock.Setup(m => m.GetAll()).ReturnsAsync(pointOfCareList); // Act var result = await _pointOfCareService.GetAll(); // Assert Assert.That(result, Is.EqualTo(pointOfCareList)); } [Test] public void UpdateConfiguration_ValidIdAndConfiguration_InvokesRepositoryUpdateConfiguration() { // Arrange var id = ObjectId.GenerateNewId(); var configuration = new PointOfCareConfiguration(); // Act & Assert Assert.That(_pointOfCareService, Is.Not.Null); Assert.That(_pointOfCareRepositoryMock, Is.Not.Null); Func act = async () => await _pointOfCareService.UpdateConfiguration(id, configuration); Assert.ThrowsAsync(act); } [Test] public async Task FindById_ValidId_ReturnsPointOfCare() { // Arrange var id = ObjectId.GenerateNewId(); var expectedPointOfCare = new PointOfCare { Id = id }; _pointOfCareRepositoryMock.Setup(m => m.FindByIdAllConfig(id)).ReturnsAsync(expectedPointOfCare); // Act var result = await _pointOfCareService.FindById(id); // Assert Assert.That(result, Is.EqualTo(expectedPointOfCare)); } // [Test] // public async Task FindByUnit_ValidUnit_ReturnsListOfPointOfCare() // { // // Arrange // var id = ObjectId.GenerateNewId(); // var pointOfCare = new PointOfCare { Id = id, UnitId = ObjectId.GenerateNewId() }; // var unit = new Unit { Id = pointOfCare.UnitId, Name = "TestUnit" }; // var expectedPointOfCareList = new List // { // new PointOfCare { Unit = unit }, // new PointOfCare { Unit = unit }, // }; // _pointOfCareRepositoryMock.Setup(m => m.FindByUnit(unit)).ReturnsAsync(expectedPointOfCareList); // // // Act // var result = await _pointOfCareService.FindByUnit(unit); // // // Assert // Assert.That(result, Is.EqualTo(expectedPointOfCareList)); // } [Test] public async Task FindByUnitAndStatus_ValidUnitIdAndStatus_ReturnsListOfPointOfCare() { // Arrange var unitId = ObjectId.GenerateNewId(); var pocStatus = StatusEnum.PointOfCare.Available; var expectedPointOfCareList = new List { new(), new() }; _pointOfCareRepositoryMock.Setup(m => m.FindByUnitAndStatus(unitId, pocStatus, false)) .ReturnsAsync(expectedPointOfCareList); // Act var result = await _pointOfCareService.FindByUnitAndStatus(unitId, pocStatus); // Assert Assert.That(result, Is.EqualTo(expectedPointOfCareList)); } [Test] public void CheckNextAdmission_ValidPatientLocation_UpdatesPoCStatus_AndCallsUpdate() { // Arrange var patientLocationId = ObjectId.GenerateNewId(); var pocToCheck = new PointOfCare { Id = patientLocationId, AdmissionId = null, // Forzamos la rama que busca la siguiente admisión Status = StatusEnum.PointOfCare.Locked // Locked → no debe actualizar. Cambia para probar actualización: // Usa Available o Reserved para que se ejecute el update. }; // Para que ejecute la lógica de actualización, cambiamos el estado inicial: pocToCheck.Status = StatusEnum.PointOfCare.Available; var nextAdmission = new Admission { Id = ObjectId.GenerateNewId() }; // 1) Cache: debe ejecutar el factory y devolver el PoC _cacheServiceMock .Setup(c => c.GetOrSetObjectAsync( It.IsAny(), It.IsAny>>(), It.IsAny(), It.IsAny())) .Returns((string _, Func> factory, TimeSpan? _, CancellationToken _) => factory()); // 2) Repo: FindById (usado por el factory del caché) _pointOfCareRepositoryMock .Setup(m => m.FindById(patientLocationId)) .ReturnsAsync(pocToCheck); // 3) AdmissionService (ruta AdmissionId == null → buscar siguiente) _admissionServiceMock .Setup(m => m.GetAdmissionByPointOfCareId(pocToCheck.Id)) .ReturnsAsync([nextAdmission]); // 4) Update(poc) → queremos esperar a que se invoque var updatedSignal = new ManualResetEventSlim(false); _pointOfCareRepositoryMock .Setup(m => m.Update(It.IsAny())) .Callback(_ => updatedSignal.Set()) .Returns(Task.CompletedTask); // Update llama internamente a FindById otra vez (en Update) _pointOfCareRepositoryMock .Setup(m => m.FindById(pocToCheck.Id)) .ReturnsAsync(pocToCheck); // 5) Ejecutar (async void) y esperar a que se dispare el update _pointOfCareService.CheckNextAdmission(patientLocationId); // Espera razonable a que termine la operación asíncrona interna var completed = updatedSignal.Wait(TimeSpan.FromSeconds(1)); Assert.That(completed, Is.True, "CheckNextAdmission no disparó Update a tiempo."); // Assert // a) Se llamó a FindById (vía caché) _pointOfCareRepositoryMock.Verify(m => m.FindById(patientLocationId), Times.AtLeastOnce); // b) Se llamó a Update con el PoC actualizado: Status Reserved + Admission asignada _pointOfCareRepositoryMock.Verify(m => m.Update( It.Is(p => p.Id == pocToCheck.Id && p.Status == StatusEnum.PointOfCare.Reserved && p.AdmissionId == nextAdmission.Id && p.Admission == nextAdmission) ), Times.Once); // c) NO verifiques FindByIdAllConfig: en CheckNextAdmission no se usa esa ruta } [Test] public async Task FindByRoom_ValidRoom_CallsRepositoryFindByRoom() { // Arrange const string room = "TestRoom"; var expectedPointOfCares = new List(); _pointOfCareRepositoryMock.Setup(m => m.FindByRoom(room)).ReturnsAsync(expectedPointOfCares); // Act var result = await _pointOfCareService.FindByRoom(room); // Assert Assert.That(result, Is.EqualTo(expectedPointOfCares)); _pointOfCareRepositoryMock.Verify(m => m.FindByRoom(room), Times.Once); } [Test] public async Task FindByBed_ValidBed_CallsRepositoryFindByBed() { // Arrange const string bed = "TestBed"; var expectedPointOfCares = new List(); _pointOfCareRepositoryMock.Setup(m => m.FindByBed(bed)).ReturnsAsync(expectedPointOfCares); // Act var result = await _pointOfCareService.FindByBed(bed); // Assert Assert.That(result, Is.EqualTo(expectedPointOfCares)); _pointOfCareRepositoryMock.Verify(m => m.FindByBed(bed), Times.Once); } }