fix tests

This commit is contained in:
Grahame Grieve 2019-02-08 16:56:53 +11:00
parent 25506ddd95
commit a04b900054
3 changed files with 151 additions and 108 deletions

View File

@ -146,13 +146,13 @@ public class SnapShotGenerationTests {
if (!test.getActionFirstRep().hasOperation())
throw new Error("Unsupported: first action must be an operation");
for (int i = 0; i < test.getAction().size(); i++) {
// if (!test.getAction().get(i).hasAssert())
// throw new Error("Unsupported: following actions must be an asserts");
// if (!test.getAction().get(i).hasAssert())
// throw new Error("Unsupported: following actions must be an asserts");
TestActionComponent action = test.getAction().get(i);
if (action.hasOperation()) {
SetupActionOperationComponent op = test.getActionFirstRep().getOperation();
if (!CodingUtilities.matches(op.getType(), "http://hl7.org/fhir/testscript-operation-codes", "snapshot")
&& !CodingUtilities.matches(op.getType(), "http://hl7.org/fhir/testscript-operation-codes", "sortDifferential"))
&& !CodingUtilities.matches(op.getType(), "http://hl7.org/fhir/testscript-operation-codes", "sortDifferential"))
throw new Error("Unsupported action operation type "+CodingUtilities.present(op.getType()));
if (!"StructureDefinition".equals(op.getResource()))
throw new Error("Unsupported action operation resource "+op.getResource());
@ -192,7 +192,7 @@ public class SnapShotGenerationTests {
public Resource fetchFixture(String id) {
if (fixtures.containsKey(id))
return fixtures.get(id);
for (TestScriptFixtureComponent ds : tests.getFixture()) {
if (id.equals(ds.getId()))
throw new Error("not done yet");
@ -304,108 +304,107 @@ public class SnapShotGenerationTests {
@Test
public void test() throws FHIRException {
try {
for (Resource cr : context.tests.getContained()) {
if (cr instanceof StructureDefinition) {
StructureDefinition sd = (StructureDefinition) cr;
if (sd.getType().equals("Extension")) {
if (TestingUtilities.context().fetchResource(StructureDefinition.class, sd.getUrl()) == null) {
sd.setUserData("path", "test-"+sd.getId()+".html");
StructureDefinition extd = TestingUtilities.context().fetchResource(StructureDefinition.class, sd.getBaseDefinition());
new ProfileUtilities(TestingUtilities.context(), null, null).generateSnapshot(extd, sd, sd.getUrl(), sd.getName());
TestingUtilities.context().cacheResource(sd);
debugSaveResource(sd);
for (Resource cr : context.tests.getContained()) {
if (cr instanceof StructureDefinition) {
StructureDefinition sd = (StructureDefinition) cr;
if (sd.getType().equals("Extension")) {
if (TestingUtilities.context().fetchResource(StructureDefinition.class, sd.getUrl()) == null) {
sd.setUserData("path", "test-"+sd.getId()+".html");
StructureDefinition extd = TestingUtilities.context().fetchResource(StructureDefinition.class, sd.getBaseDefinition());
new ProfileUtilities(TestingUtilities.context(), null, null).generateSnapshot(extd, sd, sd.getUrl(), sd.getName());
TestingUtilities.context().cacheResource(sd);
debugSaveResource(sd);
}
}
}
}
}
if (fp == null)
fp = new FHIRPathEngine(TestingUtilities.context());
fp.setHostServices(context);
if (fp == null)
fp = new FHIRPathEngine(TestingUtilities.context());
fp.setHostServices(context);
resolveFixtures();
TestScript.AssertionResponseTypes lastOpOutcome = null;
for (int i = 0; i < test.getAction().size(); i++) {
TestActionComponent action = test.getAction().get(i);
if (action.hasOperation()) {
lastOpOutcome = AssertionResponseTypes.OKAY;
try {
SetupActionOperationComponent op = action.getOperation();
Coding opType = op.getType();
if (opType.getSystem().equals("http://hl7.org/fhir/testscript-operation-codes") && opType.getCode().equals("snapshot")) {
StructureDefinition source = (StructureDefinition) context.fetchFixture(op.getSourceId());
StructureDefinition base = getSD(source.getBaseDefinition());
StructureDefinition output = source.copy();
ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context(), null, new TestPKP());
pu.setIds(source, false);
if ("sort=true".equals(op.getParams())) {
List<String> errors = new ArrayList<String>();
pu.sortDifferential(base, output, source.getName(), errors);
if (errors.size() > 0)
throw new FHIRException("Sort failed: "+errors.toString());
resolveFixtures();
TestScript.AssertionResponseTypes lastOpOutcome = null;
for (int i = 0; i < test.getAction().size(); i++) {
TestActionComponent action = test.getAction().get(i);
if (action.hasOperation()) {
lastOpOutcome = AssertionResponseTypes.OKAY;
try {
SetupActionOperationComponent op = action.getOperation();
Coding opType = op.getType();
if (opType.getSystem().equals("http://hl7.org/fhir/testscript-operation-codes") && opType.getCode().equals("snapshot")) {
StructureDefinition source = (StructureDefinition) context.fetchFixture(op.getSourceId());
StructureDefinition base = getSD(source.getBaseDefinition());
StructureDefinition output = source.copy();
ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context(), null, new TestPKP());
pu.setIds(source, false);
if ("sort=true".equals(op.getParams())) {
List<String> errors = new ArrayList<String>();
int lastCount = output.getDifferential().getElement().size();
pu.sortDifferential(base, output, source.getName(), errors);
if (errors.size() > 0)
throw new FHIRException("Sort failed: "+errors.toString());
if (lastCount != output.getDifferential().getElement().size())
throw new FHIRException("Sort failed: counts differ; at least one of the paths in the differential is illegal");
}
pu.generateSnapshot(base, output, source.getUrl(), source.getName());
debugSaveResource(output);
context.fixtures.put(op.getResponseId(), output);
context.snapshots.put(output.getUrl(), output);
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(System.getProperty("java.io.tmpdir"), op.getResponseId()+".xml")), output);
if (output.getDifferential().hasElement())
new NarrativeGenerator("", "http://hl7.org/fhir", TestingUtilities.context()).setPkp(new TestPKP()).generate(output, null);
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(System.getProperty("java.io.tmpdir"), op.getResponseId()+"-d.xml")), output);
} else if (opType.getSystem().equals("http://hl7.org/fhir/testscript-operation-codes") && opType.getCode().equals("sortDifferential")) {
StructureDefinition source = (StructureDefinition) context.fetchFixture(op.getSourceId());
StructureDefinition base = getSD(source.getBaseDefinition());
StructureDefinition output = source.copy();
ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context(), null, null);
pu.setIds(source, false);
List<String> errors = new ArrayList<String>();
pu.sortDifferential(base, output, output.getUrl(), errors);
if (!errors.isEmpty())
throw new FHIRException(errors.get(0));
context.fixtures.put(op.getResponseId(), output);
context.snapshots.put(output.getUrl(), output);
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(System.getProperty("java.io.tmpdir"), op.getResponseId()+".xml")), output);
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(System.getProperty("java.io.tmpdir"), op.getResponseId()+".xml")), output);
} else if (action.hasAssert()) {
SetupActionAssertComponent a = action.getAssert();
if (a.hasResponse() && a.getResponse().equals(TestScript.AssertionResponseTypes.BAD))
Assert.fail(action.getAssert().getLabel()+": "+action.getAssert().getDescription());
else {
boolean ok = fp.evaluateToBoolean(new StructureDefinition(), new StructureDefinition(), a.getExpression());
Assert.assertTrue(a.getLabel()+": "+a.getDescription(), ok);
}
} else {
throw new Error("Unsupported operation: " + opType.getSystem() + " : " + opType.getCode());
}
lastOpOutcome = AssertionResponseTypes.OKAY;
} catch (Exception e) {
for (int j = i+1;i < test.getAction().size(); i++) {
TestActionComponent followAction = test.getAction().get(j);
if (followAction.hasAssert() && followAction.getAssert().hasResponse() && followAction.getAssert().getResponse().equals(TestScript.AssertionResponseTypes.BAD)) {
lastOpOutcome = AssertionResponseTypes.BAD;
break;
}
}
pu.generateSnapshot(base, output, source.getUrl(), source.getName());
debugSaveResource(output);
context.fixtures.put(op.getResponseId(), output);
context.snapshots.put(output.getUrl(), output);
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(System.getProperty("java.io.tmpdir"), op.getResponseId()+".xml")), output);
if (output.getDifferential().hasElement())
new NarrativeGenerator("", "http://hl7.org/fhir", TestingUtilities.context()).setPkp(new TestPKP()).generate(output, null);
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(System.getProperty("java.io.tmpdir"), op.getResponseId()+"-d.xml")), output);
} else if (opType.getSystem().equals("http://hl7.org/fhir/testscript-operation-codes") && opType.getCode().equals("sortDifferential")) {
StructureDefinition source = (StructureDefinition) context.fetchFixture(op.getSourceId());
StructureDefinition base = getSD(source.getBaseDefinition());
StructureDefinition output = source.copy();
ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context(), null, null);
pu.setIds(source, false);
List<String> errors = new ArrayList<String>();
pu.sortDifferential(base, output, output.getUrl(), errors);
if (!errors.isEmpty())
throw new FHIRException(errors.get(0));
context.fixtures.put(op.getResponseId(), output);
context.snapshots.put(output.getUrl(), output);
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(System.getProperty("java.io.tmpdir"), op.getResponseId()+".xml")), output);
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(System.getProperty("java.io.tmpdir"), op.getResponseId()+".xml")), output);
} else {
throw new Error("Unsupported operation: " + opType.getSystem() + " : " + opType.getCode());
}
} else if (action.hasAssert()) {
SetupActionAssertComponent a = action.getAssert();
if (a.hasResponse() && a.getResponse().equals(TestScript.AssertionResponseTypes.BAD))
Assert.fail(action.getAssert().getLabel()+": "+action.getAssert().getDescription());
else {
if (a.getResponse() != null) {
Assert.assertTrue(a.getLabel()+" (response): "+a.getDescription(), a.getResponse() == lastOpOutcome);
}
if (a.hasExpression()) {
boolean ok = fp.evaluateToBoolean(new StructureDefinition(), new StructureDefinition(), a.getExpression());
Assert.assertTrue(a.getLabel()+": "+a.getDescription(), ok);
}
}
} catch (Exception e) {
boolean ok = false;
for (int j = i+1;i < test.getAction().size(); i++) {
TestActionComponent followAction = test.getAction().get(j);
if (followAction.hasAssert() && followAction.getAssert().hasResponse() && followAction.getAssert().getResponse().equals(TestScript.AssertionResponseTypes.BAD)) {
ok = true;
break;
}
}
} catch (Exception e) {
lastOpOutcome = AssertionResponseTypes.BAD;
}
} else if (action.hasAssert()) {
SetupActionAssertComponent a = action.getAssert();
if (a.getResponse() != null) {
Assert.assertTrue(a.getLabel()+" (response): "+a.getDescription(), a.getResponse() == lastOpOutcome);
}
if (a.hasExpression()) {
boolean ok = fp.evaluateToBoolean(new StructureDefinition(), new StructureDefinition(), a.getExpression());
Assert.assertTrue(a.getLabel()+": "+a.getDescription(), ok);
}
}
}
} catch (Exception e) {
e.printStackTrace();
throw new FHIRException(e);

View File

@ -216,8 +216,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
@Override
public Base resolveReference(Object appContext, String url) throws FHIRException {
ValidatorHostContext c = (ValidatorHostContext) appContext;
if (c.container != null || externalHostServices == null)
throw new Error("Not done yet - resolve "+url+" locally");
if (c.container != null)
throw new Error("Not done yet - resolve "+url+" locally (1)");
else if (externalHostServices == null)
throw new Error("Not done yet - resolve "+url+" locally (2)");
else
return externalHostServices.resolveReference(c.appContext, url);
@ -3291,12 +3293,22 @@ private String misplacedItemError(QuestionnaireItemComponent qItem) {
String url = getCanonicalURLForEntry(entry);
String id = getIdForEntry(entry);
if (url != null) {
rule(errors, IssueType.INVALID, entry.line(), entry.col(), stack.addToLiteralPath("entry", ":0"), !url.equals(fullUrl) || (url.matches(Constants.URI_REGEX) && url.endsWith("/"+id)), "The canonical URL ("+url+") cannot match the fullUrl ("+fullUrl+") unless the resource id ("+id+") also matches");
if (!(!url.equals(fullUrl) || (url.matches(uriRegexForVersion()) && url.endsWith("/"+id))))
rule(errors, IssueType.INVALID, entry.line(), entry.col(), stack.addToLiteralPath("entry", ":0"), false, "The canonical URL ("+url+") cannot match the fullUrl ("+fullUrl+") unless the resource id ("+id+") also matches");
rule(errors, IssueType.INVALID, entry.line(), entry.col(), stack.addToLiteralPath("entry", ":0"), !url.equals(fullUrl) || serverBase == null || (url.equals(Utilities.pathURL(serverBase, entry.getNamedChild("resource").fhirType(), id))), "The canonical URL ("+url+") cannot match the fullUrl ("+fullUrl+") unless on the canonical server itself");
}
}
}
public final static String URI_REGEX3 = "((http|https)://([A-Za-z0-9\\\\\\.\\:\\%\\$]*\\/)*)?(Account|ActivityDefinition|AllergyIntolerance|AdverseEvent|Appointment|AppointmentResponse|AuditEvent|Basic|Binary|BodySite|Bundle|CapabilityStatement|CarePlan|CareTeam|ChargeItem|Claim|ClaimResponse|ClinicalImpression|CodeSystem|Communication|CommunicationRequest|CompartmentDefinition|Composition|ConceptMap|Condition (aka Problem)|Consent|Contract|Coverage|DataElement|DetectedIssue|Device|DeviceComponent|DeviceMetric|DeviceRequest|DeviceUseStatement|DiagnosticReport|DocumentManifest|DocumentReference|EligibilityRequest|EligibilityResponse|Encounter|Endpoint|EnrollmentRequest|EnrollmentResponse|EpisodeOfCare|ExpansionProfile|ExplanationOfBenefit|FamilyMemberHistory|Flag|Goal|GraphDefinition|Group|GuidanceResponse|HealthcareService|ImagingManifest|ImagingStudy|Immunization|ImmunizationRecommendation|ImplementationGuide|Library|Linkage|List|Location|Measure|MeasureReport|Media|Medication|MedicationAdministration|MedicationDispense|MedicationRequest|MedicationStatement|MessageDefinition|MessageHeader|NamingSystem|NutritionOrder|Observation|OperationDefinition|OperationOutcome|Organization|Parameters|Patient|PaymentNotice|PaymentReconciliation|Person|PlanDefinition|Practitioner|PractitionerRole|Procedure|ProcedureRequest|ProcessRequest|ProcessResponse|Provenance|Questionnaire|QuestionnaireResponse|ReferralRequest|RelatedPerson|RequestGroup|ResearchStudy|ResearchSubject|RiskAssessment|Schedule|SearchParameter|Sequence|ServiceDefinition|Slot|Specimen|StructureDefinition|StructureMap|Subscription|Substance|SupplyDelivery|SupplyRequest|Task|TestScript|TestReport|ValueSet|VisionPrescription)\\/[A-Za-z0-9\\-\\.]{1,64}(\\/_history\\/[A-Za-z0-9\\-\\.]{1,64})?";
private String uriRegexForVersion() {
if ("3.0.1".equals(context.getVersion()))
return URI_REGEX3;
else
return Constants.URI_REGEX;
}
private String getCanonicalURLForEntry(Element entry) {
Element e = entry.getNamedChild("resource");
if (e == null)
@ -3961,16 +3973,16 @@ private String misplacedItemError(QuestionnaireItemComponent qItem) {
if (inv.hasExtension("http://hl7.org/fhir/StructureDefinition/elementdefinition-bestpractice") &&
ToolingExtensions.readBooleanExtension(inv, "http://hl7.org/fhir/StructureDefinition/elementdefinition-bestpractice")) {
if (bpWarnings == BestPracticeWarningLevel.Hint)
hint(errors, IssueType.INVARIANT, element.line(), element.col(), path, ok, inv.getHuman()+msg+" ["+inv.getExpression()+"]");
hint(errors, IssueType.INVARIANT, element.line(), element.col(), path, ok, inv.getHuman()+msg+" ["+n.toString()+"]");
else if (bpWarnings == BestPracticeWarningLevel.Warning)
warning(errors, IssueType.INVARIANT, element.line(), element.col(), path, ok, inv.getHuman()+msg+" ["+inv.getExpression()+"]");
warning(errors, IssueType.INVARIANT, element.line(), element.col(), path, ok, inv.getHuman()+msg+" ["+n.toString()+"]");
else if (bpWarnings == BestPracticeWarningLevel.Error)
rule(errors, IssueType.INVARIANT, element.line(), element.col(), path, ok, inv.getHuman()+msg+" ["+inv.getExpression()+"]");
rule(errors, IssueType.INVARIANT, element.line(), element.col(), path, ok, inv.getHuman()+msg+" ["+n.toString()+"]");
}
if (inv.getSeverity() == ConstraintSeverity.ERROR)
rule(errors, IssueType.INVARIANT, element.line(), element.col(), path, ok, inv.getHuman()+msg+" ["+inv.getExpression()+"]");
rule(errors, IssueType.INVARIANT, element.line(), element.col(), path, ok, inv.getHuman()+msg+" ["+n.toString()+"]");
else if (inv.getSeverity() == ConstraintSeverity.WARNING)
warning(errors, IssueType.INVARIANT, element.line(), element.line(), path, ok, inv.getHuman()+msg+" ["+inv.getExpression()+"]");
warning(errors, IssueType.INVARIANT, element.line(), element.line(), path, ok, inv.getHuman()+msg+" ["+n.toString()+"]");
}
}
@ -4346,6 +4358,7 @@ private String misplacedItemError(QuestionnaireItemComponent qItem) {
private String fixExpr(String expr) {
// this is a hack work around for past publication of wrong FHIRPath expressions
// R4
if ("(component.empty() and hasMember.empty()) implies (dataAbsentReason or value)".equals(expr))
return "(component.empty() and hasMember.empty()) implies (dataAbsentReason.exists() or value.exists())";
if ("isModifier implies isModifierReason.exists()".equals(expr))
@ -4356,10 +4369,25 @@ private String misplacedItemError(QuestionnaireItemComponent qItem) {
return "differential.element.all(id.exists()) and differential.element.id.trace('ids').isDistinct()";
if ("snapshot.element.all(id) and snapshot.element.id.trace('ids').isDistinct()".equals(expr))
return "snapshot.element.all(id.exists()) and snapshot.element.id.trace('ids').isDistinct()";
if ("".equals(expr))
return "";
if ("".equals(expr))
return "";
// R3
if ("(code or value.empty()) and (system.empty() or system = 'urn:iso:std:iso:4217')".equals(expr))
return "(code.exists() or value.empty()) and (system.empty() or system = 'urn:iso:std:iso:4217')";
if ("value.empty() or code!=component.code".equals(expr))
return "value.empty() or (code in component.code).not()";
if ("(code or value.empty()) and (system.empty() or system = %ucum) and (value.empty() or value > 0)".equals(expr))
return "(code.exists() or value.empty()) and (system.empty() or system = %ucum) and (value.empty() or value > 0)";
if ("element.all(definition and min and max)".equals(expr))
return "element.all(definition.exists() and min.exists() and max.exists())";
if ("telecom or endpoint".equals(expr))
return "telecom.exists() or endpoint.exists()";
if ("(code or value.empty()) and (system.empty() or system = %ucum) and (value.empty() or value > 0)".equals(expr))
return "(code.exists() or value.empty()) and (system.empty() or system = %ucum) and (value.empty() or value > 0)";
if ("searchType implies type = 'string'".equals(expr))
return "searchType.exists() implies type = 'string'";
if ("abatement.empty() or (abatement as boolean).not() or clinicalStatus='resolved' or clinicalStatus='remission' or clinicalStatus='inactive'".equals(expr))
return "abatement.empty() or (abatement is boolean).not() or (abatement as boolean).not() or (clinicalStatus = 'resolved') or (clinicalStatus = 'remission') or (clinicalStatus = 'inactive')";
if ("".equals(expr))
return "";
return expr;

View File

@ -770,9 +770,17 @@ public class ValidationEngine {
results.setType(Bundle.BundleType.COLLECTION);
for (String ref : refs) {
Content cnt = loadContent(ref, "validate");
OperationOutcome outcome = validate(ref, cnt.focus, cnt.cntType, profiles);
ToolingExtensions.addStringExtension(outcome, ToolingExtensions.EXT_OO_FILE, ref);
results.addEntry().setResource(outcome);
if (refs.size() > 1)
System.out.println("Validate "+ref);
try {
OperationOutcome outcome = validate(ref, cnt.focus, cnt.cntType, profiles);
ToolingExtensions.addStringExtension(outcome, ToolingExtensions.EXT_OO_FILE, ref);
if (refs.size() > 1)
produceValidationSummary(outcome);
results.addEntry().setResource(outcome);
} catch (Throwable e) {
System.out.println("Validation Infrastructure fail validating "+ref+": "+e.getMessage());
}
}
if (asBundle)
return results;
@ -780,6 +788,14 @@ public class ValidationEngine {
return results.getEntryFirstRep().getResource();
}
private void produceValidationSummary(OperationOutcome oo) {
for (OperationOutcomeIssueComponent iss : oo.getIssue()) {
if (iss.getSeverity() == org.hl7.fhir.r4.model.OperationOutcome.IssueSeverity.ERROR || iss.getSeverity() == org.hl7.fhir.r4.model.OperationOutcome.IssueSeverity.FATAL) {
System.out.println(" "+iss.getSeverity().toCode()+": "+iss.getDetails().getText());
}
}
}
public OperationOutcome validateString(String location, String source, FhirFormat format, List<String> profiles) throws Exception {
return validate(location, source.getBytes(), format, profiles);
}