From 564ae46008d074698b48357022e5af0407f2d7cc Mon Sep 17 00:00:00 2001 From: Martha Mitran Date: Tue, 12 Dec 2023 07:05:21 -0800 Subject: [PATCH] Fixes for validation lookupCode method and improve remote terminology tests (#5535) * Fixes for validation lookupCode method: (1) NullPointerException when processing designation in the remote terminology implementation (2) Inconsistency between input and output type vs. for property parameter across the board (3) Fix most of the warnings in the updated classes. (4) Code review changes * Fix unit test failure by reverting assertion to FOO_COLUMN. * Revert commit. * Update tests * Update tests - move utility class back * Update fix and tests * spotless fix * Missing branches for exception cases and add tests for the same * Spotless fix * fix tests * fix test * Address code review comments. Write the remote terminology tests in a way to make them more readable. * Revert moving utility test class * Small changes in tests * Small changes * fix checkstyle * Minor changes in exception handling and add a missing test * Address code review comments. Decouple other tests from lookupCode tests. * Update declaration of constants --------- Co-authored-by: Luke deGruchy --- .../context/support/IValidationSupport.java | 55 ++- ...tion-no-language-nullpointerexception.yaml | 6 + ...ProviderDstu3CodeSystemPropertiesTest.java | 120 ++++--- ...minologyServiceResourceProviderR4Test.java | 117 +++--- ...rceProviderR4CodeSystemPropertiesTest.java | 104 +++--- .../jpa/term/TerminologySvcDeltaR4Test.java | 2 +- ...rceProviderR5CodeSystemPropertiesTest.java | 105 +++--- .../CodeSystemLookupWithPropertiesUtil.java | 10 +- ...teTerminologyServiceValidationSupport.java | 339 +++++++++++------- .../hapi/validation/ILookupCodeTest.java | 260 ++++++++++++++ .../hapi/validation/LookupCodeDstu3Test.java | 257 +++++++++++++ ...logyServiceValidationSupportDstu3Test.java | 167 --------- .../fhir/r4/validation/LookupCodeR4Test.java | 252 +++++++++++++ ...nologyServiceValidationSupportR4Test.java} | 217 +++-------- 14 files changed, 1306 insertions(+), 705 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_0_0/5512-codesystem-lookup-with-designation-no-language-nullpointerexception.yaml create mode 100644 hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/ILookupCodeTest.java create mode 100644 hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/LookupCodeDstu3Test.java delete mode 100644 hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/RemoteTerminologyServiceValidationSupportDstu3Test.java create mode 100644 hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/LookupCodeR4Test.java rename hapi-fhir-validation/src/test/java/org/hl7/fhir/{common/hapi/validation/support/RemoteTerminologyServiceValidationSupportTest.java => r4/validation/RemoteTerminologyServiceValidationSupportR4Test.java} (74%) diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/IValidationSupport.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/IValidationSupport.java index 9528ee1d8ba..967aeb3a549 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/IValidationSupport.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/IValidationSupport.java @@ -295,8 +295,8 @@ public interface IValidationSupport { */ @Nullable default CodeValidationResult validateCode( - @Nonnull ValidationSupportContext theValidationSupportContext, - @Nonnull ConceptValidationOptions theOptions, + ValidationSupportContext theValidationSupportContext, + ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, @@ -526,8 +526,13 @@ public interface IValidationSupport { public String getPropertyName() { return myPropertyName; } + + public abstract String getType(); } + String TYPE_STRING = "string"; + String TYPE_CODING = "Coding"; + class StringConceptProperty extends BaseConceptProperty { private final String myValue; @@ -544,6 +549,10 @@ public interface IValidationSupport { public String getValue() { return myValue; } + + public String getType() { + return TYPE_STRING; + } } class CodingConceptProperty extends BaseConceptProperty { @@ -574,6 +583,10 @@ public interface IValidationSupport { public String getDisplay() { return myDisplay; } + + public String getType() { + return TYPE_CODING; + } } class CodeValidationResult { @@ -881,25 +894,35 @@ public interface IValidationSupport { } for (BaseConceptProperty next : myProperties) { + String propertyName = next.getPropertyName(); - if (!properties.isEmpty()) { - if (!properties.contains(next.getPropertyName())) { - continue; - } + if (!properties.isEmpty() && !properties.contains(propertyName)) { + continue; } IBase property = ParametersUtil.addParameterToParameters(theContext, retVal, "property"); - ParametersUtil.addPartCode(theContext, property, "code", next.getPropertyName()); + ParametersUtil.addPartCode(theContext, property, "code", propertyName); - if (next instanceof StringConceptProperty) { - StringConceptProperty prop = (StringConceptProperty) next; - ParametersUtil.addPartString(theContext, property, "value", prop.getValue()); - } else if (next instanceof CodingConceptProperty) { - CodingConceptProperty prop = (CodingConceptProperty) next; - ParametersUtil.addPartCoding( - theContext, property, "value", prop.getCodeSystem(), prop.getCode(), prop.getDisplay()); - } else { - throw new IllegalStateException(Msg.code(1739) + "Don't know how to handle " + next.getClass()); + String propertyType = next.getType(); + switch (propertyType) { + case TYPE_STRING: + StringConceptProperty stringConceptProperty = (StringConceptProperty) next; + ParametersUtil.addPartString( + theContext, property, "value", stringConceptProperty.getValue()); + break; + case TYPE_CODING: + CodingConceptProperty codingConceptProperty = (CodingConceptProperty) next; + ParametersUtil.addPartCoding( + theContext, + property, + "value", + codingConceptProperty.getCodeSystem(), + codingConceptProperty.getCode(), + codingConceptProperty.getDisplay()); + break; + default: + throw new IllegalStateException( + Msg.code(1739) + "Don't know how to handle " + next.getClass()); } } } diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_0_0/5512-codesystem-lookup-with-designation-no-language-nullpointerexception.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_0_0/5512-codesystem-lookup-with-designation-no-language-nullpointerexception.yaml new file mode 100644 index 00000000000..b55b4044b51 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_0_0/5512-codesystem-lookup-with-designation-no-language-nullpointerexception.yaml @@ -0,0 +1,6 @@ +--- +type: fix +issue: 5511 +title: 'Previously, CodeSystem `$lookup` with Remote Terminology Service enabled would throw NullPointerException +when the CodeSystem included designations with no language value. Also, there was an inconsistency between +input and output type `string` vs. `code` for property parameters. These issues have been fixed.' diff --git a/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3CodeSystemPropertiesTest.java b/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3CodeSystemPropertiesTest.java index 66eaa679850..5ea44c64476 100644 --- a/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3CodeSystemPropertiesTest.java +++ b/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3CodeSystemPropertiesTest.java @@ -4,8 +4,12 @@ import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil; import ca.uhn.fhir.rest.gclient.IOperationUntypedWithInputAndPartialOutput; import org.hl7.fhir.dstu3.model.CodeSystem; +import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent; +import org.hl7.fhir.dstu3.model.CodeSystem.ConceptPropertyComponent; import org.hl7.fhir.dstu3.model.CodeType; +import org.hl7.fhir.dstu3.model.Coding; import org.hl7.fhir.dstu3.model.Parameters; +import org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent; import org.hl7.fhir.dstu3.model.StringType; import org.hl7.fhir.dstu3.model.UriType; import org.junit.jupiter.params.ParameterizedTest; @@ -21,8 +25,12 @@ import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.ourCod import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.ourCodeSystemUrl; import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.ourPropertyA; import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.ourPropertyB; +import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.ourPropertyC; import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.ourPropertyValueA; import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.ourPropertyValueB; +import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.propertyCode; +import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.propertyCodeSystem; +import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.propertyDisplay; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; @@ -30,72 +38,70 @@ import static org.junit.jupiter.api.Assertions.assertTrue; public class ResourceProviderDstu3CodeSystemPropertiesTest extends BaseResourceProviderDstu3Test { - public static Stream parametersLookup() { - return CodeSystemLookupWithPropertiesUtil.parametersLookupWithProperties(); - } + public static Stream parametersLookup() { + return CodeSystemLookupWithPropertiesUtil.parametersLookupWithProperties(); + } - @ParameterizedTest - @MethodSource(value = "parametersLookup") - public void testLookup_withProperties_returnsCorrectParameters(List theLookupProperties, List theExpectedReturnedProperties) { - // setup - CodeSystem codeSystem = new CodeSystem(); - codeSystem.setId(ourCodeSystemId); - codeSystem.setUrl(ourCodeSystemUrl); - CodeSystem.ConceptDefinitionComponent concept = codeSystem.addConcept().setCode(ourCode); - CodeSystem.ConceptPropertyComponent propertyComponent = new CodeSystem.ConceptPropertyComponent() - .setCode(ourPropertyA).setValue(new StringType(ourPropertyValueA)); - concept.addProperty(propertyComponent); - propertyComponent = new CodeSystem.ConceptPropertyComponent() - .setCode(ourPropertyB).setValue(new StringType(ourPropertyValueB)); - concept.addProperty(propertyComponent); - myCodeSystemDao.create(codeSystem, mySrd); + @ParameterizedTest + @MethodSource(value = "parametersLookup") + public void testLookup_withProperties_returnsCorrectParameters(List theLookupProperties, List theExpectedReturnedProperties) { + // setup + CodeSystem codeSystem = new CodeSystem(); + codeSystem.setId(ourCodeSystemId); + codeSystem.setUrl(ourCodeSystemUrl); + ConceptDefinitionComponent concept = codeSystem.addConcept().setCode(ourCode) + .addProperty(new ConceptPropertyComponent().setCode(ourPropertyA).setValue(new StringType(ourPropertyValueA))) + .addProperty(new ConceptPropertyComponent().setCode(ourPropertyB).setValue(new StringType(ourPropertyValueB))) + .addProperty(new ConceptPropertyComponent().setCode(ourPropertyC).setValue(new Coding(propertyCodeSystem, propertyCode, propertyDisplay))); + myCodeSystemDao.create(codeSystem, mySrd); - // test - IOperationUntypedWithInputAndPartialOutput respParam = myClient - .operation() - .onType(CodeSystem.class) - .named(JpaConstants.OPERATION_LOOKUP) - .withParameter(Parameters.class, "code", new CodeType(ourCode)) - .andParameter("system", new UriType(ourCodeSystemUrl)); + // test + IOperationUntypedWithInputAndPartialOutput respParam = myClient + .operation() + .onType(CodeSystem.class) + .named(JpaConstants.OPERATION_LOOKUP) + .withParameter(Parameters.class, "code", new CodeType(ourCode)) + .andParameter("system", new UriType(ourCodeSystemUrl)); - theLookupProperties.forEach(p -> respParam.andParameter("property", new CodeType(p))); - Parameters parameters = respParam.execute(); + theLookupProperties.forEach(p -> respParam.andParameter("property", new CodeType(p))); + Parameters parameters = respParam.execute(); - Iterator paramIterator = parameters.getParameter().iterator(); - Parameters.ParametersParameterComponent parameter = null; - while (paramIterator.hasNext()) { - Parameters.ParametersParameterComponent currentParameter = paramIterator.next(); - if (currentParameter.getName().equals("property")) { - parameter = currentParameter; - break; - } - } + Iterator paramIterator = parameters.getParameter().iterator(); + ParametersParameterComponent parameter = null; + while (paramIterator.hasNext()) { + ParametersParameterComponent currentParameter = paramIterator.next(); + if (currentParameter.getName().equals("property")) { + parameter = currentParameter; + break; + } + } - if (theExpectedReturnedProperties.isEmpty()) { - assertNull(parameter); - return; - } + // verify + if (theExpectedReturnedProperties.isEmpty()) { + assertNull(parameter); + return; + } - Iterator propertyIterator = concept.getProperty().stream() - .filter(property -> theExpectedReturnedProperties.contains(property.getCode())).iterator(); + Iterator propertyIterator = concept.getProperty().stream() + .filter(property -> theExpectedReturnedProperties.contains(property.getCode())).iterator(); - while (propertyIterator.hasNext()) { - CodeSystem.ConceptPropertyComponent property = propertyIterator.next(); - assertNotNull(parameter); + while (propertyIterator.hasNext()) { + ConceptPropertyComponent property = propertyIterator.next(); + assertNotNull(parameter); - Iterator parameterPartIterator = parameter.getPart().iterator(); + Iterator parameterPartIterator = parameter.getPart().iterator(); - parameter = parameterPartIterator.next(); - assertEquals("code", parameter.getName()); - assertEquals(property.getCode(), ((CodeType)parameter.getValue()).getValue()); + parameter = parameterPartIterator.next(); + assertEquals("code", parameter.getName()); + assertEquals(property.getCode(), ((CodeType) parameter.getValue()).getValue()); - parameter = parameterPartIterator.next(); - assertEquals("value", parameter.getName()); - assertTrue(property.getValue().equalsShallow(parameter.getValue())); + parameter = parameterPartIterator.next(); + assertEquals("value", parameter.getName()); + assertTrue(property.getValue().equalsShallow(parameter.getValue())); - if (paramIterator.hasNext()) { - parameter = paramIterator.next(); - } - } - } + if (paramIterator.hasNext()) { + parameter = paramIterator.next(); + } + } + } } diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/RemoteTerminologyServiceResourceProviderR4Test.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/RemoteTerminologyServiceResourceProviderR4Test.java index 4e543edd508..823438e450e 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/RemoteTerminologyServiceResourceProviderR4Test.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/RemoteTerminologyServiceResourceProviderR4Test.java @@ -5,13 +5,11 @@ import ca.uhn.fhir.context.support.IValidationSupport; import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.annotation.Operation; import ca.uhn.fhir.rest.annotation.OperationParam; -import ca.uhn.fhir.rest.annotation.RequiredParam; -import ca.uhn.fhir.rest.annotation.Search; import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; -import ca.uhn.fhir.rest.param.UriParam; import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.test.utilities.server.RestfulServerExtension; +import jakarta.servlet.http.HttpServletRequest; import org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.r4.model.BooleanType; @@ -27,10 +25,9 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; -import jakarta.servlet.http.HttpServletRequest; -import java.util.List; - import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; /* @@ -45,18 +42,18 @@ public class RemoteTerminologyServiceResourceProviderR4Test { private static final String VALUE_SET_URL = "http://value.set/url"; private static final String SAMPLE_MESSAGE = "This is a sample message"; private static final FhirContext ourCtx = FhirContext.forR4Cached(); - private MyCodeSystemProvider myCodeSystemProvider = new MyCodeSystemProvider(); - private MyValueSetProvider myValueSetProvider = new MyValueSetProvider(); + private static final MyCodeSystemProvider ourCodeSystemProvider = new MyCodeSystemProvider(); + private static final MyValueSetProvider ourValueSetProvider = new MyValueSetProvider(); @RegisterExtension - public RestfulServerExtension myRestfulServerExtension = new RestfulServerExtension(ourCtx, myCodeSystemProvider, - myValueSetProvider); + public static RestfulServerExtension ourRestfulServerExtension = new RestfulServerExtension(ourCtx, ourCodeSystemProvider, + ourValueSetProvider); private RemoteTerminologyServiceValidationSupport mySvc; @BeforeEach public void before_ConfigureService() { - String myBaseUrl = "http://localhost:" + myRestfulServerExtension.getPort(); + String myBaseUrl = "http://localhost:" + ourRestfulServerExtension.getPort(); mySvc = new RemoteTerminologyServiceValidationSupport(ourCtx, myBaseUrl); mySvc.addClientInterceptor(new LoggingInterceptor(false).setLogRequestSummary(true).setLogResponseSummary(true)); } @@ -64,7 +61,7 @@ public class RemoteTerminologyServiceResourceProviderR4Test { @AfterEach public void after_UnregisterProviders() { ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE); - myRestfulServerExtension.getRestfulServer().getInterceptorService().unregisterAllInterceptors(); + ourRestfulServerExtension.getRestfulServer().getInterceptorService().unregisterAllInterceptors(); } @Test @@ -80,12 +77,13 @@ public class RemoteTerminologyServiceResourceProviderR4Test { IValidationSupport.CodeValidationResult outcome = mySvc .validateCode(null, null, CODE_SYSTEM, CODE, null, null); + assertNotNull(outcome); assertEquals(CODE, outcome.getCode()); - assertEquals(null, outcome.getSeverity()); - assertEquals(null, outcome.getMessage()); + assertNull(outcome.getSeverity()); + assertNull(outcome.getMessage()); - assertEquals(CODE, myCodeSystemProvider.myLastCode.getCode()); - assertEquals(CODE_SYSTEM, myCodeSystemProvider.myLastUrl.getValueAsString()); + assertEquals(CODE, ourCodeSystemProvider.myLastCode.getCode()); + assertEquals(CODE_SYSTEM, ourCodeSystemProvider.myLastUrl.getValueAsString()); } @Test @@ -94,15 +92,16 @@ public class RemoteTerminologyServiceResourceProviderR4Test { IValidationSupport.CodeValidationResult outcome = mySvc .validateCode(null, null, CODE_SYSTEM, CODE, DISPLAY, null); + assertNotNull(outcome); assertEquals(CODE, outcome.getCode()); assertEquals(DISPLAY, outcome.getDisplay()); - assertEquals(null, outcome.getSeverity()); - assertEquals(null, outcome.getMessage()); + assertNull(outcome.getSeverity()); + assertNull(outcome.getMessage()); - assertEquals(CODE, myCodeSystemProvider.myLastCode.getCode()); - assertEquals(DISPLAY, myCodeSystemProvider.myLastDisplay.getValue()); - assertEquals(CODE_SYSTEM, myCodeSystemProvider.myLastUrl.getValueAsString()); - assertEquals(SAMPLE_MESSAGE, myCodeSystemProvider.myNextReturnParams.getParameterValue("message").toString()); + assertEquals(CODE, ourCodeSystemProvider.myLastCode.getCode()); + assertEquals(DISPLAY, ourCodeSystemProvider.myLastDisplay.getValue()); + assertEquals(CODE_SYSTEM, ourCodeSystemProvider.myLastUrl.getValueAsString()); + assertEquals(SAMPLE_MESSAGE, ourCodeSystemProvider.myNextReturnParams.getParameterValue("message").toString()); } @Test @@ -111,65 +110,58 @@ public class RemoteTerminologyServiceResourceProviderR4Test { IValidationSupport.CodeValidationResult outcome = mySvc .validateCode(null, null, CODE_SYSTEM, CODE, null, null); + assertNotNull(outcome); assertEquals(IValidationSupport.IssueSeverity.ERROR, outcome.getSeverity()); assertEquals(SAMPLE_MESSAGE, outcome.getMessage()); - assertEquals(false, ((BooleanType)myCodeSystemProvider.myNextReturnParams.getParameterValue("result")).booleanValue()); + assertFalse(((BooleanType) ourCodeSystemProvider.myNextReturnParams.getParameterValue("result")).booleanValue()); } @Test public void testValidateCodeInValueSet_ProvidingMinimalInputs_ReturnsSuccess() { - createNextValueSetReturnParameters(true, null, null); + ourValueSetProvider.myNextReturnParams = new Parameters().addParameter("result", true); IValidationSupport.CodeValidationResult outcome = mySvc .validateCode(null, null, CODE_SYSTEM, CODE, null, VALUE_SET_URL); + assertNotNull(outcome); assertEquals(CODE, outcome.getCode()); - assertEquals(null, outcome.getSeverity()); - assertEquals(null, outcome.getMessage()); + assertNull(outcome.getSeverity()); + assertNull(outcome.getMessage()); - assertEquals(CODE, myValueSetProvider.myLastCode.getCode()); - assertEquals(VALUE_SET_URL, myValueSetProvider.myLastUrl.getValueAsString()); + assertEquals(CODE, ourValueSetProvider.myLastCode.getCode()); + assertEquals(VALUE_SET_URL, ourValueSetProvider.myLastUrl.getValueAsString()); } @Test public void testValidateCodeInValueSet_WithMessageValue_ReturnsMessage() { - createNextValueSetReturnParameters(true, DISPLAY, SAMPLE_MESSAGE); + ourValueSetProvider.myNextReturnParams = new Parameters().addParameter("result", true) + .addParameter("display", DISPLAY) + .addParameter("message", SAMPLE_MESSAGE); IValidationSupport.CodeValidationResult outcome = mySvc .validateCode(null, null, CODE_SYSTEM, CODE, DISPLAY, VALUE_SET_URL); + assertNotNull(outcome); assertEquals(CODE, outcome.getCode()); assertEquals(DISPLAY, outcome.getDisplay()); - assertEquals(null, outcome.getSeverity()); - assertEquals(null, outcome.getMessage()); + assertNull(outcome.getSeverity()); + assertNull(outcome.getMessage()); - assertEquals(CODE, myValueSetProvider.myLastCode.getCode()); - assertEquals(DISPLAY, myValueSetProvider.myLastDisplay.getValue()); - assertEquals(VALUE_SET_URL, myValueSetProvider.myLastUrl.getValueAsString()); - assertEquals(SAMPLE_MESSAGE, myValueSetProvider.myNextReturnParams.getParameterValue("message").toString()); + assertEquals(CODE, ourValueSetProvider.myLastCode.getCode()); + assertEquals(DISPLAY, ourValueSetProvider.myLastDisplay.getValue()); + assertEquals(VALUE_SET_URL, ourValueSetProvider.myLastUrl.getValueAsString()); + assertEquals(SAMPLE_MESSAGE, ourValueSetProvider.myNextReturnParams.getParameterValue("message").toString()); } private void createNextCodeSystemReturnParameters(boolean theResult, String theDisplay, String theMessage) { - myCodeSystemProvider.myNextReturnParams = new Parameters(); - myCodeSystemProvider.myNextReturnParams.addParameter("result", theResult); - myCodeSystemProvider.myNextReturnParams.addParameter("display", theDisplay); + ourCodeSystemProvider.myNextReturnParams = new Parameters(); + ourCodeSystemProvider.myNextReturnParams.addParameter("result", theResult); + ourCodeSystemProvider.myNextReturnParams.addParameter("display", theDisplay); if (theMessage != null) { - myCodeSystemProvider.myNextReturnParams.addParameter("message", theMessage); - } - } - - private void createNextValueSetReturnParameters(boolean theResult, String theDisplay, String theMessage) { - myValueSetProvider.myNextReturnParams = new Parameters(); - myValueSetProvider.myNextReturnParams.addParameter("result", theResult); - myValueSetProvider.myNextReturnParams.addParameter("display", theDisplay); - if (theMessage != null) { - myValueSetProvider.myNextReturnParams.addParameter("message", theMessage); + ourCodeSystemProvider.myNextReturnParams.addParameter("message", theMessage); } } private static class MyCodeSystemProvider implements IResourceProvider { - private UriParam myLastUrlParam; - private List myNextReturnCodeSystems; - private int myInvocationCount; private UriType myLastUrl; private CodeType myLastCode; private StringType myLastDisplay; @@ -187,7 +179,6 @@ public class RemoteTerminologyServiceResourceProviderR4Test { @OperationParam(name = "code", min = 0, max = 1) CodeType theCode, @OperationParam(name = "display", min = 0, max = 1) StringType theDisplay ) { - myInvocationCount++; myLastUrl = theCodeSystemUrl; myLastCode = theCode; myLastDisplay = theDisplay; @@ -195,13 +186,6 @@ public class RemoteTerminologyServiceResourceProviderR4Test { } - @Search - public List find(@RequiredParam(name = "url") UriParam theUrlParam) { - myLastUrlParam = theUrlParam; - assert myNextReturnCodeSystems != null; - return myNextReturnCodeSystems; - } - @Override public Class getResourceType() { return CodeSystem.class; @@ -211,14 +195,9 @@ public class RemoteTerminologyServiceResourceProviderR4Test { private static class MyValueSetProvider implements IResourceProvider { private Parameters myNextReturnParams; - private List myNextReturnValueSets; private UriType myLastUrl; private CodeType myLastCode; - private int myInvocationCount; - private UriType myLastSystem; private StringType myLastDisplay; - private ValueSet myLastValueSet; - private UriParam myLastUrlParam; @Operation(name = "validate-code", idempotent = true, returnParameters = { @OperationParam(name = "result", type = BooleanType.class, min = 1), @@ -234,22 +213,12 @@ public class RemoteTerminologyServiceResourceProviderR4Test { @OperationParam(name = "display", min = 0, max = 1) StringType theDisplay, @OperationParam(name = "valueSet") ValueSet theValueSet ) { - myInvocationCount++; myLastUrl = theValueSetUrl; myLastCode = theCode; - myLastSystem = theSystem; myLastDisplay = theDisplay; - myLastValueSet = theValueSet; return myNextReturnParams; } - @Search - public List find(@RequiredParam(name = "url") UriParam theUrlParam) { - myLastUrlParam = theUrlParam; - assert myNextReturnValueSets != null; - return myNextReturnValueSets; - } - @Override public Class getResourceType() { return ValueSet.class; diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4CodeSystemPropertiesTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4CodeSystemPropertiesTest.java index 7338a0b4174..f96556ddc36 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4CodeSystemPropertiesTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4CodeSystemPropertiesTest.java @@ -5,8 +5,12 @@ import ca.uhn.fhir.jpa.provider.BaseResourceProviderR4Test; import ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil; import ca.uhn.fhir.rest.gclient.IOperationUntypedWithInputAndPartialOutput; import org.hl7.fhir.r4.model.CodeSystem; +import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent; +import org.hl7.fhir.r4.model.CodeSystem.ConceptPropertyComponent; import org.hl7.fhir.r4.model.CodeType; +import org.hl7.fhir.r4.model.Coding; import org.hl7.fhir.r4.model.Parameters; +import org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent; import org.hl7.fhir.r4.model.StringType; import org.hl7.fhir.r4.model.UriType; import org.junit.jupiter.params.ParameterizedTest; @@ -22,70 +26,74 @@ import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.ourCod import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.ourCodeSystemUrl; import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.ourPropertyA; import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.ourPropertyB; +import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.ourPropertyC; import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.ourPropertyValueA; import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.ourPropertyValueB; +import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.propertyCode; +import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.propertyCodeSystem; +import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.propertyDisplay; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; public class ResourceProviderR4CodeSystemPropertiesTest extends BaseResourceProviderR4Test { - public static Stream parametersLookup() { - return CodeSystemLookupWithPropertiesUtil.parametersLookupWithProperties(); - } + public static Stream parametersLookup() { + return CodeSystemLookupWithPropertiesUtil.parametersLookupWithProperties(); + } - @ParameterizedTest - @MethodSource(value = "parametersLookup") - public void testLookup_withProperties_returnsCorrectParameters(List theLookupProperties, List theExpectedReturnedProperties) { - // setup - CodeSystem codeSystem = new CodeSystem(); - codeSystem.setId(ourCodeSystemId); - codeSystem.setUrl(ourCodeSystemUrl); - CodeSystem.ConceptDefinitionComponent concept = codeSystem.addConcept().setCode(ourCode); - CodeSystem.ConceptPropertyComponent propertyComponent = new CodeSystem.ConceptPropertyComponent() - .setCode(ourPropertyA).setValue(new StringType(ourPropertyValueA)); - concept.addProperty(propertyComponent); - propertyComponent = new CodeSystem.ConceptPropertyComponent() - .setCode(ourPropertyB).setValue(new StringType(ourPropertyValueB)); - concept.addProperty(propertyComponent); - myCodeSystemDao.create(codeSystem, mySrd); + @ParameterizedTest + @MethodSource(value = "parametersLookup") + public void testLookup_withProperties_returnsCorrectParameters(List theLookupProperties, List theExpectedReturnedProperties) { + // setup + CodeSystem codeSystem = new CodeSystem(); + codeSystem.setId(ourCodeSystemId); + codeSystem.setUrl(ourCodeSystemUrl); + ConceptDefinitionComponent concept = codeSystem.addConcept().setCode(ourCode) + .addProperty(new ConceptPropertyComponent().setCode(ourPropertyA).setValue(new StringType(ourPropertyValueA))) + .addProperty(new ConceptPropertyComponent().setCode(ourPropertyB).setValue(new StringType(ourPropertyValueB))) + .addProperty(new ConceptPropertyComponent().setCode(ourPropertyC).setValue(new Coding(propertyCodeSystem, propertyCode, propertyDisplay))); - // test - IOperationUntypedWithInputAndPartialOutput respParam = myClient - .operation() - .onType(CodeSystem.class) - .named(JpaConstants.OPERATION_LOOKUP) - .withParameter(Parameters.class, "code", new CodeType(ourCode)) - .andParameter("system", new UriType(ourCodeSystemUrl)); + myCodeSystemDao.create(codeSystem, mySrd); - theLookupProperties.forEach(p -> respParam.andParameter("property", new CodeType(p))); - Parameters parameters = respParam.execute(); + // test + IOperationUntypedWithInputAndPartialOutput respParam = myClient + .operation() + .onType(CodeSystem.class) + .named(JpaConstants.OPERATION_LOOKUP) + .withParameter(Parameters.class, "code", new CodeType(ourCode)) + .andParameter("system", new UriType(ourCodeSystemUrl)); + theLookupProperties.forEach(p -> respParam.andParameter("property", new CodeType(p))); + Parameters parameters = respParam.execute(); - if (theExpectedReturnedProperties.isEmpty()) { - assertFalse(parameters.hasParameter("property")); - return; - } + // verify + if (theExpectedReturnedProperties.isEmpty()) { + assertFalse(parameters.hasParameter("property")); + return; + } - assertTrue(parameters.hasParameter("property")); - Iterator parameterPropertyIterator = parameters.getParameters("property").iterator(); + assertTrue(parameters.hasParameter("property")); + Iterator parameterPropertyIterator = parameters.getParameters("property").iterator(); - Iterator propertyIterator = concept.getProperty().stream() - .filter(property -> theExpectedReturnedProperties.contains(property.getCode())).iterator(); + Iterator propertyIterator = concept.getProperty().stream() + .filter(property -> theExpectedReturnedProperties.contains(property.getCode())).iterator(); - while (propertyIterator.hasNext()) { - CodeSystem.ConceptPropertyComponent property = propertyIterator.next(); + while (propertyIterator.hasNext()) { + ConceptPropertyComponent property = propertyIterator.next(); - assertTrue(parameterPropertyIterator.hasNext()); - Parameters.ParametersParameterComponent parameter = parameterPropertyIterator.next(); - Iterator parameterPartIterator = parameter.getPart().iterator(); + assertTrue(parameterPropertyIterator.hasNext()); + ParametersParameterComponent parameter = parameterPropertyIterator.next(); + Iterator parameterPartIterator = parameter.getPart().iterator(); - parameter = parameterPartIterator.next(); - assertEquals("code", parameter.getName()); - assertEquals(property.getCode(), ((CodeType)parameter.getValue()).getCode()); + parameter = parameterPartIterator.next(); + assertEquals("code", parameter.getName()); + assertEquals(property.getCode(), ((CodeType) parameter.getValue()).getValue()); - parameter = parameterPartIterator.next(); - assertEquals("value", parameter.getName()); - assertTrue(property.getValue().equalsShallow(parameter.getValue())); - } - } + parameter = parameterPartIterator.next(); + assertEquals("value", parameter.getName()); + assertTrue(property.getValue().equalsShallow(parameter.getValue())); + + assertFalse(parameterPartIterator.hasNext()); + } + } } diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcDeltaR4Test.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcDeltaR4Test.java index 7ab96037c26..24b0673fd16 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcDeltaR4Test.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcDeltaR4Test.java @@ -510,7 +510,7 @@ public class TerminologySvcDeltaR4Test extends BaseJpaR4Test { List properties = output.getParameter().stream().filter(t -> t.getName().equals("property")).collect(Collectors.toList()); assertEquals("code", properties.get(0).getPart().get(0).getName()); - assertEquals("flavour", ((CodeType) properties.get(0).getPart().get(0).getValue()).getValueAsString()); + assertEquals("flavour", ((StringType) properties.get(0).getPart().get(0).getValue()).getValueAsString()); assertEquals("value", properties.get(0).getPart().get(1).getName()); assertEquals("Hints of lime", ((StringType) properties.get(0).getPart().get(1).getValue()).getValueAsString()); diff --git a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/provider/r5/ResourceProviderR5CodeSystemPropertiesTest.java b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/provider/r5/ResourceProviderR5CodeSystemPropertiesTest.java index e8b5be13fb4..5a9f26f8c1c 100644 --- a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/provider/r5/ResourceProviderR5CodeSystemPropertiesTest.java +++ b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/provider/r5/ResourceProviderR5CodeSystemPropertiesTest.java @@ -1,11 +1,14 @@ package ca.uhn.fhir.jpa.provider.r5; import ca.uhn.fhir.jpa.model.util.JpaConstants; -import ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil; import ca.uhn.fhir.rest.gclient.IOperationUntypedWithInputAndPartialOutput; +import ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil; import org.hl7.fhir.r5.model.CodeSystem; +import org.hl7.fhir.r5.model.CodeSystem.ConceptPropertyComponent; import org.hl7.fhir.r5.model.CodeType; +import org.hl7.fhir.r5.model.Coding; import org.hl7.fhir.r5.model.Parameters; +import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent; import org.hl7.fhir.r5.model.StringType; import org.hl7.fhir.r5.model.UriType; import org.junit.jupiter.params.ParameterizedTest; @@ -21,69 +24,73 @@ import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.ourCod import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.ourCodeSystemUrl; import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.ourPropertyA; import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.ourPropertyB; +import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.ourPropertyC; import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.ourPropertyValueA; import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.ourPropertyValueB; +import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.propertyCode; +import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.propertyCodeSystem; +import static ca.uhn.fhir.jpa.provider.CodeSystemLookupWithPropertiesUtil.propertyDisplay; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; public class ResourceProviderR5CodeSystemPropertiesTest extends BaseResourceProviderR5Test { - public static Stream parametersLookup() { - return CodeSystemLookupWithPropertiesUtil.parametersLookupWithProperties(); - } - @ParameterizedTest - @MethodSource(value = "parametersLookup") - public void testLookup_withProperties_returnsCorrectParameters(List theLookupProperties, List theExpectedReturnedProperties) { - // setup - CodeSystem codeSystem = new CodeSystem(); - codeSystem.setId(ourCodeSystemId); - codeSystem.setUrl(ourCodeSystemUrl); - CodeSystem.ConceptDefinitionComponent concept = codeSystem.addConcept().setCode(ourCode); - CodeSystem.ConceptPropertyComponent propertyComponent = new CodeSystem.ConceptPropertyComponent() - .setCode(ourPropertyA).setValue(new StringType(ourPropertyValueA)); - concept.addProperty(propertyComponent); - propertyComponent = new CodeSystem.ConceptPropertyComponent() - .setCode(ourPropertyB).setValue(new StringType(ourPropertyValueB)); - concept.addProperty(propertyComponent); - myCodeSystemDao.create(codeSystem, mySrd); + public static Stream parametersLookup() { + return CodeSystemLookupWithPropertiesUtil.parametersLookupWithProperties(); + } - // test - IOperationUntypedWithInputAndPartialOutput respParam = myClient - .operation() - .onType(CodeSystem.class) - .named(JpaConstants.OPERATION_LOOKUP) - .withParameter(Parameters.class, "code", new CodeType(ourCode)) - .andParameter("system", new UriType(ourCodeSystemUrl)); + @ParameterizedTest + @MethodSource(value = "parametersLookup") + public void testLookup_withProperties_returnsCorrectParameters(List theLookupProperties, List theExpectedReturnedProperties) { + // setup + CodeSystem codeSystem = new CodeSystem(); + codeSystem.setId(ourCodeSystemId); + codeSystem.setUrl(ourCodeSystemUrl); + CodeSystem.ConceptDefinitionComponent concept = codeSystem.addConcept().setCode(ourCode) + .addProperty(new ConceptPropertyComponent().setCode(ourPropertyA).setValue(new StringType(ourPropertyValueA))) + .addProperty(new ConceptPropertyComponent().setCode(ourPropertyB).setValue(new StringType(ourPropertyValueB))) + .addProperty(new ConceptPropertyComponent().setCode(ourPropertyC).setValue(new Coding(propertyCodeSystem, propertyCode, propertyDisplay))); + myCodeSystemDao.create(codeSystem, mySrd); - theLookupProperties.forEach(p -> respParam.andParameter("property", new CodeType(p))); - Parameters parameters = respParam.execute(); + // test + IOperationUntypedWithInputAndPartialOutput respParam = myClient + .operation() + .onType(CodeSystem.class) + .named(JpaConstants.OPERATION_LOOKUP) + .withParameter(Parameters.class, "code", new CodeType(ourCode)) + .andParameter("system", new UriType(ourCodeSystemUrl)); + theLookupProperties.forEach(p -> respParam.andParameter("property", new CodeType(p))); + Parameters parameters = respParam.execute(); - if (theExpectedReturnedProperties.isEmpty()) { - assertFalse(parameters.hasParameter("property")); - return; - } + // verify + if (theExpectedReturnedProperties.isEmpty()) { + assertFalse(parameters.hasParameter("property")); + return; + } - assertTrue(parameters.hasParameter("property")); - Iterator parameterPropertyIterator = parameters.getParameters("property").iterator(); + assertTrue(parameters.hasParameter("property")); + Iterator parameterPropertyIterator = parameters.getParameters("property").iterator(); - Iterator propertyIterator = concept.getProperty().stream() - .filter(property -> theExpectedReturnedProperties.contains(property.getCode())).iterator(); + Iterator propertyIterator = concept.getProperty().stream() + .filter(property -> theExpectedReturnedProperties.contains(property.getCode())).iterator(); - while (propertyIterator.hasNext()) { - CodeSystem.ConceptPropertyComponent property = propertyIterator.next(); + while (propertyIterator.hasNext()) { + ConceptPropertyComponent property = propertyIterator.next(); - assertTrue(parameterPropertyIterator.hasNext()); - Parameters.ParametersParameterComponent parameter = parameterPropertyIterator.next(); - Iterator parameterPartIterator = parameter.getPart().iterator(); + assertTrue(parameterPropertyIterator.hasNext()); + ParametersParameterComponent parameter = parameterPropertyIterator.next(); + Iterator parameterPartIterator = parameter.getPart().iterator(); - parameter = parameterPartIterator.next(); - assertEquals("code", parameter.getName()); - assertEquals(property.getCode(), ((CodeType)parameter.getValue()).getCode()); + parameter = parameterPartIterator.next(); + assertEquals("code", parameter.getName()); + assertEquals(property.getCode(), ((CodeType) parameter.getValue()).getValue()); - parameter = parameterPartIterator.next(); - assertEquals("value", parameter.getName()); - assertTrue(property.getValue().equalsShallow(parameter.getValue())); - } - } + parameter = parameterPartIterator.next(); + assertEquals("value", parameter.getName()); + assertTrue(property.getValue().equalsShallow(parameter.getValue())); + + assertFalse(parameterPartIterator.hasNext()); + } + } } diff --git a/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/provider/CodeSystemLookupWithPropertiesUtil.java b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/provider/CodeSystemLookupWithPropertiesUtil.java index baf2b8c623f..d68fcee92ba 100644 --- a/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/provider/CodeSystemLookupWithPropertiesUtil.java +++ b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/provider/CodeSystemLookupWithPropertiesUtil.java @@ -31,13 +31,19 @@ public class CodeSystemLookupWithPropertiesUtil { public static final String ourCodeSystemId = "CodeSystem-Example", ourCodeSystemUrl = "http://example/" + ourCodeSystemId; public static final String ourCode = "Code-WithProperties"; - public static final String ourPropertyA = "Property-A", ourPropertyB = "Property-B"; + public static final String ourPropertyA = "Property-A", ourPropertyB = "Property-B", ourPropertyC = "Property-C"; public static final String ourPropertyValueA = "Value-A", ourPropertyValueB = "Value-B"; + public static final String propertyCodeSystem = "CodeSystem-C", + propertyCode = "Code-C", + propertyDisplay = "Display-C"; public static Stream parametersLookupWithProperties() { return Stream.of( + arguments(Collections.emptyList(), List.of(ourPropertyA, ourPropertyB, ourPropertyC)), arguments(List.of(ourPropertyB), List.of(ourPropertyB)), - arguments(List.of(ourPropertyA, ourPropertyB), List.of(ourPropertyA, ourPropertyB)), + arguments( + List.of(ourPropertyA, ourPropertyB, ourPropertyC), + List.of(ourPropertyA, ourPropertyB, ourPropertyC)), arguments(List.of(ourPropertyB, ourPropertyA), List.of(ourPropertyB, ourPropertyA)), arguments(List.of(ourPropertyA, ourPropertyA), List.of(ourPropertyA, ourPropertyA)), arguments(List.of(ourPropertyB, "ABC"), List.of(ourPropertyB)), diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/RemoteTerminologyServiceValidationSupport.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/RemoteTerminologyServiceValidationSupport.java index a44cce1ee7b..08f94902a66 100644 --- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/RemoteTerminologyServiceValidationSupport.java +++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/RemoteTerminologyServiceValidationSupport.java @@ -12,6 +12,7 @@ import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.rest.api.SummaryEnum; import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.gclient.IQuery; +import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.util.BundleUtil; import ca.uhn.fhir.util.ParametersUtil; import jakarta.annotation.Nonnull; @@ -19,15 +20,25 @@ import jakarta.annotation.Nullable; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.hl7.fhir.instance.model.api.IBaseBundle; +import org.hl7.fhir.instance.model.api.IBaseDatatype; import org.hl7.fhir.instance.model.api.IBaseParameters; import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.r4.model.Base; import org.hl7.fhir.r4.model.CodeSystem; +import org.hl7.fhir.r4.model.CodeType; +import org.hl7.fhir.r4.model.Coding; +import org.hl7.fhir.r4.model.Parameters; +import org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent; +import org.hl7.fhir.r4.model.Property; +import org.hl7.fhir.r4.model.StringType; +import org.hl7.fhir.r4.model.Type; import org.hl7.fhir.r4.model.ValueSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank; @@ -42,7 +53,7 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup private static final Logger ourLog = LoggerFactory.getLogger(RemoteTerminologyServiceValidationSupport.class); private String myBaseUrl; - private List myClientInterceptors = new ArrayList<>(); + private final List myClientInterceptors = new ArrayList<>(); /** * Constructor @@ -65,8 +76,8 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup @Override public CodeValidationResult validateCode( - @Nonnull ValidationSupportContext theValidationSupportContext, - @Nonnull ConceptValidationOptions theOptions, + ValidationSupportContext theValidationSupportContext, + ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, @@ -86,7 +97,7 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup IBaseResource valueSet = theValueSet; // some external validators require the system when the code is passed - // so let's try to get it from the VS if is is not present + // so let's try to get it from the VS if is not present String codeSystem = theCodeSystem; if (isNotBlank(theCode) && isBlank(codeSystem)) { codeSystem = extractCodeSystemForCode((ValueSet) theValueSet, theCode); @@ -123,7 +134,7 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup } // when component has more than one include, their codeSystem(s) could be different, so we need to make sure - // that we are picking up the system for the include to which the code corresponds + // that we are picking up the system for the include filter to which the code corresponds for (ValueSet.ConceptSetComponent include : theValueSet.getCompose().getInclude()) { if (include.hasSystem()) { for (ValueSet.ConceptReferenceComponent concept : include.getConcept()) { @@ -222,7 +233,7 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup return generateLookupCodeResultDSTU3( code, system, (org.hl7.fhir.dstu3.model.Parameters) outcome); case R4: - return generateLookupCodeResultR4(code, system, (org.hl7.fhir.r4.model.Parameters) outcome); + return generateLookupCodeResultR4(code, system, (Parameters) outcome); } } break; @@ -244,87 +255,133 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup result.setFound(true); for (org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent parameterComponent : outcomeDSTU3.getParameter()) { + String parameterTypeAsString = Objects.toString(parameterComponent.getValue(), null); switch (parameterComponent.getName()) { case "property": org.hl7.fhir.dstu3.model.Property part = parameterComponent.getChildByName("part"); // The assumption here is that we may only have 2 elements in this part, and if so, these 2 will be // saved - if (part != null && part.hasValues() && part.getValues().size() >= 2) { - String key = ((org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent) - part.getValues().get(0)) - .getValue() - .toString(); - String value = ((org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent) - part.getValues().get(1)) - .getValue() - .toString(); - if (!StringUtils.isEmpty(key) && !StringUtils.isEmpty(value)) { - result.getProperties().add(new StringConceptProperty(key, value)); - } + if (part == null || part.getValues().size() < 2) { + continue; + } + BaseConceptProperty conceptProperty = createBaseConceptPropertyDstu3(part.getValues()); + if (conceptProperty != null) { + result.getProperties().add(conceptProperty); } break; case "designation": - ConceptDesignation conceptDesignation = new ConceptDesignation(); - for (org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent designationComponent : - parameterComponent.getPart()) { - switch (designationComponent.getName()) { - case "language": - conceptDesignation.setLanguage( - designationComponent.getValue().toString()); - break; - case "use": - org.hl7.fhir.dstu3.model.Coding coding = - (org.hl7.fhir.dstu3.model.Coding) designationComponent.getValue(); - if (coding != null) { - conceptDesignation.setUseSystem(coding.getSystem()); - conceptDesignation.setUseCode(coding.getCode()); - conceptDesignation.setUseDisplay(coding.getDisplay()); - } - break; - case "value": - conceptDesignation.setValue( - ((designationComponent.getValue() == null) - ? null - : designationComponent - .getValue() - .toString())); - break; - } - } + ConceptDesignation conceptDesignation = createConceptDesignationDstu3(parameterComponent); result.getDesignations().add(conceptDesignation); break; case "name": - result.setCodeSystemDisplayName( - ((parameterComponent.getValue() == null) - ? null - : parameterComponent.getValue().toString())); + result.setCodeSystemDisplayName(parameterTypeAsString); break; case "version": - result.setCodeSystemVersion( - ((parameterComponent.getValue() == null) - ? null - : parameterComponent.getValue().toString())); + result.setCodeSystemVersion(parameterTypeAsString); break; case "display": - result.setCodeDisplay( - ((parameterComponent.getValue() == null) - ? null - : parameterComponent.getValue().toString())); + result.setCodeDisplay(parameterTypeAsString); break; case "abstract": - result.setCodeIsAbstract( - ((parameterComponent.getValue() == null) - ? false - : Boolean.parseBoolean( - parameterComponent.getValue().toString()))); + result.setCodeIsAbstract(Boolean.parseBoolean(parameterTypeAsString)); break; } } return result; } - private LookupCodeResult generateLookupCodeResultR4( - String theCode, String theSystem, org.hl7.fhir.r4.model.Parameters outcomeR4) { + private static BaseConceptProperty createBaseConceptPropertyDstu3(List theValues) { + org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent part1 = + (org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent) theValues.get(0); + String propertyName = ((org.hl7.fhir.dstu3.model.CodeType) part1.getValue()).getValue(); + + BaseConceptProperty conceptProperty = null; + org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent part2 = + (org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent) theValues.get(1); + + org.hl7.fhir.dstu3.model.Type value = part2.getValue(); + if (value == null) { + return conceptProperty; + } + String fhirType = value.fhirType(); + switch (fhirType) { + case TYPE_STRING: + org.hl7.fhir.dstu3.model.StringType stringType = (org.hl7.fhir.dstu3.model.StringType) part2.getValue(); + conceptProperty = new StringConceptProperty(propertyName, stringType.getValue()); + break; + case TYPE_CODING: + org.hl7.fhir.dstu3.model.Coding coding = (org.hl7.fhir.dstu3.model.Coding) part2.getValue(); + conceptProperty = new CodingConceptProperty( + propertyName, coding.getSystem(), coding.getCode(), coding.getDisplay()); + break; + default: + throw new InternalErrorException(Msg.code(2450) + "Property type " + fhirType + " is not supported."); + } + return conceptProperty; + } + + public static BaseConceptProperty createConceptProperty(final String theName, final IBaseDatatype theValue) { + if (theValue instanceof Type) { + return createConceptPropertyR4(theName, (Type) theValue); + } + if (theValue instanceof org.hl7.fhir.dstu3.model.Type) { + return createConceptPropertyDstu3(theName, (org.hl7.fhir.dstu3.model.Type) theValue); + } + return null; + } + + private static BaseConceptProperty createConceptPropertyDstu3( + final String theName, final org.hl7.fhir.dstu3.model.Type theValue) { + if (theValue == null) { + return null; + } + BaseConceptProperty conceptProperty; + String fhirType = theValue.fhirType(); + switch (fhirType) { + case IValidationSupport.TYPE_STRING: + org.hl7.fhir.dstu3.model.StringType stringType = (org.hl7.fhir.dstu3.model.StringType) theValue; + conceptProperty = new StringConceptProperty(theName, stringType.getValue()); + break; + case IValidationSupport.TYPE_CODING: + org.hl7.fhir.dstu3.model.Coding coding = (org.hl7.fhir.dstu3.model.Coding) theValue; + conceptProperty = + new CodingConceptProperty(theName, coding.getSystem(), coding.getCode(), coding.getDisplay()); + break; + default: + throw new InternalErrorException(Msg.code(2451) + "Property type " + fhirType + " is not supported."); + } + return conceptProperty; + } + + private ConceptDesignation createConceptDesignationDstu3( + org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent theParameterComponent) { + ConceptDesignation conceptDesignation = new ConceptDesignation(); + for (org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent designationComponent : + theParameterComponent.getPart()) { + org.hl7.fhir.dstu3.model.Type designationComponentValue = designationComponent.getValue(); + if (designationComponentValue == null) { + continue; + } + switch (designationComponent.getName()) { + case "language": + conceptDesignation.setLanguage(designationComponentValue.toString()); + break; + case "use": + org.hl7.fhir.dstu3.model.Coding coding = + (org.hl7.fhir.dstu3.model.Coding) designationComponentValue; + conceptDesignation.setUseSystem(coding.getSystem()); + conceptDesignation.setUseCode(coding.getCode()); + conceptDesignation.setUseDisplay(coding.getDisplay()); + break; + case "value": + conceptDesignation.setValue(designationComponent.getValue().toString()); + break; + } + } + return conceptDesignation; + } + + private LookupCodeResult generateLookupCodeResultR4(String theCode, String theSystem, Parameters outcomeR4) { // NOTE: I wanted to put all of this logic into the IValidationSupport Class, but it would've required adding // several new dependencies on version-specific libraries and that is explicitly forbidden (see comment in // POM). @@ -332,87 +389,115 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup result.setSearchedForCode(theCode); result.setSearchedForSystem(theSystem); result.setFound(true); - for (org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent parameterComponent : - outcomeR4.getParameter()) { + for (ParametersParameterComponent parameterComponent : outcomeR4.getParameter()) { + String parameterTypeAsString = Objects.toString(parameterComponent.getValue(), null); switch (parameterComponent.getName()) { case "property": - org.hl7.fhir.r4.model.Property part = parameterComponent.getChildByName("part"); + Property part = parameterComponent.getChildByName("part"); // The assumption here is that we may only have 2 elements in this part, and if so, these 2 will be // saved - if (part != null && part.hasValues() && part.getValues().size() >= 2) { - String key = ((org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent) - part.getValues().get(0)) - .getValue() - .toString(); - String value = ((org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent) - part.getValues().get(1)) - .getValue() - .toString(); - if (!StringUtils.isEmpty(key) && !StringUtils.isEmpty(value)) { - result.getProperties().add(new StringConceptProperty(key, value)); - } + if (part == null || part.getValues().size() < 2) { + continue; + } + BaseConceptProperty conceptProperty = createBaseConceptPropertyR4(part.getValues()); + if (conceptProperty != null) { + result.getProperties().add(conceptProperty); } break; case "designation": - ConceptDesignation conceptDesignation = new ConceptDesignation(); - for (org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent designationComponent : - parameterComponent.getPart()) { - switch (designationComponent.getName()) { - case "language": - conceptDesignation.setLanguage( - designationComponent.getValue().toString()); - break; - case "use": - org.hl7.fhir.r4.model.Coding coding = - (org.hl7.fhir.r4.model.Coding) designationComponent.getValue(); - if (coding != null) { - conceptDesignation.setUseSystem(coding.getSystem()); - conceptDesignation.setUseCode(coding.getCode()); - conceptDesignation.setUseDisplay(coding.getDisplay()); - } - break; - case "value": - conceptDesignation.setValue( - ((designationComponent.getValue() == null) - ? null - : designationComponent - .getValue() - .toString())); - break; - } - } + ConceptDesignation conceptDesignation = createConceptDesignationR4(parameterComponent); result.getDesignations().add(conceptDesignation); break; case "name": - result.setCodeSystemDisplayName( - ((parameterComponent.getValue() == null) - ? null - : parameterComponent.getValue().toString())); + result.setCodeSystemDisplayName(parameterTypeAsString); break; case "version": - result.setCodeSystemVersion( - ((parameterComponent.getValue() == null) - ? null - : parameterComponent.getValue().toString())); + result.setCodeSystemVersion(parameterTypeAsString); break; case "display": - result.setCodeDisplay( - ((parameterComponent.getValue() == null) - ? null - : parameterComponent.getValue().toString())); + result.setCodeDisplay(parameterTypeAsString); break; case "abstract": - result.setCodeIsAbstract( - ((parameterComponent.getValue() == null) - ? false - : Boolean.parseBoolean( - parameterComponent.getValue().toString()))); + result.setCodeIsAbstract(Boolean.parseBoolean(parameterTypeAsString)); break; } } return result; } + private static BaseConceptProperty createBaseConceptPropertyR4(List values) { + ParametersParameterComponent part1 = (ParametersParameterComponent) values.get(0); + String propertyName = ((CodeType) part1.getValue()).getValue(); + + ParametersParameterComponent part2 = (ParametersParameterComponent) values.get(1); + + Type value = part2.getValue(); + if (value == null) { + return null; + } + BaseConceptProperty conceptProperty; + String fhirType = value.fhirType(); + switch (fhirType) { + case IValidationSupport.TYPE_STRING: + StringType stringType = (StringType) part2.getValue(); + conceptProperty = new StringConceptProperty(propertyName, stringType.getValue()); + break; + case IValidationSupport.TYPE_CODING: + Coding coding = (Coding) part2.getValue(); + conceptProperty = new CodingConceptProperty( + propertyName, coding.getSystem(), coding.getCode(), coding.getDisplay()); + break; + default: + throw new InternalErrorException(Msg.code(2452) + "Property type " + fhirType + " is not supported."); + } + return conceptProperty; + } + + private static BaseConceptProperty createConceptPropertyR4(final String theName, final Type theValue) { + BaseConceptProperty conceptProperty; + + String fhirType = theValue.fhirType(); + switch (fhirType) { + case IValidationSupport.TYPE_STRING: + StringType stringType = (StringType) theValue; + conceptProperty = new StringConceptProperty(theName, stringType.getValue()); + break; + case IValidationSupport.TYPE_CODING: + Coding coding = (Coding) theValue; + conceptProperty = + new CodingConceptProperty(theName, coding.getSystem(), coding.getCode(), coding.getDisplay()); + break; + default: + throw new InternalErrorException(Msg.code(2453) + "Property type " + fhirType + " is not supported."); + } + return conceptProperty; + } + + private ConceptDesignation createConceptDesignationR4(ParametersParameterComponent theParameterComponent) { + ConceptDesignation conceptDesignation = new ConceptDesignation(); + for (ParametersParameterComponent designationComponent : theParameterComponent.getPart()) { + Type designationComponentValue = designationComponent.getValue(); + if (designationComponentValue == null) { + continue; + } + switch (designationComponent.getName()) { + case "language": + conceptDesignation.setLanguage(designationComponentValue.toString()); + break; + case "use": + Coding coding = (Coding) designationComponentValue; + conceptDesignation.setUseSystem(coding.getSystem()); + conceptDesignation.setUseCode(coding.getCode()); + conceptDesignation.setUseDisplay(coding.getDisplay()); + break; + case "value": + conceptDesignation.setValue(designationComponentValue.toString()); + break; + } + } + return conceptDesignation; + } + @Override public IBaseResource fetchValueSet(String theValueSetUrl) { // force the remote server to send the whole resource. @@ -514,7 +599,7 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup .execute(); List resultValues = ParametersUtil.getNamedParameterValuesAsString(getFhirContext(), output, "result"); - if (resultValues.size() < 1 || isBlank(resultValues.get(0))) { + if (resultValues.isEmpty() || isBlank(resultValues.get(0))) { return null; } Validate.isTrue(resultValues.size() == 1, "Response contained %d 'result' values", resultValues.size()); @@ -527,7 +612,7 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup retVal.setCode(theCode); List displayValues = ParametersUtil.getNamedParameterValuesAsString(getFhirContext(), output, "display"); - if (displayValues.size() > 0) { + if (!displayValues.isEmpty()) { retVal.setDisplay(displayValues.get(0)); } @@ -536,7 +621,7 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup retVal.setSeverity(IssueSeverity.ERROR); List messageValues = ParametersUtil.getNamedParameterValuesAsString(getFhirContext(), output, "message"); - if (messageValues.size() > 0) { + if (!messageValues.isEmpty()) { retVal.setMessage(messageValues.get(0)); } } @@ -575,7 +660,7 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup /** * Sets the FHIR Terminology Server base URL * - * @param theBaseUrl The base URL, e.g. "https://hapi.fhir.org/baseR4" + * @param theBaseUrl The base URL, e.g. "..." */ public void setBaseUrl(String theBaseUrl) { Validate.notBlank(theBaseUrl, "theBaseUrl must be provided"); diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/ILookupCodeTest.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/ILookupCodeTest.java new file mode 100644 index 00000000000..966a795eef3 --- /dev/null +++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/ILookupCodeTest.java @@ -0,0 +1,260 @@ +package org.hl7.fhir.common.hapi.validation; + +import ca.uhn.fhir.context.support.IValidationSupport; +import ca.uhn.fhir.context.support.IValidationSupport.LookupCodeResult; +import ca.uhn.fhir.context.support.LookupCodeRequest; +import ca.uhn.fhir.rest.server.IResourceProvider; +import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; +import org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport; +import org.hl7.fhir.instance.model.api.IBaseDatatype; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; + +import static org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport.createConceptProperty; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +public interface ILookupCodeTest { + String DISPLAY = "DISPLAY"; + String LANGUAGE = "en"; + String CODE_SYSTEM = "CODE_SYS"; + String CODE_SYSTEM_VERSION = "CODE_SYS_VERSION"; + String CODE_SYSTEM_NAME = "Code System"; + String CODE = "CODE"; + + interface IValidationTest { + + RemoteTerminologyServiceValidationSupport getService(); + IResourceProvider getCodeSystemProvider(); + } + + @Nested + interface ILookupCodeUnsupportedPropertyTypeTest extends IValidationTest { + + String getInvalidValueErrorCode(); + + String getInvalidValueErrorCodeForConvert(); + + @Override + IMySimpleCodeSystemProvider getCodeSystemProvider(); + + @Test + default void testLookupCode_forCodeSystemWithPropertyInvalidValue_throwsException() { + // test and verify + try { + getService().lookupCode(null, new LookupCodeRequest(CODE_SYSTEM, CODE, LANGUAGE, null)); + fail(); + } catch (InternalErrorException e) { + assertTrue(e.getMessage().contains(getInvalidValueErrorCode() + ": Property type " + getCodeSystemProvider().getPropertyValue().fhirType() + " is not supported")); + } + } + + @Test + default void testCreateConceptProperty_forCodeSystemWithPropertyInvalidValue_throwsException() { + // test and verify + try { + RemoteTerminologyServiceValidationSupport.createConceptProperty("property", getCodeSystemProvider().getPropertyValue()); + fail(); + } catch (InternalErrorException e) { + assertTrue(e.getMessage().contains(getInvalidValueErrorCodeForConvert() + ": Property type " + getCodeSystemProvider().getPropertyValue().fhirType() + " is not supported")); + } + } + } + + @Nested + interface ILookupCodeSupportedPropertyTest extends IValidationTest { + IMyCodeSystemProvider getCodeSystemProvider(); + + Stream getEmptyPropertyValues(); + + Stream getPropertyValues(); + + Stream getDesignations(); + + void verifyProperty(IValidationSupport.BaseConceptProperty theConceptProperty, String theExpectedPropertName, IBaseDatatype theExpectedValue); + + @Test + default void testLookupCode_forCodeSystemWithBlankCode_throwsException() { + try { + getService().lookupCode(null, new LookupCodeRequest(CODE_SYSTEM, "")); + fail(); + } catch (IllegalArgumentException e) { + assertEquals("theCode must be provided", e.getMessage()); + } + } + + @Test + default void testLookupCode_forCodeSystemWithPropertyInvalidType_throwsException() { + LookupCodeResult result = new LookupCodeResult(); + result.getProperties().add(new IValidationSupport.BaseConceptProperty("someProperty") { + public String getType() { + return "someUnsupportedType"; + } + }); + getCodeSystemProvider().setLookupCodeResult(result); + + try { + getService().lookupCode(null, new LookupCodeRequest(CODE_SYSTEM, CODE, LANGUAGE, null)); + fail(); + } catch (InternalErrorException e) { + assertTrue(e.getMessage().contains("HAPI-1739: Don't know how to handle ")); + } + } + + @ParameterizedTest + @MethodSource(value = "getEmptyPropertyValues") + default void testLookupCode_forCodeSystemWithPropertyEmptyValue_returnsCorrectParameters(IBaseDatatype thePropertyValue) { + // setup + final String propertyName = "someProperty"; + IValidationSupport.BaseConceptProperty property = createConceptProperty(propertyName, thePropertyValue); + LookupCodeResult result = new LookupCodeResult(); + result.getProperties().add(property); + getCodeSystemProvider().setLookupCodeResult(result); + + // test + LookupCodeResult outcome = getService().lookupCode(null, new LookupCodeRequest(CODE_SYSTEM, CODE, LANGUAGE, List.of(propertyName))); + + // verify + assertNotNull(outcome); + Optional propertyOptional = outcome.getProperties().stream().findFirst().filter(a -> propertyName.equals(a.getPropertyName())); + assertFalse(propertyOptional.isPresent()); + } + + @Test + default void testLookupCode_forCodeSystemWithParameters_returnsCorrectParameters() { + // setup + LookupCodeResult result = new LookupCodeResult().setFound(true).setSearchedForCode(CODE).setSearchedForSystem(CODE_SYSTEM); + result.setCodeIsAbstract(false); + result.setCodeSystemVersion(CODE_SYSTEM_VERSION); + result.setCodeSystemDisplayName(CODE_SYSTEM_NAME); + result.setCodeDisplay(DISPLAY); + getCodeSystemProvider().setLookupCodeResult(result); + + // test + LookupCodeResult outcome = getService().lookupCode(null, new LookupCodeRequest(CODE_SYSTEM, CODE, LANGUAGE, null)); + + // verify + assertNotNull(outcome); + assertEquals(CODE, getCodeSystemProvider().getCode()); + assertEquals(CODE_SYSTEM, getCodeSystemProvider().getSystem()); + assertEquals(result.getCodeSystemDisplayName(), outcome.getCodeSystemDisplayName()); + assertEquals(result.getCodeDisplay(), outcome.getCodeDisplay()); + assertEquals(result.getCodeSystemVersion(), outcome.getCodeSystemVersion()); + assertEquals(result.isCodeIsAbstract(), outcome.isCodeIsAbstract()); + } + + @ParameterizedTest + @MethodSource(value = "getPropertyValues") + default void testLookupCode_forCodeSystemWithProperty_returnsCorrectProperty(IBaseDatatype thePropertyValue) { + // setup + final String propertyName = "someProperty"; + LookupCodeResult result = new LookupCodeResult() + .setFound(true).setSearchedForCode(CODE).setSearchedForSystem(CODE_SYSTEM); + result.setCodeIsAbstract(false); + result.setCodeSystemVersion(CODE_SYSTEM_VERSION); + result.setCodeSystemDisplayName(CODE_SYSTEM_NAME); + result.setCodeDisplay(DISPLAY); + IValidationSupport.BaseConceptProperty property = createConceptProperty(propertyName, thePropertyValue); + result.getProperties().add(property); + getCodeSystemProvider().setLookupCodeResult(result); + + // test + LookupCodeResult outcome = getService().lookupCode(null, new LookupCodeRequest(CODE_SYSTEM, CODE, LANGUAGE, List.of(propertyName))); + + // verify + assertNotNull(outcome); + assertEquals(CODE, getCodeSystemProvider().getCode()); + assertEquals(CODE_SYSTEM, getCodeSystemProvider().getSystem()); + assertEquals(result.getCodeSystemDisplayName(), outcome.getCodeSystemDisplayName()); + assertEquals(result.getCodeDisplay(), outcome.getCodeDisplay()); + assertEquals(result.getCodeSystemVersion(), outcome.getCodeSystemVersion()); + assertEquals(result.isCodeIsAbstract(), outcome.isCodeIsAbstract()); + + Optional propertyOptional = outcome.getProperties().stream().findFirst().filter(a -> propertyName.equals(a.getPropertyName())); + assertTrue(propertyOptional.isPresent()); + IValidationSupport.BaseConceptProperty outputProperty = propertyOptional.get(); + + verifyProperty(outputProperty, propertyName, thePropertyValue); + } + + @ParameterizedTest + @MethodSource(value = "getDesignations") + default void testLookupCode_withCodeSystemWithDesignation_returnsCorrectDesignation(final IValidationSupport.ConceptDesignation theConceptDesignation) { + // setup + LookupCodeResult result = new LookupCodeResult(); + result.getDesignations().add(theConceptDesignation); + getCodeSystemProvider().setLookupCodeResult(result); + + // test + LookupCodeResult outcome = getService().lookupCode(null, new LookupCodeRequest(CODE_SYSTEM, CODE, LANGUAGE, null)); + + // verify + assertNotNull(outcome); + + Collection designations = outcome.getDesignations(); + assertEquals(1, designations.size()); + + IValidationSupport.ConceptDesignation designation = designations.iterator().next(); + assertEquals(theConceptDesignation.getValue(), designation.getValue()); + assertEquals(theConceptDesignation.getLanguage(), designation.getLanguage()); + assertEquals(theConceptDesignation.getUseCode(), designation.getUseCode()); + assertEquals(theConceptDesignation.getUseSystem(), designation.getUseSystem()); + assertEquals(theConceptDesignation.getUseDisplay(), designation.getUseDisplay()); + } + + @Test + default void testLookupCode_withCodeSystemWithMultipleDesignations_returnsCorrectDesignations() { + // setup + final String code1 = "code1"; + final String code2 = "code2"; + + IValidationSupport.ConceptDesignation designation1 = new IValidationSupport.ConceptDesignation().setUseCode(code1).setUseSystem("system1").setValue("value1").setLanguage("en"); + IValidationSupport.ConceptDesignation designation2 = new IValidationSupport.ConceptDesignation().setUseCode(code2).setUseSystem("system2").setValue("value2").setLanguage("es"); + LookupCodeResult result = new LookupCodeResult(); + result.getDesignations().add(designation1); + result.getDesignations().add(designation2); + getCodeSystemProvider().setLookupCodeResult(result); + + // test + LookupCodeResult outcome = getService().lookupCode(null, new LookupCodeRequest(CODE_SYSTEM, CODE, LANGUAGE, null)); + + // verify + assertNotNull(outcome); + + Collection designations = outcome.getDesignations(); + assertEquals(2, designations.size()); + + for (IValidationSupport.ConceptDesignation designation : designations) { + IValidationSupport.ConceptDesignation expectedDesignation = code1.equals(designation.getUseCode()) ? designation1 : designation2; + assertEquals(expectedDesignation.getValue(), designation.getValue()); + assertEquals(expectedDesignation.getLanguage(), designation.getLanguage()); + assertEquals(expectedDesignation.getUseCode(), designation.getUseCode()); + assertEquals(expectedDesignation.getUseSystem(), designation.getUseSystem()); + assertEquals(expectedDesignation.getUseDisplay(), designation.getUseDisplay()); + } + } + } + + + interface IMyCodeSystemProvider extends IResourceProvider { + String getCode(); + String getSystem(); + + void setLookupCodeResult(LookupCodeResult theLookupCodeResult); + } + + interface IMySimpleCodeSystemProvider extends IResourceProvider { + IBaseDatatype getPropertyValue(); + } +} diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/LookupCodeDstu3Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/LookupCodeDstu3Test.java new file mode 100644 index 00000000000..6bf78229f1e --- /dev/null +++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/LookupCodeDstu3Test.java @@ -0,0 +1,257 @@ +package org.hl7.fhir.dstu3.hapi.validation; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.IValidationSupport; +import ca.uhn.fhir.context.support.IValidationSupport.ConceptDesignation; +import ca.uhn.fhir.context.support.IValidationSupport.LookupCodeResult; +import ca.uhn.fhir.i18n.Msg; +import ca.uhn.fhir.jpa.model.util.JpaConstants; +import ca.uhn.fhir.rest.annotation.Operation; +import ca.uhn.fhir.rest.annotation.OperationParam; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; +import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; +import ca.uhn.fhir.test.utilities.server.RestfulServerExtension; +import jakarta.servlet.http.HttpServletRequest; +import org.hl7.fhir.common.hapi.validation.ILookupCodeTest.ILookupCodeSupportedPropertyTest; +import org.hl7.fhir.common.hapi.validation.ILookupCodeTest.ILookupCodeUnsupportedPropertyTypeTest; +import org.hl7.fhir.common.hapi.validation.ILookupCodeTest.IMyCodeSystemProvider; +import org.hl7.fhir.common.hapi.validation.ILookupCodeTest.IMySimpleCodeSystemProvider; +import org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport; +import org.hl7.fhir.dstu3.model.BooleanType; +import org.hl7.fhir.dstu3.model.CodeSystem; +import org.hl7.fhir.dstu3.model.CodeType; +import org.hl7.fhir.dstu3.model.Coding; +import org.hl7.fhir.dstu3.model.Parameters; +import org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent; +import org.hl7.fhir.dstu3.model.StringType; +import org.hl7.fhir.dstu3.model.Type; +import org.hl7.fhir.dstu3.model.UriType; +import org.hl7.fhir.instance.model.api.IBaseDatatype; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.params.provider.Arguments; + +import java.util.List; +import java.util.stream.Stream; + +import static ca.uhn.fhir.context.support.IValidationSupport.BaseConceptProperty; +import static ca.uhn.fhir.context.support.IValidationSupport.CodingConceptProperty; +import static ca.uhn.fhir.context.support.IValidationSupport.StringConceptProperty; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class LookupCodeDstu3Test { + private static final FhirContext ourCtx = FhirContext.forDstu3Cached(); + @RegisterExtension + public static RestfulServerExtension ourRestfulServerExtension = new RestfulServerExtension(ourCtx); + private final RemoteTerminologyServiceValidationSupport mySvc = new RemoteTerminologyServiceValidationSupport(ourCtx); + + @BeforeEach + public void before() { + String baseUrl = "http://localhost:" + ourRestfulServerExtension.getPort(); + mySvc.setBaseUrl(baseUrl); + mySvc.addClientInterceptor(new LoggingInterceptor(true)); + } + + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + @Nested + class LookupCodeUnsupportedPropertyTypeDstu3Test implements ILookupCodeUnsupportedPropertyTypeTest { + private final MySimplePropertyCodeSystemProviderDstu3 myMySimplePropertyCodeSystemProvider = new MySimplePropertyCodeSystemProviderDstu3(); + + @Override + public IMySimpleCodeSystemProvider getCodeSystemProvider() { + return myMySimplePropertyCodeSystemProvider; + } + + @Override + public RemoteTerminologyServiceValidationSupport getService() { + return mySvc; + } + + @Override + public String getInvalidValueErrorCode() { + return "HAPI-2450"; + } + + @Override + public String getInvalidValueErrorCodeForConvert() { + return "HAPI-2451"; + } + + @BeforeEach + public void before() { + // TODO: use another type when "code" is added to the supported types + myMySimplePropertyCodeSystemProvider.myPropertyName = "somePropertyName"; + myMySimplePropertyCodeSystemProvider.myPropertyValue = new CodeType("someCode"); + ourRestfulServerExtension.getRestfulServer().registerProvider(myMySimplePropertyCodeSystemProvider); + } + } + + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + @Nested + class ILookupCodeSupportedPropertyDstu3Test implements ILookupCodeSupportedPropertyTest { + private final MyCodeSystemProviderDstu3 myCodeSystemProvider = new MyCodeSystemProviderDstu3(); + + @Override + public IMyCodeSystemProvider getCodeSystemProvider() { + return myCodeSystemProvider; + } + + @Override + public RemoteTerminologyServiceValidationSupport getService() { + return mySvc; + } + + @BeforeEach + public void before() { + ourRestfulServerExtension.getRestfulServer().registerProvider(myCodeSystemProvider); + } + + public void verifyProperty(BaseConceptProperty theConceptProperty, String theExpectedPropertName, IBaseDatatype theExpectedValue) { + assertEquals(theExpectedPropertName, theConceptProperty.getPropertyName()); + String type = theConceptProperty.getType(); + switch (type) { + case IValidationSupport.TYPE_STRING -> { + assertTrue(theExpectedValue instanceof StringType); + StringType stringValue = (StringType) theExpectedValue; + assertTrue(theConceptProperty instanceof StringConceptProperty); + StringConceptProperty stringConceptProperty = (StringConceptProperty) theConceptProperty; + assertEquals(stringValue.getValue(), stringConceptProperty.getValue()); + } + case IValidationSupport.TYPE_CODING -> { + assertTrue(theExpectedValue instanceof Coding); + Coding coding = (Coding) theExpectedValue; + assertTrue(theConceptProperty instanceof CodingConceptProperty); + CodingConceptProperty codingConceptProperty = (CodingConceptProperty) theConceptProperty; + assertEquals(coding.getCode(), codingConceptProperty.getCode()); + assertEquals(coding.getSystem(), codingConceptProperty.getCodeSystem()); + assertEquals(coding.getDisplay(), codingConceptProperty.getDisplay()); + } + default -> + throw new InternalErrorException(Msg.code(2451) + "Property type " + type + " is not supported."); + } + } + + public Stream getEmptyPropertyValues() { + return Stream.of( + Arguments.arguments(new StringType()), + Arguments.arguments(new StringType("")), + Arguments.arguments(new Coding()), + Arguments.arguments(new Coding("", null, null)), + Arguments.arguments(new Coding("", "", null)), + Arguments.arguments(new Coding(null, "", null)) + ); + } + + public Stream getPropertyValues() { + return Stream.of( + Arguments.arguments(new StringType("value")), + Arguments.arguments(new Coding("code", "system", "display")) + ); + } + + public Stream getDesignations() { + return Stream.of( + Arguments.arguments(new ConceptDesignation().setLanguage("en").setUseCode("code1").setUseSystem("system-1").setUseDisplay("display").setValue("some value")), + Arguments.arguments(new ConceptDesignation().setUseCode("code2").setUseSystem("system1").setUseDisplay("display").setValue("someValue")), + Arguments.arguments(new ConceptDesignation().setUseCode("code2").setUseSystem("system1").setValue("someValue")), + Arguments.arguments(new ConceptDesignation().setUseCode("code2").setUseSystem("system1")), + Arguments.arguments(new ConceptDesignation().setUseCode("code2")) + ); + } + } + + static class MySimplePropertyCodeSystemProviderDstu3 implements IMySimpleCodeSystemProvider { + + String myPropertyName; + Type myPropertyValue; + + @Override + public IBaseDatatype getPropertyValue() { + return myPropertyValue; + } + + @Override + public Class getResourceType() { + return CodeSystem.class; + } + + @Operation(name = JpaConstants.OPERATION_LOOKUP, idempotent = true, returnParameters= { + @OperationParam(name = "name", type = StringType.class, min = 1), + @OperationParam(name = "version", type = StringType.class, min = 0), + @OperationParam(name = "display", type = StringType.class, min = 1), + @OperationParam(name = "abstract", type = BooleanType.class, min = 1), + @OperationParam(name = "property", min = 0, max = OperationParam.MAX_UNLIMITED) + }) + public Parameters lookup( + HttpServletRequest theServletRequest, + @OperationParam(name = "code", max = 1) CodeType theCode, + @OperationParam(name = "system", max = 1) UriType theSystem, + @OperationParam(name = "coding", max = 1) Coding theCoding, + @OperationParam(name = "version", max = 1) StringType theVersion, + @OperationParam(name = "displayLanguage", max = 1) CodeType theDisplayLanguage, + @OperationParam(name= " property", max = OperationParam.MAX_UNLIMITED) List thePropertyNames, + RequestDetails theRequestDetails + ) { + ParametersParameterComponent component = new ParametersParameterComponent(); + component.setName("property"); + component.addPart(new ParametersParameterComponent().setName("code").setValue(new CodeType(myPropertyName))); + component.addPart(new ParametersParameterComponent().setName("value").setValue(myPropertyValue)); + return new Parameters().addParameter(component); + } + + } + + static class MyCodeSystemProviderDstu3 implements IMyCodeSystemProvider { + private UriType mySystemUrl; + private CodeType myCode; + private LookupCodeResult myLookupCodeResult; + + @Override + public Class getResourceType() { + return CodeSystem.class; + } + + @Override + public String getCode() { + return myCode != null ? myCode.getValueAsString() : null; + } + + @Override + public String getSystem() { + return mySystemUrl != null ? mySystemUrl.getValueAsString() : null; + } + + @Override + public void setLookupCodeResult(LookupCodeResult theLookupCodeResult) { + myLookupCodeResult = theLookupCodeResult; + } + + @Operation(name = JpaConstants.OPERATION_LOOKUP, idempotent = true, returnParameters= { + @OperationParam(name = "name", type = StringType.class, min = 1), + @OperationParam(name = "version", type = StringType.class, min = 0), + @OperationParam(name = "display", type = StringType.class, min = 1), + @OperationParam(name = "abstract", type = BooleanType.class, min = 1), + @OperationParam(name = "property", min = 0, max = OperationParam.MAX_UNLIMITED) + }) + public Parameters lookup( + HttpServletRequest theServletRequest, + @OperationParam(name = "code", max = 1) CodeType theCode, + @OperationParam(name = "system", max = 1) UriType theSystem, + @OperationParam(name = "coding", max = 1) Coding theCoding, + @OperationParam(name = "version", max = 1) StringType theVersion, + @OperationParam(name = "displayLanguage", max = 1) CodeType theDisplayLanguage, + @OperationParam(name= " property", max = OperationParam.MAX_UNLIMITED) List thePropertyNames, + RequestDetails theRequestDetails + ) { + myCode = theCode; + mySystemUrl = theSystem; + + return (Parameters)myLookupCodeResult.toParameters(theRequestDetails.getFhirContext(), thePropertyNames); + } + } +} diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/RemoteTerminologyServiceValidationSupportDstu3Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/RemoteTerminologyServiceValidationSupportDstu3Test.java deleted file mode 100644 index af961377fda..00000000000 --- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/RemoteTerminologyServiceValidationSupportDstu3Test.java +++ /dev/null @@ -1,167 +0,0 @@ -package org.hl7.fhir.dstu3.hapi.validation; - -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.context.support.IValidationSupport; -import ca.uhn.fhir.context.support.LookupCodeRequest; -import ca.uhn.fhir.jpa.model.util.JpaConstants; -import ca.uhn.fhir.rest.annotation.Operation; -import ca.uhn.fhir.rest.annotation.OperationParam; -import ca.uhn.fhir.rest.api.server.RequestDetails; -import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; -import ca.uhn.fhir.rest.server.IResourceProvider; -import ca.uhn.fhir.test.utilities.server.RestfulServerExtension; -import org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport; -import org.hl7.fhir.dstu3.model.BooleanType; -import org.hl7.fhir.dstu3.model.CodeSystem; -import org.hl7.fhir.dstu3.model.CodeType; -import org.hl7.fhir.dstu3.model.Coding; -import org.hl7.fhir.dstu3.model.Parameters; -import org.hl7.fhir.dstu3.model.StringType; -import org.hl7.fhir.dstu3.model.UriType; -import org.hl7.fhir.instance.model.api.IBaseResource; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; - -import jakarta.servlet.http.HttpServletRequest; -import java.util.Iterator; -import java.util.List; -import java.util.Set; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -public class RemoteTerminologyServiceValidationSupportDstu3Test { - private static final String DISPLAY = "DISPLAY"; - private static final String LANGUAGE = "en"; - private static final String CODE_SYSTEM = "CODE_SYS"; - private static final String CODE_SYSTEM_NAME = "Code System"; - private static final String CODE = "CODE"; - - private static final FhirContext ourCtx = FhirContext.forDstu3(); - - @RegisterExtension - public static RestfulServerExtension ourRestfulServerExtension = new RestfulServerExtension(ourCtx); - - private RemoteTerminologyServiceValidationSupport mySvc; - private MyCodeSystemProvider myCodeSystemProvider; - - @BeforeEach - public void before() { - myCodeSystemProvider = new MyCodeSystemProvider(); - ourRestfulServerExtension.getRestfulServer().registerProvider(myCodeSystemProvider); - String baseUrl = "http://localhost:" + ourRestfulServerExtension.getPort(); - mySvc = new RemoteTerminologyServiceValidationSupport(ourCtx); - mySvc.setBaseUrl(baseUrl); - mySvc.addClientInterceptor(new LoggingInterceptor(true)); - } - - @Test - public void testLookupOperationWithAllParams_CodeSystem_Success() { - myCodeSystemProvider.myNextLookupCodeResult = new IValidationSupport.LookupCodeResult(); - myCodeSystemProvider.myNextLookupCodeResult.setFound(true); - myCodeSystemProvider.myNextLookupCodeResult.setCodeSystemVersion(CODE_SYSTEM); - myCodeSystemProvider.myNextLookupCodeResult.setSearchedForCode(CODE); - myCodeSystemProvider.myNextLookupCodeResult.setCodeSystemDisplayName(CODE_SYSTEM_NAME); - myCodeSystemProvider.myNextLookupCodeResult.setCodeDisplay(DISPLAY); - - // property - String propertyName = "birthDate"; - String propertyValue = "1930-01-01"; - IValidationSupport.BaseConceptProperty property = new IValidationSupport.StringConceptProperty(propertyName, propertyValue); - myCodeSystemProvider.myNextLookupCodeResult.getProperties().add(property); - - // designation - IValidationSupport.ConceptDesignation designation = new IValidationSupport.ConceptDesignation(); - designation.setLanguage("en"); - designation.setUseCode("code"); - designation.setUseSystem("system"); - designation.setUseDisplay("display"); - designation.setValue("some value"); - myCodeSystemProvider.myNextLookupCodeResult.getDesignations().add(designation); - - IValidationSupport.LookupCodeResult outcome = mySvc.lookupCode(null, new LookupCodeRequest(CODE_SYSTEM, CODE, LANGUAGE, Set.of("birthDate"))); - assertNotNull(outcome, "Call to lookupCode() should return a non-NULL result!"); - assertEquals(DISPLAY, outcome.getCodeDisplay()); - assertEquals(CODE_SYSTEM, outcome.getCodeSystemVersion()); - - assertEquals(CODE, myCodeSystemProvider.myLastCode.asStringValue()); - assertEquals(CODE_SYSTEM, myCodeSystemProvider.myLastUrl.getValueAsString()); - - Parameters.ParametersParameterComponent propertyComponent = null; - Parameters.ParametersParameterComponent designationComponent = null; - for (Parameters.ParametersParameterComponent parameterComponent : myCodeSystemProvider.myNextReturnParams.getParameter()) { - if ("property".equals(parameterComponent.getName())) { - propertyComponent = parameterComponent; - } - if ("designation".equals(parameterComponent.getName())) { - designationComponent = parameterComponent; - } - } - - assertNotNull(propertyComponent); - - Iterator propertyComponentIterator = propertyComponent.getPart().iterator(); - propertyComponent = propertyComponentIterator.next(); - assertEquals("code", propertyComponent.getName()); - assertEquals(propertyName, ((StringType)propertyComponent.getValue()).getValue()); - - propertyComponent = propertyComponentIterator.next(); - assertEquals("value", propertyComponent.getName()); - assertEquals(propertyValue, ((StringType)propertyComponent.getValue()).getValue()); - - assertNotNull(designationComponent); - Iterator partParameter = designationComponent.getPart().iterator(); - designationComponent = partParameter.next(); - assertEquals("language", designationComponent.getName()); - assertEquals(LANGUAGE, designationComponent.getValue().toString()); - - designationComponent = partParameter.next(); - assertEquals("use", designationComponent.getName()); - Coding coding = (Coding)designationComponent.getValue(); - assertNotNull(coding, "Coding value returned via designation use should NOT be NULL!"); - assertEquals("code", coding.getCode()); - assertEquals("system", coding.getSystem()); - assertEquals("display", coding.getDisplay()); - - designationComponent = partParameter.next(); - assertEquals("value", designationComponent.getName()); - assertEquals("some value", designationComponent.getValue().toString()); - } - - private static class MyCodeSystemProvider implements IResourceProvider { - private UriType myLastUrl; - private CodeType myLastCode; - private Parameters myNextReturnParams; - private IValidationSupport.LookupCodeResult myNextLookupCodeResult; - - @Operation(name = JpaConstants.OPERATION_LOOKUP, idempotent = true, returnParameters= { - @OperationParam(name="name", type=StringType.class, min=1), - @OperationParam(name="version", type=StringType.class, min=0), - @OperationParam(name="display", type=StringType.class, min=1), - @OperationParam(name="abstract", type=BooleanType.class, min=1), - @OperationParam(name="property", min = 0, max = OperationParam.MAX_UNLIMITED) - }) - public Parameters lookup( - HttpServletRequest theServletRequest, - @OperationParam(name="code", min=0, max=1) CodeType theCode, - @OperationParam(name="system", min=0, max=1) UriType theSystem, - @OperationParam(name="coding", min=0, max=1) Coding theCoding, - @OperationParam(name="version", min=0, max=1) StringType theVersion, - @OperationParam(name="displayLanguage", min=0, max=1) CodeType theDisplayLanguage, - @OperationParam(name="property", min = 0, max = OperationParam.MAX_UNLIMITED) List thePropertyNames, - RequestDetails theRequestDetails - ) { - myLastCode = theCode; - myLastUrl = theSystem; - - myNextReturnParams = (Parameters)myNextLookupCodeResult.toParameters(theRequestDetails.getFhirContext(), thePropertyNames); - return myNextReturnParams; - } - - @Override - public Class getResourceType() { - return CodeSystem.class; - } - } -} diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/LookupCodeR4Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/LookupCodeR4Test.java new file mode 100644 index 00000000000..9fb662a8a3b --- /dev/null +++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/LookupCodeR4Test.java @@ -0,0 +1,252 @@ +package org.hl7.fhir.r4.validation; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.IValidationSupport; +import ca.uhn.fhir.i18n.Msg; +import ca.uhn.fhir.jpa.model.util.JpaConstants; +import ca.uhn.fhir.rest.annotation.Operation; +import ca.uhn.fhir.rest.annotation.OperationParam; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; +import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; +import ca.uhn.fhir.test.utilities.server.RestfulServerExtension; +import jakarta.servlet.http.HttpServletRequest; +import org.hl7.fhir.common.hapi.validation.ILookupCodeTest.ILookupCodeSupportedPropertyTest; +import org.hl7.fhir.common.hapi.validation.ILookupCodeTest.ILookupCodeUnsupportedPropertyTypeTest; +import org.hl7.fhir.common.hapi.validation.ILookupCodeTest.IMyCodeSystemProvider; +import org.hl7.fhir.common.hapi.validation.ILookupCodeTest.IMySimpleCodeSystemProvider; +import org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport; +import org.hl7.fhir.instance.model.api.IBaseDatatype; +import org.hl7.fhir.instance.model.api.IBaseParameters; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.r4.model.BooleanType; +import org.hl7.fhir.r4.model.CodeSystem; +import org.hl7.fhir.r4.model.CodeType; +import org.hl7.fhir.r4.model.Coding; +import org.hl7.fhir.r4.model.Parameters; +import org.hl7.fhir.r4.model.StringType; +import org.hl7.fhir.r4.model.Type; +import org.hl7.fhir.r4.model.UriType; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.params.provider.Arguments; + +import java.util.List; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class LookupCodeR4Test { + private static final FhirContext ourCtx = FhirContext.forR4Cached(); + @RegisterExtension + public static RestfulServerExtension ourRestfulServerExtension = new RestfulServerExtension(ourCtx); + private final RemoteTerminologyServiceValidationSupport mySvc = new RemoteTerminologyServiceValidationSupport(ourCtx); + + @BeforeEach + public void before() { + String baseUrl = "http://localhost:" + ourRestfulServerExtension.getPort(); + mySvc.setBaseUrl(baseUrl); + mySvc.addClientInterceptor(new LoggingInterceptor(true)); + } + + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + @Nested + class LookupCodeUnsupportedPropertyTypeR4Test implements ILookupCodeUnsupportedPropertyTypeTest { + private final MySimplePropertyCodeSystemProviderR4 myMySimplePropertyCodeSystemProvider = new MySimplePropertyCodeSystemProviderR4(); + + @Override + public IMySimpleCodeSystemProvider getCodeSystemProvider() { + return myMySimplePropertyCodeSystemProvider; + } + + @Override + public RemoteTerminologyServiceValidationSupport getService() { + return mySvc; + } + + @Override + public String getInvalidValueErrorCode() { + return "HAPI-2452"; + } + + + @Override + public String getInvalidValueErrorCodeForConvert() { + return "HAPI-2453"; + } + + @BeforeEach + public void before() { + // TODO: use another type when "code" is added to the supported types + myMySimplePropertyCodeSystemProvider.myPropertyName = "somePropertyName"; + myMySimplePropertyCodeSystemProvider.myPropertyValue = new CodeType("someCode"); + ourRestfulServerExtension.getRestfulServer().registerProvider(myMySimplePropertyCodeSystemProvider); + } + } + + @TestInstance(TestInstance.Lifecycle.PER_CLASS) + @Nested + class ILookupCodeSupportedPropertyR4Test implements ILookupCodeSupportedPropertyTest { + private final MyCodeSystemProviderR4 myCodeSystemProvider = new MyCodeSystemProviderR4(); + + @Override + public IMyCodeSystemProvider getCodeSystemProvider() { + return myCodeSystemProvider; + } + + @Override + public RemoteTerminologyServiceValidationSupport getService() { + return mySvc; + } + + @BeforeEach + public void before() { + ourRestfulServerExtension.getRestfulServer().registerProvider(myCodeSystemProvider); + } + + @Override + public void verifyProperty(IValidationSupport.BaseConceptProperty theConceptProperty, String theExpectedPropertName, IBaseDatatype theExpectedValue) { + assertEquals(theExpectedPropertName, theConceptProperty.getPropertyName()); + String type = theConceptProperty.getType(); + switch (type) { + case IValidationSupport.TYPE_STRING -> { + assertTrue(theExpectedValue instanceof StringType); + StringType stringValue = (StringType) theExpectedValue; + assertTrue(theConceptProperty instanceof IValidationSupport.StringConceptProperty); + IValidationSupport.StringConceptProperty stringConceptProperty = (IValidationSupport.StringConceptProperty) theConceptProperty; + assertEquals(stringValue.getValue(), stringConceptProperty.getValue()); + } + case IValidationSupport.TYPE_CODING -> { + assertTrue(theExpectedValue instanceof Coding); + Coding coding = (Coding) theExpectedValue; + assertTrue(theConceptProperty instanceof IValidationSupport.CodingConceptProperty); + IValidationSupport.CodingConceptProperty codingConceptProperty = (IValidationSupport.CodingConceptProperty) theConceptProperty; + assertEquals(coding.getCode(), codingConceptProperty.getCode()); + assertEquals(coding.getSystem(), codingConceptProperty.getCodeSystem()); + assertEquals(coding.getDisplay(), codingConceptProperty.getDisplay()); + } + default -> + throw new InternalErrorException(Msg.code(2451) + "Property type " + type + " is not supported."); + } + } + + public Stream getEmptyPropertyValues() { + return Stream.of( + Arguments.arguments(new StringType()), + Arguments.arguments(new StringType("")), + Arguments.arguments(new Coding()), + Arguments.arguments(new Coding("", null, null)), + Arguments.arguments(new Coding("", "", null)), + Arguments.arguments(new Coding(null, "", null)) + ); + } + + public Stream getPropertyValues() { + return Stream.of( + Arguments.arguments(new StringType("value")), + Arguments.arguments(new Coding("code", "system", "display")) + ); + } + + + + public Stream getDesignations() { + return Stream.of( + Arguments.arguments(new IValidationSupport.ConceptDesignation().setLanguage("en").setUseCode("code1").setUseSystem("system-1").setUseDisplay("display").setValue("some value")), + Arguments.arguments(new IValidationSupport.ConceptDesignation().setUseCode("code2").setUseSystem("system1").setUseDisplay("display").setValue("someValue")), + Arguments.arguments(new IValidationSupport.ConceptDesignation().setUseCode("code2").setUseSystem("system1").setValue("someValue")), + Arguments.arguments(new IValidationSupport.ConceptDesignation().setUseCode("code2").setUseSystem("system1")), + Arguments.arguments(new IValidationSupport.ConceptDesignation().setUseCode("code2")) + ); + } + } + + static class MySimplePropertyCodeSystemProviderR4 implements IMySimpleCodeSystemProvider { + String myPropertyName; + Type myPropertyValue; + + @Override + public IBaseDatatype getPropertyValue() { + return myPropertyValue; + } + + @Override + public Class getResourceType() { + return CodeSystem.class; + } + + @Operation(name = JpaConstants.OPERATION_LOOKUP, idempotent = true, returnParameters= { + @OperationParam(name = "name", type = StringType.class, min = 1), + @OperationParam(name = "version", type = StringType.class, min = 0), + @OperationParam(name = "display", type = StringType.class, min = 1), + @OperationParam(name = "abstract", type = BooleanType.class, min = 1), + @OperationParam(name = "property", min = 0, max = OperationParam.MAX_UNLIMITED) + }) + public Parameters lookup( + HttpServletRequest theServletRequest, + @OperationParam(name = "code", max = 1) CodeType theCode, + @OperationParam(name = "system", max = 1) UriType theSystem, + @OperationParam(name = "coding", max = 1) Coding theCoding, + @OperationParam(name = "version", max = 1) StringType theVersion, + @OperationParam(name = "displayLanguage", max = 1) CodeType theDisplayLanguage, + @OperationParam(name= " property", max = OperationParam.MAX_UNLIMITED) List thePropertyNames, + RequestDetails theRequestDetails + ) { + Parameters.ParametersParameterComponent component = new Parameters.ParametersParameterComponent(); + component.setName("property"); + component.addPart(new Parameters.ParametersParameterComponent().setName("code").setValue(new CodeType(myPropertyName))); + component.addPart(new Parameters.ParametersParameterComponent().setName("value").setValue(myPropertyValue)); + return new Parameters().addParameter(component); + } + } + + static class MyCodeSystemProviderR4 implements IMyCodeSystemProvider { + private UriType mySystemUrl; + private CodeType myCode; + private IValidationSupport.LookupCodeResult myLookupCodeResult; + + @Override + public void setLookupCodeResult(IValidationSupport.LookupCodeResult theLookupCodeResult) { + myLookupCodeResult = theLookupCodeResult; + } + + @Operation(name = JpaConstants.OPERATION_LOOKUP, idempotent = true, returnParameters= { + @OperationParam(name = "name", type = StringType.class, min = 1), + @OperationParam(name = "version", type = StringType.class), + @OperationParam(name = "display", type = StringType.class, min = 1), + @OperationParam(name = "abstract", type = BooleanType.class, min = 1), + @OperationParam(name = "property", type = StringType.class, min = 0, max = OperationParam.MAX_UNLIMITED) + }) + public IBaseParameters lookup( + HttpServletRequest theServletRequest, + @OperationParam(name = "code", max = 1) CodeType theCode, + @OperationParam(name = "system",max = 1) UriType theSystem, + @OperationParam(name = "coding", max = 1) Coding theCoding, + @OperationParam(name = "version", max = 1) StringType theVersion, + @OperationParam(name = "displayLanguage", max = 1) CodeType theDisplayLanguage, + @OperationParam(name = "property", max = OperationParam.MAX_UNLIMITED) List thePropertyNames, + RequestDetails theRequestDetails + ) { + myCode = theCode; + mySystemUrl = theSystem; + return myLookupCodeResult.toParameters(theRequestDetails.getFhirContext(), thePropertyNames); + } + @Override + public Class getResourceType() { + return CodeSystem.class; + } + + @Override + public String getCode() { + return myCode != null ? myCode.getValueAsString() : null; + } + + @Override + public String getSystem() { + return mySystemUrl != null ? mySystemUrl.getValueAsString() : null; + } + } +} diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/support/RemoteTerminologyServiceValidationSupportTest.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyServiceValidationSupportR4Test.java similarity index 74% rename from hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/support/RemoteTerminologyServiceValidationSupportTest.java rename to hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyServiceValidationSupportR4Test.java index d98785bb2aa..eca05ae6d05 100644 --- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/support/RemoteTerminologyServiceValidationSupportTest.java +++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyServiceValidationSupportR4Test.java @@ -1,11 +1,10 @@ -package org.hl7.fhir.common.hapi.validation.support; +package org.hl7.fhir.r4.validation; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.support.ConceptValidationOptions; import ca.uhn.fhir.context.support.IValidationSupport; import ca.uhn.fhir.context.support.TranslateConceptResult; import ca.uhn.fhir.context.support.TranslateConceptResults; -import ca.uhn.fhir.context.support.LookupCodeRequest; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.parser.IJsonLikeParser; import ca.uhn.fhir.rest.annotation.IdParam; @@ -24,6 +23,8 @@ import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.test.utilities.server.RestfulServerExtension; import ca.uhn.fhir.util.ParametersUtil; import com.google.common.collect.Lists; +import jakarta.servlet.http.HttpServletRequest; +import org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport; import org.hl7.fhir.instance.model.api.IBaseCoding; import org.hl7.fhir.instance.model.api.IBaseParameters; import org.hl7.fhir.instance.model.api.IBaseResource; @@ -39,19 +40,15 @@ import org.hl7.fhir.r4.model.StringType; import org.hl7.fhir.r4.model.UriType; import org.hl7.fhir.r4.model.ValueSet; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; -import jakarta.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; -import java.util.Iterator; import java.util.List; -import java.util.Set; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.lessThan; @@ -61,9 +58,8 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; -public class RemoteTerminologyServiceValidationSupportTest { +public class RemoteTerminologyServiceValidationSupportR4Test { private static final String DISPLAY = "DISPLAY"; - private static final String LANGUAGE = "en"; private static final String CODE_SYSTEM = "CODE_SYS"; private static final String CODE_SYSTEM_NAME = "Code System"; private static final String CODE = "CODE"; @@ -84,27 +80,20 @@ public class RemoteTerminologyServiceValidationSupportTest { private static final FhirContext ourCtx = FhirContext.forR4Cached(); @RegisterExtension - public static RestfulServerExtension ourRestfulServerExtension = new RestfulServerExtension(ourCtx); + public static RestfulServerExtension myRestfulServerExtension = new RestfulServerExtension(ourCtx); - private MyValueSetProvider myValueSetProvider; - private RemoteTerminologyServiceValidationSupport mySvc; - private MyCodeSystemProvider myCodeSystemProvider; - private MyConceptMapProvider myConceptMapProvider; + private final MyValueSetProvider myValueSetProvider = new MyValueSetProvider(); + private final MyCodeSystemProvider myCodeSystemProvider = new MyCodeSystemProvider(); + private final MyConceptMapProvider myConceptMapProvider = new MyConceptMapProvider(); + private final RemoteTerminologyServiceValidationSupport mySvc = new RemoteTerminologyServiceValidationSupport(ourCtx); @BeforeEach public void before() { - myValueSetProvider = new MyValueSetProvider(); - ourRestfulServerExtension.getRestfulServer().registerProvider(myValueSetProvider); + myRestfulServerExtension.getRestfulServer().registerProvider(myValueSetProvider); + myRestfulServerExtension.getRestfulServer().registerProvider(myCodeSystemProvider); + myRestfulServerExtension.getRestfulServer().registerProvider(myConceptMapProvider); - myCodeSystemProvider = new MyCodeSystemProvider(); - ourRestfulServerExtension.getRestfulServer().registerProvider(myCodeSystemProvider); - - myConceptMapProvider = new MyConceptMapProvider(); - ourRestfulServerExtension.getRestfulServer().registerProvider(myConceptMapProvider); - - String baseUrl = "http://localhost:" + ourRestfulServerExtension.getPort(); - - mySvc = new RemoteTerminologyServiceValidationSupport(ourCtx); + String baseUrl = "http://localhost:" + myRestfulServerExtension.getPort(); mySvc.setBaseUrl(baseUrl); mySvc.addClientInterceptor(new LoggingInterceptor(true)); } @@ -117,78 +106,7 @@ public class RemoteTerminologyServiceValidationSupportTest { @Test public void testValidateCode_withBlankCode_returnsNull() { IValidationSupport.CodeValidationResult outcome = mySvc.validateCode(null, null, CODE_SYSTEM, "", DISPLAY, VALUE_SET_URL); - assertNull(outcome); - } - - - @Test - public void testLookupCode_forCodeSystemWithAllParams_returnsCorrectParameters() { - myCodeSystemProvider.myNextLookupCodeResult = new IValidationSupport.LookupCodeResult(); - myCodeSystemProvider.myNextLookupCodeResult.setFound(true); - myCodeSystemProvider.myNextLookupCodeResult.setCodeSystemVersion(CODE_SYSTEM); - myCodeSystemProvider.myNextLookupCodeResult.setSearchedForCode(CODE); - myCodeSystemProvider.myNextLookupCodeResult.setCodeSystemDisplayName(CODE_SYSTEM_NAME); - myCodeSystemProvider.myNextLookupCodeResult.setCodeDisplay(DISPLAY); - - // property - String propertyName = "birthDate"; - String propertyValue = "1930-01-01"; - IValidationSupport.BaseConceptProperty property = new IValidationSupport.StringConceptProperty(propertyName, propertyValue); - myCodeSystemProvider.myNextLookupCodeResult.getProperties().add(property); - - // designation - IValidationSupport.ConceptDesignation designation = new IValidationSupport.ConceptDesignation(); - designation.setLanguage("en"); - designation.setUseCode("code"); - designation.setUseSystem("system"); - designation.setUseDisplay("display"); - designation.setValue("some value"); - myCodeSystemProvider.myNextLookupCodeResult.getDesignations().add(designation); - - IValidationSupport.LookupCodeResult outcome = mySvc.lookupCode(null, new LookupCodeRequest(CODE_SYSTEM, CODE, null, Set.of("birthDate"))); - assertNotNull(outcome, "Call to lookupCode() should return a non-NULL result!"); - assertEquals(DISPLAY, outcome.getCodeDisplay()); - assertEquals(CODE_SYSTEM, outcome.getCodeSystemVersion()); - assertEquals(CODE_SYSTEM_NAME, myCodeSystemProvider.myNextReturnParams.getParameterValue("name").toString()); - - assertEquals(CODE, myCodeSystemProvider.myLastCode.getCode()); - assertEquals(CODE_SYSTEM, myCodeSystemProvider.myLastUrl.getValueAsString()); - - Parameters.ParametersParameterComponent propertyComponent = myCodeSystemProvider.myNextReturnParams.getParameter("property"); - assertNotNull(propertyComponent); - - Iterator propertyComponentIterator = propertyComponent.getPart().iterator(); - propertyComponent = propertyComponentIterator.next(); - assertEquals("code", propertyComponent.getName()); - assertEquals(propertyName, ((StringType)propertyComponent.getValue()).getValue()); - - propertyComponent = propertyComponentIterator.next(); - assertEquals("value", propertyComponent.getName()); - assertEquals(propertyValue, ((StringType)propertyComponent.getValue()).getValue()); - - Parameters.ParametersParameterComponent designationComponent = myCodeSystemProvider.myNextReturnParams.getParameter("designation"); - Iterator partParameter = designationComponent.getPart().iterator(); - designationComponent = partParameter.next(); - assertEquals("language", designationComponent.getName()); - assertEquals(LANGUAGE, designationComponent.getValue().toString()); - - designationComponent = partParameter.next(); - assertEquals("use", designationComponent.getName()); - Coding coding = (Coding)designationComponent.getValue(); - assertNotNull(coding, "Coding value returned via designation use should NOT be NULL!"); - assertEquals("code", coding.getCode()); - assertEquals("system", coding.getSystem()); - assertEquals("display", coding.getDisplay()); - - designationComponent = partParameter.next(); - assertEquals("value", designationComponent.getName()); - assertEquals("some value", designationComponent.getValue().toString()); - } - - @Test - public void testLookupCode_forCodeSystemWithBlankCode_throwsException() { - Assertions.assertThrows(IllegalArgumentException.class, - () -> mySvc.lookupCode(null, new LookupCodeRequest(CODE_SYSTEM, ""))); + assertNull(outcome); } @Test @@ -199,26 +117,26 @@ public class RemoteTerminologyServiceValidationSupportTest { assertNotNull(outcome); assertEquals(CODE, outcome.getCode()); assertEquals(DISPLAY, outcome.getDisplay()); - assertNull(outcome.getSeverity()); - assertNull(outcome.getMessage()); + assertNull(outcome.getSeverity()); + assertNull(outcome.getMessage()); assertEquals(CODE, myValueSetProvider.myLastCode.getCode()); assertEquals(DISPLAY, myValueSetProvider.myLastDisplay.getValue()); assertEquals(CODE_SYSTEM, myValueSetProvider.myLastSystem.getValue()); assertEquals(VALUE_SET_URL, myValueSetProvider.myLastUrl.getValue()); - assertNull(myValueSetProvider.myLastValueSet); + assertNull(myValueSetProvider.myLastValueSet); } @Test void testFetchValueSet_forcesSummaryFalse() { - // given + // given myValueSetProvider.myNextReturnValueSets = new ArrayList<>(); // when mySvc.fetchValueSet(VALUE_SET_URL); - // then - assertEquals(SummaryEnum.FALSE, myValueSetProvider.myLastSummaryParam); + // then + assertEquals(SummaryEnum.FALSE, myValueSetProvider.myLastSummaryParam); } @Test @@ -227,8 +145,8 @@ public class RemoteTerminologyServiceValidationSupportTest { IValidationSupport.CodeValidationResult outcome = mySvc.validateCode(null, null, CODE_SYSTEM, CODE, DISPLAY, VALUE_SET_URL); assertNotNull(outcome); - assertNull(outcome.getCode()); - assertNull(outcome.getDisplay()); + assertNull(outcome.getCode()); + assertNull(outcome.getDisplay()); assertEquals(IValidationSupport.IssueSeverity.ERROR, outcome.getSeverity()); assertEquals(ERROR_MESSAGE, outcome.getMessage()); @@ -236,7 +154,7 @@ public class RemoteTerminologyServiceValidationSupportTest { assertEquals(DISPLAY, myValueSetProvider.myLastDisplay.getValue()); assertEquals(CODE_SYSTEM, myValueSetProvider.myLastSystem.getValue()); assertEquals(VALUE_SET_URL, myValueSetProvider.myLastUrl.getValue()); - assertNull(myValueSetProvider.myLastValueSet); + assertNull(myValueSetProvider.myLastValueSet); } @Test @@ -252,11 +170,11 @@ public class RemoteTerminologyServiceValidationSupportTest { assertNotNull(outcome); assertEquals(CODE, outcome.getCode()); assertEquals(DISPLAY, outcome.getDisplay()); - assertNull(outcome.getSeverity()); - assertNull(outcome.getMessage()); + assertNull(outcome.getSeverity()); + assertNull(outcome.getMessage()); - assertEquals(CODE, myCodeSystemProvider.myLastCode.getCode()); - assertEquals(CODE_SYSTEM, myCodeSystemProvider.myLastUrl.getValueAsString()); + assertEquals(CODE, myCodeSystemProvider.myCode.getCode()); + assertEquals(CODE_SYSTEM, myCodeSystemProvider.mySystemUrl.getValueAsString()); } @@ -271,14 +189,14 @@ public class RemoteTerminologyServiceValidationSupportTest { assertNotNull(outcome); assertEquals(CODE, outcome.getCode()); assertEquals(DISPLAY, outcome.getDisplay()); - assertNull(outcome.getSeverity()); - assertNull(outcome.getMessage()); + assertNull(outcome.getSeverity()); + assertNull(outcome.getMessage()); assertEquals(CODE, myValueSetProvider.myLastCode.getCode()); assertEquals(DISPLAY, myValueSetProvider.myLastDisplay.getValue()); assertEquals(CODE_SYSTEM, myValueSetProvider.myLastSystem.getValue()); assertEquals(VALUE_SET_URL, myValueSetProvider.myLastUrl.getValueAsString()); - assertNull(myValueSetProvider.myLastValueSet); + assertNull(myValueSetProvider.myLastValueSet); } /** @@ -292,7 +210,7 @@ public class RemoteTerminologyServiceValidationSupportTest { valueSet.setUrl(VALUE_SET_URL); IValidationSupport.CodeValidationResult outcome = mySvc.validateCodeInValueSet(null, new ConceptValidationOptions().setInferSystem(true), null, CODE, DISPLAY, valueSet); - assertNull(outcome); + assertNull(outcome); } @Test @@ -336,7 +254,7 @@ public class RemoteTerminologyServiceValidationSupportTest { TranslateConceptResults results = mySvc.translateConcept(request); assertNotNull(results); - assertTrue(results.getResult()); + assertTrue(results.getResult()); assertEquals(results.getResults().size(), 2); for(TranslateConceptResult result : results.getResults()) { assertEquals(singleResult, result); @@ -361,7 +279,7 @@ public class RemoteTerminologyServiceValidationSupportTest { TranslateConceptResults results = mySvc.translateConcept(request); assertNotNull(results); - assertFalse(results.getResult()); + assertFalse(results.getResult()); assertEquals(results.getResults().size(), 0); assertNull(myConceptMapProvider.myLastCodeableConcept); @@ -556,7 +474,7 @@ public class RemoteTerminologyServiceValidationSupportTest { myValueSetProvider.myNextReturnValueSets = new ArrayList<>(); boolean outcome = mySvc.isValueSetSupported(null, "http://loinc.org/VS"); - assertFalse(outcome); + assertFalse(outcome); assertEquals("http://loinc.org/VS", myValueSetProvider.myLastUrlParam.getValue()); } @@ -566,7 +484,7 @@ public class RemoteTerminologyServiceValidationSupportTest { myValueSetProvider.myNextReturnValueSets.add((ValueSet) new ValueSet().setId("ValueSet/123")); boolean outcome = mySvc.isValueSetSupported(null, "http://loinc.org/VS"); - assertTrue(outcome); + assertTrue(outcome); assertEquals("http://loinc.org/VS", myValueSetProvider.myLastUrlParam.getValue()); } @@ -575,7 +493,7 @@ public class RemoteTerminologyServiceValidationSupportTest { myCodeSystemProvider.myNextReturnCodeSystems = new ArrayList<>(); boolean outcome = mySvc.isCodeSystemSupported(null, "http://loinc.org"); - assertFalse(outcome); + assertFalse(outcome); assertEquals("http://loinc.org", myCodeSystemProvider.myLastUrlParam.getValue()); } @@ -585,30 +503,30 @@ public class RemoteTerminologyServiceValidationSupportTest { myCodeSystemProvider.myNextReturnCodeSystems.add((CodeSystem) new CodeSystem().setId("CodeSystem/123")); boolean outcome = mySvc.isCodeSystemSupported(null, "http://loinc.org"); - assertTrue(outcome); + assertTrue(outcome); assertEquals("http://loinc.org", myCodeSystemProvider.myLastUrlParam.getValue()); } private void createNextValueSetReturnParameters(boolean theResult, String theDisplay, String theMessage) { - myValueSetProvider.myNextReturnParams = new Parameters(); - myValueSetProvider.myNextReturnParams.addParameter("result", theResult); - myValueSetProvider.myNextReturnParams.addParameter("display", theDisplay); - if (theMessage != null) { - myValueSetProvider.myNextReturnParams.addParameter("message", theMessage); - } + myValueSetProvider.myNextReturnParams = new Parameters() + .addParameter("result", theResult) + .addParameter("display", theDisplay) + .addParameter("message", theMessage); } - private static class MyCodeSystemProvider implements IResourceProvider { - + static private class MyCodeSystemProvider implements IResourceProvider { private SummaryEnum myLastSummaryParam; private UriParam myLastUrlParam; private List myNextReturnCodeSystems; - private UriType myLastUrl; - private CodeType myLastCode; - private Parameters myNextReturnParams; - private IValidationSupport.LookupCodeResult myNextLookupCodeResult; + private UriType mySystemUrl; + private CodeType myCode; private IValidationSupport.CodeValidationResult myNextValidationResult; + @Override + public Class getResourceType() { + return CodeSystem.class; + } + @Operation(name = "validate-code", idempotent = true, returnParameters = { @OperationParam(name = "result", type = BooleanType.class, min = 1), @OperationParam(name = "message", type = StringType.class), @@ -617,37 +535,13 @@ public class RemoteTerminologyServiceValidationSupportTest { public IBaseParameters validateCode( HttpServletRequest theServletRequest, @IdParam(optional = true) IdType theId, - @OperationParam(name = "url", min = 0, max = 1) UriType theCodeSystemUrl, + @OperationParam(name = "url", min = 0, max = 1) UriType theSystem, @OperationParam(name = "code", min = 0, max = 1) CodeType theCode, @OperationParam(name = "display", min = 0, max = 1) StringType theDisplay ) { - myLastUrl = theCodeSystemUrl; - myLastCode = theCode; - myNextReturnParams = (Parameters)myNextValidationResult.toParameters(ourCtx); - return myNextReturnParams; - } - - @Operation(name = JpaConstants.OPERATION_LOOKUP, idempotent = true, returnParameters= { - @OperationParam(name="name", type=StringType.class, min=1), - @OperationParam(name="version", type=StringType.class, min=0), - @OperationParam(name="display", type=StringType.class, min=1), - @OperationParam(name="abstract", type=BooleanType.class, min=1), - @OperationParam(name="property", min = 0, max = OperationParam.MAX_UNLIMITED) - }) - public IBaseParameters lookup( - HttpServletRequest theServletRequest, - @OperationParam(name="code", min=0, max=1) CodeType theCode, - @OperationParam(name="system", min=0, max=1) UriType theSystem, - @OperationParam(name="coding", min=0, max=1) Coding theCoding, - @OperationParam(name="version", min=0, max=1) StringType theVersion, - @OperationParam(name="displayLanguage", min=0, max=1) CodeType theDisplayLanguage, - @OperationParam(name="property", min = 0, max = OperationParam.MAX_UNLIMITED) List thePropertyNames, - RequestDetails theRequestDetails - ) { - myLastCode = theCode; - myLastUrl = theSystem; - myNextReturnParams = (Parameters)myNextLookupCodeResult.toParameters(theRequestDetails.getFhirContext(), thePropertyNames); - return myNextReturnParams; + myCode = theCode; + mySystemUrl = theSystem; + return myNextValidationResult.toParameters(ourCtx); } @Search @@ -657,11 +551,6 @@ public class RemoteTerminologyServiceValidationSupportTest { assert myNextReturnCodeSystems != null; return myNextReturnCodeSystems; } - - @Override - public Class getResourceType() { - return CodeSystem.class; - } }