using adas_core.Application.Customizations.HRYC; using adas_core.Application.Services.Interfaces; using adas_core.Domain.Enums; using adas_core.Domain.Models; using adas_core.Domain.Models.AppSettings; using adas_core.Domain.Models.MongoModels; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using MongoDB.Bson; using Moq; using Options = Microsoft.Extensions.Options.Options; namespace adas_core.Test.Customizations.HRYC; /// /// Provides an NUnit test fixture that verifies the behavior of calculated observations. /// /// /// Decorated with to mark the class as a container for related NUnit test methods that exercise calculated observation logic. /// /// [TestFixture] public class CalculatedObservationsTest { /// /// Initializes the test environment for by mocking , , , and , configuring the latter to look up NEWS alert configurations by and return when no entry matches, registering all dependencies through a , and providing a sample resolved by its . /// /// [SetUp] public void Setup() { _observationServiceMock = new Mock(); var observationServiceLazy = new Lazy(() => _observationServiceMock.Object); _patientServiceMock = new Mock(); var patientServiceLazy = new Lazy(() => _patientServiceMock.Object); _lightBeaconServiceMock = new Mock(); var lightBeaconServiceLazy = new Lazy(() => _lightBeaconServiceMock.Object); var listAlertNewsObsConfig = new List { new() { Name = "Alarm_NEWS_ALERT", Alarm = new AlarmConfig { Enabled = true, Beacon = new AlarmItem { Enabled = true, Color = "RED" } } }, new() { Name = "Alarm_NEWS_OFF", Alarm = new AlarmConfig { Enabled = true, Beacon = new AlarmItem { Enabled = true, Color = "NONE" } } }, new() { Name = "Alarm_NEWS_WARNING", Alarm = new AlarmConfig { Enabled = true, Beacon = new AlarmItem { Enabled = true, Color = "YELLOW" } } } }; _configObservationServiceMock = new Mock(); _configObservationServiceMock .Setup(x => x.Get(It.IsAny(), It.IsAny())) .ReturnsAsync((PatientObservation patientObservation, bool _) => { // Busca el elemento en la lista que coincida con la propiedad "Name" recibida como parámetro var configItem = listAlertNewsObsConfig.FirstOrDefault(c => c.Name == patientObservation.Name); // Si se encuentra el elemento, devuélvelo; de lo contrario, devuelve null return configItem; }); _optionsApiSettings = Options.Create(_apiSettings); _logger = new Mock>(); _optionsApiSettings.Value.HighFrequencyVentilation = _highFrequencyVentilationValues; _optionsApiSettings.Value.InvasiveVentilation = _invasiveVentilationValues; _optionsApiSettings.Value.NonInvasiveVentilation = _nonInvasiveVentilationValues; var serviceCollection = new ServiceCollection(); serviceCollection.AddSingleton(observationServiceLazy); serviceCollection.AddSingleton(patientServiceLazy); serviceCollection.AddSingleton(lightBeaconServiceLazy); serviceCollection.AddSingleton(_configObservationServiceMock.Object); serviceCollection.AddSingleton(_optionsApiSettings); serviceCollection.AddSingleton(_logger.Object); var serviceProvider = serviceCollection.BuildServiceProvider(); _calculatedObservations = new CalculatedObservations(serviceProvider); _patientId = ObjectId.GenerateNewId(); _patientPocId = ObjectId.GenerateNewId(); _patientUnitId = ObjectId.GenerateNewId(); _patient = new Patient { Id = _patientId, UnitId = _patientUnitId, PointOfCareId = _patientPocId }; _patientServiceMock.Setup(m => m.FindById(_patientId, It.IsAny())) .ReturnsAsync(_patient); } private CalculatedObservations _calculatedObservations; private Mock _observationServiceMock; private Mock _patientServiceMock; private Mock _lightBeaconServiceMock; private Mock _configObservationServiceMock; private Mock> _logger; private readonly ApiSettings _apiSettings = new() { ConfigObservation = new ConfigObservationSettings { IgnoreUnknownObservation = false } }; private IOptions _optionsApiSettings; private readonly List _highFrequencyVentilationValues = ["HNF"]; private readonly List _nonInvasiveVentilationValues = ["BIPAP", "CPAP"]; private readonly List _invasiveVentilationValues = []; private ObjectId _patientId = ObjectId.GenerateNewId(); private ObjectId _patientPocId = ObjectId.GenerateNewId(); private ObjectId _patientUnitId = ObjectId.GenerateNewId(); private Patient _patient; /// /// Verifies that mapping a with NEWS coding, when the resolved enables a beacon alarm with , triggers the light beacon service to send to the patient's . /// /// [Test] public async Task Calculate_CheckBeaconOnNEWS_Should_Send_PowerOff() { var observation = new PatientObservation { Name = "NEWS", CodingSystem = "ADAS", Expires = 15, Value = 4, PatientId = _patientId, Time = DateTime.Now }; var obsConfig = new ConfigObservation { Name = "Alarm_NewsOff", Alarm = new AlarmConfig { Enabled = true, Beacon = new AlarmItem { Enabled = true, BeaconColor = AlarmEnum.BeaconColor.None } } }; _configObservationServiceMock.Setup(c => c.Get(It.IsAny(), false)) .ReturnsAsync(obsConfig); await _calculatedObservations.Map(observation, false); _lightBeaconServiceMock.Verify( x => x.SendColor(It.Is(l => l.Equals(_patient.PointOfCareId)), LightBeaconColor.Off), Times.Once); } /// /// Verifies that when a with the "NEWS" name, "ADAS" coding system, and a value of 6 is processed, and the resolved enables a yellow beacon alarm, the is invoked exactly once to send to the patient's point of care. /// /// [Test] public async Task Calculate_CheckBeaconOnNEWS_Should_Send_Yellow() { var observation = new PatientObservation { Name = "NEWS", CodingSystem = "ADAS", Expires = 15, Value = 6, PatientId = _patientId, Time = DateTime.Now }; var obsConfig = new ConfigObservation { Name = "Alarm_NewsWarning", Alarm = new AlarmConfig { Enabled = true, Beacon = new AlarmItem { Enabled = true, BeaconColor = AlarmEnum.BeaconColor.Yellow } } }; _configObservationServiceMock.Setup(c => c.Get(It.IsAny(), false)) .ReturnsAsync(obsConfig); await _calculatedObservations.Map(observation, false); _lightBeaconServiceMock.Verify( x => x.SendColor(It.Is(l => l.Equals(_patient.PointOfCareId)), LightBeaconColor.Yellow), Times.Once); } /// /// Verifies that when a using the NEWS coding system is mapped and the resolved configuration defines an enabled red beacon alarm, the light beacon service is invoked exactly once to send the red color to the patient's point of care. /// /// [Test] public async Task Calculate_CheckBeaconOnNEWS_Should_Send_Red() { var observation = new PatientObservation { Name = "NEWS", CodingSystem = "ADAS", Expires = 15, Value = 8, PatientId = _patientId, Time = DateTime.Now }; var obsConfig = new ConfigObservation { Name = "Alarm_NewsAlert", Alarm = new AlarmConfig { Enabled = true, Beacon = new AlarmItem { Enabled = true, BeaconColor = AlarmEnum.BeaconColor.Red } } }; _configObservationServiceMock.Setup(c => c.Get(It.IsAny(), false)) .ReturnsAsync(obsConfig); await _calculatedObservations.Map(observation, false); _lightBeaconServiceMock.Verify( x => x.SendColor(It.Is(l => l.Equals(_patient.PointOfCareId)), LightBeaconColor.Red), Times.Once); } /// /// Verifies that .Map correctly produces a with name NEWS_EXTR_HI_Resp_Rate, coding system ADAS, and the same numeric value as the supplied respiratory rate (FR) when the latest ventilator rate, SpO2 and FiO2 observations are available. /// /// [Ignore("old NEWS calc")] [Test] public async Task Calculate_FR_Returns_NEWS_EXTR_HI_Resp_Rate() { var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = _patientId, Value = 90, Name = "FR" }; var observationVent = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = _patientId, Value = 90, Name = "Vent_Rat" }; var observationSpo2 = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = _patientId, Value = 90, Name = "SpO2" }; var observationFiO2 = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = _patientId, Value = 90, Name = "FiO2" }; _observationServiceMock .Setup(l => l.FindLastObservations(_patientId, 1, new List { "Vent_Rate" })) .ReturnsAsync([observationVent]); _observationServiceMock .Setup(l => l.FindLastObservations(_patientId, 1, new List { "FiO2", "SpO2" })) .ReturnsAsync([observationSpo2, observationFiO2]); await _calculatedObservations.Map(observation, false); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "NEWS_EXTR_HI_Resp_Rate" && arg.CodingSystem == "ADAS" && arg.Value.ToString() == "90" ), true, true)); } /// /// Verifies that mapping a named FR with an invalid (non-numeric) value does not produce a NEWS_EXTR_HI respiratory rate result and instead raises a , even when valid Vent_Rat, SpO2, and FiO2 observations are available for the same patient. /// /// [Test] public async Task Calculate_FR_Does_Not_Returns_NEWS_EXTR_HI_Resp_Rate_When_Invalid_Value() { var patientId = ObjectId.GenerateNewId(); var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = "90a", Name = "FR" }; var observationVent = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 90, Name = "Vent_Rat" }; var observationSpo2 = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 90, Name = "SpO2" }; var observationFiO2 = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 90, Name = "FiO2" }; _observationServiceMock .Setup(l => l.FindLastObservations(patientId, 1, new List { "Vent_Rate" })) .ReturnsAsync([observationVent]); _observationServiceMock .Setup(l => l.FindLastObservations(patientId, 1, new List { "FiO2", "SpO2" })) .ReturnsAsync([observationSpo2, observationFiO2]); Func act = () => _calculatedObservations.Map(observation, false); Assert.ThrowsAsync(act); } /// /// Verifies that mapping a respiratory rate (FR) observation through /// produces a /// NEWS_HI_Resp_Rate observation with the expected value (23) and coding system /// (ADAS), resolving the ventilator rate (Vent_Rat), SpO2, and FiO2 /// inputs via the mocked calls and inserting /// the result through . /// /// [Ignore("old NEWS calc")] [Test] public async Task Calculate_FR_Returns_NEWS_HI_Resp_Rate() { { var patientId = ObjectId.GenerateNewId(); var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 23, Name = "FR" }; var observationVent = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 90, Name = "Vent_Rat" }; var observationSpo2 = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 90, Name = "SpO2" }; var observationFiO2 = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 90, Name = "FiO2" }; _observationServiceMock .Setup(l => l.FindLastObservations(patientId, 1, new List { "Vent_Rate" })) .ReturnsAsync([observationVent]); _observationServiceMock .Setup(l => l.FindLastObservations(patientId, 1, new List { "FiO2", "SpO2" })) .ReturnsAsync([observationSpo2, observationFiO2]); await _calculatedObservations.Map(observation, false); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "NEWS_HI_Resp_Rate" && arg.CodingSystem == "ADAS" && arg.Value.ToString() == "23" ), true, true)); } } /// /// Verifies (under the legacy NEWS calculation path, currently ignored via ) that mapping a respiratory rate (FR) produces an inserted NEWS_EXTR_LO_Resp_Rate observation tagged with the ADAS coding system and carrying the same numeric value, using mocked supporting observations for ventilation rate (Vent_Rate) and oxygenation (SpO2, FiO2). /// /// [Ignore("old NEWS calc")] [Test] public async Task Calculate_FR_Returns_NEWS_EXTR_LO_Resp_Rate() { { var patientId = ObjectId.GenerateNewId(); var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 7, Name = "FR" }; var observationVent = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 90, Name = "Vent_Rat" }; var observationSpo2 = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 90, Name = "SpO2" }; var observationFiO2 = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 90, Name = "FiO2" }; _observationServiceMock .Setup(l => l.FindLastObservations(patientId, 1, new List { "Vent_Rate" })) .ReturnsAsync([observationVent]); _observationServiceMock .Setup(l => l.FindLastObservations(patientId, 1, new List { "FiO2", "SpO2" })) .ReturnsAsync([observationSpo2, observationFiO2]); await _calculatedObservations.Map(observation, false); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "NEWS_EXTR_LO_Resp_Rate" && arg.CodingSystem == "ADAS" && arg.Value.ToString() == "7" ), true, true)); } } /// /// Verifies that mapping a with an SpO2 value of 90 produces an inserted named NEWS_EXTR_LO_SpO2 using the ADAS coding system, by mocking the lookup of the last FiO2 and FR observations for the same . The test is annotated with [Ignore] because it targets the legacy NEWS calculation logic. /// /// [Ignore("old NEWS calc")] [Test] public async Task Calculate_SpO2_Returns_NEWS_EXTR_LO_SpO2() { { var patientId = ObjectId.GenerateNewId(); var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 90, Name = "SpO2" }; var observationFr = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 90, Name = "FR" }; _observationServiceMock .Setup(l => l.FindLastObservations(patientId, 1, new List { "FiO2", "FR" })) .ReturnsAsync([observation, observationFr]); await _calculatedObservations.Map(observation, false); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "NEWS_EXTR_LO_SpO2" && arg.CodingSystem == "ADAS" && arg.Value.ToString() == "90" ), true, true)); } } /// /// Verifies that mapping a SpO2 produces a NEWS Low SpO2 score with name "NEWS_LO_SpO2", coding system "ADAS", and a value reflecting the source SpO2 reading (93), while relying on the last available respiratory rate (FR) observation for the calculation. /// /// [Ignore("old NEWS calc")] [Test] public async Task Calculate_SpO2_Returns_NEWS_LO_SpO2() { { var patientId = ObjectId.GenerateNewId(); var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 93, Name = "SpO2" }; var observationFr = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 90, Name = "FR" }; _observationServiceMock .Setup(l => l.FindLastObservations(patientId, 1, new List { "FiO2", "FR" })) .ReturnsAsync([observation, observationFr]); await _calculatedObservations.Map(observation, false); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "NEWS_LO_SpO2" && arg.CodingSystem == "ADAS" && arg.Value.ToString() == "93" ), true, true)); } } /// /// Verifies that mapping a whose is Temperature results in a derived named NEWS_EXTR_LO_Temperature, coded under the ADAS system, and carrying the original numeric . /// Marked with because it covers the legacy NEWS calculation logic. /// /// [Ignore("old NEWS calc")] [Test] public async Task Calculate_Temperature_Returns_NEWS_EXTR_LO_Temperature() { { var patientId = ObjectId.GenerateNewId(); var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 30, Name = "Temperature" }; await _calculatedObservations.Map(observation, false); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "NEWS_EXTR_LO_Temperature" && arg.CodingSystem == "ADAS" && arg.Value.ToString() == "30" ), true, true)); } } /// /// Verifies that mapping a high with name "Temperature" and value 40 produces a calculated NEWS high-temperature observation (NEWS_HI_Temperature) under the ADAS coding system. /// /// [Ignore("old NEWS calc")] [Test] public async Task Calculate_Temperature_Returns_NEWS_HI_Temperature() { { var patientId = ObjectId.GenerateNewId(); var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 40, Name = "Temperature" }; await _calculatedObservations.Map(observation, false); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "NEWS_HI_Temperature" && arg.CodingSystem == "ADAS" && arg.Value.ToString() == "40" ), true, true)); } } /// /// Verifies that mapping a with the name "TAs" produces an associated low NEWS extra observation named "NEWS_EXTR_LO_TAs" in the ADAS coding system, carrying the same numeric value as the source observation. /// /// [Ignore("old NEWS calc")] [Test] public async Task Calculate_TAs_Returns_NEWS_EXTR_LO_TAs() { { var patientId = ObjectId.GenerateNewId(); var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 80, Name = "TAs" }; await _calculatedObservations.Map(observation, false); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "NEWS_EXTR_LO_TAs" && arg.CodingSystem == "ADAS" && arg.Value.ToString() == "80" ), true, true)); } } /// /// Verifies that when a TAs (systolic blood pressure) is mapped, a derived NEWS_LO_TAs observation is inserted with the expected and . /// This test is currently ignored because it targets the old NEWS calculation logic. /// /// [Ignore("old NEWS calc")] [Test] public async Task Calculate_TAs_Returns_NEWS_LO_TAs() { { var patientId = ObjectId.GenerateNewId(); var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 95, Name = "TAs" }; await _calculatedObservations.Map(observation, false); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "NEWS_LO_TAs" && arg.CodingSystem == "ADAS" && arg.Value.ToString() == "95" ), true, true)); } } /// /// Verifies that mapping a named "TAs" with a value of 240 produces an inserted observation named "NEWS_EXTR_HI_TAs" under the "ADAS" coding system through . The test is currently ignored as it covers the old NEWS calculation logic. /// /// [Ignore("old NEWS calc")] [Test] public async Task Calculate_TAs_Returns_NEWS_EXTR_HI_TAs() { { var patientId = ObjectId.GenerateNewId(); var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 240, Name = "TAs" }; await _calculatedObservations.Map(observation, false); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "NEWS_EXTR_HI_TAs" && arg.CodingSystem == "ADAS" && arg.Value.ToString() == "240" ), true, true)); } } /// /// Verifies that mapping a with the name "FC" and a value of 20 produces an inserted calculated observation named "NEWS_EXTR_LO_FC" using the "ADAS" coding system, where the inserted value matches the original value of 20. /// /// [Ignore("old NEWS calc")] [Test] public async Task Calculate_FC_Returns_NEWS_EXTR_LO_FC() { { var patientId = ObjectId.GenerateNewId(); var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 20, Name = "FC" }; await _calculatedObservations.Map(observation, false); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "NEWS_EXTR_LO_FC" && arg.CodingSystem == "ADAS" && arg.Value.ToString() == "20" ), true, true)); } } /// /// Verifies that mapping a with a heart rate (FC) value of 140 through the calculation pipeline produces a derived NEWS extra-high heart rate (NEWS_EXTR_HI_FC) observation carrying the same value and tagged with the ADAS coding system. /// /// [Ignore("old NEWS calc")] [Test] public async Task Calculate_FC_Returns_NEWS_EXTR_HI_FC() { { var patientId = ObjectId.GenerateNewId(); var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 140, Name = "FC" }; await _calculatedObservations.Map(observation, false); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "NEWS_EXTR_HI_FC" && arg.CodingSystem == "ADAS" && arg.Value.ToString() == "140" ), true, true)); } } /// /// Verifies that mapping a named "FC" with value 120 produces a derived "NEWS_HI_FC" observation that is inserted through the observation service under the "ADAS" coding system with the original value preserved. /// The test is marked as ignored because it targets the legacy NEWS calculation flow. /// /// [Ignore("old NEWS calc")] [Test] public async Task Calculate_FC_Returns_NEWS_HI_FC() { { var patientId = ObjectId.GenerateNewId(); var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 120, Name = "FC" }; await _calculatedObservations.Map(observation, false); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "NEWS_HI_FC" && arg.CodingSystem == "ADAS" && arg.Value.ToString() == "120" ), true, true)); } } /// /// Verifies that during the pre-mapping of a list of items, any observation named MDC_VENT_RESP_RATE (code 151586) is removed from the resulting list and inserted as a separate observation via . /// /// [Test] public async Task Check_MDC_VENT_RESP_RATE_IsInsertedBefore_And_RemoveFromList() { var patientId = ObjectId.GenerateNewId(); var now = DateTime.Now; var listObsToOrder = new List { new() { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 7, Code = "151586", CodingSystem = "MDC", Name = "MDC_VENT_RESP_RATE", Time = now }, new() { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 113, ParentData = new ParentDataClass { Code = "69965", CodingSystem = "MDC", Name = "MDC_DEV_MON_PHYSIO_MULTI_PARAM_MDS" }, Code = "151562", CodingSystem = "MDC", Name = "MDC_RESP_RATE", Time = now }, new() { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 11, ParentData = new ParentDataClass { Code = "69965", CodingSystem = "MDC", Name = "MDC_DEV_MON_PHYSIO_MULTI_PARAM_MDS" }, Code = "150456", CodingSystem = "MDC", Name = "MDC_PULS_OXIM_SAT_O2", Time = now } }; var orderedList = await _calculatedObservations.PreMapList(listObsToOrder); Assert.That(orderedList.All(obs => obs.Name != "MDC_VENT_RESP_RATE"), Is.True); _observationServiceMock.Verify(o => o.InsertObservation( It.Is(obs => obs.Code != null && obs.Code == "151586"), true, true), Times.Once); } /// /// Verifies that when mapping processes a respiratory-rate observation alongside a preceding vent-rate observation returned by , the calculated respiratory-rate observation is inserted with its offset by one second from the source observation and with its populated from the vent-rate observation. /// /// [Test] public async Task Check_Insert_Resp_Rate_Calculated_HasTimePlusOneSecond_And_Resp_Rate_Calculated_HasVentRateAsParent() { var patientId = ObjectId.GenerateNewId(); var now = DateTime.Now; var nowPlusOneSecond = now.AddSeconds(1); var ventRate = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 7, Code = "151586", CodingSystem = "MDC", Name = "Vent_Rate", Time = now }; var fr = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 113, ParentData = new ParentDataClass { Code = "69965", CodingSystem = "MDC", Name = "MDC_DEV_MON_PHYSIO_MULTI_PARAM_MDS" }, Code = "151562", CodingSystem = "MDC", Name = "FR", Time = now }; _observationServiceMock.Setup(o => o.FindLastObservations(patientId, 1, It.IsAny>())) .ReturnsAsync([ventRate]); await _calculatedObservations.Map(ventRate, false); await _calculatedObservations.Map(fr, false); _observationServiceMock.Verify(o => o.InsertObservation( It.Is(obs => obs.ParentData != null && obs.ParentData.Name == "Vent_Rate" && obs.Time == nowPlusOneSecond), true, true), Times.Once); } /// /// Verifies that mapping a patient observation with the name Resp_Mode and value PC-AC /// through .Map produces a calculated observation named /// Resp_Type using the ADAS coding system with the value /// . /// /// A representing the asynchronous unit test execution. /// [Test] public async Task Calculate_Ventilation_Mode_Should_Return_INVASIVE() { var patientId = ObjectId.GenerateNewId(); var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = "PC-AC", Name = "Resp_Mode" }; await _calculatedObservations.Map(observation, false); _observationServiceMock.Verify(o => o.InsertIfChanged("Resp_Type", It.Is(arg => arg.Name == "Resp_Type" && arg.CodingSystem == "ADAS" && arg.Value.ToString() == RespirationType.Invasive.ToString() ), true, true)); } /// /// Verifies that mapping a for respiratory mode with a non-invasive ventilation value produces a calculated Resp_Type observation classified as . /// /// [Test] public async Task Calculate_Ventilation_Mode_Should_Return_NON_INVASIVE() { { var patientId = ObjectId.GenerateNewId(); var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = _nonInvasiveVentilationValues[0].Trim(), Name = "Resp_Mode" }; await _calculatedObservations.Map(observation, false); _observationServiceMock.Verify(o => o.InsertIfChanged("Resp_Type", It.Is(arg => arg.Name == "Resp_Type" && arg.CodingSystem == "ADAS" && arg.Value.ToString() == RespirationType.NonInvasive.ToString() ), true, true)); } } /// /// Verifies that mapping a whose is "Resp_Mode" and is "HNF" causes the calculation service to insert an observation with the "Resp_Type", the "ADAS", and the set to . /// /// [Test] public async Task Calculate_Ventilation_Mode_Should_Return_HIGH_FREQUENCY() { { var patientId = ObjectId.GenerateNewId(); var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = _highFrequencyVentilationValues[0].Trim(), Name = "Resp_Mode", Code = "HNF" }; await _calculatedObservations.Map(observation, false); _observationServiceMock.Verify(o => o.InsertIfChanged("Resp_Type", It.Is(arg => arg.Name == "Resp_Type" && arg.CodingSystem == "ADAS" && arg.Value.ToString() == RespirationType.HighFrequencyVentilation.ToString() ), true, true)); } } //[Test] //public void CalculateCam_Icu_Received_1_Return_Positivo() //{ // var patientId = ObjectId.GenerateNewId(); // var now = DateTime.Now; // var observation = new PatientObservation // { // id = ObjectId.GenerateNewId(), // patientid = patientId, // value = 1, // name = "Cam_Icu" // }; // calculatedObservations.Map(observation, false); // observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => // arg.name == "Cam_IcuCalculated" && // arg.codingSystem == "ADAS" && // arg.value.ToString() == "Positivo" // ), true, true)); //} //[Test] //public void CalculateCam_Icu_Received_0_Return_Negativo() //{ // var patientId = ObjectId.GenerateNewId(); // var now = DateTime.Now; // var observation = new PatientObservation // { // id = ObjectId.GenerateNewId(), // patientid = patientId, // value = 0, // name = "Cam_Icu" // }; // calculatedObservations.Map(observation, false); // observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => // arg.name == "Cam_IcuCalculated" && // arg.codingSystem == "ADAS" && // arg.value.ToString() == "Negativo" // ), true, true)); //} //[Test] //public void CalculateCam_Icu_Received_different_0_1_Return_Value_null() //{ // var patientId = ObjectId.GenerateNewId(); // var now = DateTime.Now; // var observation = new PatientObservation // { // id = ObjectId.GenerateNewId(), // patientid = patientId, // value=2, // name = "Cam_Icu" // }; // calculatedObservations.Map(observation, false); // observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => // arg.name == "Cam_IcuCalculated" && // arg.codingSystem == "ADAS" && // arg.value==null // ), true, true)); //} //[Test] //public void CalculateCam_Icu_Received_null_Return_Value_null() //{ // var patientId = ObjectId.GenerateNewId(); // var now = DateTime.Now; // var observation = new PatientObservation // { // id = ObjectId.GenerateNewId(), // patientid = patientId, // name = "Cam_Icu" // }; // calculatedObservations.Map(observation, false); // observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => // arg.name == "Cam_IcuCalculated" && // arg.codingSystem == "ADAS" && // arg.value == null // ), true, true)); //} /// /// Verifies that the mapping logic computes a diuresis-to-weight ratio of 43.6 from a diuresis observation of 3924 and a weight observation of 90 for the same patient, inserting the result as a new named "Diuresis_Weight". /// /// [Test] public async Task CalculateDiuresis_Weight_Received_D_3924_W_90_Return_43_6() { var patientId = ObjectId.GenerateNewId(); var patientObservation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 90, Name = "Weight_Current" }; var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 3924, Name = "Diuresis" }; _observationServiceMock.Setup(o => o.FindLastObservations(patientId, 1, It.IsAny>())) .ReturnsAsync([patientObservation]); await _calculatedObservations.Map(observation, false); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "Diuresis_Weight" && arg.PatientId == patientId && Math.Abs((double)arg.Value - 43.6) < 0.1 ), true, true)); } /// /// Verifies that . correctly computes the diuresis-to-weight ratio as 43.6 when the latest diuresis observation value is 3924 and the current weight observation value is 90, and persists a derived named "Diuresis_Weight" for the same . /// /// [Test] public async Task CalculateDiuresis_Weight_D_3924_Receive_W_90_Return_43_6() { var patientId = ObjectId.GenerateNewId(); var patientObservation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 3924, Name = "Diuresis" }; var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 90, Name = "Weight_Current" }; _observationServiceMock.Setup(o => o.FindLastObservations(patientId, 1, It.IsAny>())) .ReturnsAsync([patientObservation]); await _calculatedObservations.Map(observation, false); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "Diuresis_Weight" && arg.PatientId == patientId && Math.Abs((double)arg.Value - 43.6) <= 0 ), true, true)); } /// /// Verifies that when a with the name Weight_Current is received but no prior diuresis observations exist for the patient, the mapping does not insert any calculated observation. /// /// [Test] public async Task CalculateDiuresis_Weight_Received_W_90_D_Null_Return_Nothing() { var patientId = ObjectId.GenerateNewId(); var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 90, Name = "Weight_Current" }; _observationServiceMock.Setup(o => o.FindLastObservations(patientId, 1, It.IsAny>())) .ReturnsAsync([]); await _calculatedObservations.Map(observation, false); _observationServiceMock.Verify(o => o.InsertObservation(It.IsAny(), true, true), Times.Never); } /// /// Verifies that when receives a Diuresis observation with value 3924 and the lookup for the last observation returns no results, the calculated "Diuresis_Weight" observation is not inserted. /// /// [Test] public async Task CalculateDiuresis_Weight_Received_D_3924_W_Null_Return_Nothing() { var patientId = ObjectId.GenerateNewId(); var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = 3924, Name = "Diuresis" }; _observationServiceMock.Setup(s => s.FindLastObservations(It.IsAny(), 1, It.IsAny>())) .ReturnsAsync([]); await _calculatedObservations.Map(observation, false); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "Diuresis_Weight" && arg.PatientId == patientId ), true, true), Times.Never); } /// /// Verifies that mapping a named "AllergiesObs" containing an empty list of produces a calculated named "Allergies" with an empty string value for the given patient. /// /// [Test] public async Task CalculateAllergiesObservation_Received_AllergiesObs_Emty_Return_Allergies_Emty() { var patientId = ObjectId.GenerateNewId(); List patientAllergiesValues = []; var patientObservation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = patientAllergiesValues, Name = "AllergiesObs" }; await _calculatedObservations.Map(patientObservation, false); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "Allergies" && arg.PatientId == patientId && (string)arg.Value == string.Empty ), true, true)); } /// /// Verifies that mapping a named "AllergiesObs" that contains non-pharmacological allergies (such as "Latex" and "Alergia ambiental") results in the insertion of an "Allergies" observation whose value is the uppercase, comma-separated concatenation of the allergy types (e.g., "LATEX, AMBIENTAL"). /// /// [Test] public async Task CalculateAllergiesObservation_Received_AllergiesObs_Without_Farmacos_Return_Allergies() { var patientId = ObjectId.GenerateNewId(); List patientAllergiesValues = [ new() { Type = "Latex", Value = "Si", Notes = "" }, new() { Type = "Alergia ambiental", Value = "Estacional", Notes = "epitelio de perro, mezcla de gramíneas salvajes," } ]; var patientObservation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = patientAllergiesValues, Name = "AllergiesObs" }; await _calculatedObservations.Map(patientObservation, false); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "Allergies" && arg.PatientId == patientId && (string)arg.Value == "LATEX, AMBIENTAL" ), true, true)); } /// /// Verifies that consolidates a received AllergiesObs containing one drug allergy (fármacos), a latex allergy, and an environmental allergy into a single named Allergies for the same , with the values merged into the formatted string LATEX, AMBIENTAL, FÁRMACOS (METILPREDNISOLONA). /// /// [Test] public async Task CalculateAllergiesObservation_Received_AllergiesObs_With_1_Farmacos_Return_Allergies() { var patientId = ObjectId.GenerateNewId(); List patientAllergiesValues = [ new() { Type = "Alergia a fármacos", Value = "METILPREDNISOLONA", Notes = "Tolera dexametasona y actocortina" }, new() { Type = "Latex", Value = "Si", Notes = "" }, new() { Type = "Alergia ambiental", Value = "Estacional", Notes = "epitelio de perro, mezcla de gramíneas salvajes," } ]; var patientObservation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = patientAllergiesValues, Name = "AllergiesObs" }; await _calculatedObservations.Map(patientObservation, false); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "Allergies" && arg.PatientId == patientId && (string)arg.Value == "LATEX, AMBIENTAL, FÁRMACOS (METILPREDNISOLONA)" ), true, true)); } /// /// Verifies that aggregates a received AllergiesObs observation containing multiple allergy types — including two drug allergies (METILPREDNISOLONA and Penicilina/cefalosporinas), a latex allergy and an environmental allergy — into a single named Allergies, whose value combines the allergy categories and the drug allergens into the expected grouped string. /// /// [Test] public async Task CalculateAllergiesObservation_Received_AllergiesObs_With_2_Farmacos_Return_Allergies() { var patientId = ObjectId.GenerateNewId(); List patientAllergiesValues = [ new() { Type = "Alergia a fármacos", Value = "METILPREDNISOLONA", Notes = "Tolera dexametasona y actocortina" }, new() { Type = "Latex", Value = "Si", Notes = "" }, new() { Type = "Alergia a fármacos", Value = "Penicilina/cefalosporinas" }, new() { Type = "Alergia ambiental", Value = "Estacional", Notes = "epitelio de perro, mezcla de gramíneas salvajes," } ]; var patientObservation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Value = patientAllergiesValues, Name = "AllergiesObs" }; await _calculatedObservations.Map(patientObservation, false); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "Allergies" && arg.PatientId == patientId && (string)arg.Value == "LATEX, AMBIENTAL, FÁRMACOS (METILPREDNISOLONA, PENICILINA/CEFALOSPORINAS)" ), true, true)); } /// /// Verifies that when a carrying a of type "Drenaje ventricular" with volume 60 and height 8 is processed by the calculator, two derived observations are inserted: one named "DVE" carrying the volume value and another named "Drainage_Height" carrying the height value, both under the "ADAS" coding system. /// /// [Test] public async Task Calculate_Drainages_Received_volume_60_height_8_Return_DVE_height() { var patientId = ObjectId.GenerateNewId(); var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Name = "DrainagesObs", Value = new PatientDrainagesValue { Type = "Drenaje ventricular", Volume = 60, Height = 8 } }; await _calculatedObservations.Map(observation, false); int valueParsed; _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "DVE" && arg.CodingSystem == "ADAS" && arg.PatientId == patientId && int.TryParse(arg.Value.ToString(), out valueParsed) && valueParsed == 60 ), true, true)); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "Drainage_Height" && arg.CodingSystem == "ADAS" && arg.PatientId == patientId && int.TryParse(arg.Value.ToString(), out valueParsed) && valueParsed == 8 ), true, true)); } /// /// Verifies that mapping a carrying a of type "Drenaje ventricular" with a volume of 60 and no height produces a "DVE" observation while suppressing the "Drainage_Height" observation. /// /// [Test] public async Task Calculate_Drainages_Received_volume_60_height_null_Return_DVE() { var patientId = ObjectId.GenerateNewId(); var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Name = "DrainagesObs", Value = new PatientDrainagesValue { Type = "Drenaje ventricular", Volume = 60 } }; await _calculatedObservations.Map(observation, false); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "DVE" && arg.CodingSystem == "ADAS" && arg.PatientId == patientId && int.Parse(arg.Value.ToString()!) == 60 ), true, true)); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "Drainage_Height" && arg.CodingSystem == "ADAS" && arg.PatientId == patientId ), true, true), Times.Never); } /// /// Verifies that when a containing a /// has a null received volume but a defined height (8), the mapping inserts a new observation named "Drainage_Height" /// with the height value while not creating a "DVE" observation. /// /// [Test] public async Task Calculate_Drainages_Received_volume_null_height_8_Return_height() { var patientId = ObjectId.GenerateNewId(); var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Name = "DrainagesObs", Value = new PatientDrainagesValue { Type = "Drenaje ventricular", Height = 8 } }; await _calculatedObservations.Map(observation, false); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "DVE" && arg.CodingSystem == "ADAS" && arg.PatientId == patientId ), true, true), Times.Never); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "Drainage_Height" && arg.CodingSystem == "ADAS" && arg.PatientId == patientId && int.Parse(arg.Value.ToString()!) == 8 ), true, true)); } /// /// Tests that mapping a of drainages type with null volume and null height values /// does not generate any calculated DVE or Drainage_Height observations. /// /// [Test] public async Task Calculate_Drainages_Received_volume_null_height_null_Return_nothing() { var patientId = ObjectId.GenerateNewId(); var observation = new PatientObservation { Id = ObjectId.GenerateNewId(), PatientId = patientId, Name = "DrainagesObs", Value = new PatientDrainagesValue { Type = "Drenaje ventricular" } }; await _calculatedObservations.Map(observation, false); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "DVE" && arg.CodingSystem == "ADAS" && arg.PatientId == patientId ), true, true), Times.Never); _observationServiceMock.Verify(o => o.InsertObservation(It.Is(arg => arg.Name == "Drainage_Height" && arg.CodingSystem == "ADAS" && arg.PatientId == patientId ), true, true), Times.Never); } }