Skip to content

Commit 4c12b8e

Browse files
authored
Merge branch 'dev' into nm/LEGLINK-796_ScheduleMultiMeasure
2 parents 0641ab6 + 6333aa8 commit 4c12b8e

10 files changed

Lines changed: 605 additions & 54 deletions

File tree

DotNet/ServiceTests/UnitTests/Terminology/Services/CodeGroupCacheServiceTests.cs

Lines changed: 113 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
using System.Globalization;
22
using CsvHelper;
33
using CsvHelper.Configuration;
4-
using Hl7.Fhir.Model;
54
using LantanaGroup.Link.Terminology.Application.Models;
65
using LantanaGroup.Link.Terminology.Application.Settings;
76
using LantanaGroup.Link.Terminology.Services;
87
using Microsoft.Extensions.Caching.Memory;
98
using Microsoft.Extensions.Logging;
109
using Microsoft.Extensions.Options;
1110
using Moq;
12-
using Xunit;
1311
using Task = System.Threading.Tasks.Task;
1412

1513
namespace UnitTests.Terminology;
@@ -135,6 +133,12 @@ public void ProcessCodeSystemCsv_InvalidColumnCount_ThrowsException()
135133
CallBase = true
136134
};
137135

136+
mockService
137+
.Setup(x => x.SetCodeGroup(It.IsAny<CodeGroup>()));
138+
139+
mockService
140+
.Setup(x => x.SetCodeGroup(It.IsAny<CodeGroup>()));
141+
138142
// Arrange
139143
var codeGroup = new CodeGroup
140144
{
@@ -258,6 +262,52 @@ public void ProcessValueSetCsv_WithValidData_CallsSetCodeGroup()
258262
Times.Once);
259263
}
260264

265+
[Fact]
266+
public void ProcessValueSetCsv_WithScientificNotationCodes_LogsSingleAggregatedWarning()
267+
{
268+
var mockCache = new Mock<IMemoryCache>();
269+
var mockConfig = new Mock<IOptions<TerminologyConfig>>();
270+
271+
mockConfig.Setup(x => x.Value).Returns(_config);
272+
273+
var mockService = new Mock<CodeGroupCacheService>(
274+
_loggerMock.Object,
275+
mockCache.Object,
276+
mockConfig.Object)
277+
{
278+
CallBase = true
279+
};
280+
281+
mockService
282+
.Setup(x => x.SetCodeGroup(It.IsAny<CodeGroup>()));
283+
284+
var csvData = "system,code,display\r\n" +
285+
"http://test.system,1e10,One\r\n" +
286+
"http://test.system,123,Two\r\n" +
287+
"http://test.system,2E+05,Three";
288+
289+
using var reader = new StringReader(csvData);
290+
using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
291+
292+
var codeGroup = new CodeGroup
293+
{
294+
Id = "test-id",
295+
Type = CodeGroup.CodeGroupTypes.ValueSet,
296+
Url = "http://test.valueset",
297+
Version = "1.0",
298+
Resource = new ValueSet
299+
{
300+
Id = "test-id",
301+
Url = "http://test.valueset",
302+
Version = "1.0"
303+
}
304+
};
305+
306+
mockService.Object.ProcessValueSetCsv(codeGroup, csv);
307+
308+
VerifyScientificNotationWarning(2, "test-id");
309+
}
310+
261311
[Theory]
262312
[InlineData("code,display\r\n" +
263313
"123,Test Display\r\n" +
@@ -378,6 +428,51 @@ public void ProcessCodeSystemCsv_WithValidData_CallsSetCodeGroup()
378428
Times.Once);
379429
}
380430

431+
[Fact]
432+
public void ProcessCodeSystemCsv_WithScientificNotationCodes_LogsSingleAggregatedWarning()
433+
{
434+
var mockCache = new Mock<IMemoryCache>();
435+
var mockConfig = new Mock<IOptions<TerminologyConfig>>();
436+
437+
mockConfig.Setup(x => x.Value).Returns(_config);
438+
439+
var mockService = new Mock<CodeGroupCacheService>(
440+
_loggerMock.Object,
441+
mockCache.Object,
442+
mockConfig.Object)
443+
{
444+
CallBase = true
445+
};
446+
447+
mockService
448+
.Setup(x => x.SetCodeGroup(It.IsAny<CodeGroup>()));
449+
450+
var csvData = "code,display\r\n" +
451+
"1e10,One\r\n" +
452+
"123,Two\r\n" +
453+
"2E+05,Three";
454+
455+
using var csv = CreateCsvReader(csvData);
456+
457+
var codeGroup = new CodeGroup
458+
{
459+
Id = "test-id",
460+
Type = CodeGroup.CodeGroupTypes.CodeSystem,
461+
Url = "http://test.codesystem",
462+
Version = "1.0",
463+
Resource = new CodeSystem
464+
{
465+
Id = "test-id",
466+
Url = "http://test.codesystem",
467+
Version = "1.0"
468+
}
469+
};
470+
471+
mockService.Object.ProcessCodeSystemCsv(codeGroup, csv);
472+
473+
VerifyScientificNotationWarning(2, "test-id");
474+
}
475+
381476
[Fact]
382477
public async Task LoadCache_PopulatesCacheWithRetrievableCodeSystem()
383478
{
@@ -773,6 +868,20 @@ private static string BuildCodeSystemJson(string? version)
773868
"\"url\": \"http://test.codesystem\"" + versionField + " }";
774869
}
775870

871+
private void VerifyScientificNotationWarning(int expectedCount, string expectedCodeGroupId)
872+
{
873+
_loggerMock.Verify(
874+
x => x.Log(
875+
It.Is<LogLevel>(level => level == LogLevel.Warning),
876+
It.IsAny<EventId>(),
877+
It.Is<It.IsAnyType>((state, _) =>
878+
state.ToString()!.Contains($"Found {expectedCount} code(s)") &&
879+
state.ToString()!.Contains($"code group {expectedCodeGroupId}")),
880+
It.IsAny<Exception>(),
881+
It.IsAny<Func<It.IsAnyType, Exception?, string>>()),
882+
Times.Once);
883+
}
884+
776885
[Fact]
777886
public async Task GetCodeGroup_NoVersion_ReturnsSemanticallyLatestVersion()
778887
{
@@ -872,7 +981,7 @@ protected internal override string[] GetFiles(string path, string searchPattern)
872981
: Array.Empty<string>();
873982
}
874983

875-
protected internal override System.Threading.Tasks.Task<string> ReadAllTextAsync(string path) =>
876-
System.Threading.Tasks.Task.FromResult(_fileContents[path]);
984+
protected internal override Task<string> ReadAllTextAsync(string path) =>
985+
Task.FromResult(_fileContents[path]);
877986
}
878987
}

DotNet/ServiceTests/UnitTests/Terminology/Services/FhirServiceTests.cs

Lines changed: 134 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,8 @@
22
using LantanaGroup.Link.Shared.Application.SerDes;
33
using LantanaGroup.Link.Terminology.Application.Interfaces;
44
using LantanaGroup.Link.Terminology.Application.Models;
5-
using LantanaGroup.Link.Terminology.Application.Settings;
65
using LantanaGroup.Link.Terminology.Services;
7-
using Microsoft.Extensions.Caching.Memory;
86
using Microsoft.Extensions.Logging;
9-
using Microsoft.Extensions.Options;
107
using Moq;
118
using Code = LantanaGroup.Link.Terminology.Application.Models.Code;
129

@@ -1174,6 +1171,140 @@ public void ValidateCodeInCodeSystem_WithCodeableConcept_InParameters_ReturnsTru
11741171
Assert.True(resultParameter.Value);
11751172
}
11761173

1174+
[Fact]
1175+
public void LookupCodeInCodeSystem_WithCodeAndSystem_ReturnsNameVersionDisplay()
1176+
{
1177+
// Arrange
1178+
var codeSystemId = "lookup-cs-id";
1179+
var codeSystemUrl = "http://lookup.system";
1180+
var codeSystemVersion = "2.0.0";
1181+
var code = "lookup-code";
1182+
var display = "Lookup Display";
1183+
var name = "LookupCodeSystem";
1184+
1185+
var mockCodeGroup = new CodeGroup
1186+
{
1187+
Id = codeSystemId,
1188+
Url = codeSystemUrl,
1189+
Name = name,
1190+
Version = codeSystemVersion,
1191+
Type = CodeGroup.CodeGroupTypes.CodeSystem,
1192+
Codes = new Dictionary<string, List<Code>>
1193+
{
1194+
{ codeSystemUrl, new List<Code> { new() { Value = code, Display = display } } }
1195+
}
1196+
};
1197+
1198+
_mockCacheService
1199+
.Setup(x => x.GetCodeGroup(CodeGroup.CodeGroupTypes.CodeSystem, codeSystemUrl, codeSystemVersion))
1200+
.Returns(mockCodeGroup);
1201+
1202+
// Act
1203+
var result = _service.LookupCodeInCodeSystem(null, null, codeSystemUrl, code, codeSystemVersion, null);
1204+
1205+
// Assert
1206+
Assert.Equal(name, result.GetSingleValue<FhirString>("name")?.Value);
1207+
Assert.Equal(codeSystemVersion, result.GetSingleValue<FhirString>("version")?.Value);
1208+
Assert.Equal(display, result.GetSingleValue<FhirString>("display")?.Value);
1209+
}
1210+
1211+
[Fact]
1212+
public void LookupCodeInCodeSystem_WithCodingParameter_ReturnsNameVersionDisplay()
1213+
{
1214+
// Arrange
1215+
var codeSystemId = "lookup-cs-id";
1216+
var codeSystemUrl = "http://lookup.system";
1217+
var codeSystemVersion = "3.1.4";
1218+
var code = "lookup-code";
1219+
var display = "Lookup Display";
1220+
var name = "LookupCodeSystem";
1221+
1222+
var mockCodeGroup = new CodeGroup
1223+
{
1224+
Id = codeSystemId,
1225+
Url = codeSystemUrl,
1226+
Name = name,
1227+
Version = codeSystemVersion,
1228+
Type = CodeGroup.CodeGroupTypes.CodeSystem,
1229+
Codes = new Dictionary<string, List<Code>>
1230+
{
1231+
{ codeSystemUrl, new List<Code> { new() { Value = code, Display = display } } }
1232+
}
1233+
};
1234+
1235+
_mockCacheService
1236+
.Setup(x => x.GetCodeGroup(CodeGroup.CodeGroupTypes.CodeSystem, codeSystemUrl, codeSystemVersion))
1237+
.Returns(mockCodeGroup);
1238+
1239+
var parameters = new Parameters();
1240+
parameters.Add("version", new FhirString(codeSystemVersion));
1241+
parameters.Add("coding", new Coding(codeSystemUrl, code, null));
1242+
1243+
// Act
1244+
var result = _service.LookupCodeInCodeSystem(null, null, null, null, null, parameters);
1245+
1246+
// Assert
1247+
Assert.Equal(name, result.GetSingleValue<FhirString>("name")?.Value);
1248+
Assert.Equal(codeSystemVersion, result.GetSingleValue<FhirString>("version")?.Value);
1249+
Assert.Equal(display, result.GetSingleValue<FhirString>("display")?.Value);
1250+
}
1251+
1252+
[Fact]
1253+
public void LookupCodeInCodeSystem_WithVersionNoMatch_ThrowsKeyNotFoundException()
1254+
{
1255+
// Arrange
1256+
var codeSystemUrl = "http://lookup.system";
1257+
var requestedVersion = "9.9.9";
1258+
var fallbackCodeGroup = new CodeGroup
1259+
{
1260+
Id = "lookup-cs-id",
1261+
Url = codeSystemUrl,
1262+
Name = "LookupCodeSystem",
1263+
Version = "1.0.0",
1264+
Type = CodeGroup.CodeGroupTypes.CodeSystem,
1265+
Codes = new Dictionary<string, List<Code>>
1266+
{
1267+
{ codeSystemUrl, new List<Code> { new() { Value = "lookup-code", Display = "Lookup Display" } } }
1268+
}
1269+
};
1270+
1271+
_mockCacheService
1272+
.Setup(x => x.GetCodeGroup(CodeGroup.CodeGroupTypes.CodeSystem, codeSystemUrl, requestedVersion))
1273+
.Returns(fallbackCodeGroup);
1274+
1275+
// Act / Assert
1276+
Assert.Throws<KeyNotFoundException>(() =>
1277+
_service.LookupCodeInCodeSystem(null, null, codeSystemUrl, "lookup-code", requestedVersion, null));
1278+
}
1279+
1280+
[Fact]
1281+
public void LookupCodeInCodeSystem_WithCodeSystemAndCoding_ThrowsArgumentException()
1282+
{
1283+
// Arrange
1284+
var parameters = new Parameters();
1285+
parameters.Add("coding", new Coding("http://lookup.system", "lookup-code", null));
1286+
1287+
// Act / Assert
1288+
Assert.Throws<ArgumentException>(() =>
1289+
_service.LookupCodeInCodeSystem(null, null, "http://lookup.system", "lookup-code", null, parameters));
1290+
}
1291+
1292+
[Fact]
1293+
public void GetMetaData_CodeSystemOperations_IncludesLookupOperation()
1294+
{
1295+
// Act
1296+
var result = _service.GetMetaData();
1297+
1298+
// Assert
1299+
var codeSystemResource = result.Rest
1300+
.SelectMany(rest => rest.Resource)
1301+
.First(resource => resource.Type == "CodeSystem");
1302+
1303+
Assert.Contains(codeSystemResource.Operation, operation =>
1304+
operation.Name == "lookup" &&
1305+
operation.Definition == "http://hl7.org/fhir/OperationDefinition/CodeSystem-lookup");
1306+
}
1307+
11771308
#endregion
11781309

11791310
#region ExpandValueSet Tests

0 commit comments

Comments
 (0)