11package uk .nhs .adaptors .gp2gp .ehr .mapper .diagnosticreport ;
22
33import static org .assertj .core .api .Assertions .assertThat ;
4+ import static org .assertj .core .api .AssertionsForClassTypes .assertThatThrownBy ;
5+ import static org .junit .Assert .assertFalse ;
46import static org .junit .jupiter .api .Assertions .assertAll ;
57import static org .mockito .ArgumentMatchers .any ;
68import static org .mockito .Mockito .when ;
79import java .util .ArrayList ;
810import java .util .Collections ;
911import java .util .List ;
12+ import java .util .NoSuchElementException ;
1013import java .util .Optional ;
1114import java .util .stream .Stream ;
1215
1316import org .hl7 .fhir .dstu3 .model .Bundle ;
1417import org .hl7 .fhir .dstu3 .model .CodeableConcept ;
18+ import org .hl7 .fhir .dstu3 .model .Coding ;
1519import org .hl7 .fhir .dstu3 .model .DiagnosticReport ;
1620import org .hl7 .fhir .dstu3 .model .IdType ;
1721import org .hl7 .fhir .dstu3 .model .Observation ;
5458@ ExtendWith (MockitoExtension .class )
5559@ MockitoSettings (strictness = Strictness .LENIENT )
5660class DiagnosticReportMapperTest {
61+
5762 private static final String TEST_FILE_DIRECTORY = "/ehr/mapper/diagnosticreport/" ;
5863
5964 private static final String INPUT_JSON_BUNDLE = "fhir_bundle.json" ;
6065 private static final String INPUT_JSON_BUNDLE_WITH_FILING_COMMENTS = "fhir_bundle_with_filing_comments.json" ;
6166
6267 private static final String TEST_ID = "5E496953-065B-41F2-9577-BE8F2FBD0757" ;
68+ public static final String NOT_PRESENT_SPECIMEN_ID_PREFIX = "NOT-PRESENT-SPECIMEN-" ;
69+ private static final String COMMENT_NOTE = "37331000000100" ;
6370
6471 private static final String INPUT_JSON_REQUIRED_DATA = "diagnostic-report-with-required-data.json" ;
6572 private static final String INPUT_JSON_EMPTY_SPECIMENS = "diagnostic-report-with-empty-specimens.json" ;
@@ -128,6 +135,75 @@ public void tearDown() {
128135 messageContext .resetMessageContext ();
129136 }
130137
138+ @ Test
139+ void shouldAssignDummySpecimenOnlyToNonFilingObservationsWithoutSpecimen () {
140+
141+ Observation obsWithoutSpecimen = new Observation ();
142+ obsWithoutSpecimen .setId ("obs1" );
143+
144+ Observation obsWithSpecimen = new Observation ();
145+ obsWithSpecimen .setId ("obs2" );
146+ obsWithSpecimen .setSpecimen (new Reference ("real-specimen" ));
147+
148+ Observation filingCommentObs = new Observation ();
149+ filingCommentObs .setId ("obs3" );
150+ filingCommentObs .getCode ().addCoding (new Coding ().setCode (COMMENT_NOTE ));
151+
152+ List <Observation > observations = List .of (obsWithoutSpecimen , obsWithSpecimen , filingCommentObs );
153+
154+ Specimen dummySpecimen = new Specimen ();
155+ dummySpecimen .setId (NOT_PRESENT_SPECIMEN_ID_PREFIX + "123" );
156+ List <Specimen > specimens = List .of (dummySpecimen );
157+
158+ List <Observation > result = mapper .assignDummySpecimensToObservationsWithNoSpecimen (observations , specimens );
159+
160+ assertThat (obsWithoutSpecimen .getSpecimen ())
161+ .isNotNull ()
162+ .extracting (Reference ::getReference )
163+ .isEqualTo (dummySpecimen .getId ());
164+
165+ assertThat (obsWithSpecimen .getSpecimen ())
166+ .extracting (Reference ::getReference )
167+ .isEqualTo ("real-specimen" );
168+
169+ assertFalse (filingCommentObs .hasSpecimen ());
170+ assertThat (result ).containsExactlyInAnyOrder (obsWithoutSpecimen , obsWithSpecimen , filingCommentObs );
171+ }
172+
173+ @ Test
174+ void shouldThrowIfNoDummySpecimenFound () {
175+
176+ Observation obsWithoutSpecimen = new Observation ();
177+ List <Observation > observations = List .of (obsWithoutSpecimen );
178+
179+ List <Specimen > specimens = List .of ();
180+
181+ assertThatThrownBy (() -> mapper .assignDummySpecimensToObservationsWithNoSpecimen (observations , specimens ))
182+ .isInstanceOf (NoSuchElementException .class );
183+ }
184+
185+ @ Test
186+ void shouldAssignDummySpecimenToObservationsWithoutSpecimen () {
187+
188+ Observation obsWithoutSpecimen = new Observation ();
189+ Observation obsWithSpecimen = new Observation ();
190+ obsWithSpecimen .setSpecimen (new Reference ("real-specimen" ));
191+
192+ List <Observation > observations = List .of (obsWithoutSpecimen , obsWithSpecimen );
193+
194+ Specimen dummySpecimen = new Specimen ();
195+ dummySpecimen .setId ("dummy-" + NOT_PRESENT_SPECIMEN_ID_PREFIX );
196+ Specimen realSpecimen = new Specimen ();
197+ realSpecimen .setId ("real-specimen" );
198+ List <Specimen > specimens = List .of (realSpecimen , dummySpecimen );
199+
200+ List <Observation > result = mapper .assignDummySpecimensToObservationsWithNoSpecimen (observations , specimens );
201+
202+ assertThat (result ).hasSize (2 );
203+ assertThat (result .get (0 ).getSpecimen ().getReference ()).contains (dummySpecimen .getId ());
204+ assertThat (result .get (1 ).getSpecimen ().getReference ()).contains ("real-specimen" );
205+ }
206+
131207 @ ParameterizedTest
132208 @ MethodSource ("resourceFileParams" )
133209 void When_MappingDiagnosticReportJson_Expect_CompoundStatementXmlOutput (String inputJson , String outputXml ) {
@@ -250,12 +326,14 @@ void When_DiagnosticReport_With_ObservationEffectivePeriodAndCommentNote_Expect_
250326 }
251327
252328 @ Test
253- void When_DiagnosticReport_With_NoReferencedSpecimenAndFilingCommentWithNoComment_Expect_MatchesSnapshotXml () {
329+ void When_DR_With_NoReferencedSpecimenAndFilingCommentWithNoComment_Expect_MatchesSnapshotXmlIncludesSpecimenRoleWithNotPresentTag () {
254330 final String diagnosticReportFileName = "diagnostic-report-with-no-specimen.json" ;
255331 final DiagnosticReport diagnosticReport = getDiagnosticReportResourceFromJson (diagnosticReportFileName );
256332 final Bundle bundle = getBundleResourceFromJson (INPUT_JSON_BUNDLE );
257333 final InputBundle inputBundle = new InputBundle (bundle );
258334 final String expectedXml = getXmlStringFromFile (TEST_FILE_DIRECTORY , "diagnostic-report-with-no-specimen.xml" );
335+ final List <String > expectedXPaths = Collections .singletonList (
336+ "/component/CompoundStatement/component/CompoundStatement/specimen/specimenRole/id[@extension=\" NOT PRESENT\" ]" );
259337
260338 when (specimenMapper .mapSpecimenToCompoundStatement (
261339 any (Specimen .class ),
@@ -288,6 +366,7 @@ void When_DiagnosticReport_With_NoReferencedSpecimenAndFilingCommentWithNoCommen
288366 final String actualXml = mapper .mapDiagnosticReportToCompoundStatement (diagnosticReport );
289367
290368 assertThat (actualXml ).isEqualToIgnoringWhitespace (expectedXml );
369+ assertThatXml (actualXml ).containsAllXPaths (expectedXPaths );
291370 }
292371
293372 /**
@@ -307,7 +386,7 @@ void When_DiagnosticReport_Has_SpecimenAndUnlinkedTestResult_Expect_ADummySpecim
307386
308387 // This checks that the unlinked test result is given a dummy specimen.
309388 assertThat (actualXml ).containsIgnoringWhitespaces (
310- "<!-- Mapped Specimen with id: DUMMY -SPECIMEN-5E496953-065B-41F2-9577-BE8F2FBD0757 "
389+ "<!-- Mapped Specimen with id: NOT-PRESENT -SPECIMEN-5E496953-065B-41F2-9577-BE8F2FBD0757 "
311390 + "with linked Observations: Observation/TestResult-WithoutSpecimenReference-->" );
312391 }
313392
@@ -408,7 +487,7 @@ void When_DiagnosticReport_Has_SpecimenALinkedTestResultAndAnUnlinkedTestResult_
408487 final String actualXml = mapper .mapDiagnosticReportToCompoundStatement (diagnosticReport );
409488 // This checks that the unlinked observation is given a dummy specimen.
410489 assertThat (actualXml ).containsIgnoringWhitespaces (
411- "<!-- Mapped Specimen with id: DUMMY -SPECIMEN-5E496953-065B-41F2-9577-BE8F2FBD0757 "
490+ "<!-- Mapped Specimen with id: NOT-PRESENT -SPECIMEN-5E496953-065B-41F2-9577-BE8F2FBD0757 "
412491 + "with linked Observations: Observation/TestResult-WithoutSpecimenReference-->" );
413492
414493 }
0 commit comments