mirror of
https://github.com/hapifhir/org.hl7.fhir.core.git
synced 2025-03-05 19:09:11 +00:00
fixing broken links, and r4/r5 map testing
This commit is contained in:
parent
b5bbe5108b
commit
824f51f82e
@ -323,48 +323,48 @@ public class AdditionalBindingsRenderer {
|
||||
boolean r5 = context == null || context.getWorker() == null ? false : VersionUtilities.isR5Plus(context.getWorker().getVersion());
|
||||
switch (purpose) {
|
||||
case "maximum":
|
||||
td.ah(r5 ? "valueset-additional-binding-purpose.html#additional-binding-purpose-maximum" : corePath+"extension-elementdefinition-maxvalueset.html", "A required binding, for use when the binding strength is 'extensible' or 'preferred'").tx("Max Binding");
|
||||
td.ah(r5 ? corePath+"valueset-additional-binding-purpose.html#additional-binding-purpose-maximum" : corePath+"extension-elementdefinition-maxvalueset.html", "A required binding, for use when the binding strength is 'extensible' or 'preferred'").tx("Max Binding");
|
||||
break;
|
||||
case "minimum":
|
||||
td.ah(r5 ? "valueset-additional-binding-purpose.html#additional-binding-purpose-minimum" : corePath+"extension-elementdefinition-minvalueset.html", "The minimum allowable value set - any conformant system SHALL support all these codes").tx("Min Binding");
|
||||
td.ah(r5 ? corePath+"valueset-additional-binding-purpose.html#additional-binding-purpose-minimum" : corePath+"extension-elementdefinition-minvalueset.html", "The minimum allowable value set - any conformant system SHALL support all these codes").tx("Min Binding");
|
||||
break;
|
||||
case "required" :
|
||||
td.ah(r5 ? "valueset-additional-binding-purpose.html#additional-binding-purpose-required" : corePath+"terminologies.html#strength", "Validators will check this binding (strength = required)").tx("Required Binding");
|
||||
td.ah(r5 ? corePath+"valueset-additional-binding-purpose.html#additional-binding-purpose-required" : corePath+"terminologies.html#strength", "Validators will check this binding (strength = required)").tx("Required Binding");
|
||||
break;
|
||||
case "extensible" :
|
||||
td.ah(r5 ? "valueset-additional-binding-purpose.html#additional-binding-purpose-extensible" : corePath+"terminologies.html#strength", "Validators will check this binding (strength = extensible)").tx("Extensible Binding");
|
||||
td.ah(r5 ? corePath+"valueset-additional-binding-purpose.html#additional-binding-purpose-extensible" : corePath+"terminologies.html#strength", "Validators will check this binding (strength = extensible)").tx("Extensible Binding");
|
||||
break;
|
||||
case "current" :
|
||||
if (r5) {
|
||||
td.ah(r5 ? "valueset-additional-binding-purpose.html#additional-binding-purpose-current" : corePath+"terminologies.html#strength", "New records are required to use this value set, but legacy records may use other codes").tx("Current Binding");
|
||||
td.ah(r5 ? corePath+"valueset-additional-binding-purpose.html#additional-binding-purpose-current" : corePath+"terminologies.html#strength", "New records are required to use this value set, but legacy records may use other codes").tx("Current Binding");
|
||||
} else {
|
||||
td.span(null, "New records are required to use this value set, but legacy records may use other codes").tx("Required");
|
||||
}
|
||||
break;
|
||||
case "preferred" :
|
||||
if (r5) {
|
||||
td.ah(r5 ? "valueset-additional-binding-purpose.html#additional-binding-purpose-preferred" : corePath+"terminologies.html#strength", "This is the value set that is recommended (documentation should explain why)").tx("Preferred Binding");
|
||||
td.ah(r5 ? corePath+"valueset-additional-binding-purpose.html#additional-binding-purpose-preferred" : corePath+"terminologies.html#strength", "This is the value set that is recommended (documentation should explain why)").tx("Preferred Binding");
|
||||
} else {
|
||||
td.span(null, "This is the value set that is recommended (documentation should explain why)").tx("Recommended");
|
||||
}
|
||||
break;
|
||||
case "ui" :
|
||||
if (r5) {
|
||||
td.ah(r5 ? "valueset-additional-binding-purpose.html#additional-binding-purpose-ui" : corePath+"terminologies.html#strength", "This value set is provided to user look up in a given context").tx("UI Binding");
|
||||
td.ah(r5 ? corePath+"valueset-additional-binding-purpose.html#additional-binding-purpose-ui" : corePath+"terminologies.html#strength", "This value set is provided to user look up in a given context").tx("UI Binding");
|
||||
} else {
|
||||
td.span(null, "This value set is provided to user look up in a given context").tx("UI");
|
||||
}
|
||||
break;
|
||||
case "starter" :
|
||||
if (r5) {
|
||||
td.ah(r5 ? "valueset-additional-binding-purpose.html#additional-binding-purpose-starter" : corePath+"terminologies.html#strength", "This value set is a good set of codes to start with when designing your system").tx("Starter Set");
|
||||
td.ah(r5 ? corePath+"valueset-additional-binding-purpose.html#additional-binding-purpose-starter" : corePath+"terminologies.html#strength", "This value set is a good set of codes to start with when designing your system").tx("Starter Set");
|
||||
} else {
|
||||
td.span(null, "This value set is a good set of codes to start with when designing your system").tx("Starter");
|
||||
}
|
||||
break;
|
||||
case "component" :
|
||||
if (r5) {
|
||||
td.ah(r5 ? "valueset-additional-binding-purpose.html#additional-binding-purpose-component" : corePath+"terminologies.html#strength", "This value set is a component of the base value set").tx("Component");
|
||||
td.ah(r5 ? corePath+"valueset-additional-binding-purpose.html#additional-binding-purpose-component" : corePath+"terminologies.html#strength", "This value set is a component of the base value set").tx("Component");
|
||||
} else {
|
||||
td.span(null, "This value set is a component of the base value set").tx("Component");
|
||||
}
|
||||
|
@ -243,8 +243,9 @@ public abstract class ParserBase {
|
||||
return logical;
|
||||
}
|
||||
|
||||
public void setLogical(StructureDefinition logical) {
|
||||
public ParserBase setLogical(StructureDefinition logical) {
|
||||
this.logical = logical;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -2761,4 +2761,30 @@ public class StructureMapUtilities {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ResolvedGroup getGroupForUrl(StructureMap map, String url, StructureMapInputMode mode) {
|
||||
for (StructureMapGroupComponent grp : map.getGroup()) {
|
||||
if (grp.getTypeMode() != StructureMapGroupTypeMode.NULL) {
|
||||
for (StructureMapGroupInputComponent p : grp.getInput()) {
|
||||
if (mode == null || mode == p.getMode()) {
|
||||
String t = resolveInputType(p, map);
|
||||
if (url.equals(t)) {
|
||||
return new ResolvedGroup(map, grp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getInputType(ResolvedGroup grp, StructureMapInputMode mode) {
|
||||
if (grp.getTargetGroup().getInput().size() != 2 || grp.getTargetGroup().getInput().get(0).getMode() == grp.getTargetGroup().getInput().get(1).getMode()) {
|
||||
return null;
|
||||
} else if (grp.getTargetGroup().getInput().get(0).getMode() == mode) {
|
||||
return resolveInputType(grp.getTargetGroup().getInput().get(0), grp.getTargetMap());
|
||||
} else {
|
||||
return resolveInputType(grp.getTargetGroup().getInput().get(1), grp.getTargetMap());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -47,7 +47,7 @@ public class ValidatorUtils {
|
||||
}
|
||||
}
|
||||
|
||||
protected static IWorkerContext.IContextResourceLoader loaderForVersion(String version) {
|
||||
public static IWorkerContext.IContextResourceLoader loaderForVersion(String version) {
|
||||
if (Utilities.noString(version)) {
|
||||
return null;
|
||||
}
|
||||
|
@ -1,26 +1,96 @@
|
||||
package org.hl7.fhir.validation.special;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hl7.fhir.r5.model.Enumerations.PublicationStatus;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
|
||||
import org.hl7.fhir.r5.model.StructureMap;
|
||||
import org.hl7.fhir.r5.model.StructureMap.StructureMapInputMode;
|
||||
import org.hl7.fhir.convertors.loaders.loaderR5.R4ToR5Loader;
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
import org.hl7.fhir.r4.formats.IParser.OutputStyle;
|
||||
import org.hl7.fhir.r4.model.Resource;
|
||||
import org.hl7.fhir.r4.model.ResourceFactory;
|
||||
import org.hl7.fhir.r4.test.utils.TestingUtilities;
|
||||
import org.hl7.fhir.r5.context.SimpleWorkerContext;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext.IContextResourceLoader;
|
||||
import org.hl7.fhir.r5.context.SimpleWorkerContext.SimpleWorkerContextBuilder;
|
||||
import org.hl7.fhir.r5.elementmodel.Element;
|
||||
import org.hl7.fhir.r5.utils.structuremap.ResolvedGroup;
|
||||
import org.hl7.fhir.r5.utils.structuremap.StructureMapUtilities;
|
||||
import org.hl7.fhir.r5.utils.structuremap.VariableMode;
|
||||
import org.hl7.fhir.utilities.TextFile;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.VersionUtilities;
|
||||
import org.hl7.fhir.utilities.json.JsonException;
|
||||
import org.hl7.fhir.utilities.json.model.JsonElement;
|
||||
import org.hl7.fhir.utilities.json.model.JsonObject;
|
||||
import org.hl7.fhir.utilities.json.model.JsonProperty;
|
||||
import org.hl7.fhir.utilities.json.parser.JsonParser;
|
||||
import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager;
|
||||
import org.hl7.fhir.utilities.npm.NpmPackage;
|
||||
import org.hl7.fhir.validation.IgLoader;
|
||||
import org.hl7.fhir.validation.ValidatorUtils;
|
||||
import org.hl7.fhir.validation.special.R4R5MapTester.Stats;
|
||||
|
||||
public class R4R5MapTester {
|
||||
|
||||
public class Stats {
|
||||
|
||||
private Set<String> errors = new HashSet<>();
|
||||
private int total;
|
||||
private int parsed;
|
||||
private int forward;
|
||||
|
||||
public void example() {
|
||||
total++;
|
||||
}
|
||||
|
||||
public void parsed() {
|
||||
parsed++;
|
||||
}
|
||||
|
||||
public void error(String s) {
|
||||
errors.add(s);
|
||||
}
|
||||
|
||||
public void forward() {
|
||||
forward++;
|
||||
}
|
||||
|
||||
public int totalCount() {
|
||||
return total;
|
||||
}
|
||||
|
||||
public int parseCount() {
|
||||
return parsed;
|
||||
}
|
||||
|
||||
public String summary() {
|
||||
if (errors.size() == 0) {
|
||||
return "All OK";
|
||||
} else {
|
||||
return String.join(", ", errors);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean ok() {
|
||||
return errors.size() == 0;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean saveProcess = false;
|
||||
|
||||
private SimpleWorkerContext context;
|
||||
private FilesystemPackageCacheManager pcm;
|
||||
private StructureMapUtilities utils;
|
||||
@ -32,18 +102,29 @@ public class R4R5MapTester {
|
||||
new R4R5MapTester().testMaps(args[0]);
|
||||
}
|
||||
|
||||
private void testMaps(String src) throws JsonException, IOException {
|
||||
public void testMaps(String src) throws JsonException, IOException {
|
||||
log("Load Test Outcomes");
|
||||
JsonObject json = JsonParser.parseObjectFromFile(Utilities.path(src, "input", "_data", "conversions.json"));
|
||||
log("Load R5");
|
||||
pcm = new FilesystemPackageCacheManager(true);
|
||||
context = new SimpleWorkerContextBuilder().withAllowLoadingDuplicates(true).fromPackage(pcm.loadPackage("hl7.fhir.r5.core#current"));
|
||||
log("Load Maps");
|
||||
context.loadFromPackage(pcm.loadPackage("hl7.fhir.uv.extensions#dev"), null);
|
||||
// context.loadFromPackage(pcm.loadPackage(), null);
|
||||
|
||||
loadPackage("hl7.fhir.uv.extensions#dev");
|
||||
loadPackage("hl7.fhir.r4.core#4.0.1");
|
||||
loadPackage("hl7.fhir.r4b.core#4.3.0");
|
||||
|
||||
log("Load R4 Examples");
|
||||
NpmPackage r4Examples = pcm.loadPackage("hl7.fhir.r4.examples");
|
||||
log("Load R4B Examples");
|
||||
NpmPackage r4bExamples = pcm.loadPackage("hl7.fhir.r4b.examples");
|
||||
|
||||
|
||||
utils = new StructureMapUtilities(context);
|
||||
allMaps = context.fetchResourcesByType(StructureMap.class);
|
||||
|
||||
log("Resource Count = "+context.getResourceNames().size());
|
||||
log("Go. "+context.getResourceNames().size()+" types of resources");
|
||||
log("Map Count = "+allMaps.size());
|
||||
boolean changed = false;
|
||||
for (JsonProperty jp : json.getProperties()) {
|
||||
@ -53,8 +134,8 @@ public class R4R5MapTester {
|
||||
StructureDefinition sd = context.fetchTypeDefinition(rn);
|
||||
List<StructureMap> mapSrc = utils.getMapsForUrl(allMaps, sd.getUrl(), StructureMapInputMode.SOURCE);
|
||||
List<StructureMap> mapTgt = utils.getMapsForUrl(allMaps, sd.getUrl(), StructureMapInputMode.TARGET);
|
||||
changed = checkMaps(rn, o.getJsonObject("r4"), "http://hl7.org/fhir/4.0", mapSrc, mapTgt) || changed;
|
||||
changed = checkMaps(rn, o.getJsonObject("r4b"), "http://hl7.org/fhir/4.0", mapSrc, mapTgt) || changed;
|
||||
changed = checkMaps(sd, o.getJsonObject("r4"), "http://hl7.org/fhir/4.0", mapSrc, mapTgt, r4Examples) || changed;
|
||||
changed = checkMaps(sd, o.getJsonObject("r4b"), "http://hl7.org/fhir/4.3", mapSrc, mapTgt, r4bExamples) || changed;
|
||||
}
|
||||
if (changed) {
|
||||
JsonParser.compose(json, new FileOutputStream(Utilities.path(src, "input", "_data", "conversions.json")), true);
|
||||
@ -76,7 +157,15 @@ public class R4R5MapTester {
|
||||
|
||||
}
|
||||
|
||||
private boolean checkMaps(String rn, JsonObject json, String ns, List<StructureMap> mapSrc, List<StructureMap> mapTgt) {
|
||||
private void loadPackage(String pid) throws FHIRException, IOException {
|
||||
log("Load "+pid);
|
||||
NpmPackage npm = pcm.loadPackage(pid);
|
||||
IContextResourceLoader loader = ValidatorUtils.loaderForVersion(npm.fhirVersion());
|
||||
loader.setPatchUrls(VersionUtilities.isCorePackage(npm.id()));
|
||||
int count = context.loadFromPackage(npm, loader);
|
||||
}
|
||||
|
||||
private boolean checkMaps(StructureDefinition sd, JsonObject json, String ns, List<StructureMap> mapSrc, List<StructureMap> mapTgt, NpmPackage examples) throws IOException {
|
||||
List<StructureMap> src = utils.getMapsForUrlPrefix(mapSrc, ns, StructureMapInputMode.TARGET);
|
||||
List<StructureMap> tgt = utils.getMapsForUrlPrefix(mapTgt, ns, StructureMapInputMode.SOURCE);
|
||||
if (src.size() + tgt.size() == 0) {
|
||||
@ -92,9 +181,30 @@ public class R4R5MapTester {
|
||||
isDraft = map.getStatus() == PublicationStatus.DRAFT || isDraft;
|
||||
}
|
||||
json.set("status", ""+(src.size()+tgt.size())+" Maps Defined"+(isDraft ? " (draft)" : ""));
|
||||
if (context.getResourceNames().contains(rn)) {
|
||||
json.set("testColor", "#ffcccc");
|
||||
json.set("testMessage", "To Do");
|
||||
json.set("testColor", "#ffcccc");
|
||||
if (sd.getKind() == StructureDefinitionKind.RESOURCE) {
|
||||
if (tgt.size() == 1 && src.size() == 1) {
|
||||
StructureMap tgtM = tgt.get(0);
|
||||
ResolvedGroup tgtG = utils.getGroupForUrl(tgtM, sd.getUrl(), StructureMapInputMode.TARGET);
|
||||
String tgtU = utils.getInputType(tgtG, StructureMapInputMode.SOURCE);
|
||||
assert tgtU.startsWith(ns);
|
||||
StructureMap srcM = src.get(0);
|
||||
ResolvedGroup srcG = utils.getGroupForUrl(srcM, sd.getUrl(), StructureMapInputMode.SOURCE);
|
||||
String srcU = utils.getInputType(srcG, StructureMapInputMode.TARGET);
|
||||
assert srcU.startsWith(ns);
|
||||
if (!srcU.equals(tgtU)) {
|
||||
json.set("testMessage", "Maps do not round trip to same resource ("+Utilities.tail(srcU)+" -> "+Utilities.tail(tgtU)+") - can't test");
|
||||
} else {
|
||||
StructureDefinition tsd = context.fetchResource(StructureDefinition.class, srcU);
|
||||
if (tsd == null) {
|
||||
json.set("testMessage", "Undefined type "+srcU);
|
||||
} else {
|
||||
testRoundTrips(sd, json, tgtG, srcG, tsd, examples);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
json.set("testMessage", "Multiple matching maps ("+src.size()+"/"+tgt.size()+") - no tests performed");
|
||||
}
|
||||
} else {
|
||||
json.set("testColor", "#eeeeee");
|
||||
json.set("testMessage", "n/a");
|
||||
@ -103,6 +213,44 @@ public class R4R5MapTester {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void testRoundTrips(StructureDefinition sd, JsonObject json, ResolvedGroup tgtG, ResolvedGroup srcG, StructureDefinition tsd, NpmPackage examples) throws IOException {
|
||||
|
||||
Stats stats = new Stats();
|
||||
for (String s : examples.listResources(tsd.getType())) {
|
||||
log(" Test "+examples.id()+"::"+s);
|
||||
try {
|
||||
testRoundTrip(sd, tsd, tgtG, srcG, stats, examples.load("package", s));
|
||||
} catch (Exception e) {
|
||||
log("error: "+e.getMessage());
|
||||
stats.error("Error: "+e.getMessage());
|
||||
}
|
||||
}
|
||||
json.set("total", stats.totalCount());
|
||||
json.set("parsed", stats.parseCount());
|
||||
json.set("testMessage", stats.summary());
|
||||
if (stats.ok()) {
|
||||
json.set("testColor", "#d4ffdf");
|
||||
}
|
||||
}
|
||||
|
||||
private void testRoundTrip(StructureDefinition sd, StructureDefinition tsd, ResolvedGroup tgtG, ResolvedGroup srcG, Stats stats, InputStream stream) throws FHIRFormatError, DefinitionException, FHIRException, IOException {
|
||||
stats.example();
|
||||
Element r4 = new org.hl7.fhir.r5.elementmodel.JsonParser(context).setLogical(tsd).parseSingle(stream);
|
||||
stats.parsed();
|
||||
String id = r4.getIdBase();
|
||||
checkSave(id, "src.loaded", r4);
|
||||
|
||||
Resource r5 = ResourceFactory.createResource(sd.getType());
|
||||
utils.transform(context, r4, tgtG.getTargetMap(), r4);
|
||||
stats.forward();
|
||||
}
|
||||
|
||||
private void checkSave(String id, String state, Element e) {
|
||||
if (saveProcess) {
|
||||
// new org.hl7.fhir.r4.elementmodel.JsonParser(context).compose(r3, bso, OutputStyle.PRETTY, null);
|
||||
}
|
||||
}
|
||||
|
||||
private void log(String msg) {
|
||||
System.out.println(msg);
|
||||
}
|
||||
|
2
pom.xml
2
pom.xml
@ -19,7 +19,7 @@
|
||||
|
||||
<properties>
|
||||
<hapi_fhir_version>6.2.1</hapi_fhir_version>
|
||||
<validator_test_case_version>1.2.20</validator_test_case_version>
|
||||
<validator_test_case_version>1.2.21-SNAPSHOT</validator_test_case_version>
|
||||
<junit_jupiter_version>5.7.1</junit_jupiter_version>
|
||||
<junit_platform_launcher_version>1.8.2</junit_platform_launcher_version>
|
||||
<maven_surefire_version>3.0.0-M5</maven_surefire_version>
|
||||
|
Loading…
x
Reference in New Issue
Block a user