diff --git a/hapi-fhir-validation/pom.xml b/hapi-fhir-validation/pom.xml index b4d75655adc..2d48adf7cff 100644 --- a/hapi-fhir-validation/pom.xml +++ b/hapi-fhir-validation/pom.xml @@ -11,7 +11,7 @@ hapi-fhir-validation bundle - 3.6.2-PHRFIX + 3.6.3-PHRFIX HAPI FHIR - Validation diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/r4/validation/DefaultEnableWhenEvaluator.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/r4/validation/DefaultEnableWhenEvaluator.java index 0b23e006564..4a8981518f8 100644 --- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/r4/validation/DefaultEnableWhenEvaluator.java +++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/r4/validation/DefaultEnableWhenEvaluator.java @@ -65,11 +65,33 @@ public class DefaultEnableWhenEvaluator implements IEnableWhenEvaluator { .anyMatch(answer -> evaluateAnswer(answer, enableCondition.getAnswer(), enableCondition.getOperator())); return new EnableWhenResult(result, linkId, enableCondition, questionnaireResponse); } + + public Type convertToType(Element element) { + Type b = new Factory().create(element.fhirType()); + if (b instanceof PrimitiveType) { + ((PrimitiveType) b).setValueAsString(element.primitiveValue()); + } else { + for (Element child : element.getChildren()) { + if (!isExtension(child)) { + b.setProperty(child.getName(), convertToType(child)); + } + } + } + return b; + } + + + private boolean isExtension(Element element) { + return "Extension".equals(element.fhirType()); + } protected boolean evaluateAnswer(Element answer, Type expectedAnswer, QuestionnaireItemOperator questionnaireItemOperator) { Type actualAnswer; + if (isExtension(answer)) { + return false; + } try { - actualAnswer = answer.asType(); + actualAnswer = convertToType(answer); } catch (FHIRException e) { throw new UnprocessableEntityException("Unexpected answer type", e); } @@ -81,7 +103,7 @@ public class DefaultEnableWhenEvaluator implements IEnableWhenEvaluator { } else if ((expectedAnswer instanceof PrimitiveType)) { return comparePrimitiveAnswer((PrimitiveType)actualAnswer, (PrimitiveType)expectedAnswer, questionnaireItemOperator); } else if (expectedAnswer instanceof Quantity) { - return compareQuantityAnswer((Quantity)expectedAnswer, (Quantity)actualAnswer, questionnaireItemOperator); + return compareQuantityAnswer((Quantity)actualAnswer, (Quantity)expectedAnswer, questionnaireItemOperator); } // TODO: Attachment, reference? throw new UnprocessableEntityException("Unimplemented answer type: " + expectedAnswer.getClass()); @@ -143,14 +165,9 @@ public class DefaultEnableWhenEvaluator implements IEnableWhenEvaluator { return item.getChildrenByName(ANSWER_ELEMENT) .stream() .flatMap(c -> c.getChildren().stream()) - .filter(DefaultEnableWhenEvaluator::notExtension) .collect(Collectors.toList()); } - private static boolean notExtension(Element e) { - return !Extension.class.isAssignableFrom(e.getClass()); - } - private boolean compareCodingAnswer(Coding expectedAnswer, Coding actualAnswer, QuestionnaireItemOperator questionnaireItemOperator) { boolean result = compareSystems(expectedAnswer, actualAnswer) && compareCodes(expectedAnswer, actualAnswer); if (questionnaireItemOperator == QuestionnaireItemOperator.EQUAL){ diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/QuestionnaireResponseValidatorDstu3Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/QuestionnaireResponseValidatorDstu3Test.java index 7a535344c0e..44f4eaab0fe 100644 --- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/QuestionnaireResponseValidatorDstu3Test.java +++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/QuestionnaireResponseValidatorDstu3Test.java @@ -18,6 +18,7 @@ import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemComponent; import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemEnableWhenComponent; import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemOptionComponent; import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemType; +import org.hl7.fhir.dstu3.model.QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent; import org.hl7.fhir.dstu3.model.QuestionnaireResponse.QuestionnaireResponseItemComponent; import org.hl7.fhir.dstu3.model.QuestionnaireResponse.QuestionnaireResponseStatus; import org.junit.AfterClass; @@ -33,6 +34,9 @@ import java.util.List; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.hasSize; +import static org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemType.BOOLEAN; +import static org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemType.CHOICE; +import static org.hl7.fhir.dstu3.model.QuestionnaireResponse.QuestionnaireResponseStatus.COMPLETED; import static org.junit.Assert.*; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; @@ -554,7 +558,34 @@ public class QuestionnaireResponseValidatorDstu3Test { errors.getMessages().stream().filter(vm -> vm.getMessage().contains("Structural Error")) .anyMatch(vm -> vm.getMessage().contains("link1"))); } - + + @Test + public void testAnswerIsValueCodingWithExtensionInside() throws Exception { + Questionnaire q = new Questionnaire(); + Coding qcoding = new Coding(); + qcoding.setCode("1293"); + q.addItem().setLinkId("1B").setRequired(true).setType(CHOICE).addOption().setValue(qcoding); + q.addItem().setLinkId("2B").setType(BOOLEAN).addEnableWhen().setQuestion("1B").setAnswer(qcoding); + + QuestionnaireResponse qr = new QuestionnaireResponse(); + qr.setStatus(COMPLETED); + qr.getQuestionnaire().setReference(QUESTIONNAIRE_URL); + QuestionnaireResponseItemComponent qrItem = qr.addItem().setLinkId("1B"); + Coding coding = new Coding(); + coding.setCode("1293"); + QuestionnaireResponseItemAnswerComponent answer = qrItem.addAnswer(); + answer.setValue(coding); + coding.addExtension("http://hl7.org/fhir/StructureDefinition/questionnaire-hidden", new BooleanType(true)); + qr.addItem().setLinkId("2B").addAnswer().setValue(new BooleanType(true)); + + String reference = qr.getQuestionnaire().getReference(); + when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(reference))).thenReturn(q); + + ValidationResult errors = myVal.validateWithResult(qr); + assertThat(errors.toString(), containsString("No issues")); + + } + @Test public void testEmbeddedItemInChoice() { String questionnaireRef = QUESTIONNAIRE_URL;