diff --git a/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4MultiMeasureService.java b/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4MultiMeasureService.java index cf26e1651..8849fa7ea 100644 --- a/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4MultiMeasureService.java +++ b/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4MultiMeasureService.java @@ -153,7 +153,8 @@ protected void populationMeasureReport( // add reporter if available if (reporter != null && !reporter.isEmpty()) { - measureReport.setReporter(r4MeasureServiceUtils.getReporter(reporter)); + measureReport.setReporter( + r4MeasureServiceUtils.getReporter(reporter).orElse(null)); } // add id to measureReport initializeReport(measureReport); @@ -211,7 +212,8 @@ protected void subjectMeasureReport( // add reporter if available if (reporter != null && !reporter.isEmpty()) { - measureReport.setReporter(r4MeasureServiceUtils.getReporter(reporter)); + measureReport.setReporter( + r4MeasureServiceUtils.getReporter(reporter).orElse(null)); } // add id to measureReport initializeReport(measureReport); diff --git a/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/utils/R4MeasureServiceUtils.java b/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/utils/R4MeasureServiceUtils.java index d85ab5961..22a9e01cd 100644 --- a/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/utils/R4MeasureServiceUtils.java +++ b/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/utils/R4MeasureServiceUtils.java @@ -23,6 +23,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.r4.model.Bundle; @@ -137,13 +138,13 @@ public MeasureReport addSubjectReference(MeasureReport measureReport, String pra return measureReport; } - public Reference getReporter(String reporter) { - if (!reporter.isEmpty() && !reporter.contains("/")) { + public Optional getReporter(String reporter) { + if (reporter != null && !reporter.isEmpty() && !reporter.contains("/")) { throw new IllegalArgumentException( "R4MultiMeasureService requires '[ResourceType]/[ResourceId]' format to set MeasureReport.reporter reference."); } Reference reference = null; - if (!reporter.isEmpty()) { + if (reporter != null && !reporter.isEmpty()) { if (reporter.startsWith(RESOURCE_TYPE_PRACTITIONER_ROLE)) { reference = new Reference(Ids.ensureIdType(reporter, RESOURCE_TYPE_PRACTITIONER_ROLE)); } else if (reporter.startsWith(RESOURCE_TYPE_PRACTITIONER)) { @@ -157,7 +158,7 @@ public Reference getReporter(String reporter) { } } - return reference; + return Optional.ofNullable(reference); } public Measure resolveById(IdType id) { diff --git a/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/utils/R4MeasureServiceUtilsTest.java b/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/utils/R4MeasureServiceUtilsTest.java new file mode 100644 index 000000000..1d51a6a13 --- /dev/null +++ b/cqf-fhir-cr/src/test/java/org/opencds/cqf/fhir/cr/measure/r4/utils/R4MeasureServiceUtilsTest.java @@ -0,0 +1,73 @@ +package org.opencds.cqf.fhir.cr.measure.r4.utils; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.fail; + +import jakarta.annotation.Nullable; +import java.util.Optional; +import java.util.stream.Stream; +import org.hl7.fhir.r4.model.Reference; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.opencds.cqf.fhir.api.Repository; +import org.opencds.cqf.fhir.utility.monad.Either; +import org.opencds.cqf.fhir.utility.monad.Eithers; + +@ExtendWith(MockitoExtension.class) +class R4MeasureServiceUtilsTest { + private static final String PRACTITIONER = "Practitioner/pra1"; + private static final String PRACTITIONER_ROLE = "PractitionerRole/praRol1"; + private static final String ORGANIZATION = "Organization/org1"; + private static final String LOCATION = "Location/loc1"; + private static final String PATIENT = "Patient/pat1"; + private static final String GROUP = "Group/grp1"; + private static final IllegalArgumentException EXCEPTION_ILLEGAL_REPORTER = new IllegalArgumentException( + "R4MultiMeasureService requires '[ResourceType]/[ResourceId]' format to set MeasureReport.reporter reference."); + private static final Either EITHER_ILLEGAL_ARGUMENT_EXCEPTION = + Eithers.forRight(EXCEPTION_ILLEGAL_REPORTER); + private static final Either, Exception> EITHER_EMPTY_RESULT = buildEitherLeft(null); + + @Mock + private Repository repository; + + private static Stream params() { + return Stream.of( + Arguments.of(null, EITHER_EMPTY_RESULT), + Arguments.of(PRACTITIONER, buildEitherLeft(PRACTITIONER)), + Arguments.of(PRACTITIONER_ROLE, buildEitherLeft(PRACTITIONER_ROLE)), + Arguments.of(ORGANIZATION, buildEitherLeft(ORGANIZATION)), + Arguments.of(LOCATION, buildEitherLeft(LOCATION)), + Arguments.of(PATIENT, EITHER_ILLEGAL_ARGUMENT_EXCEPTION), + Arguments.of(GROUP, EITHER_ILLEGAL_ARGUMENT_EXCEPTION)); + } + + @ParameterizedTest + @MethodSource("params") + void getReporter(@Nullable String theReporter, Either, Exception> theExpectedReporterOrError) { + final R4MeasureServiceUtils subject = new R4MeasureServiceUtils(repository); + + if (theExpectedReporterOrError.isRight()) { + final Exception expectedException = theExpectedReporterOrError.right(); + assertThrows( + expectedException.getClass(), + () -> subject.getReporter(theReporter), + expectedException.getMessage()); + } else if (theExpectedReporterOrError.isLeft()) { + final Optional optReporter = subject.getReporter(theReporter); + assertEquals( + theExpectedReporterOrError.left().map(Reference::getReference), + optReporter.map(Reference::getReference)); + } else { + fail("Expecting an Either with only a left or a right but it has neither."); + } + } + + private static Either, Exception> buildEitherLeft(@Nullable String theId) { + return Eithers.forLeft(Optional.ofNullable(theId).map(Reference::new)); + } +}