From eeb4fe62b7643ad7c1ac4f5480212d37a0868e5a Mon Sep 17 00:00:00 2001 From: Heinz-Dieter Conradi Date: Mon, 12 Mar 2018 11:08:23 +0100 Subject: [PATCH 1/3] Test questionnaire with embedded items for DSTU3. The test for an item embedded in a text item works as expected. However, the embedded item in a choice or openchoice case triggers an NPE. --- ...estionnaireResponseValidatorDstu3Test.java | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) 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 010913ad1cc..ba9d6dfbbfa 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 @@ -1,6 +1,7 @@ package org.hl7.fhir.dstu3.hapi.validation; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.SingleValidationMessage; @@ -216,6 +217,156 @@ public class QuestionnaireResponseValidatorDstu3Test { assertThat(errors.toString(), containsString("No response found for required item link0")); } + @Test + public void testEmbeddedItemInChoice() { + String questionnaireRef = "http://example.com/Questionnaire/q1"; + String valueSetRef = "http://somevalueset"; + String codeSystemUrl = "http://codesystems.com/system"; + String codeValue = "code0"; + + // create the questionnaire + QuestionnaireItemComponent item1 = new QuestionnaireItemComponent(); + item1.setLinkId("link1") + .setType(QuestionnaireItemType.CHOICE) + .setOptions(new Reference(valueSetRef)); + + item1.addItem().setLinkId("link11") + .setType(QuestionnaireItemType.TEXT); + + Questionnaire q = new Questionnaire(); + q.addItem(item1); + when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(questionnaireRef))) + .thenReturn(q); + + CodeSystem codeSystem = new CodeSystem(); + codeSystem.setContent(CodeSystemContentMode.COMPLETE); + codeSystem.setUrl(codeSystemUrl); + codeSystem.addConcept().setCode(codeValue); + when(myValSupport.fetchCodeSystem(any(FhirContext.class), eq(codeSystemUrl))) + .thenReturn(codeSystem); + + ValueSet options = new ValueSet(); + options.getCompose().addInclude().setSystem(codeSystemUrl).addConcept().setCode(codeValue); + when(myValSupport.fetchResource(any(FhirContext.class), eq(ValueSet.class), eq(valueSetRef))) + .thenReturn(options); + when(myValSupport.validateCode(any(FhirContext.class), eq(codeSystemUrl), eq(codeValue), any(String.class))) + .thenReturn(new CodeValidationResult(new ConceptDefinitionComponent(new CodeType(codeValue)))); + + IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true); + String qXml = xmlParser.encodeResourceToString(q); + ourLog.info(qXml); + + // create the response + QuestionnaireResponse qa = new QuestionnaireResponse(); + qa.setStatus(QuestionnaireResponseStatus.INPROGRESS); + qa.getQuestionnaire().setReference(questionnaireRef); + qa.addItem().setLinkId("link1") + .addAnswer() + .addItem().setLinkId("link11"); + + String rXml = xmlParser.encodeResourceToString(qa); + ourLog.info(rXml); + + ValidationResult errors = myVal.validateWithResult(qa); + + ourLog.info(errors.toString()); + assertThat(errors.getMessages(), empty()); + } + + @Test + public void testEmbeddedItemInOpenChoice() { + String questionnaireRef = "http://example.com/Questionnaire/q1"; + String valueSetRef = "http://somevalueset"; + String codeSystemUrl = "http://codesystems.com/system"; + String codeValue = "code0"; + + // create the questionnaire + QuestionnaireItemComponent item1 = new QuestionnaireItemComponent(); + item1.setLinkId("link1") + .setType(QuestionnaireItemType.OPENCHOICE) + .setOptions(new Reference(valueSetRef)); + + item1.addItem().setLinkId("link11") + .setType(QuestionnaireItemType.TEXT); + + Questionnaire q = new Questionnaire(); + q.addItem(item1); + when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(questionnaireRef))) + .thenReturn(q); + + CodeSystem codeSystem = new CodeSystem(); + codeSystem.setContent(CodeSystemContentMode.COMPLETE); + codeSystem.setUrl(codeSystemUrl); + codeSystem.addConcept().setCode(codeValue); + when(myValSupport.fetchCodeSystem(any(FhirContext.class), eq(codeSystemUrl))) + .thenReturn(codeSystem); + + ValueSet options = new ValueSet(); + options.getCompose().addInclude().setSystem(codeSystemUrl).addConcept().setCode(codeValue); + when(myValSupport.fetchResource(any(FhirContext.class), eq(ValueSet.class), eq(valueSetRef))) + .thenReturn(options); + when(myValSupport.validateCode(any(FhirContext.class), eq(codeSystemUrl), eq(codeValue), any(String.class))) + .thenReturn(new CodeValidationResult(new ConceptDefinitionComponent(new CodeType(codeValue)))); + + IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true); + String qXml = xmlParser.encodeResourceToString(q); + ourLog.info(qXml); + + // create the response + QuestionnaireResponse qa = new QuestionnaireResponse(); + qa.setStatus(QuestionnaireResponseStatus.INPROGRESS); + qa.getQuestionnaire().setReference(questionnaireRef); + qa.addItem().setLinkId("link1") + .addAnswer() + .addItem().setLinkId("link11"); + + String rXml = xmlParser.encodeResourceToString(qa); + ourLog.info(rXml); + + ValidationResult errors = myVal.validateWithResult(qa); + + ourLog.info(errors.toString()); + assertThat(errors.getMessages(), empty()); + } + + @Test + public void testEmbeddedItemInString() { + String questionnaireRef = "http://example.com/Questionnaire/q1"; + + // create the questionnaire + QuestionnaireItemComponent item1 = new QuestionnaireItemComponent(); + item1.setLinkId("link1") + .setType(QuestionnaireItemType.TEXT); + + item1.addItem().setLinkId("link11") + .setType(QuestionnaireItemType.TEXT); + + Questionnaire q = new Questionnaire(); + q.addItem(item1); + when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(questionnaireRef))) + .thenReturn(q); + + IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true); + String qXml = xmlParser.encodeResourceToString(q); + ourLog.info(qXml); + + // create the response + QuestionnaireResponse qa = new QuestionnaireResponse(); + qa.setStatus(QuestionnaireResponseStatus.INPROGRESS); + qa.getQuestionnaire().setReference(questionnaireRef); + qa.addItem().setLinkId("link1") + .addAnswer() + .addItem().setLinkId("link11"); + + String rXml = xmlParser.encodeResourceToString(qa); + ourLog.info(rXml); + + ValidationResult errors = myVal.validateWithResult(qa); + + ourLog.info(errors.toString()); + assertThat(errors.getMessages(), empty()); + } + @Test public void testValidateQuestionnaireResponseWithValueSetChoiceAnswer() { /* From 1aff1326914a0c9ead290b54dbf41562504aeea5 Mon Sep 17 00:00:00 2001 From: Heinz-Dieter Conradi Date: Tue, 13 Mar 2018 09:12:09 +0100 Subject: [PATCH 2/3] Test questionnaire with embedded items for R4. The test for an item embedded in a text item works as expected. However, the embedded item in a choice or openchoice case triggers an NPE. --- .../QuestionnaireResponseValidatorR4Test.java | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/QuestionnaireResponseValidatorR4Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/QuestionnaireResponseValidatorR4Test.java index 0b1dfafe23f..7a12f447606 100644 --- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/QuestionnaireResponseValidatorR4Test.java +++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/QuestionnaireResponseValidatorR4Test.java @@ -1,6 +1,7 @@ package org.hl7.fhir.r4.validation; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.SingleValidationMessage; @@ -218,6 +219,156 @@ public class QuestionnaireResponseValidatorR4Test { assertThat(errors.toString(), containsString("No response found for required item link0")); } + @Test + public void testEmbeddedItemInChoice() { + String questionnaireRef = "http://example.com/Questionnaire/q1"; + String valueSetRef = "http://somevalueset"; + String codeSystemUrl = "http://codesystems.com/system"; + String codeValue = "code0"; + + // create the questionnaire + QuestionnaireItemComponent item1 = new QuestionnaireItemComponent(); + item1.setLinkId("link1") + .setType(QuestionnaireItemType.CHOICE) + .setOptions(valueSetRef); + + item1.addItem().setLinkId("link11") + .setType(QuestionnaireItemType.TEXT); + + Questionnaire q = new Questionnaire(); + q.addItem(item1); + when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(questionnaireRef))) + .thenReturn(q); + + CodeSystem codeSystem = new CodeSystem(); + codeSystem.setContent(CodeSystemContentMode.COMPLETE); + codeSystem.setUrl(codeSystemUrl); + codeSystem.addConcept().setCode(codeValue); + when(myValSupport.fetchCodeSystem(any(FhirContext.class), eq(codeSystemUrl))) + .thenReturn(codeSystem); + + ValueSet options = new ValueSet(); + options.getCompose().addInclude().setSystem(codeSystemUrl).addConcept().setCode(codeValue); + when(myValSupport.fetchResource(any(FhirContext.class), eq(ValueSet.class), eq(valueSetRef))) + .thenReturn(options); + when(myValSupport.validateCode(any(FhirContext.class), eq(codeSystemUrl), eq(codeValue), any(String.class))) + .thenReturn(new CodeValidationResult(new ConceptDefinitionComponent(new CodeType(codeValue)))); + + IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true); + String qXml = xmlParser.encodeResourceToString(q); + ourLog.info(qXml); + + // create the response + QuestionnaireResponse qa = new QuestionnaireResponse(); + qa.setStatus(QuestionnaireResponseStatus.INPROGRESS); + qa.setQuestionnaire(questionnaireRef); + qa.addItem().setLinkId("link1") + .addAnswer() + .addItem().setLinkId("link11"); + + String rXml = xmlParser.encodeResourceToString(qa); + ourLog.info(rXml); + + ValidationResult errors = myVal.validateWithResult(qa); + + ourLog.info(errors.toString()); + assertThat(errors.getMessages(), empty()); + } + + @Test + public void testEmbeddedItemInOpenChoice() { + String questionnaireRef = "http://example.com/Questionnaire/q1"; + String valueSetRef = "http://somevalueset"; + String codeSystemUrl = "http://codesystems.com/system"; + String codeValue = "code0"; + + // create the questionnaire + QuestionnaireItemComponent item1 = new QuestionnaireItemComponent(); + item1.setLinkId("link1") + .setType(QuestionnaireItemType.OPENCHOICE) + .setOptions(valueSetRef); + + item1.addItem().setLinkId("link11") + .setType(QuestionnaireItemType.TEXT); + + Questionnaire q = new Questionnaire(); + q.addItem(item1); + when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(questionnaireRef))) + .thenReturn(q); + + CodeSystem codeSystem = new CodeSystem(); + codeSystem.setContent(CodeSystemContentMode.COMPLETE); + codeSystem.setUrl(codeSystemUrl); + codeSystem.addConcept().setCode(codeValue); + when(myValSupport.fetchCodeSystem(any(FhirContext.class), eq(codeSystemUrl))) + .thenReturn(codeSystem); + + ValueSet options = new ValueSet(); + options.getCompose().addInclude().setSystem(codeSystemUrl).addConcept().setCode(codeValue); + when(myValSupport.fetchResource(any(FhirContext.class), eq(ValueSet.class), eq(valueSetRef))) + .thenReturn(options); + when(myValSupport.validateCode(any(FhirContext.class), eq(codeSystemUrl), eq(codeValue), any(String.class))) + .thenReturn(new CodeValidationResult(new ConceptDefinitionComponent(new CodeType(codeValue)))); + + IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true); + String qXml = xmlParser.encodeResourceToString(q); + ourLog.info(qXml); + + // create the response + QuestionnaireResponse qa = new QuestionnaireResponse(); + qa.setStatus(QuestionnaireResponseStatus.INPROGRESS); + qa.setQuestionnaire(questionnaireRef); + qa.addItem().setLinkId("link1") + .addAnswer() + .addItem().setLinkId("link11"); + + String rXml = xmlParser.encodeResourceToString(qa); + ourLog.info(rXml); + + ValidationResult errors = myVal.validateWithResult(qa); + + ourLog.info(errors.toString()); + assertThat(errors.getMessages(), empty()); + } + + @Test + public void testEmbeddedItemInString() { + String questionnaireRef = "http://example.com/Questionnaire/q1"; + + // create the questionnaire + QuestionnaireItemComponent item1 = new QuestionnaireItemComponent(); + item1.setLinkId("link1") + .setType(QuestionnaireItemType.TEXT); + + item1.addItem().setLinkId("link11") + .setType(QuestionnaireItemType.TEXT); + + Questionnaire q = new Questionnaire(); + q.addItem(item1); + when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(questionnaireRef))) + .thenReturn(q); + + IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true); + String qXml = xmlParser.encodeResourceToString(q); + ourLog.info(qXml); + + // create the response + QuestionnaireResponse qa = new QuestionnaireResponse(); + qa.setStatus(QuestionnaireResponseStatus.INPROGRESS); + qa.setQuestionnaire(questionnaireRef); + qa.addItem().setLinkId("link1") + .addAnswer() + .addItem().setLinkId("link11"); + + String rXml = xmlParser.encodeResourceToString(qa); + ourLog.info(rXml); + + ValidationResult errors = myVal.validateWithResult(qa); + + ourLog.info(errors.toString()); + assertThat(errors.getMessages(), empty()); + } + @Test public void testOpenchoiceAnswer() { String questionnaireRef = "http://example.com/Questionnaire/q1"; From baf53efd325df51521bd053f32bf2dfa920a56e1 Mon Sep 17 00:00:00 2001 From: Heinz-Dieter Conradi Date: Tue, 13 Mar 2018 09:17:36 +0100 Subject: [PATCH 3/3] Fixing the NPE in the InstanceValidator --- .../fhir/r4/validation/InstanceValidator.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/r4/validation/InstanceValidator.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/r4/validation/InstanceValidator.java index 826dacb7127..4407a8ed276 100644 --- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/r4/validation/InstanceValidator.java +++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/r4/validation/InstanceValidator.java @@ -2561,19 +2561,23 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat break; case CHOICE: String itemType=validateQuestionnaireResponseItemType(errors, answer, ns, "Coding", "date", "time", "integer", "string"); - if (itemType.equals("Coding")) validateAnswerCode(errors, answer, ns, qsrc, qItem, false); - else if (itemType.equals("date")) checkOption(errors, answer, ns, qsrc, qItem, "date"); - else if (itemType.equals("time")) checkOption(errors, answer, ns, qsrc, qItem, "time"); - else if (itemType.equals("integer")) checkOption(errors, answer, ns, qsrc, qItem, "integer"); - else if (itemType.equals("string")) checkOption(errors, answer, ns, qsrc, qItem, "string"); + if (itemType != null) { + if (itemType.equals("Coding")) validateAnswerCode(errors, answer, ns, qsrc, qItem, false); + else if (itemType.equals("date")) checkOption(errors, answer, ns, qsrc, qItem, "date"); + else if (itemType.equals("time")) checkOption(errors, answer, ns, qsrc, qItem, "time"); + else if (itemType.equals("integer")) checkOption(errors, answer, ns, qsrc, qItem, "integer"); + else if (itemType.equals("string")) checkOption(errors, answer, ns, qsrc, qItem, "string"); + } break; case OPENCHOICE: itemType=validateQuestionnaireResponseItemType(errors, answer, ns, "Coding", "date", "time", "integer", "string"); - if (itemType.equals("Coding")) validateAnswerCode(errors, answer, ns, qsrc, qItem, true); - else if (itemType.equals("date")) checkOption(errors, answer, ns, qsrc, qItem, "date"); - else if (itemType.equals("time")) checkOption(errors, answer, ns, qsrc, qItem, "time"); - else if (itemType.equals("integer")) checkOption(errors, answer, ns, qsrc, qItem, "integer"); - else if (itemType.equals("string")) checkOption(errors, answer, ns, qsrc, qItem, "string", true); + if (itemType != null) { + if (itemType.equals("Coding")) validateAnswerCode(errors, answer, ns, qsrc, qItem, true); + else if (itemType.equals("date")) checkOption(errors, answer, ns, qsrc, qItem, "date"); + else if (itemType.equals("time")) checkOption(errors, answer, ns, qsrc, qItem, "time"); + else if (itemType.equals("integer")) checkOption(errors, answer, ns, qsrc, qItem, "integer"); + else if (itemType.equals("string")) checkOption(errors, answer, ns, qsrc, qItem, "string", true); + } break; case QUESTION: case NULL: