mirror of
https://github.com/hapifhir/org.hl7.fhir.core.git
synced 2025-03-09 14:31:17 +00:00
significant work on tests to support version comparison
This commit is contained in:
parent
115fa8a497
commit
50dbc9bda1
@ -9,6 +9,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
|
||||
import org.hl7.fhir.r5.model.CanonicalResource;
|
||||
import org.hl7.fhir.r5.model.PrimitiveType;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
@ -81,6 +82,34 @@ public abstract class CanonicalResourceComparer extends ResourceComparer {
|
||||
this.intersection = intersection;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String toTable() {
|
||||
String s = null;
|
||||
if (left != null && right != null && !left.getUrl().equals(right.getUrl())) {
|
||||
s = "<td>"+left.getUrl()+"</td><td>"+right.getUrl()+"</td>";
|
||||
} else if (left != null) {
|
||||
s = "<td colspan=2>"+left.getUrl()+"</td>";
|
||||
} else {
|
||||
s = "<td colspan=2>"+right.getUrl()+"</td>";
|
||||
}
|
||||
s = s + "<td><a href=\""+getId()+".html\">Comparison</a></td>";
|
||||
s = s + "<td>"+outcomeSummary()+"</td>";
|
||||
return "<tr style=\"background-color: "+(hasErrors() ? COLOR_DIFFERENT : COLOR_DIFFERENT_LESS)+"\">"+s+"</tr>\r\n";
|
||||
}
|
||||
|
||||
protected boolean hasErrors() {
|
||||
MessageCounts cnts = new MessageCounts();
|
||||
countMessages(cnts);
|
||||
return cnts.getErrors() > 0;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void countMessages(MessageCounts cnts) {
|
||||
for (StructuralMatch<String> sm : metadata.values()) {
|
||||
sm.countMessages(cnts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public CanonicalResourceComparer(ComparisonSession session) {
|
||||
|
@ -9,6 +9,7 @@ import java.util.Map;
|
||||
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
|
||||
import org.hl7.fhir.r5.model.CodeSystem;
|
||||
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionDesignationComponent;
|
||||
@ -55,6 +56,18 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
|
||||
protected String summary() {
|
||||
return "CodeSystem: "+left.present()+" vs "+right.present();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String fhirType() {
|
||||
return "CodeSystem";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void countMessages(MessageCounts cnts) {
|
||||
super.countMessages(cnts);
|
||||
combined.countMessages(cnts);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private CodeSystem right;
|
||||
|
@ -2,6 +2,8 @@ package org.hl7.fhir.r5.comparison;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@ -13,6 +15,7 @@ import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.PathEngineException;
|
||||
import org.hl7.fhir.r5.comparison.CodeSystemComparer.CodeSystemComparison;
|
||||
import org.hl7.fhir.r5.comparison.ProfileComparer.ProfileComparison;
|
||||
import org.hl7.fhir.r5.comparison.ResourceComparer.PlaceHolderComparison;
|
||||
import org.hl7.fhir.r5.comparison.ResourceComparer.ResourceComparison;
|
||||
import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison;
|
||||
|
||||
@ -35,14 +38,16 @@ import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
|
||||
|
||||
public class ComparisonRenderer implements IEvaluationContext {
|
||||
|
||||
private IWorkerContext context;
|
||||
private IWorkerContext contextLeft;
|
||||
private IWorkerContext contextRight;
|
||||
private ComparisonSession session;
|
||||
private Map<String, String> templates = new HashMap<>();
|
||||
private String folder;
|
||||
|
||||
public ComparisonRenderer(IWorkerContext context, String folder, ComparisonSession session) {
|
||||
public ComparisonRenderer(IWorkerContext contextLeft, IWorkerContext contextRight, String folder, ComparisonSession session) {
|
||||
super();
|
||||
this.context = context;
|
||||
this.contextLeft = contextLeft;
|
||||
this.contextRight = contextRight;
|
||||
this.folder = folder;
|
||||
this.session = session;
|
||||
}
|
||||
@ -54,12 +59,13 @@ public class ComparisonRenderer implements IEvaluationContext {
|
||||
public void render() throws IOException {
|
||||
dumpBinaries();
|
||||
StringBuilder b = new StringBuilder();
|
||||
|
||||
for (String id : sorted(session.getCompares().keySet())) {
|
||||
ResourceComparison comp = session.getCompares().get(id);
|
||||
renderComparison(id, comp);
|
||||
b.append("<li><a href=\""+comp.getId()+".html\">"+Utilities.escapeXml(comp.summary())+"</a></li>\r\n");
|
||||
}
|
||||
b.append("<table class=\"grid\">\r\n");
|
||||
List<String> list = sorted(session.getCompares().keySet());
|
||||
processList(list, b, "CodeSystem");
|
||||
processList(list, b, "ValueSet");
|
||||
processList(list, b, "StructureDefinition");
|
||||
b.append("</table>\r\n");
|
||||
|
||||
Map<String, Base> vars = new HashMap<>();
|
||||
CodeSystemComparer cs = new CodeSystemComparer(session);
|
||||
vars.put("title", new StringType(session.getTitle()));
|
||||
@ -69,6 +75,23 @@ public class ComparisonRenderer implements IEvaluationContext {
|
||||
TextFile.stringToFile(cnt, file("index.html"));
|
||||
}
|
||||
|
||||
private void processList(List<String> list, StringBuilder b, String name) throws IOException {
|
||||
// TODO Auto-generated method stub
|
||||
boolean first = true;
|
||||
for (String id : list) {
|
||||
ResourceComparison comp = session.getCompares().get(id);
|
||||
if (comp.fhirType().equals(name)) {
|
||||
if (first) {
|
||||
first = false;
|
||||
b.append("<tr><td colspan=4><b>"+name+"</b></td></tr>\r\n");
|
||||
}
|
||||
renderComparison(id, comp);
|
||||
b.append(comp.toTable());
|
||||
//"<li><a href=\""+comp.getId()+".html\">"+Utilities.escapeXml(comp.summary())+"</a></li>\r\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> sorted(Set<String> keySet) {
|
||||
List<String> list = new ArrayList<>();
|
||||
list.addAll(keySet);
|
||||
@ -77,8 +100,11 @@ public class ComparisonRenderer implements IEvaluationContext {
|
||||
}
|
||||
|
||||
private void dumpBinaries() throws IOException {
|
||||
for (String k : context.getBinaries().keySet()) {
|
||||
TextFile.bytesToFile(context.getBinaries().get(k), Utilities.path(folder, k));
|
||||
for (String k : contextLeft.getBinaries().keySet()) {
|
||||
TextFile.bytesToFile(contextLeft.getBinaries().get(k), Utilities.path(folder, k));
|
||||
}
|
||||
for (String k : contextRight.getBinaries().keySet()) {
|
||||
TextFile.bytesToFile(contextRight.getBinaries().get(k), Utilities.path(folder, k));
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,9 +115,23 @@ public class ComparisonRenderer implements IEvaluationContext {
|
||||
renderValueSet(id, (ValueSetComparison) comp);
|
||||
} else if (comp instanceof CodeSystemComparison) {
|
||||
renderCodeSystem(id, (CodeSystemComparison) comp);
|
||||
} else if (comp instanceof PlaceHolderComparison) {
|
||||
renderPlaceHolder(id, (PlaceHolderComparison) comp);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderPlaceHolder(String id, PlaceHolderComparison comp) throws IOException {
|
||||
String cnt = "";
|
||||
if (comp.getE() != null) {
|
||||
StringWriter sw = new StringWriter();
|
||||
PrintWriter pw = new PrintWriter(sw);
|
||||
comp.getE().printStackTrace(pw);
|
||||
cnt = sw.toString();
|
||||
}
|
||||
cnt = "<html><body><pre>"+cnt+"</pre></body></html>\r\n";
|
||||
TextFile.stringToFile(cnt, file(comp.getId()+".html"));
|
||||
}
|
||||
|
||||
private void renderCodeSystem(String id, CodeSystemComparison comp) throws IOException {
|
||||
String template = templates.get("CodeSystem");
|
||||
Map<String, Base> vars = new HashMap<>();
|
||||
@ -138,7 +178,7 @@ public class ComparisonRenderer implements IEvaluationContext {
|
||||
private void renderProfile(String id, ProfileComparison comp) throws IOException {
|
||||
String template = templates.get("Profile");
|
||||
Map<String, Base> vars = new HashMap<>();
|
||||
ProfileComparer cs = new ProfileComparer(session, new ProfileUtilities(session.getContext(), null, session.getPkp()));
|
||||
ProfileComparer cs = new ProfileComparer(session, new ProfileUtilities(session.getContextLeft(), null, session.getPkp()), new ProfileUtilities(session.getContextRight(), null, session.getPkp()));
|
||||
vars.put("left", new StringType(comp.getLeft().present()));
|
||||
vars.put("right", new StringType(comp.getRight().present()));
|
||||
vars.put("leftId", new StringType(comp.getLeft().getId()));
|
||||
@ -155,7 +195,7 @@ public class ComparisonRenderer implements IEvaluationContext {
|
||||
}
|
||||
|
||||
private String processTemplate(String template, String name, Map<String, Base> vars) {
|
||||
LiquidEngine engine = new LiquidEngine(context, this);
|
||||
LiquidEngine engine = new LiquidEngine(contextRight, this);
|
||||
LiquidDocument doc = engine.parse(template, name+".template");
|
||||
return engine.evaluate(doc, Tuple.fromMap(vars), vars);
|
||||
}
|
||||
|
@ -25,24 +25,30 @@ import org.hl7.fhir.utilities.Utilities;
|
||||
public class ComparisonSession {
|
||||
|
||||
private Map<String, ResourceComparison> compares = new HashMap<>();
|
||||
private IWorkerContext context;
|
||||
private IWorkerContext contextLeft;
|
||||
private IWorkerContext contextRight;
|
||||
private String sessiondId;
|
||||
private int count;
|
||||
private boolean debug;
|
||||
private String title;
|
||||
private ProfileKnowledgeProvider pkp;
|
||||
|
||||
public ComparisonSession(IWorkerContext context, String title, ProfileKnowledgeProvider pkp) {
|
||||
public ComparisonSession(IWorkerContext contextLeft, IWorkerContext contextRight, String title, ProfileKnowledgeProvider pkp) {
|
||||
super();
|
||||
this.context = context;
|
||||
this.contextLeft = contextLeft;
|
||||
this.contextRight = contextRight;
|
||||
this.sessiondId = UUID.randomUUID().toString().toLowerCase();
|
||||
this.title = title;
|
||||
this.pkp = pkp;
|
||||
// debug = true;
|
||||
}
|
||||
|
||||
public IWorkerContext getContext() {
|
||||
return context;
|
||||
public IWorkerContext getContextLeft() {
|
||||
return contextLeft;
|
||||
}
|
||||
|
||||
public IWorkerContext getContextRight() {
|
||||
return contextRight;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
@ -50,11 +56,11 @@ public class ComparisonSession {
|
||||
}
|
||||
|
||||
public ResourceComparison compare(String left, String right) throws DefinitionException, FHIRFormatError, IOException {
|
||||
CanonicalResource l = (CanonicalResource) context.fetchResource(Resource.class, left);
|
||||
CanonicalResource l = (CanonicalResource) contextLeft.fetchResource(Resource.class, left);
|
||||
if (l == null) {
|
||||
throw new DefinitionException("Unable to resolve "+left);
|
||||
}
|
||||
CanonicalResource r = (CanonicalResource) context.fetchResource(Resource.class, right);
|
||||
CanonicalResource r = (CanonicalResource) contextRight.fetchResource(Resource.class, right);
|
||||
if (r == null) {
|
||||
throw new DefinitionException("Unable to resolve "+right);
|
||||
}
|
||||
@ -62,30 +68,54 @@ public class ComparisonSession {
|
||||
}
|
||||
|
||||
public ResourceComparison compare(CanonicalResource left, CanonicalResource right) throws DefinitionException, FHIRFormatError, IOException {
|
||||
String key = key(left.getUrl(), left.getVersion(), right.getUrl(), right.getVersion());
|
||||
if (compares.containsKey(key)) {
|
||||
// if null then the comparison is in progress.
|
||||
// this can happen when profiles refer to each other
|
||||
return compares.get(key);
|
||||
}
|
||||
compares.put(key, null);
|
||||
if (left instanceof CodeSystem && right instanceof CodeSystem) {
|
||||
CodeSystemComparer cs = new CodeSystemComparer(this);
|
||||
CodeSystemComparison csc = cs.compare((CodeSystem) left, (CodeSystem) right);
|
||||
if (left != null && right != null) {
|
||||
String key = key(left.getUrl(), left.getVersion(), right.getUrl(), right.getVersion());
|
||||
if (compares.containsKey(key)) {
|
||||
// if null then the comparison is in progress.
|
||||
// this can happen when profiles refer to each other
|
||||
return compares.get(key);
|
||||
}
|
||||
compares.put(key, null);
|
||||
try {
|
||||
if (left instanceof CodeSystem && right instanceof CodeSystem) {
|
||||
CodeSystemComparer cs = new CodeSystemComparer(this);
|
||||
CodeSystemComparison csc = cs.compare((CodeSystem) left, (CodeSystem) right);
|
||||
compares.put(key, csc);
|
||||
return csc;
|
||||
} else if (left instanceof ValueSet && right instanceof ValueSet) {
|
||||
ValueSetComparer cs = new ValueSetComparer(this);
|
||||
ValueSetComparison csc = cs.compare((ValueSet) left, (ValueSet) right);
|
||||
compares.put(key, csc);
|
||||
return csc;
|
||||
} else if (left instanceof StructureDefinition && right instanceof StructureDefinition) {
|
||||
ProfileComparer cs = new ProfileComparer(this, new ProfileUtilities(contextLeft, null, pkp), new ProfileUtilities(contextRight, null, pkp));
|
||||
ProfileComparison csc = cs.compare((StructureDefinition) left, (StructureDefinition) right);
|
||||
compares.put(key, csc);
|
||||
return csc;
|
||||
} else {
|
||||
throw new FHIRException("Unable to compare resources of type "+left.fhirType()+" and "+right.fhirType());
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
ResourceComparer.PlaceHolderComparison csc = new ResourceComparer.PlaceHolderComparison(left, right, e);
|
||||
compares.put(key, csc);
|
||||
return csc;
|
||||
}
|
||||
} else if (left != null) {
|
||||
String key = key(left.getUrl(), left.getVersion(), left.getUrl(), left.getVersion());
|
||||
if (compares.containsKey(key)) {
|
||||
return compares.get(key);
|
||||
}
|
||||
ResourceComparer.PlaceHolderComparison csc = new ResourceComparer.PlaceHolderComparison(left, right);
|
||||
compares.put(key, csc);
|
||||
return csc;
|
||||
} else if (left instanceof ValueSet && right instanceof ValueSet) {
|
||||
ValueSetComparer cs = new ValueSetComparer(this);
|
||||
ValueSetComparison csc = cs.compare((ValueSet) left, (ValueSet) right);
|
||||
compares.put(key, csc);
|
||||
return csc;
|
||||
} else if (left instanceof StructureDefinition && right instanceof StructureDefinition) {
|
||||
ProfileComparer cs = new ProfileComparer(this, new ProfileUtilities(context, null, pkp));
|
||||
ProfileComparison csc = cs.compare((StructureDefinition) left, (StructureDefinition) right);
|
||||
compares.put(key, csc);
|
||||
return csc;
|
||||
return csc;
|
||||
} else {
|
||||
throw new FHIRException("Unable to compare ");
|
||||
String key = key(right.getUrl(), right.getVersion(), right.getUrl(), right.getVersion());
|
||||
if (compares.containsKey(key)) {
|
||||
return compares.get(key);
|
||||
}
|
||||
ResourceComparer.PlaceHolderComparison csc = new ResourceComparer.PlaceHolderComparison(left, right);
|
||||
compares.put(key, csc);
|
||||
return csc;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,9 +9,11 @@ import java.util.List;
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
|
||||
import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison;
|
||||
import org.hl7.fhir.r5.conformance.ProfileUtilities;
|
||||
import org.hl7.fhir.r5.conformance.ProfileUtilities.UnusedTracker;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||
import org.hl7.fhir.r5.formats.IParser;
|
||||
import org.hl7.fhir.r5.model.Base;
|
||||
import org.hl7.fhir.r5.model.Coding;
|
||||
@ -63,16 +65,29 @@ public class ProfileComparer extends CanonicalResourceComparer {
|
||||
protected String summary() {
|
||||
return "Profile: "+left.present()+" vs "+right.present();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String fhirType() {
|
||||
return "StructureDefinition";
|
||||
}
|
||||
@Override
|
||||
protected void countMessages(MessageCounts cnts) {
|
||||
super.countMessages(cnts);
|
||||
combined.countMessages(cnts);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private ProfileUtilities utils;
|
||||
private ProfileUtilities utilsLeft;
|
||||
private ProfileUtilities utilsRight;
|
||||
|
||||
public ProfileComparer(ComparisonSession session, ProfileUtilities utils) {
|
||||
public ProfileComparer(ComparisonSession session, ProfileUtilities utilsLeft, ProfileUtilities utilsRight) {
|
||||
super(session);
|
||||
this.utils = utils;
|
||||
this.utilsLeft = utilsLeft;
|
||||
this.utilsRight = utilsRight;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -110,8 +125,8 @@ public class ProfileComparer extends CanonicalResourceComparer {
|
||||
comparePrimitives("baseDefinition", left.getBaseDefinitionElement(), right.getBaseDefinitionElement(), res.getMetadata(), IssueSeverity.ERROR, res);
|
||||
|
||||
if (left.getType().equals(right.getType())) {
|
||||
DefinitionNavigator ln = new DefinitionNavigator(session.getContext(), left);
|
||||
DefinitionNavigator rn = new DefinitionNavigator(session.getContext(), right);
|
||||
DefinitionNavigator ln = new DefinitionNavigator(session.getContextLeft(), left);
|
||||
DefinitionNavigator rn = new DefinitionNavigator(session.getContextRight(), right);
|
||||
StructuralMatch<ElementDefinition> sm = new StructuralMatch<ElementDefinition>(ln.current(), rn.current());
|
||||
compareElements(res, sm, ln.path(), null, ln, rn);
|
||||
res.combined = sm;
|
||||
@ -122,9 +137,9 @@ public class ProfileComparer extends CanonicalResourceComparer {
|
||||
private void check(StructureDefinition sd, String name) {
|
||||
if (sd == null)
|
||||
throw new DefinitionException("No StructureDefinition provided ("+name+": "+sd.getName()+")");
|
||||
if (sd.getType().equals("Extension")) {
|
||||
throw new DefinitionException("StructureDefinition is for an extension - use ExtensionComparer instead ("+name+": "+sd.getName()+")");
|
||||
}
|
||||
// if (sd.getType().equals("Extension")) {
|
||||
// throw new DefinitionException("StructureDefinition is for an extension - use ExtensionComparer instead ("+name+": "+sd.getName()+")");
|
||||
// }
|
||||
if (sd.getDerivation() == TypeDerivationRule.SPECIALIZATION) {
|
||||
throw new DefinitionException("StructureDefinition is not for an profile - can't be compared ("+name+": "+sd.getName()+")");
|
||||
}
|
||||
@ -143,10 +158,10 @@ public class ProfileComparer extends CanonicalResourceComparer {
|
||||
}
|
||||
|
||||
// not allowed to be different:
|
||||
ruleEqual(comp, res, left.current().getDefaultValue(), right.current().getDefaultValue(), "defaultValue", path);
|
||||
ruleEqual(comp, res, left.current().getMeaningWhenMissingElement(), right.current().getMeaningWhenMissingElement(), "meaningWhenMissing", path);
|
||||
ruleEqual(comp, res, left.current().getIsModifierElement(), right.current().getIsModifierElement(), "isModifier", path);
|
||||
ruleEqual(comp, res, left.current().getIsSummaryElement(), right.current().getIsSummaryElement(), "isSummary", path);
|
||||
// ruleEqual(comp, res, left.current().getDefaultValue(), right.current().getDefaultValue(), "defaultValue", path);
|
||||
// ruleEqual(comp, res, left.current().getMeaningWhenMissingElement(), right.current().getMeaningWhenMissingElement(), "meaningWhenMissing", path);
|
||||
// ruleEqual(comp, res, left.current().getIsModifierElement(), right.current().getIsModifierElement(), "isModifier", path); - this check belongs in the core
|
||||
// ruleEqual(comp, res, left.current().getIsSummaryElement(), right.current().getIsSummaryElement(), "isSummary", path); - so does this
|
||||
|
||||
// we ignore slicing right now - we're going to clone the root one anyway, and then think about clones
|
||||
// simple stuff
|
||||
@ -317,15 +332,15 @@ public class ProfileComparer extends CanonicalResourceComparer {
|
||||
} else if (vRight == null) {
|
||||
vm(IssueSeverity.ERROR, "Removed "+name, path, comp.getMessages(), res.getMessages());
|
||||
} else if (!Base.compareDeep(vLeft, vRight, false)) {
|
||||
vm(IssueSeverity.ERROR, name+" must be the same ("+toString(vLeft)+"/"+toString(vRight)+")", path, comp.getMessages(), res.getMessages());
|
||||
vm(IssueSeverity.ERROR, name+" must be the same ("+toString(vLeft, true)+"/"+toString(vRight, false)+")", path, comp.getMessages(), res.getMessages());
|
||||
}
|
||||
}
|
||||
|
||||
private String toString(DataType val) throws IOException {
|
||||
private String toString(DataType val, boolean left) throws IOException {
|
||||
if (val instanceof PrimitiveType)
|
||||
return "\"" + ((PrimitiveType) val).getValueAsString()+"\"";
|
||||
|
||||
IParser jp = session.getContext().newJsonParser();
|
||||
IParser jp = left ? session.getContextLeft().newJsonParser() : session.getContextRight().newJsonParser();
|
||||
return jp.composeString(val, "value");
|
||||
}
|
||||
|
||||
@ -468,13 +483,13 @@ public class ProfileComparer extends CanonicalResourceComparer {
|
||||
private Collection<? extends TypeRefComponent> unionTypes(ProfileComparison comp, StructuralMatch<ElementDefinition> res, String path, List<TypeRefComponent> left, List<TypeRefComponent> right) throws DefinitionException, IOException, FHIRFormatError {
|
||||
List<TypeRefComponent> result = new ArrayList<TypeRefComponent>();
|
||||
for (TypeRefComponent l : left)
|
||||
checkAddTypeUnion(comp, res, path, result, l);
|
||||
checkAddTypeUnion(comp, res, path, result, l, session.getContextLeft());
|
||||
for (TypeRefComponent r : right)
|
||||
checkAddTypeUnion(comp, res, path, result, r);
|
||||
checkAddTypeUnion(comp, res, path, result, r, session.getContextRight());
|
||||
return result;
|
||||
}
|
||||
|
||||
private void checkAddTypeUnion(ProfileComparison comp, StructuralMatch<ElementDefinition> res, String path, List<TypeRefComponent> results, TypeRefComponent nw) throws DefinitionException, IOException, FHIRFormatError {
|
||||
private void checkAddTypeUnion(ProfileComparison comp, StructuralMatch<ElementDefinition> res, String path, List<TypeRefComponent> results, TypeRefComponent nw, IWorkerContext ctxt) throws DefinitionException, IOException, FHIRFormatError {
|
||||
boolean pfound = false;
|
||||
boolean tfound = false;
|
||||
nw = nw.copy();
|
||||
@ -491,15 +506,15 @@ public class ProfileComparer extends CanonicalResourceComparer {
|
||||
ex.setProfile(null);
|
||||
} else {
|
||||
// both have profiles. Is one derived from the other?
|
||||
StructureDefinition sdex = session.getContext().fetchResource(StructureDefinition.class, ex.getProfile().get(0).getValue());
|
||||
StructureDefinition sdnw = session.getContext().fetchResource(StructureDefinition.class, nw.getProfile().get(0).getValue());
|
||||
StructureDefinition sdex = ((IWorkerContext) ex.getUserData("ctxt")).fetchResource(StructureDefinition.class, ex.getProfile().get(0).getValue());
|
||||
StructureDefinition sdnw = ctxt.fetchResource(StructureDefinition.class, nw.getProfile().get(0).getValue());
|
||||
if (sdex != null && sdnw != null) {
|
||||
if (sdex == sdnw) {
|
||||
if (sdex.getUrl().equals(sdnw.getUrl())) {
|
||||
pfound = true;
|
||||
} else if (derivesFrom(sdex, sdnw)) {
|
||||
} else if (derivesFrom(sdex, sdnw, ((IWorkerContext) ex.getUserData("ctxt")))) {
|
||||
ex.setProfile(nw.getProfile());
|
||||
pfound = true;
|
||||
} else if (derivesFrom(sdnw, sdex)) {
|
||||
} else if (derivesFrom(sdnw, sdex, ctxt)) {
|
||||
pfound = true;
|
||||
} else if (sdnw.getSnapshot().getElement().get(0).getPath().equals(sdex.getSnapshot().getElement().get(0).getPath())) {
|
||||
ProfileComparison compP = (ProfileComparison) session.compare(sdex, sdnw);
|
||||
@ -519,15 +534,15 @@ public class ProfileComparer extends CanonicalResourceComparer {
|
||||
ex.setTargetProfile(null);
|
||||
} else {
|
||||
// both have profiles. Is one derived from the other?
|
||||
StructureDefinition sdex = session.getContext().fetchResource(StructureDefinition.class, ex.getTargetProfile().get(0).getValue());
|
||||
StructureDefinition sdnw = session.getContext().fetchResource(StructureDefinition.class, nw.getTargetProfile().get(0).getValue());
|
||||
StructureDefinition sdex = ((IWorkerContext) ex.getUserData("ctxt")).fetchResource(StructureDefinition.class, ex.getTargetProfile().get(0).getValue());
|
||||
StructureDefinition sdnw = ctxt.fetchResource(StructureDefinition.class, nw.getTargetProfile().get(0).getValue());
|
||||
if (sdex != null && sdnw != null) {
|
||||
if (sdex == sdnw) {
|
||||
if (matches(sdex, sdnw)) {
|
||||
tfound = true;
|
||||
} else if (derivesFrom(sdex, sdnw)) {
|
||||
} else if (derivesFrom(sdex, sdnw, ((IWorkerContext) ex.getUserData("ctxt")))) {
|
||||
ex.setTargetProfile(nw.getTargetProfile());
|
||||
tfound = true;
|
||||
} else if (derivesFrom(sdnw, sdex)) {
|
||||
} else if (derivesFrom(sdnw, sdex, ctxt)) {
|
||||
tfound = true;
|
||||
} else if (sdnw.getSnapshot().getElement().get(0).getPath().equals(sdex.getSnapshot().getElement().get(0).getPath())) {
|
||||
ProfileComparison compP = (ProfileComparison) session.compare(sdex, sdnw);
|
||||
@ -540,17 +555,33 @@ public class ProfileComparer extends CanonicalResourceComparer {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!tfound || !pfound)
|
||||
if (!tfound || !pfound) {
|
||||
nw.setUserData("ctxt", ctxt);
|
||||
results.add(nw);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean derivesFrom(StructureDefinition left, StructureDefinition right) {
|
||||
private boolean matches(StructureDefinition s1, StructureDefinition s2) {
|
||||
if (!s1.getUrl().equals(s2.getUrl())) {
|
||||
return false;
|
||||
}
|
||||
if (s1.getDerivation() == TypeDerivationRule.SPECIALIZATION && s2.getDerivation() == TypeDerivationRule.SPECIALIZATION) {
|
||||
return true; // arbitrary; we're just not interested in pursuing cross version differences
|
||||
}
|
||||
if (s1.hasVersion()) {
|
||||
return s1.getVersion().equals(s2.getVersion());
|
||||
} else {
|
||||
return !s2.hasVersion();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean derivesFrom(StructureDefinition left, StructureDefinition right, IWorkerContext ctxt) {
|
||||
StructureDefinition sd = left;
|
||||
while (sd != null) {
|
||||
if (right.getUrl().equals(sd.getBaseDefinition())) {
|
||||
return true;
|
||||
}
|
||||
sd = sd.hasBaseDefinition() ? session.getContext().fetchResource(StructureDefinition.class, sd.getBaseDefinition()) : null;
|
||||
sd = sd.hasBaseDefinition() ? ctxt.fetchResource(StructureDefinition.class, sd.getBaseDefinition()) : null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -574,14 +605,14 @@ public class ProfileComparer extends CanonicalResourceComparer {
|
||||
pfound = true;
|
||||
c.setProfile(r.getProfile());
|
||||
} else {
|
||||
StructureDefinition sdl = resolveProfile(comp, res, path, l.getProfile().get(0).getValue(), comp.getLeft().getName());
|
||||
StructureDefinition sdr = resolveProfile(comp, res, path, r.getProfile().get(0).getValue(), comp.getRight().getName());
|
||||
StructureDefinition sdl = resolveProfile(comp, res, path, l.getProfile().get(0).getValue(), comp.getLeft().getName(), session.getContextLeft());
|
||||
StructureDefinition sdr = resolveProfile(comp, res, path, r.getProfile().get(0).getValue(), comp.getRight().getName(), session.getContextRight());
|
||||
if (sdl != null && sdr != null) {
|
||||
if (sdl == sdr) {
|
||||
pfound = true;
|
||||
} else if (derivesFrom(sdl, sdr)) {
|
||||
} else if (derivesFrom(sdl, sdr, session.getContextLeft())) {
|
||||
pfound = true;
|
||||
} else if (derivesFrom(sdr, sdl)) {
|
||||
} else if (derivesFrom(sdr, sdl, session.getContextRight())) {
|
||||
c.setProfile(r.getProfile());
|
||||
pfound = true;
|
||||
} else if (sdl.getType().equals(sdr.getType())) {
|
||||
@ -601,14 +632,14 @@ public class ProfileComparer extends CanonicalResourceComparer {
|
||||
tfound = true;
|
||||
c.setTargetProfile(r.getTargetProfile());
|
||||
} else {
|
||||
StructureDefinition sdl = resolveProfile(comp, res, path, l.getTargetProfile().get(0).getValue(), comp.getLeft().getName());
|
||||
StructureDefinition sdr = resolveProfile(comp, res, path, r.getTargetProfile().get(0).getValue(), comp.getRight().getName());
|
||||
StructureDefinition sdl = resolveProfile(comp, res, path, l.getTargetProfile().get(0).getValue(), comp.getLeft().getName(), session.getContextLeft());
|
||||
StructureDefinition sdr = resolveProfile(comp, res, path, r.getTargetProfile().get(0).getValue(), comp.getRight().getName(), session.getContextRight());
|
||||
if (sdl != null && sdr != null) {
|
||||
if (sdl == sdr) {
|
||||
if (matches(sdl, sdr)) {
|
||||
tfound = true;
|
||||
} else if (derivesFrom(sdl, sdr)) {
|
||||
} else if (derivesFrom(sdl, sdr, session.getContextLeft())) {
|
||||
tfound = true;
|
||||
} else if (derivesFrom(sdr, sdl)) {
|
||||
} else if (derivesFrom(sdr, sdl, session.getContextRight())) {
|
||||
c.setTargetProfile(r.getTargetProfile());
|
||||
tfound = true;
|
||||
} else if (sdl.getType().equals(sdr.getType())) {
|
||||
@ -713,8 +744,8 @@ public class ProfileComparer extends CanonicalResourceComparer {
|
||||
return true;
|
||||
} else {
|
||||
// ok, now we compare the value sets. This may be unresolvable.
|
||||
ValueSet lvs = resolveVS(comp.getLeft(), left.getValueSet());
|
||||
ValueSet rvs = resolveVS(comp.getRight(), right.getValueSet());
|
||||
ValueSet lvs = resolveVS(comp.getLeft(), left.getValueSet(), session.getContextLeft());
|
||||
ValueSet rvs = resolveVS(comp.getRight(), right.getValueSet(), session.getContextRight());
|
||||
if (lvs == null) {
|
||||
vm(IssueSeverity.ERROR, "Unable to resolve left value set "+left.getValueSet().toString()+" at "+path, path, comp.getMessages(), res.getMessages());
|
||||
return true;
|
||||
@ -739,6 +770,9 @@ public class ProfileComparer extends CanonicalResourceComparer {
|
||||
if (!lvs.getUrl().equals(rvs.getUrl())) {
|
||||
return false;
|
||||
}
|
||||
if (isCore(lvs) && isCore(rvs)) {
|
||||
return true;
|
||||
}
|
||||
if (lvs.hasVersion()) {
|
||||
if (!lvs.getVersion().equals(rvs.getVersion())) {
|
||||
return false;
|
||||
@ -749,6 +783,10 @@ public class ProfileComparer extends CanonicalResourceComparer {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isCore(ValueSet vs) {
|
||||
return vs.getUrl().startsWith("http://hl7.org/fhir/ValueSet");
|
||||
}
|
||||
|
||||
private List<ElementDefinitionConstraintComponent> intersectConstraints(String path, List<ElementDefinitionConstraintComponent> left, List<ElementDefinitionConstraintComponent> right) {
|
||||
List<ElementDefinitionConstraintComponent> result = new ArrayList<ElementDefinitionConstraintComponent>();
|
||||
for (ElementDefinitionConstraintComponent l : left) {
|
||||
@ -771,7 +809,9 @@ public class ProfileComparer extends CanonicalResourceComparer {
|
||||
if (Utilities.equals(r.getId(), l.getId()) || (Utilities.equals(r.getXpath(), l.getXpath()) && r.getSeverity() == l.getSeverity()))
|
||||
found = true;
|
||||
if (!found) {
|
||||
vm(IssueSeverity.INFORMATION, "StructureDefinition "+comp.getLeft().getName()+" has a constraint that is removed in "+comp.getRight().getName()+" and it is uncertain whether they are compatible ("+l.getExpression()+")", path, comp.getMessages(), res.getMessages());
|
||||
if (!Utilities.existsInList(l.getExpression(), "hasValue() or (children().count() > id.count())", "extension.exists() != value.exists()")) {
|
||||
vm(IssueSeverity.INFORMATION, "StructureDefinition "+comp.getLeft().getName()+" has a constraint that is removed in "+comp.getRight().getName()+" and it is uncertain whether they are compatible ("+l.getExpression()+")", path, comp.getMessages(), res.getMessages());
|
||||
}
|
||||
}
|
||||
result.add(l);
|
||||
}
|
||||
@ -781,14 +821,16 @@ public class ProfileComparer extends CanonicalResourceComparer {
|
||||
if (Utilities.equals(r.getId(), l.getId()) || (Utilities.equals(r.getXpath(), l.getXpath()) && r.getSeverity() == l.getSeverity()))
|
||||
found = true;
|
||||
if (!found) {
|
||||
vm(IssueSeverity.INFORMATION, "StructureDefinition "+comp.getRight().getName()+" has added constraint that is not found in "+comp.getLeft().getName()+" and it is uncertain whether they are compatible ("+r.getExpression()+")", path, comp.getMessages(), res.getMessages());
|
||||
if (!Utilities.existsInList(r.getExpression(), "hasValue() or (children().count() > id.count())", "extension.exists() != value.exists()")) {
|
||||
vm(IssueSeverity.INFORMATION, "StructureDefinition "+comp.getRight().getName()+" has added constraint that is not found in "+comp.getLeft().getName()+" and it is uncertain whether they are compatible ("+r.getExpression()+")", path, comp.getMessages(), res.getMessages());
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private StructureDefinition resolveProfile(ProfileComparison comp, StructuralMatch<ElementDefinition> res, String path, String url, String name) {
|
||||
StructureDefinition sd = session.getContext().fetchResource(StructureDefinition.class, url);
|
||||
private StructureDefinition resolveProfile(ProfileComparison comp, StructuralMatch<ElementDefinition> res, String path, String url, String name, IWorkerContext ctxt) {
|
||||
StructureDefinition sd = ctxt.fetchResource(StructureDefinition.class, url);
|
||||
if (sd == null) {
|
||||
ValidationMessage vm = vmI(IssueSeverity.WARNING, "Unable to resolve profile "+url+" in profile "+name, path);
|
||||
}
|
||||
@ -809,8 +851,8 @@ public class ProfileComparer extends CanonicalResourceComparer {
|
||||
if (Base.compareDeep(left.getValueSet(), right.getValueSet(), false))
|
||||
union.setValueSet(left.getValueSet());
|
||||
else {
|
||||
ValueSet lvs = resolveVS(comp.getLeft(), left.getValueSet());
|
||||
ValueSet rvs = resolveVS(comp.getRight(), right.getValueSet());
|
||||
ValueSet lvs = resolveVS(comp.getLeft(), left.getValueSet(), session.getContextLeft());
|
||||
ValueSet rvs = resolveVS(comp.getRight(), right.getValueSet(), session.getContextRight());
|
||||
if (lvs != null && rvs != null) {
|
||||
ValueSetComparison compP = (ValueSetComparison) session.compare(lvs, rvs);
|
||||
if (compP != null) {
|
||||
@ -825,15 +867,15 @@ public class ProfileComparer extends CanonicalResourceComparer {
|
||||
return union;
|
||||
}
|
||||
|
||||
private ValueSet resolveVS(StructureDefinition ctxtLeft, String vsRef) {
|
||||
private ValueSet resolveVS(StructureDefinition ctxtLeft, String vsRef, IWorkerContext ctxt) {
|
||||
if (vsRef == null)
|
||||
return null;
|
||||
return session.getContext().fetchResource(ValueSet.class, vsRef);
|
||||
return ctxt.fetchResource(ValueSet.class, vsRef);
|
||||
}
|
||||
|
||||
public XhtmlNode renderStructure(ProfileComparison comp, String id, String prefix, String corePath) throws FHIRException, IOException {
|
||||
HierarchicalTableGenerator gen = new HierarchicalTableGenerator(Utilities.path("[tmp]", "compare"), false, true);
|
||||
gen.setTranslator(session.getContext().translator());
|
||||
gen.setTranslator(session.getContextRight().translator());
|
||||
TableModel model = gen.initComparisonTable(corePath, id);
|
||||
genElementComp(null /* oome back to this later */, gen, model.getRows(), comp.combined, corePath, prefix, null, true);
|
||||
return gen.generate(model, prefix, 0, null);
|
||||
@ -849,7 +891,7 @@ public class ProfileComparer extends CanonicalResourceComparer {
|
||||
rows.add(row);
|
||||
String path = combined.either().getPath();
|
||||
row.setAnchor(path);
|
||||
row.setColor(utils.getRowColor(combined.either(), false));
|
||||
row.setColor(utilsRight.getRowColor(combined.either(), false));
|
||||
if (eitherHasSlicing(combined))
|
||||
row.setLineColor(1);
|
||||
else if (eitherHasSliceName(combined))
|
||||
@ -895,17 +937,17 @@ public class ProfileComparer extends CanonicalResourceComparer {
|
||||
String leftColor = !combined.hasLeft() ? COLOR_NO_ROW_LEFT : combined.hasErrors() ? COLOR_DIFFERENT : null;
|
||||
String rightColor = !combined.hasRight() ? COLOR_NO_ROW_LEFT : combined.hasErrors() ? COLOR_DIFFERENT : null;
|
||||
if (combined.hasLeft()) {
|
||||
nc = utils.genElementNameCell(gen, combined.getLeft(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used , ref, sName);
|
||||
nc = utilsRight.genElementNameCell(gen, combined.getLeft(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used , ref, sName);
|
||||
} else {
|
||||
nc = utils.genElementNameCell(gen, combined.getRight(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used , ref, sName);
|
||||
nc = utilsRight.genElementNameCell(gen, combined.getRight(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used , ref, sName);
|
||||
}
|
||||
if (combined.hasLeft()) {
|
||||
frame(utils.genElementCells(gen, combined.getLeft(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used , ref, sName, nc), leftColor);
|
||||
frame(utilsRight.genElementCells(gen, combined.getLeft(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used , ref, sName, nc), leftColor);
|
||||
} else {
|
||||
frame(spacers(row, 4, gen), leftColor);
|
||||
}
|
||||
if (combined.hasRight()) {
|
||||
frame(utils.genElementCells(gen, combined.getRight(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used, ref, sName, nc), rightColor);
|
||||
frame(utilsRight.genElementCells(gen, combined.getRight(), "??", true, corePath, prefix, root, false, false, null, typesRow, row, false, ext, used, ref, sName, nc), rightColor);
|
||||
} else {
|
||||
frame(spacers(row, 4, gen), rightColor);
|
||||
}
|
||||
|
@ -3,6 +3,13 @@ package org.hl7.fhir.r5.comparison;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
|
||||
import org.hl7.fhir.r5.comparison.ResourceComparer.ResourceComparison;
|
||||
import org.hl7.fhir.r5.model.CanonicalResource;
|
||||
import org.hl7.fhir.r5.model.CodeSystem;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
|
||||
@ -14,8 +21,33 @@ import org.hl7.fhir.utilities.xhtml.NodeType;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||
|
||||
public class ResourceComparer {
|
||||
|
||||
public static class MessageCounts {
|
||||
private int errors;
|
||||
private int warnings;
|
||||
private int hints;
|
||||
public int getErrors() {
|
||||
return errors;
|
||||
}
|
||||
public int getWarnings() {
|
||||
return warnings;
|
||||
}
|
||||
public int getHints() {
|
||||
return hints;
|
||||
}
|
||||
public void error() {
|
||||
errors++;
|
||||
}
|
||||
public void warning() {
|
||||
warnings++;
|
||||
}
|
||||
public void hint() {
|
||||
hints++;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class ResourceComparison {
|
||||
|
||||
public static abstract class ResourceComparison {
|
||||
private String id;
|
||||
private String leftId;
|
||||
private String rightId;
|
||||
@ -48,13 +80,115 @@ public class ResourceComparer {
|
||||
}
|
||||
|
||||
protected abstract String summary();
|
||||
|
||||
protected abstract String fhirType();
|
||||
|
||||
protected abstract String toTable();
|
||||
|
||||
protected String outcomeSummary() {
|
||||
MessageCounts cnts = new MessageCounts();
|
||||
countMessages(cnts);
|
||||
return
|
||||
Integer.toString(cnts.getErrors())+" "+Utilities.pluralize("Breaking Change", cnts.getErrors())+", "+
|
||||
Integer.toString(cnts.getWarnings())+" "+Utilities.pluralize("Change", cnts.getWarnings())+", "+
|
||||
Integer.toString(cnts.getHints())+" "+Utilities.pluralize("Note", cnts.getHints());
|
||||
}
|
||||
|
||||
protected abstract void countMessages(MessageCounts cnts);
|
||||
}
|
||||
|
||||
|
||||
public static class PlaceHolderComparison extends ResourceComparison {
|
||||
private CanonicalResource left;
|
||||
private CanonicalResource right;
|
||||
private Throwable e;
|
||||
|
||||
public PlaceHolderComparison(CanonicalResource left, CanonicalResource right) {
|
||||
super(left == null ? right.getId() : left.getId(), right == null ? left.getId() : right.getId());
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
public PlaceHolderComparison(CanonicalResource left, CanonicalResource right, Throwable e) {
|
||||
super(left == null ? right.getId() : left.getId(), right == null ? left.getId() : right.getId());
|
||||
this.e = e;
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String abbreviation() {
|
||||
CanonicalResource cr = left == null ? right : left;
|
||||
if (cr instanceof CodeSystem) {
|
||||
return "cs";
|
||||
} else if (cr instanceof ValueSet) {
|
||||
return "vs";
|
||||
} else if (cr instanceof StructureDefinition) {
|
||||
return "sd";
|
||||
} else {
|
||||
return "xx";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String summary() {
|
||||
if (e != null) {
|
||||
return e.getMessage();
|
||||
}
|
||||
CanonicalResource cr = left == null ? right : left;
|
||||
return cr.fhirType()+(left == null ? " Added" : " Removed");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String fhirType() {
|
||||
CanonicalResource cr = left == null ? right : left;
|
||||
return cr.fhirType();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String toTable() {
|
||||
String s = null;
|
||||
String color = null;
|
||||
if (left != null && right != null && !left.getUrl().equals(right.getUrl())) {
|
||||
s = "<td>"+left.getUrl()+"</td><td>"+right.getUrl()+"</td>";
|
||||
} else if (left != null) {
|
||||
s = "<td colspan=2>"+left.getUrl()+"</td>";
|
||||
} else {
|
||||
s = "<td colspan=2>"+right.getUrl()+"</td>";
|
||||
}
|
||||
if (left == null) {
|
||||
s = s + "<td>Added</td>";
|
||||
color = COLOR_NO_ROW_LEFT;
|
||||
} else if (right == null) {
|
||||
s = s + "<td>Removed</td>";
|
||||
color = COLOR_NO_ROW_RIGHT;
|
||||
} else {
|
||||
s = s + "<td><a href=\""+getId()+".html\">Failed<a></td>";
|
||||
color = COLOR_ISSUE;
|
||||
}
|
||||
s = s + "<td>"+(e != null ? Utilities.escapeXml(e.getMessage()) : "")+"</td>";
|
||||
return "<tr style=\"background-color: "+color+"\">"+s+"</tr>\r\n";
|
||||
}
|
||||
|
||||
public Throwable getE() {
|
||||
return e;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void countMessages(MessageCounts cnts) {
|
||||
if (e != null) {
|
||||
cnts.error();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public final static String COLOR_NO_ROW_LEFT = "#ffffb3";
|
||||
public final static String COLOR_NO_CELL_LEFT = "#ffff4d";
|
||||
public final static String COLOR_NO_ROW_RIGHT = "#ffecb3";
|
||||
public final static String COLOR_NO_CELL_RIGHT = "#ffcc33";
|
||||
public final static String COLOR_DIFFERENT = "#f0b3ff";
|
||||
public final static String COLOR_DIFFERENT_LESS = "#f8e6ff";
|
||||
public final static String COLOR_ISSUE = "#ffad99";
|
||||
|
||||
protected ComparisonSession session;
|
||||
|
@ -3,6 +3,7 @@ package org.hl7.fhir.r5.comparison;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
|
||||
@ -87,5 +88,21 @@ public class StructuralMatch<T> {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void countMessages(MessageCounts cnts) {
|
||||
for (ValidationMessage vm : getMessages()) {
|
||||
if (vm.getLevel() == IssueSeverity.ERROR) {
|
||||
cnts.error();
|
||||
} else if (vm.getLevel() == IssueSeverity.WARNING) {
|
||||
cnts.warning();
|
||||
} else if (vm.getLevel() == IssueSeverity.INFORMATION) {
|
||||
cnts.hint();
|
||||
}
|
||||
}
|
||||
for (StructuralMatch<T> c : children) {
|
||||
c.countMessages(cnts);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -7,6 +7,8 @@ import java.util.List;
|
||||
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||
import org.hl7.fhir.r5.model.CanonicalType;
|
||||
import org.hl7.fhir.r5.model.Element;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
@ -66,7 +68,26 @@ public class ValueSetComparer extends CanonicalResourceComparer {
|
||||
@Override
|
||||
protected String summary() {
|
||||
return "ValueSet: "+left.present()+" vs "+right.present();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String fhirType() {
|
||||
return "ValueSet";
|
||||
}
|
||||
@Override
|
||||
protected void countMessages(MessageCounts cnts) {
|
||||
super.countMessages(cnts);
|
||||
if (includes != null) {
|
||||
includes.countMessages(cnts);
|
||||
}
|
||||
if (excludes != null) {
|
||||
excludes.countMessages(cnts);
|
||||
}
|
||||
if (expansion != null) {
|
||||
expansion.countMessages(cnts);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public ValueSetComparer(ComparisonSession session) {
|
||||
@ -372,16 +393,16 @@ public class ValueSetComparer extends CanonicalResourceComparer {
|
||||
}
|
||||
|
||||
private void compareExpansions(ValueSet left, ValueSet right, ValueSetComparison res) {
|
||||
ValueSet expL = left.hasExpansion() ? left : expand(left, res, "left");
|
||||
ValueSet expR = left.hasExpansion() ? left : expand(right, res, "right");
|
||||
ValueSet expL = left.hasExpansion() ? left : expand(left, res, "left", session.getContextLeft());
|
||||
ValueSet expR = left.hasExpansion() ? left : expand(right, res, "right", session.getContextRight());
|
||||
if (expL != null && expR != null) {
|
||||
// ignore the parameters for now
|
||||
compareConcepts(expL.getExpansion().getContains(), expR.getExpansion().getContains(), res.forceExpansion(), res.getUnion().getExpansion().getContains(), res.getIntersection().getExpansion().getContains(), "ValueSet.expansion.contains", res);
|
||||
}
|
||||
}
|
||||
|
||||
private ValueSet expand(ValueSet vs, ValueSetComparison res, String name) {
|
||||
ValueSetExpansionOutcome vse =session.getContext().expandVS(vs, true, false);
|
||||
private ValueSet expand(ValueSet vs, ValueSetComparison res, String name, IWorkerContext ctxt) {
|
||||
ValueSetExpansionOutcome vse = ctxt.expandVS(vs, true, false);
|
||||
if (vse.getValueset() != null) {
|
||||
return vse.getValueset();
|
||||
} else {
|
||||
@ -682,6 +703,11 @@ public class ValueSetComparer extends CanonicalResourceComparer {
|
||||
p.tx("Unable to generate expansion - see errors");
|
||||
return p;
|
||||
}
|
||||
if (csc.getExpansion().getChildren().isEmpty()) {
|
||||
XhtmlNode p = new XhtmlNode(NodeType.Element, "p");
|
||||
p.tx("Expansion is empty");
|
||||
return p;
|
||||
}
|
||||
// columns: code(+system), version, display , abstract, inactive,
|
||||
boolean hasSystem = csc.getExpansion().getChildren().isEmpty() ? false : getSystemVaries(csc.getExpansion(), csc.getExpansion().getChildren().get(0).either().getSystem());
|
||||
boolean hasVersion = findVersion(csc.getExpansion());
|
||||
|
@ -116,7 +116,7 @@ public class ComparisonTests {
|
||||
CanonicalResource left = load("left");
|
||||
CanonicalResource right = load("right");
|
||||
|
||||
ComparisonSession session = new ComparisonSession(context, "Comparison Tests", null);
|
||||
ComparisonSession session = new ComparisonSession(context, context, "Comparison Tests", null);
|
||||
|
||||
if (left instanceof CodeSystem && right instanceof CodeSystem) {
|
||||
CodeSystemComparer cs = new CodeSystemComparer(session);
|
||||
@ -146,7 +146,7 @@ public class ComparisonTests {
|
||||
ProfileUtilities utils = new ProfileUtilities(context, null, null);
|
||||
genSnapshot(utils, (StructureDefinition) left);
|
||||
genSnapshot(utils, (StructureDefinition) right);
|
||||
ProfileComparer pc = new ProfileComparer(session, utils);
|
||||
ProfileComparer pc = new ProfileComparer(session, utils, utils);
|
||||
ProfileComparison csc = pc.compare((StructureDefinition) left, (StructureDefinition) right);
|
||||
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", "comparison", name + "-union.json")), csc.getUnion());
|
||||
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", "comparison", name + "-intersection.json")), csc.getIntersection());
|
||||
|
Loading…
x
Reference in New Issue
Block a user