Files
adas-core/adas-core.Test/Customizations/HRYC/CalculatedObservationsTest.cs
T

1564 lines
60 KiB
C#

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;
/// <summary>
/// Provides an NUnit test fixture that verifies the behavior of calculated observations.
/// </summary>
/// <remarks>
/// Decorated with <see cref="TestFixtureAttribute"/> to mark the class as a container for related NUnit test methods that exercise calculated observation logic.
/// </remarks>
/// <!-- aidoc:v1 sig=ce3e368 -->
[TestFixture]
public class CalculatedObservationsTest
{
/// <summary>
/// Initializes the test environment for <see cref="CalculatedObservations"/> by mocking <see cref="IObservationService"/>, <see cref="IPatientService"/>, <see cref="ILightBeaconService"/>, and <see cref="IConfigObservationService"/>, configuring the latter to look up NEWS alert configurations by <see cref="PatientObservation.Name"/> and return <see langword="null"/> when no entry matches, registering all dependencies through a <see cref="ServiceCollection"/>, and providing a sample <see cref="Patient"/> resolved by its <see cref="Patient.Id"/>.
/// </summary>
/// <!-- aidoc:v1 sig=dee8bf2 body=439c7b9 -->
[SetUp]
public void Setup()
{
_observationServiceMock = new Mock<IObservationService>();
var observationServiceLazy = new Lazy<IObservationService>(() => _observationServiceMock.Object);
_patientServiceMock = new Mock<IPatientService>();
var patientServiceLazy = new Lazy<IPatientService>(() => _patientServiceMock.Object);
_lightBeaconServiceMock = new Mock<ILightBeaconService>();
var lightBeaconServiceLazy = new Lazy<ILightBeaconService>(() => _lightBeaconServiceMock.Object);
var listAlertNewsObsConfig = new List<ConfigObservation>
{
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<IConfigObservationService>();
_configObservationServiceMock
.Setup(x => x.Get(It.IsAny<PatientObservation>(), It.IsAny<bool>()))
.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<ILogger<CalculatedObservations>>();
_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<bool>()))
.ReturnsAsync(_patient);
}
private CalculatedObservations _calculatedObservations;
private Mock<IObservationService> _observationServiceMock;
private Mock<IPatientService> _patientServiceMock;
private Mock<ILightBeaconService> _lightBeaconServiceMock;
private Mock<IConfigObservationService> _configObservationServiceMock;
private Mock<ILogger<CalculatedObservations>> _logger;
private readonly ApiSettings _apiSettings = new()
{
ConfigObservation = new ConfigObservationSettings
{
IgnoreUnknownObservation = false
}
};
private IOptions<ApiSettings> _optionsApiSettings;
private readonly List<string> _highFrequencyVentilationValues = ["HNF"];
private readonly List<string> _nonInvasiveVentilationValues = ["BIPAP", "CPAP"];
private readonly List<string> _invasiveVentilationValues = [];
private ObjectId _patientId = ObjectId.GenerateNewId();
private ObjectId _patientPocId = ObjectId.GenerateNewId();
private ObjectId _patientUnitId = ObjectId.GenerateNewId();
private Patient _patient;
/// <summary>
/// Verifies that mapping a <see cref="PatientObservation"/> with <c>NEWS</c> coding, when the resolved <see cref="ConfigObservation"/> enables a beacon alarm with <see cref="AlarmEnum.BeaconColor.None"/>, triggers the light beacon service to send <see cref="LightBeaconColor.Off"/> to the patient's <see cref="BasePatientObservation.PointOfCareId"/>.
/// </summary>
/// <!-- aidoc:v1 sig=e823ca6 body=65dc365 -->
[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<PatientObservation>(), false))
.ReturnsAsync(obsConfig);
await _calculatedObservations.Map(observation, false);
_lightBeaconServiceMock.Verify(
x => x.SendColor(It.Is<ObjectId>(l => l.Equals(_patient.PointOfCareId)), LightBeaconColor.Off),
Times.Once);
}
/// <summary>
/// Verifies that when a <see cref="PatientObservation"/> with the "NEWS" name, "ADAS" coding system, and a value of 6 is processed, and the resolved <see cref="ConfigObservation"/> enables a yellow beacon alarm, the <see cref="LightBeaconService"/> is invoked exactly once to send <see cref="LightBeaconColor.Yellow"/> to the patient's point of care.
/// </summary>
/// <!-- aidoc:v1 sig=aa7e929 body=e6fe577 -->
[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<PatientObservation>(), false))
.ReturnsAsync(obsConfig);
await _calculatedObservations.Map(observation, false);
_lightBeaconServiceMock.Verify(
x => x.SendColor(It.Is<ObjectId>(l => l.Equals(_patient.PointOfCareId)),
LightBeaconColor.Yellow), Times.Once);
}
/// <summary>
/// Verifies that when a <see cref="PatientObservation"/> 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.
/// </summary>
/// <!-- aidoc:v1 sig=843f672 body=55f19b1 -->
[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<PatientObservation>(), false))
.ReturnsAsync(obsConfig);
await _calculatedObservations.Map(observation, false);
_lightBeaconServiceMock.Verify(
x => x.SendColor(It.Is<ObjectId>(l => l.Equals(_patient.PointOfCareId)), LightBeaconColor.Red),
Times.Once);
}
/// <summary>
/// Verifies that <see cref="_calculatedObservations"/>.Map correctly produces a <see cref="PatientObservation"/> with name <c>NEWS_EXTR_HI_Resp_Rate</c>, coding system <c>ADAS</c>, and the same numeric value as the supplied respiratory rate (<c>FR</c>) when the latest ventilator rate, <c>SpO2</c> and <c>FiO2</c> observations are available.
/// </summary>
/// <!-- aidoc:v1 sig=49f263a body=aad4daf -->
[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<string> { "Vent_Rate" }))
.ReturnsAsync([observationVent]);
_observationServiceMock
.Setup(l => l.FindLastObservations(_patientId, 1, new List<string> { "FiO2", "SpO2" }))
.ReturnsAsync([observationSpo2, observationFiO2]);
await _calculatedObservations.Map(observation, false);
_observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
arg.Name == "NEWS_EXTR_HI_Resp_Rate" &&
arg.CodingSystem == "ADAS" &&
arg.Value.ToString() == "90"
), true, true));
}
/// <summary>
/// Verifies that mapping a <see cref="PatientObservation"/> named <c>FR</c> with an invalid (non-numeric) value does not produce a NEWS_EXTR_HI respiratory rate result and instead raises a <see cref="FormatException"/>, even when valid <c>Vent_Rat</c>, <c>SpO2</c>, and <c>FiO2</c> observations are available for the same patient.
/// </summary>
/// <!-- aidoc:v1 sig=80e9384 body=260f9f8 -->
[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<string> { "Vent_Rate" }))
.ReturnsAsync([observationVent]);
_observationServiceMock
.Setup(l => l.FindLastObservations(patientId, 1, new List<string> { "FiO2", "SpO2" }))
.ReturnsAsync([observationSpo2, observationFiO2]);
Func<Task> act = () => _calculatedObservations.Map(observation, false);
Assert.ThrowsAsync<FormatException>(act);
}
/// <summary>
/// Verifies that mapping a respiratory rate (<c>FR</c>) observation through
/// <see cref="ICalculatedObservations.Map(PatientObservation, bool)"/> produces a
/// <c>NEWS_HI_Resp_Rate</c> observation with the expected value (<c>23</c>) and coding system
/// (<c>ADAS</c>), resolving the ventilator rate (<c>Vent_Rat</c>), <c>SpO2</c>, and <c>FiO2</c>
/// inputs via the mocked <see cref="IObservationService.FindLastObservations"/> calls and inserting
/// the result through <see cref="IObservationService.InsertObservation"/>.
/// </summary>
/// <!-- aidoc:v1 sig=36eec84 body=c350cc3 -->
[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<string> { "Vent_Rate" }))
.ReturnsAsync([observationVent]);
_observationServiceMock
.Setup(l => l.FindLastObservations(patientId, 1, new List<string> { "FiO2", "SpO2" }))
.ReturnsAsync([observationSpo2, observationFiO2]);
await _calculatedObservations.Map(observation, false);
_observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
arg.Name == "NEWS_HI_Resp_Rate" &&
arg.CodingSystem == "ADAS" &&
arg.Value.ToString() == "23"
), true, true));
}
}
/// <summary>
/// Verifies (under the legacy NEWS calculation path, currently ignored via <see cref="IgnoreAttribute"/>) that mapping a respiratory rate (<c>FR</c>) <see cref="PatientObservation"/> produces an inserted <c>NEWS_EXTR_LO_Resp_Rate</c> observation tagged with the <c>ADAS</c> coding system and carrying the same numeric value, using mocked supporting observations for ventilation rate (<c>Vent_Rate</c>) and oxygenation (<c>SpO2</c>, <c>FiO2</c>).
/// </summary>
/// <!-- aidoc:v1 sig=4fa8ea2 body=f8aaeaa -->
[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<string> { "Vent_Rate" }))
.ReturnsAsync([observationVent]);
_observationServiceMock
.Setup(l => l.FindLastObservations(patientId, 1, new List<string> { "FiO2", "SpO2" }))
.ReturnsAsync([observationSpo2, observationFiO2]);
await _calculatedObservations.Map(observation, false);
_observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
arg.Name == "NEWS_EXTR_LO_Resp_Rate" &&
arg.CodingSystem == "ADAS" &&
arg.Value.ToString() == "7"
), true, true));
}
}
/// <summary>
/// Verifies that mapping a <see cref="PatientObservation"/> with an SpO2 value of 90 produces an inserted <see cref="PatientObservation"/> named <c>NEWS_EXTR_LO_SpO2</c> using the <c>ADAS</c> coding system, by mocking the lookup of the last <c>FiO2</c> and <c>FR</c> observations for the same <see cref="PatientObservation.PatientId"/>. The test is annotated with <c>[Ignore]</c> because it targets the legacy NEWS calculation logic.
/// </summary>
/// <!-- aidoc:v1 sig=937a891 body=deafefb -->
[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<string> { "FiO2", "FR" }))
.ReturnsAsync([observation, observationFr]);
await _calculatedObservations.Map(observation, false);
_observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
arg.Name == "NEWS_EXTR_LO_SpO2" &&
arg.CodingSystem == "ADAS" &&
arg.Value.ToString() == "90"
), true, true));
}
}
/// <summary>
/// Verifies that mapping a SpO2 <see cref="PatientObservation"/> produces a NEWS Low SpO2 score <see cref="PatientObservation"/> 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.
/// </summary>
/// <!-- aidoc:v1 sig=686d725 body=e5019f8 -->
[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<string> { "FiO2", "FR" }))
.ReturnsAsync([observation, observationFr]);
await _calculatedObservations.Map(observation, false);
_observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
arg.Name == "NEWS_LO_SpO2" &&
arg.CodingSystem == "ADAS" &&
arg.Value.ToString() == "93"
), true, true));
}
}
/// <summary>
/// Verifies that mapping a <see cref="PatientObservation"/> whose <see cref="BasePatientObservation.Name"/> is <c>Temperature</c> results in a derived <see cref="PatientObservation"/> named <c>NEWS_EXTR_LO_Temperature</c>, coded under the <c>ADAS</c> system, and carrying the original numeric <see cref="BasePatientObservation.Value"/>.
/// Marked with <see cref="IgnoreAttribute"/> because it covers the legacy NEWS calculation logic.
/// </summary>
/// <!-- aidoc:v1 sig=34bdb7c body=0b6d2c3 -->
[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<PatientObservation>(arg =>
arg.Name == "NEWS_EXTR_LO_Temperature" &&
arg.CodingSystem == "ADAS" &&
arg.Value.ToString() == "30"
), true, true));
}
}
/// <summary>
/// Verifies that mapping a high <see cref="PatientObservation"/> with name "Temperature" and value 40 produces a calculated NEWS high-temperature observation (<c>NEWS_HI_Temperature</c>) under the <c>ADAS</c> coding system.
/// </summary>
/// <!-- aidoc:v1 sig=2cfd40e body=7a7791e -->
[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<PatientObservation>(arg =>
arg.Name == "NEWS_HI_Temperature" &&
arg.CodingSystem == "ADAS" &&
arg.Value.ToString() == "40"
), true, true));
}
}
/// <summary>
/// Verifies that mapping a <see cref="PatientObservation"/> 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.
/// </summary>
/// <!-- aidoc:v1 sig=32954ae body=a546520 -->
[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<PatientObservation>(arg =>
arg.Name == "NEWS_EXTR_LO_TAs" &&
arg.CodingSystem == "ADAS" &&
arg.Value.ToString() == "80"
), true, true));
}
}
/// <summary>
/// Verifies that when a <c>TAs</c> (systolic blood pressure) <see cref="PatientObservation"/> is mapped, a derived <c>NEWS_LO_TAs</c> observation is inserted with the expected <see cref="PatientObservation.CodingSystem"/> and <see cref="PatientObservation.Value"/>.
/// This test is currently ignored because it targets the old NEWS calculation logic.
/// </summary>
/// <!-- aidoc:v1 sig=a6cacee body=6089652 -->
[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<PatientObservation>(arg =>
arg.Name == "NEWS_LO_TAs" &&
arg.CodingSystem == "ADAS" &&
arg.Value.ToString() == "95"
), true, true));
}
}
/// <summary>
/// Verifies that mapping a <see cref="PatientObservation"/> named "TAs" with a value of 240 produces an inserted observation named "NEWS_EXTR_HI_TAs" under the "ADAS" coding system through <see cref="_calculatedObservations"/>. The test is currently ignored as it covers the old NEWS calculation logic.
/// </summary>
/// <!-- aidoc:v1 sig=1b56dd6 body=7a377a8 -->
[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<PatientObservation>(arg =>
arg.Name == "NEWS_EXTR_HI_TAs" &&
arg.CodingSystem == "ADAS" &&
arg.Value.ToString() == "240"
), true, true));
}
}
/// <summary>
/// Verifies that mapping a <see cref="PatientObservation"/> 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.
/// </summary>
/// <!-- aidoc:v1 sig=58742a8 body=f2f71c1 -->
[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<PatientObservation>(arg =>
arg.Name == "NEWS_EXTR_LO_FC" &&
arg.CodingSystem == "ADAS" &&
arg.Value.ToString() == "20"
), true, true));
}
}
/// <summary>
/// Verifies that mapping a <see cref="PatientObservation"/> with a heart rate (FC) value of 140 through the calculation pipeline produces a derived NEWS extra-high heart rate (<c>NEWS_EXTR_HI_FC</c>) observation carrying the same value and tagged with the ADAS coding system.
/// </summary>
/// <!-- aidoc:v1 sig=1eb9206 body=e721300 -->
[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<PatientObservation>(arg =>
arg.Name == "NEWS_EXTR_HI_FC" &&
arg.CodingSystem == "ADAS" &&
arg.Value.ToString() == "140"
), true, true));
}
}
/// <summary>
/// Verifies that mapping a <see cref="PatientObservation"/> 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.
/// </summary>
/// <!-- aidoc:v1 sig=2bf5811 body=3387162 -->
[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<PatientObservation>(arg =>
arg.Name == "NEWS_HI_FC" &&
arg.CodingSystem == "ADAS" &&
arg.Value.ToString() == "120"
), true, true));
}
}
/// <summary>
/// Verifies that during the pre-mapping of a list of <see cref="PatientObservation"/> items, any observation named <c>MDC_VENT_RESP_RATE</c> (code <c>151586</c>) is removed from the resulting list and inserted as a separate observation via <see cref="IObservationService.InsertObservation"/>.
/// </summary>
/// <!-- aidoc:v1 sig=fb56de1 body=f339d1c -->
[Test]
public async Task Check_MDC_VENT_RESP_RATE_IsInsertedBefore_And_RemoveFromList()
{
var patientId = ObjectId.GenerateNewId();
var now = DateTime.Now;
var listObsToOrder = new List<PatientObservation>
{
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<PatientObservation>(obs =>
obs.Code != null &&
obs.Code == "151586"), true, true), Times.Once);
}
/// <summary>
/// Verifies that when <see cref="PatientObservation"/> mapping processes a respiratory-rate observation alongside a preceding vent-rate observation returned by <see cref="IObservationService.FindLastObservations"/>, the calculated respiratory-rate observation is inserted with its <see cref="PatientObservation.Time"/> offset by one second from the source observation and with its <see cref="PatientObservation.ParentData"/> populated from the vent-rate observation.
/// </summary>
/// <!-- aidoc:v1 sig=c5af3a7 body=2299b03 -->
[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<List<string>>()))
.ReturnsAsync([ventRate]);
await _calculatedObservations.Map(ventRate, false);
await _calculatedObservations.Map(fr, false);
_observationServiceMock.Verify(o => o.InsertObservation(
It.Is<PatientObservation>(obs =>
obs.ParentData != null &&
obs.ParentData.Name == "Vent_Rate" &&
obs.Time == nowPlusOneSecond), true, true), Times.Once);
}
/// <summary>
/// Verifies that mapping a patient observation with the name <c>Resp_Mode</c> and value <c>PC-AC</c>
/// through <see cref="_calculatedObservations"/>.Map produces a calculated observation named
/// <c>Resp_Type</c> using the <c>ADAS</c> coding system with the value
/// <see cref="RespirationType.Invasive"/>.
/// </summary>
/// <returns>A <see cref="Task"/> representing the asynchronous unit test execution.</returns>
/// <!-- aidoc:v1 sig=480e248 body=e8d6f79 -->
[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<PatientObservation>(arg =>
arg.Name == "Resp_Type" &&
arg.CodingSystem == "ADAS" &&
arg.Value.ToString() == RespirationType.Invasive.ToString()
), true, true));
}
/// <summary>
/// Verifies that mapping a <see cref="PatientObservation"/> for respiratory mode with a non-invasive ventilation value produces a calculated <c>Resp_Type</c> observation classified as <see cref="RespirationType.NonInvasive"/>.
/// </summary>
/// <!-- aidoc:v1 sig=11ecdaa body=7ef6d7b -->
[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<PatientObservation>(arg =>
arg.Name == "Resp_Type" &&
arg.CodingSystem == "ADAS" &&
arg.Value.ToString() == RespirationType.NonInvasive.ToString()
), true, true));
}
}
/// <summary>
/// Verifies that mapping a <see cref="PatientObservation"/> whose <see cref="PatientObservation.Name"/> is "Resp_Mode" and <see cref="PatientObservation.Code"/> is "HNF" causes the calculation service to insert an observation with the <see cref="PatientObservation.Name"/> "Resp_Type", the <see cref="PatientObservation.CodingSystem"/> "ADAS", and the <see cref="PatientObservation.Value"/> set to <see cref="RespirationType.HighFrequencyVentilation"/>.
/// </summary>
/// <!-- aidoc:v1 sig=64e7ba4 body=1553933 -->
[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<PatientObservation>(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<PatientObservation>(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<PatientObservation>(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<PatientObservation>(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<PatientObservation>(arg =>
// arg.name == "Cam_IcuCalculated" &&
// arg.codingSystem == "ADAS" &&
// arg.value == null
// ), true, true));
//}
/// <summary>
/// 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 <see cref="PatientObservation"/> named "Diuresis_Weight".
/// </summary>
/// <!-- aidoc:v1 sig=5a47059 body=df4b18b -->
[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<List<string>>()))
.ReturnsAsync([patientObservation]);
await _calculatedObservations.Map(observation, false);
_observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
arg.Name == "Diuresis_Weight" &&
arg.PatientId == patientId &&
Math.Abs((double)arg.Value - 43.6) < 0.1
), true, true));
}
/// <summary>
/// Verifies that <see cref="_calculatedObservations"/>.<see cref="ICalculatedObservations.Map(PatientObservation, bool)"/> 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 <see cref="PatientObservation"/> named "Diuresis_Weight" for the same <paramref name="patientId"/>.
/// </summary>
/// <!-- aidoc:v1 sig=b46e7fe body=50dd2ac -->
/// <!-- aidoc-review:v1 severity=low kind=extra_param
/// "<paramref name=\"patientId\"/> references a local variable, not a method parameter; the test method has no parameters." -->
[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<List<string>>()))
.ReturnsAsync([patientObservation]);
await _calculatedObservations.Map(observation, false);
_observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
arg.Name == "Diuresis_Weight" &&
arg.PatientId == patientId &&
Math.Abs((double)arg.Value - 43.6) <= 0
), true, true));
}
/// <summary>
/// Verifies that when a <see cref="PatientObservation"/> with the name <c>Weight_Current</c> is received but no prior diuresis observations exist for the patient, the mapping does not insert any calculated observation.
/// </summary>
/// <!-- aidoc:v1 sig=7c61653 body=30e7115 -->
[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<List<string>>()))
.ReturnsAsync([]);
await _calculatedObservations.Map(observation, false);
_observationServiceMock.Verify(o => o.InsertObservation(It.IsAny<PatientObservation>(), true, true),
Times.Never);
}
/// <summary>
/// Verifies that when <see cref="PatientObservation.Map"/> 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.
/// </summary>
/// <!-- aidoc:v1 sig=7539e9b body=c0f4109 -->
[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<ObjectId>(), 1, It.IsAny<List<string>>()))
.ReturnsAsync([]);
await _calculatedObservations.Map(observation, false);
_observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
arg.Name == "Diuresis_Weight" &&
arg.PatientId == patientId
), true, true), Times.Never);
}
/// <summary>
/// Verifies that mapping a <see cref="PatientObservation"/> named "AllergiesObs" containing an empty list of <see cref="PatientAllergiesValue"/> produces a calculated <see cref="PatientObservation"/> named "Allergies" with an empty string value for the given patient.
/// </summary>
/// <!-- aidoc:v1 sig=aabc273 body=af29e9f -->
[Test]
public async Task CalculateAllergiesObservation_Received_AllergiesObs_Emty_Return_Allergies_Emty()
{
var patientId = ObjectId.GenerateNewId();
List<PatientAllergiesValue> 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<PatientObservation>(arg =>
arg.Name == "Allergies" &&
arg.PatientId == patientId &&
(string)arg.Value == string.Empty
), true, true));
}
/// <summary>
/// Verifies that mapping a <see cref="PatientObservation"/> 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").
/// </summary>
/// <!-- aidoc:v1 sig=87f619d body=739c72a -->
[Test]
public async Task CalculateAllergiesObservation_Received_AllergiesObs_Without_Farmacos_Return_Allergies()
{
var patientId = ObjectId.GenerateNewId();
List<PatientAllergiesValue> 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<PatientObservation>(arg =>
arg.Name == "Allergies" &&
arg.PatientId == patientId &&
(string)arg.Value == "LATEX, AMBIENTAL"
), true, true));
}
/// <summary>
/// Verifies that <see cref="CalculatedObservations.Map(PatientObservation, bool)"/> consolidates a received <c>AllergiesObs</c> <see cref="PatientObservation"/> containing one drug allergy (fármacos), a latex allergy, and an environmental allergy into a single <see cref="PatientObservation"/> named <c>Allergies</c> for the same <see cref="PatientObservation.PatientId"/>, with the values merged into the formatted string <c>LATEX, AMBIENTAL, FÁRMACOS (METILPREDNISOLONA)</c>.
/// </summary>
/// <!-- aidoc:v1 sig=6202c3a body=ca57051 -->
[Test]
public async Task CalculateAllergiesObservation_Received_AllergiesObs_With_1_Farmacos_Return_Allergies()
{
var patientId = ObjectId.GenerateNewId();
List<PatientAllergiesValue> 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<PatientObservation>(arg =>
arg.Name == "Allergies" &&
arg.PatientId == patientId &&
(string)arg.Value == "LATEX, AMBIENTAL, FÁRMACOS (METILPREDNISOLONA)"
), true, true));
}
/// <summary>
/// Verifies that <see cref="CalculateAllergiesObservation"/> aggregates a received <c>AllergiesObs</c> observation containing multiple allergy types — including two drug allergies (<c>METILPREDNISOLONA</c> and <c>Penicilina/cefalosporinas</c>), a latex allergy and an environmental allergy — into a single <see cref="PatientObservation"/> named <c>Allergies</c>, whose value combines the allergy categories and the drug allergens into the expected grouped string.
/// </summary>
/// <!-- aidoc:v1 sig=661f407 body=8eae86e -->
[Test]
public async Task CalculateAllergiesObservation_Received_AllergiesObs_With_2_Farmacos_Return_Allergies()
{
var patientId = ObjectId.GenerateNewId();
List<PatientAllergiesValue> 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<PatientObservation>(arg =>
arg.Name == "Allergies" &&
arg.PatientId == patientId &&
(string)arg.Value == "LATEX, AMBIENTAL, FÁRMACOS (METILPREDNISOLONA, PENICILINA/CEFALOSPORINAS)"
), true, true));
}
/// <summary>
/// Verifies that when a <see cref="PatientObservation"/> carrying a <see cref="PatientDrainagesValue"/> 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.
/// </summary>
/// <!-- aidoc:v1 sig=0c97fe5 body=b098a53 -->
[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<PatientObservation>(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<PatientObservation>(arg =>
arg.Name == "Drainage_Height" &&
arg.CodingSystem == "ADAS" &&
arg.PatientId == patientId &&
int.TryParse(arg.Value.ToString(), out valueParsed) && valueParsed == 8
), true, true));
}
/// <summary>
/// Verifies that mapping a <see cref="PatientObservation"/> carrying a <see cref="PatientDrainagesValue"/> of type "Drenaje ventricular" with a volume of 60 and no height produces a "DVE" observation while suppressing the "Drainage_Height" observation.
/// </summary>
/// <!-- aidoc:v1 sig=b24ca90 body=c070bf1 -->
[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<PatientObservation>(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<PatientObservation>(arg =>
arg.Name == "Drainage_Height" &&
arg.CodingSystem == "ADAS" &&
arg.PatientId == patientId
), true, true), Times.Never);
}
/// <summary>
/// Verifies that when a <see cref="PatientObservation"/> containing a <see cref="PatientDrainagesValue"/>
/// 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.
/// </summary>
/// <!-- aidoc:v1 sig=9f6bb92 body=73e12d9 -->
[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<PatientObservation>(arg =>
arg.Name == "DVE" &&
arg.CodingSystem == "ADAS" &&
arg.PatientId == patientId
), true, true), Times.Never);
_observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
arg.Name == "Drainage_Height" &&
arg.CodingSystem == "ADAS" &&
arg.PatientId == patientId &&
int.Parse(arg.Value.ToString()!) == 8
), true, true));
}
/// <summary>
/// Tests that mapping a <see cref="PatientObservation"/> of drainages type with null volume and null height values
/// does not generate any calculated <c>DVE</c> or <c>Drainage_Height</c> observations.
/// </summary>
/// <!-- aidoc:v1 sig=ff5bb6d body=bf2607d -->
[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<PatientObservation>(arg =>
arg.Name == "DVE" &&
arg.CodingSystem == "ADAS" &&
arg.PatientId == patientId
), true, true), Times.Never);
_observationServiceMock.Verify(o => o.InsertObservation(It.Is<PatientObservation>(arg =>
arg.Name == "Drainage_Height" &&
arg.CodingSystem == "ADAS" &&
arg.PatientId == patientId
), true, true), Times.Never);
}
}