package ca.uhn.fhir.validation;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.stringContainsInOrder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.hamcrest.core.StringContains;
import org.junit.AfterClass;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.ExtensionDt;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu2.composite.TimingDt;
import ca.uhn.fhir.model.dstu2.resource.Condition;
import ca.uhn.fhir.model.dstu2.resource.MedicationOrder;
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.valueset.ConditionVerificationStatusEnum;
import ca.uhn.fhir.model.dstu2.valueset.ContactPointSystemEnum;
import ca.uhn.fhir.model.dstu2.valueset.NarrativeStatusEnum;
import ca.uhn.fhir.model.dstu2.valueset.UnitsOfTimeEnum;
import ca.uhn.fhir.model.primitive.DateDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.parser.StrictErrorHandler;
import ca.uhn.fhir.parser.XmlParserDstu2Test.TestPatientFor327;
import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.validation.schematron.SchematronBaseValidator;
public class ResourceValidatorDstu2Test {
private static FhirContext ourCtx = FhirContext.forDstu2();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceValidatorDstu2Test.class);
private FhirValidator createFhirValidator() {
FhirValidator val = ourCtx.newValidator();
val.setValidateAgainstStandardSchema(true);
val.setValidateAgainstStandardSchematron(true);
return val;
}
private String logOperationOutcome(ValidationResult result) {
OperationOutcome operationOutcome = (OperationOutcome) result.toOperationOutcome();
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationOutcome);
ourLog.info(encoded);
return encoded;
}
/**
* See issue #50
*/
@Test()
public void testOutOfBoundsDate() {
Patient p = new Patient();
p.setBirthDate(new DateDt("2000-12-31"));
// Put in an invalid date
IParser parser = ourCtx.newXmlParser();
parser.setParserErrorHandler(new StrictErrorHandler());
String encoded = parser.setPrettyPrint(true).encodeResourceToString(p).replace("2000-12-31", "2000-15-31");
ourLog.info(encoded);
assertThat(encoded, StringContains.containsString("2000-15-31"));
ValidationResult result = ourCtx.newValidator().validateWithResult(encoded);
String resultString = parser.setPrettyPrint(true).encodeResourceToString(result.toOperationOutcome());
ourLog.info(resultString);
assertEquals(2, ((OperationOutcome)result.toOperationOutcome()).getIssue().size());
assertThat(resultString, StringContains.containsString("cvc-pattern-valid"));
try {
parser.parseResource(encoded);
fail();
} catch (DataFormatException e) {
assertEquals("DataFormatException at [[row,col {unknown-source}]: [2,4]]: Invalid attribute value \"2000-15-31\": Invalid date/time format: \"2000-15-31\"", e.getMessage());
}
}
@SuppressWarnings("deprecation")
@Test
public void testSchemaBundleValidator() throws IOException {
String res = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("bundle-example.json"));
Bundle b = ourCtx.newJsonParser().parseBundle(res);
FhirValidator val = createFhirValidator();
val.validate(b);
MedicationOrder p = (MedicationOrder) b.getEntries().get(0).getResource();
TimingDt timing = new TimingDt();
timing.getRepeat().setDuration(123);
timing.getRepeat().setDurationUnits((UnitsOfTimeEnum) null);
p.getDosageInstructionFirstRep().setTiming(timing);
try {
val.validate(b);
fail();
} catch (ValidationFailureException e) {
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(e.getOperationOutcome());
ourLog.info(encoded);
assertThat(encoded, containsString("tim-1:"));
}
}
@Test
public void testSchemaBundleValidatorFails() throws IOException {
String res = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("bundle-example.json"), StandardCharsets.UTF_8);
Bundle b = ourCtx.newJsonParser().parseBundle(res);
FhirValidator val = createFhirValidator();
ValidationResult validationResult = val.validateWithResult(b);
assertTrue(validationResult.isSuccessful());
MedicationOrder p = (MedicationOrder) b.getEntries().get(0).getResource();
TimingDt timing = new TimingDt();
timing.getRepeat().setDuration(123);
timing.getRepeat().setDurationUnits((UnitsOfTimeEnum) null);
p.getDosageInstructionFirstRep().setTiming(timing);
validationResult = val.validateWithResult(b);
assertFalse(validationResult.isSuccessful());
String encoded = logOperationOutcome(validationResult);
assertThat(encoded, containsString("tim-1:"));
}
@Test
public void testSchemaBundleValidatorIsSuccessful() throws IOException {
String res = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("bundle-example.json"), StandardCharsets.UTF_8);
Bundle b = ourCtx.newJsonParser().parseBundle(res);
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(b));
FhirValidator val = createFhirValidator();
ValidationResult result = val.validateWithResult(b);
OperationOutcome operationOutcome = (OperationOutcome) result.toOperationOutcome();
assertTrue(result.toString(), result.isSuccessful());
assertNotNull(operationOutcome);
assertEquals(1, operationOutcome.getIssue().size());
}
// @Test
// public void testValidateWithAny() {
// Provenance prov = new Provenance();
// prov.
//
// IParser p = FhirContext.forDstu2().newJsonParser().setPrettyPrint(true);
// String messageString = p.encodeResourceToString(myPatient);
// ourLog.info(messageString);
//
// FhirValidator val = ourCtx.newValidator();
//// val.setValidateAgainstStandardSchema(true);
//// val.setValidateAgainstStandardSchematron(true);
// val.registerValidatorModule(new SchemaBaseValidator(ourCtx));
// val.registerValidatorModule(new SchematronBaseValidator(ourCtx));
//
// ValidationResult result = val.validateWithResult(messageString);
//
// OperationOutcome operationOutcome = (OperationOutcome) result.toOperationOutcome();
// String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationOutcome);
// ourLog.info(encoded);
//
// assertTrue(result.isSuccessful());
// }
@SuppressWarnings("deprecation")
@Test
public void testSchemaResourceValidator() throws IOException {
String res = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("patient-example-dicom.json"));
Patient p = ourCtx.newJsonParser().parseResource(Patient.class, res);
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p));
FhirValidator val = ourCtx.newValidator();
val.setValidateAgainstStandardSchema(true);
val.setValidateAgainstStandardSchematron(false);
val.validate(p);
p.getAnimal().getBreed().setText("The Breed");
try {
val.validate(p);
fail();
} catch (ValidationFailureException e) {
OperationOutcome operationOutcome = (OperationOutcome) e.getOperationOutcome();
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationOutcome));
assertEquals(1, operationOutcome.getIssue().size());
assertThat(operationOutcome.getIssueFirstRep().getDetailsElement().getValue(), containsString("cvc-complex-type"));
}
}
@Test
public void testSchematronResourceValidator() throws IOException {
String res = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("patient-example-dicom.json"), StandardCharsets.UTF_8);
Patient p = ourCtx.newJsonParser().parseResource(Patient.class, res);
FhirValidator val = ourCtx.newValidator();
val.setValidateAgainstStandardSchema(false);
val.setValidateAgainstStandardSchematron(true);
ValidationResult validationResult = val.validateWithResult(p);
assertTrue(validationResult.isSuccessful());
p.getTelecomFirstRep().setValue("123-4567");
validationResult = val.validateWithResult(p);
assertFalse(validationResult.isSuccessful());
OperationOutcome operationOutcome = (OperationOutcome) validationResult.toOperationOutcome();
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationOutcome));
assertEquals(1, operationOutcome.getIssue().size());
assertThat(operationOutcome.getIssueFirstRep().getDiagnostics(), containsString("cpt-2:"));
p.getTelecomFirstRep().setSystem(ContactPointSystemEnum.EMAIL);
validationResult = val.validateWithResult(p);
assertTrue(validationResult.isSuccessful());
}
/**
* Make sure that the elements that appear in all resources (meta, language, extension, etc)
* all appear in the correct order
*/
@Test
public void testValidateResourceWithResourceElements() {
TestPatientFor327 patient = new TestPatientFor327();
patient.setBirthDate(new Date(), TemporalPrecisionEnum.DAY);
patient.setId("123");
patient.getText().setDiv("<div>FOO</div>");
patient.getText().setStatus(NarrativeStatusEnum.GENERATED);
patient.getLanguage().setValue("en");
patient.addUndeclaredExtension(true, "http://foo").setValue(new StringDt("MOD"));
ResourceMetadataKeyEnum.UPDATED.put(patient, new InstantDt(new Date()));
List<ResourceReferenceDt> conditions = new ArrayList<ResourceReferenceDt>();
Condition condition = new Condition();
condition.getPatient().setReference("Patient/123");
condition.addBodySite().setText("BODY SITE");
condition.getCode().setText("CODE");
condition.setVerificationStatus(ConditionVerificationStatusEnum.CONFIRMED);
conditions.add(new ResourceReferenceDt(condition));
patient.setCondition(conditions);
patient.addIdentifier().setSystem("http://foo").setValue("123");
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient);
ourLog.info(encoded);
FhirValidator val = createFhirValidator();
ValidationResult result = val.validateWithResult(encoded);
String messageString = logOperationOutcome(result);
assertTrue(result.isSuccessful());
assertThat(messageString, containsString("No issues"));
}
/**
* See
* https://groups.google.com/d/msgid/hapi-fhir/a266083f-6454-4cf0-a431-c6500f052bea%40googlegroups.com?utm_medium=
* email&utm_source=footer
*/
@Test
public void testValidateWithExtensionsJson() {
PatientProfileDstu2 myPatient = new PatientProfileDstu2();
myPatient.setColorPrimary(new CodeableConceptDt("http://example.com#animalColor", "furry-grey"));
myPatient.setColorSecondary(new CodeableConceptDt("http://example.com#animalColor", "furry-white"));
myPatient.setOwningOrganization(new ResourceReferenceDt("Organization/2.25.79433498044103547197447759549862032393"));
myPatient.addName().addFamily("FamilyName");
myPatient.addUndeclaredExtension(new ExtensionDt().setUrl("http://foo.com/example").setValue(new StringDt("String Extension")));
IParser p = FhirContext.forDstu2().newJsonParser().setPrettyPrint(true);
String messageString = p.encodeResourceToString(myPatient);
ourLog.info(messageString);
//@formatter:off
assertThat(messageString, stringContainsInOrder(
"meta",
"String Extension",
"Organization/2.25.79433498044103547197447759549862032393",
"furry-grey",
"furry-white",
"FamilyName"
));
assertThat(messageString, not(stringContainsInOrder(
"extension",
"meta"
)));
//@formatter:on
FhirValidator val = ourCtx.newValidator();
val.registerValidatorModule(new SchemaBaseValidator(ourCtx));
val.registerValidatorModule(new SchematronBaseValidator(ourCtx));
ValidationResult result = val.validateWithResult(messageString);
logOperationOutcome(result);
assertTrue(result.isSuccessful());
assertThat(messageString, containsString("valueReference"));
assertThat(messageString, not(containsString("valueResource")));
}
/**
* See
* https://groups.google.com/d/msgid/hapi-fhir/a266083f-6454-4cf0-a431-c6500f052bea%40googlegroups.com?utm_medium=
* email&utm_source=footer
*/
@Test
public void testValidateWithExtensionsXml() {
PatientProfileDstu2 myPatient = new PatientProfileDstu2();
myPatient.setColorPrimary(new CodeableConceptDt("http://example.com#animalColor", "furry-grey"));
myPatient.setColorSecondary(new CodeableConceptDt("http://example.com#animalColor", "furry-white"));
myPatient.setOwningOrganization(new ResourceReferenceDt("Organization/2.25.79433498044103547197447759549862032393"));
myPatient.addName().addFamily("FamilyName");
myPatient.addUndeclaredExtension(new ExtensionDt().setUrl("http://foo.com/example").setValue(new StringDt("String Extension")));
IParser p = FhirContext.forDstu2().newXmlParser().setPrettyPrint(true);
String messageString = p.encodeResourceToString(myPatient);
ourLog.info(messageString);
//@formatter:off
assertThat(messageString, stringContainsInOrder(
"meta",
"Organization/2.25.79433498044103547197447759549862032393",
"furry-grey",
"furry-white",
"String Extension",
"FamilyName"
));
assertThat(messageString, not(stringContainsInOrder(
"extension",
"meta"
)));
assertThat(messageString, containsString("url=\"http://ahr.copa.inso.tuwien.ac.at/StructureDefinition/Patient#animal-colorSecondary\""));
assertThat(messageString, containsString("url=\"http://foo.com/example\""));
//@formatter:on
FhirValidator val = ourCtx.newValidator();
val.registerValidatorModule(new SchemaBaseValidator(ourCtx));
val.registerValidatorModule(new SchematronBaseValidator(ourCtx));
ValidationResult result = val.validateWithResult(messageString);
logOperationOutcome(result);
assertTrue(result.isSuccessful());
assertThat(messageString, containsString("valueReference"));
assertThat(messageString, not(containsString("valueResource")));
}
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
}
}