fix how CodeableConcept is validated, and add Tx interaction logging by validator

This commit is contained in:
Grahame Grieve 2020-01-11 06:22:16 +11:00
parent 46e1e5edd4
commit ef085a847e
15 changed files with 240 additions and 77 deletions

View File

@ -26,7 +26,7 @@ import java.util.Map;
import org.hl7.fhir.dstu2.utils.client.FHIRToolingClient;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.context.HTMLClientLogger;
import org.hl7.fhir.r5.utils.client.ToolingClientLogger;
import org.hl7.fhir.r5.model.CapabilityStatement;
import org.hl7.fhir.r5.model.Parameters;
import org.hl7.fhir.r5.model.TerminologyCapabilities;
@ -81,7 +81,7 @@ public class TerminologyClientR2 implements TerminologyClient {
}
@Override
public void setLogger(HTMLClientLogger txLog) {
public void setLogger(ToolingClientLogger txLog) {
// ignored in this version - need to roll R4 internal changes back to R2 if desired
}

View File

@ -26,7 +26,7 @@ import java.util.Map;
import org.hl7.fhir.dstu3.utils.client.FHIRToolingClient;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.context.HTMLClientLogger;
import org.hl7.fhir.r5.utils.client.ToolingClientLogger;
import org.hl7.fhir.r5.model.CapabilityStatement;
import org.hl7.fhir.r5.model.Parameters;
import org.hl7.fhir.r5.model.TerminologyCapabilities;
@ -79,7 +79,7 @@ public class TerminologyClientR3 implements TerminologyClient {
}
@Override
public void setLogger(HTMLClientLogger txLog) {
public void setLogger(ToolingClientLogger txLog) {
// ignored in this version - need to roll R4 internal changes back to R2 if desired
}

View File

@ -26,7 +26,7 @@ import java.util.Map;
import org.hl7.fhir.r4.utils.client.FHIRToolingClient;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.context.HTMLClientLogger;
import org.hl7.fhir.r5.utils.client.ToolingClientLogger;
import org.hl7.fhir.r5.model.CapabilityStatement;
import org.hl7.fhir.r5.model.Parameters;
import org.hl7.fhir.r5.model.TerminologyCapabilities;
@ -79,7 +79,7 @@ public class TerminologyClientR4 implements TerminologyClient {
}
@Override
public void setLogger(HTMLClientLogger txLog) {
public void setLogger(ToolingClientLogger txLog) {
// ignored in this version - need to roll R4 internal changes back to R2 if desired
}

View File

@ -79,12 +79,14 @@ import org.hl7.fhir.r5.terminologies.ValueSetExpander.TerminologyServiceErrorCla
import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.r5.terminologies.ValueSetExpanderSimple;
import org.hl7.fhir.r5.utils.ToolingExtensions;
import org.hl7.fhir.r5.utils.client.ToolingClientLogger;
import org.hl7.fhir.utilities.OIDUtils;
import org.hl7.fhir.utilities.TerminologyServiceOptions;
import org.hl7.fhir.utilities.TranslationServices;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.hl7.fhir.utilities.validation.ValidationOptions.ValueSetMode;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
@ -148,7 +150,7 @@ public abstract class BaseWorkerContext implements IWorkerContext {
private boolean allowLoadingDuplicates;
protected TerminologyClient txClient;
protected HTMLClientLogger txLog;
protected ToolingClientLogger txLog;
private TerminologyCapabilities txcaps;
private boolean canRunWithoutTerminology;
protected boolean noTerminologyServer;
@ -593,8 +595,12 @@ public abstract class BaseWorkerContext implements IWorkerContext {
}
private void setTerminologyOptions(ValidationOptions options, Parameters pIn) {
if (!Utilities.noString(options.getLanguage()))
if (!Utilities.noString(options.getLanguage())) {
pIn.addParameter("displayLanguage", options.getLanguage());
}
if (options.getValueSetMode() != ValueSetMode.ALL_CHECKS) {
pIn.addParameter("valueSetMode", options.getValueSetMode().toString());
}
}
@Override

View File

@ -241,7 +241,11 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
try {
tlog("Connect to "+client.getAddress());
txClient = client;
txLog = new HTMLClientLogger(log);
if (log != null && log.endsWith(".txt")) {
txLog = new TextClientLogger(log);
} else {
txLog = new HTMLClientLogger(log);
}
txClient.setLogger(txLog);
return txClient.getCapabilitiesStatementQuick().getSoftware().getVersion();
} catch (Exception e) {

View File

@ -0,0 +1,92 @@
package org.hl7.fhir.r5.context;
/*-
* #%L
* org.hl7.fhir.r5
* %%
* Copyright (C) 2014 - 2019 Health Level 7
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.util.List;
import org.hl7.fhir.r5.utils.client.ToolingClientLogger;
import org.hl7.fhir.utilities.Utilities;
public class TextClientLogger implements ToolingClientLogger {
private PrintStream file;
private int id = 0;
private String lastId;
public TextClientLogger(String log) {
if (log != null) {
try {
file = new PrintStream(new FileOutputStream(log));
} catch (FileNotFoundException e) {
}
}
}
@Override
public void logRequest(String method, String url, List<String> headers, byte[] body) {
if (file == null)
return;
id++;
lastId = Integer.toString(id);
file.println("\r\n--- "+lastId+" -----------------\r\nRequest: \r\n");
file.println(method+" "+url+" HTTP/1.0");
for (String s : headers)
file.println(Utilities.escapeXml(s));
if (body != null) {
file.println("");
try {
file.println(Utilities.escapeXml(new String(body, "UTF-8")));
} catch (UnsupportedEncodingException e) {
}
}
}
@Override
public void logResponse(String outcome, List<String> headers, byte[] body) {
if (file == null)
return;
file.println("\r\n\r\nResponse: \r\n");
file.println(outcome);
for (String s : headers)
file.println(Utilities.escapeXml(s));
if (body != null) {
file.println("");
try {
file.println(Utilities.escapeXml(new String(body, "UTF-8")));
} catch (UnsupportedEncodingException e) {
}
}
}
public String getLastId() {
return lastId;
}
public void clearLastId() {
lastId = null;
}
}

View File

@ -29,6 +29,7 @@ import org.hl7.fhir.r5.model.CapabilityStatement;
import org.hl7.fhir.r5.model.Parameters;
import org.hl7.fhir.r5.model.TerminologyCapabilities;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.utils.client.ToolingClientLogger;
public interface TerminologyClient {
public String getAddress();
@ -37,7 +38,7 @@ public interface TerminologyClient {
public Parameters validateCS(Parameters pin) throws FHIRException;
public Parameters validateVS(Parameters pin) throws FHIRException;
public void setTimeout(int i) throws FHIRException;
public void setLogger(HTMLClientLogger txLog) throws FHIRException;
public void setLogger(ToolingClientLogger txLog) throws FHIRException;
public CapabilityStatement getCapabilitiesStatementQuick() throws FHIRException;
public Parameters lookupCode(Map<String, String> params) throws FHIRException;
}

View File

@ -31,6 +31,7 @@ import org.hl7.fhir.r5.model.Parameters;
import org.hl7.fhir.r5.model.TerminologyCapabilities;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.utils.client.FHIRToolingClient;
import org.hl7.fhir.r5.utils.client.ToolingClientLogger;
public class TerminologyClientR5 implements TerminologyClient {
@ -71,7 +72,7 @@ public class TerminologyClientR5 implements TerminologyClient {
}
@Override
public void setLogger(HTMLClientLogger txLog) {
public void setLogger(ToolingClientLogger txLog) {
client.setLogger(txLog);
}

View File

@ -48,6 +48,7 @@ import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.TerminologyServiceOptions;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.hl7.fhir.utilities.validation.ValidationOptions.ValueSetMode;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
public class ValueSetCheckerSimple implements ValueSetChecker {
@ -67,22 +68,24 @@ public class ValueSetCheckerSimple implements ValueSetChecker {
// first, we validate the codings themselves
List<String> errors = new ArrayList<String>();
List<String> warnings = new ArrayList<String>();
for (Coding c : code.getCoding()) {
if (!c.hasSystem())
warnings.add("Coding has no system - cannot validate");
CodeSystem cs = context.fetchCodeSystem(c.getSystem());
ValidationResult res = null;
if (cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) {
res = context.validateCode(options.noClient(), c, null);
} else {
res = validateCode(c, cs);
if (options.getValueSetMode() != ValueSetMode.CHECK_MEMERSHIP_ONLY) {
for (Coding c : code.getCoding()) {
if (!c.hasSystem())
warnings.add("Coding has no system - cannot validate");
CodeSystem cs = context.fetchCodeSystem(c.getSystem());
ValidationResult res = null;
if (cs == null || cs.getContent() != CodeSystemContentMode.COMPLETE) {
res = context.validateCode(options.noClient(), c, null);
} else {
res = validateCode(c, cs);
}
if (!res.isOk())
errors.add(res.getMessage());
else if (res.getMessage() != null)
warnings.add(res.getMessage());
}
if (!res.isOk())
errors.add(res.getMessage());
else if (res.getMessage() != null)
warnings.add(res.getMessage());
}
if (valueset != null) {
if (valueset != null && options.getValueSetMode() != ValueSetMode.NO_MEMBERSHIP_CHECK) {
boolean ok = false;
for (Coding c : code.getCoding()) {
ok = ok || codeInValueSet(c.getSystem(), c.getCode());
@ -101,38 +104,45 @@ public class ValueSetCheckerSimple implements ValueSetChecker {
public ValidationResult validateCode(Coding code) throws FHIRException {
String warningMessage = null;
// first, we validate the concept itself
String system = code.hasSystem() ? code.getSystem() : getValueSetSystem();
if (system == null && !code.hasDisplay()) { // dealing with just a plain code (enum)
system = systemForCodeInValueSet(code.getCode());
}
if (!code.hasSystem())
code.setSystem(system);
boolean inExpansion = checkExpansion(code);
CodeSystem cs = context.fetchCodeSystem(system);
if (cs == null) {
warningMessage = "Unable to resolve system "+system+" - system is not specified or implicit";
if (!inExpansion)
throw new FHIRException(warningMessage);
}
if (cs!=null && cs.getContent() != CodeSystemContentMode.COMPLETE) {
warningMessage = "Unable to resolve system "+system+" - system is not complete";
if (!inExpansion)
throw new FHIRException(warningMessage);
}
ValidationResult res =null;
if (cs!=null)
res = validateCode(code, cs);
boolean inExpansion = false;
String system = code.hasSystem() ? code.getSystem() : getValueSetSystem();
if (options.getValueSetMode() != ValueSetMode.CHECK_MEMERSHIP_ONLY) {
if (system == null && !code.hasDisplay()) { // dealing with just a plain code (enum)
system = systemForCodeInValueSet(code.getCode());
}
if (!code.hasSystem())
code.setSystem(system);
inExpansion = checkExpansion(code);
CodeSystem cs = context.fetchCodeSystem(system);
if (cs == null) {
warningMessage = "Unable to resolve system "+system+" - system is not specified or implicit";
if (!inExpansion)
throw new FHIRException(warningMessage);
}
if (cs!=null && cs.getContent() != CodeSystemContentMode.COMPLETE) {
warningMessage = "Unable to resolve system "+system+" - system is not complete";
if (!inExpansion)
throw new FHIRException(warningMessage);
}
if (cs!=null)
res = validateCode(code, cs);
} else {
inExpansion = checkExpansion(code);
}
// then, if we have a value set, we check it's in the value set
if ((res==null || res.isOk()) && valueset != null && !codeInValueSet(system, code.getCode())) {
if (!inExpansion)
res.setMessage("Not in value set "+valueset.getUrl()).setSeverity(IssueSeverity.ERROR);
else if (warningMessage!=null)
res = new ValidationResult(IssueSeverity.WARNING, "Code found in expansion, however: " + warningMessage);
else
res.setMessage("Code found in expansion, however: " + res.getMessage());
if (valueset != null && options.getValueSetMode() != ValueSetMode.NO_MEMBERSHIP_CHECK) {
if ((res==null || res.isOk()) && !codeInValueSet(system, code.getCode())) {
if (!inExpansion)
res.setMessage("Not in value set "+valueset.getUrl()).setSeverity(IssueSeverity.ERROR);
else if (warningMessage!=null)
res = new ValidationResult(IssueSeverity.WARNING, "Code found in expansion, however: " + warningMessage);
else
res.setMessage("Code found in expansion, however: " + res.getMessage());
}
}
return res;
}

View File

@ -27,4 +27,8 @@ public interface ToolingClientLogger {
public void logRequest(String method, String url, List<String> headers, byte[] body);
public void logResponse(String outcome, List<String> headers, byte[] body);
public String getLastId();
public void clearLastId();
}

View File

@ -1,10 +1,16 @@
package org.hl7.fhir.utilities.validation;
public class ValidationOptions {
public enum ValueSetMode {
ALL_CHECKS, CHECK_MEMERSHIP_ONLY, NO_MEMBERSHIP_CHECK
}
private String language;
private boolean useServer = true;
private boolean useClient = true;
private boolean guessSystem = false;
private ValueSetMode valueSetMode = ValueSetMode.ALL_CHECKS;
public ValidationOptions() {
super();
@ -67,10 +73,28 @@ public class ValidationOptions {
public String toJson() {
return "\"lang\":\""+language+"\", \"useServer\":\""+Boolean.toString(useServer)+"\", \"useClient\":\""+Boolean.toString(useClient)+"\", \"guessSystem\":\""+Boolean.toString(guessSystem)+"\"";
return "\"lang\":\""+language+"\", \"useServer\":\""+Boolean.toString(useServer)+"\", \"useClient\":\""+Boolean.toString(useClient)+"\", \"guessSystem\":\""+Boolean.toString(guessSystem)+"\", \"valueSetMode\":\""+valueSetMode.toString()+"\"";
}
public static ValidationOptions defaults() {
return new ValidationOptions("en-US");
}
public ValidationOptions checkValueSetOnly() {
ValidationOptions n = this.copy();
n.valueSetMode = ValueSetMode.CHECK_MEMERSHIP_ONLY;
return n;
}
public ValidationOptions noCheckValueSetMembership() {
ValidationOptions n = this.copy();
n.valueSetMode = ValueSetMode.NO_MEMBERSHIP_CHECK;
return n;
}
public ValueSetMode getValueSetMode() {
return valueSetMode;
}
}

View File

@ -530,7 +530,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
public void addAncestorProfiles(StructureDefinition sd) {
if (sd.hasDerivation() && sd.getDerivation().equals(StructureDefinition.TypeDerivationRule.CONSTRAINT)) {
if (sd.hasDerivation() && sd.getDerivation() == StructureDefinition.TypeDerivationRule.CONSTRAINT) {
StructureDefinition parentSd = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition());
if (parentSd != null && !profiles.containsKey(parentSd)) {
ProfileUsage pu = new ProfileUsage(parentSd);
@ -944,7 +944,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
return true; // we don't validate these
else {
CodeSystem cs = getCodeSystem(system);
if (rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, cs != null, "Unknown Code System " + system)) {
if (rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, cs != null, "Unknown Code System '" + system+"'")) {
ConceptDefinitionComponent def = getCodeDefinition(cs, code);
if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, def != null, "Unknown Code (" + system + "#" + code + ")"))
return warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, display == null || display.equals(def.getDisplay()), "Display should be '" + def.getDisplay() + "'");
@ -962,6 +962,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
rule(errors, IssueType.CODEINVALID, element.line(), element.col(), path, false, "Invalid System URI: "+system+" - cannot use a value set URI as a system");
// Lloyd: This error used to prohibit checking for downstream issues, but there are some cases where that checking needs to occur. Please talk to me before changing the code back.
}
hint(errors, IssueType.UNKNOWN, element.line(), element.col(), path, false, "Code System URI '"+system+"' is unknown so the code cannot be validated");
return true;
}
catch (Exception e) {
@ -1076,7 +1077,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (!atLeastOneSystemIsSupported && binding.getStrength() == BindingStrength.EXAMPLE) {
// ignore this since we can't validate but it doesn't matter..
} else {
ValidationResult vr = context.validateCode(new ValidationOptions(stack.workingLang), cc, valueset); // we're going to validate the codings directly
ValidationResult vr = context.validateCode(new ValidationOptions(stack.workingLang).checkValueSetOnly(), cc, valueset); // we're going to validate the codings directly, so only check the valueset
if (!vr.isOk()) {
bindingsOk = false;
if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) {
@ -1112,12 +1113,16 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
// to validate, we'll validate that the codes actually exist
if (bindingsOk) {
for (Coding nextCoding : cc.getCoding()) {
String nextCode = nextCoding.getCode();
String nextSystem = nextCoding.getSystem();
if (isNotBlank(nextCode) && isNotBlank(nextSystem) && context.supportsSystem(nextSystem)) {
ValidationResult vr = context.validateCode(new ValidationOptions(stack.workingLang), nextSystem, nextCode, null);
if (!vr.isOk()) {
txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, "Code {0} is not a valid code in code system {1}", nextCode, nextSystem);
if (isNotBlank(nextCoding.getCode()) && isNotBlank(nextCoding.getSystem()) && context.supportsSystem(nextCoding.getSystem())) {
ValidationResult vr = context.validateCode(new ValidationOptions(stack.workingLang).noCheckValueSetMembership(), nextCoding, valueset);
if (vr.getSeverity() != null) {
if (vr.getSeverity() == IssueSeverity.INFORMATION) {
txHint(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getMessage());
} else if (vr.getSeverity() == IssueSeverity.WARNING) {
txWarning(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getMessage());
} else {
txRule(errors, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getMessage());
}
}
}
}
@ -4335,9 +4340,6 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
Element resource, Element element, String actualType, NodeStack stack, boolean inCodeableConcept, boolean checkDisplayInContext, String extensionUrl) throws FHIRException, FHIRException, IOException {
// element.markValidation(profile, definition);
if (debug) {
System.out.println(" "+stack.getLiteralPath());
}
// time = System.nanoTime();
// check type invariants
checkInvariants(hostContext, errors, profile, definition, resource, element, stack, false);
@ -4376,6 +4378,7 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
public void checkChild(ValidatorHostContext hostContext, List<ValidationMessage> errors, StructureDefinition profile, ElementDefinition definition,
Element resource, Element element, String actualType, NodeStack stack, boolean inCodeableConcept, boolean checkDisplayInContext, ElementInfo ei, String extensionUrl)
throws FHIRException, IOException, DefinitionException {
List<String> profiles = new ArrayList<String>();
if (ei.definition != null) {
String type = null;
@ -4446,6 +4449,9 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
}
}
NodeStack localStack = stack.push(ei.element, ei.count, ei.definition, type == null ? typeDefn : resolveType(type, ei.definition.getType()));
if (debug) {
System.out.println(" "+localStack.getLiteralPath());
}
String localStackLiterapPath = localStack.getLiteralPath();
String eiPath = ei.path;
assert(eiPath.equals(localStackLiterapPath)) : "ei.path: " + ei.path + " - localStack.getLiteralPath: " + localStackLiterapPath;

View File

@ -276,6 +276,11 @@ public class Validator {
System.out.println("Specified destination (-dest parameter) is not valid: \""+dest+"\")");
else {
// first, prepare the context
String txLog = null;
if (hasParam(args, "-txLog")) {
txLog = getParam(args, "-txLog");
new File(txLog).delete();
}
String v = getParam(args, "-version");
if (v == null) {
v = "current";
@ -314,7 +319,7 @@ public class Validator {
}
String definitions = VersionUtilities.packageForVersion(v)+"#"+v;
System.out.println("Loading (v = "+v+", tx server http://tx.fhir.org)");
ValidationEngine validator = new ValidationEngine(definitions, "http://tx.fhir.org", null, FhirPublication.fromCode(v));
ValidationEngine validator = new ValidationEngine(definitions, "http://tx.fhir.org", txLog, FhirPublication.fromCode(v));
for (int i = 0; i < args.length; i++) {
if ("-ig".equals(args[i])) {
if (i+1 == args.length)

View File

@ -129,7 +129,7 @@ public class ValidationEngineTests {
int h = hints(op);
Assert.assertTrue(e == 1);
Assert.assertTrue(w == 0);
Assert.assertTrue(h == 0);
Assert.assertTrue(h == 1);
if (!TestUtilities.silent)
System.out.println(" .. done: "+Integer.toString(e)+" errors, "+Integer.toString(w)+" warnings, "+Integer.toString(h)+" information messages");
}

View File

@ -93,23 +93,28 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour
@Test
public void test() throws Exception {
System.out.println("Name: " + name+" - base");
String txLog = null;
if (content.has("txLog")) {
txLog = content.get("txLog").getAsString();
}
String v = "5.0";
List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
if (content.has("version"))
if (content.has("version")) {
v = content.get("version").getAsString();
}
v = VersionUtilities.getMajMin(v);
if (!ve.containsKey(v)) {
if (v.startsWith("5.0"))
ve.put(v, new ValidationEngine("hl7.fhir.r5.core#current", DEF_TX, null, FhirPublication.R5, true));
ve.put(v, new ValidationEngine("hl7.fhir.r5.core#current", DEF_TX, txLog, FhirPublication.R5, true));
else if (v.startsWith("3.0"))
ve.put(v, new ValidationEngine("hl7.fhir.r3.core#3.0.2", DEF_TX, null, FhirPublication.STU3, true));
ve.put(v, new ValidationEngine("hl7.fhir.r3.core#3.0.2", DEF_TX, txLog, FhirPublication.STU3, true));
else if (v.startsWith("4.0"))
ve.put(v, new ValidationEngine("hl7.fhir.r4.core#4.0.1", DEF_TX, null, FhirPublication.R4, true));
ve.put(v, new ValidationEngine("hl7.fhir.r4.core#4.0.1", DEF_TX, txLog, FhirPublication.R4, true));
else if (v.startsWith("1.0"))
ve.put(v, new ValidationEngine("hl7.fhir.r2.core#1.0.2", DEF_TX, null, FhirPublication.DSTU2, true));
ve.put(v, new ValidationEngine("hl7.fhir.r2.core#1.0.2", DEF_TX, txLog, FhirPublication.DSTU2, true));
else if (v.startsWith("1.4"))
ve.put(v, new ValidationEngine("hl7.fhir.r2b.core#1.4.0", DEF_TX, null, FhirPublication.DSTU2016May, true));
ve.put(v, new ValidationEngine("hl7.fhir.r2b.core#1.4.0", DEF_TX, txLog, FhirPublication.DSTU2016May, true));
else
throw new Exception("unknown version "+v);
}
@ -155,6 +160,11 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour
}
}
List<ValidationMessage> errors = new ArrayList<ValidationMessage>();
if (content.getAsJsonObject("java").has("debug")) {
val.setDebug(content.getAsJsonObject("java").get("debug").getAsBoolean());
} else {
val.setDebug(false);
}
if (name.endsWith(".json"))
val.validate(null, errors, IOUtils.toInputStream(testCaseContent, Charsets.UTF_8), FhirFormat.JSON);
else
@ -277,7 +287,7 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour
}
if (vm.getLevel() == IssueSeverity.INFORMATION) {
hc++;
if (java.has("infoCount")) {
if (java.has("infoCount") || java.has("debug")) {
System.out.println("hint: "+vm.getDisplay());
}
}