Skip to content

Commit

Permalink
Ensure that R4MeasureServiceUtils handles a null reporter gracefully …
Browse files Browse the repository at this point in the history
…by returning Optional (#504)

* Ensure that R4MeasureServiceUtils handles a null reporter gracefully by returning Optional.

* Spotless.
  • Loading branch information
lukedegruchy authored Aug 15, 2024
1 parent eefcec9 commit 1f20345
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Reference> 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)) {
Expand All @@ -157,7 +158,7 @@ public Reference getReporter(String reporter) {
}
}

return reference;
return Optional.ofNullable(reference);
}

public Measure resolveById(IdType id) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Object, IllegalArgumentException> EITHER_ILLEGAL_ARGUMENT_EXCEPTION =
Eithers.forRight(EXCEPTION_ILLEGAL_REPORTER);
private static final Either<Optional<Reference>, Exception> EITHER_EMPTY_RESULT = buildEitherLeft(null);

@Mock
private Repository repository;

private static Stream<Arguments> 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<Optional<Reference>, 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<Reference> 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<Optional<Reference>, Exception> buildEitherLeft(@Nullable String theId) {
return Eithers.forLeft(Optional.ofNullable(theId).map(Reference::new));
}
}

0 comments on commit 1f20345

Please sign in to comment.