add cross version snapshot generation tests
This commit is contained in:
parent
335b5587b3
commit
298b39e615
|
@ -0,0 +1,12 @@
|
||||||
|
package org.hl7.fhir.conversion.tests;
|
||||||
|
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.Suite;
|
||||||
|
import org.junit.runners.Suite.SuiteClasses;
|
||||||
|
|
||||||
|
@RunWith(Suite.class)
|
||||||
|
@SuiteClasses({
|
||||||
|
SnapShotGenerationTestsX.class})
|
||||||
|
public class CrossVersionLibraryTests {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,544 @@
|
||||||
|
package org.hl7.fhir.conversion.tests;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.commons.lang3.NotImplementedException;
|
||||||
|
import org.hl7.fhir.exceptions.DefinitionException;
|
||||||
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
|
import org.hl7.fhir.exceptions.FHIRFormatError;
|
||||||
|
import org.hl7.fhir.exceptions.PathEngineException;
|
||||||
|
import org.hl7.fhir.r5.conformance.ProfileUtilities;
|
||||||
|
import org.hl7.fhir.r5.conformance.ProfileUtilities.ProfileKnowledgeProvider;
|
||||||
|
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
|
||||||
|
import org.hl7.fhir.r5.formats.JsonParser;
|
||||||
|
import org.hl7.fhir.r5.formats.XmlParser;
|
||||||
|
import org.hl7.fhir.r5.model.Base;
|
||||||
|
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent;
|
||||||
|
import org.hl7.fhir.r5.model.ExpressionNode.CollectionStatus;
|
||||||
|
import org.hl7.fhir.r5.model.Resource;
|
||||||
|
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||||
|
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
|
||||||
|
import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule;
|
||||||
|
import org.hl7.fhir.r5.model.TypeDetails;
|
||||||
|
import org.hl7.fhir.r5.model.ValueSet;
|
||||||
|
import org.hl7.fhir.r5.utils.FHIRPathEngine;
|
||||||
|
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
|
||||||
|
import org.hl7.fhir.r5.utils.IResourceValidator;
|
||||||
|
import org.hl7.fhir.r5.utils.NarrativeGenerator;
|
||||||
|
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.xml.XMLUtil;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.junit.runners.Parameterized;
|
||||||
|
import org.junit.runners.Parameterized.Parameters;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
import junit.framework.Assert;
|
||||||
|
|
||||||
|
@RunWith(Parameterized.class)
|
||||||
|
public class SnapShotGenerationTestsX {
|
||||||
|
|
||||||
|
public enum TestFetchMode {
|
||||||
|
INPUT,
|
||||||
|
OUTPUT,
|
||||||
|
INCLUDE
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Rule {
|
||||||
|
private String description;
|
||||||
|
private String expression;
|
||||||
|
public Rule(String description, String expression) {
|
||||||
|
super();
|
||||||
|
this.description = description;
|
||||||
|
this.expression = expression;
|
||||||
|
}
|
||||||
|
public Rule(Element rule) {
|
||||||
|
super();
|
||||||
|
this.description = rule.getAttribute("text");
|
||||||
|
this.expression = rule.getAttribute("fhirpath");
|
||||||
|
}
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
public String getExpression() {
|
||||||
|
return expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TestDetails {
|
||||||
|
private String id;
|
||||||
|
private String include;
|
||||||
|
private String register;
|
||||||
|
private String regex;
|
||||||
|
private boolean gen;
|
||||||
|
private boolean sort;
|
||||||
|
private boolean fail;
|
||||||
|
private boolean newSliceProcessing;
|
||||||
|
private boolean debug;
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
private List<Rule> rules = new ArrayList<>();
|
||||||
|
private StructureDefinition source;
|
||||||
|
private StructureDefinition included;
|
||||||
|
private StructureDefinition expected;
|
||||||
|
private StructureDefinition output;
|
||||||
|
|
||||||
|
public TestDetails(Element test) {
|
||||||
|
super();
|
||||||
|
gen = "true".equals(test.getAttribute("gen"));
|
||||||
|
sort = "true".equals(test.getAttribute("sort"));
|
||||||
|
fail = "true".equals(test.getAttribute("fail"));
|
||||||
|
newSliceProcessing = !"false".equals(test.getAttribute("new-slice-processing"));
|
||||||
|
debug = "true".equals(test.getAttribute("debug"));
|
||||||
|
|
||||||
|
id = test.getAttribute("id");
|
||||||
|
include = test.getAttribute("include");
|
||||||
|
register = test.getAttribute("register");
|
||||||
|
regex = test.getAttribute("regex");
|
||||||
|
version = test.getAttribute("version");
|
||||||
|
Element rule = XMLUtil.getFirstChild(test);
|
||||||
|
while (rule != null && rule.getNodeName().equals("rule")) {
|
||||||
|
rules.add(new Rule(rule));
|
||||||
|
rule = XMLUtil.getNextSibling(rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
public boolean isSort() {
|
||||||
|
return sort;
|
||||||
|
}
|
||||||
|
public boolean isGen() {
|
||||||
|
return gen;
|
||||||
|
}
|
||||||
|
public String getInclude() {
|
||||||
|
return include;
|
||||||
|
}
|
||||||
|
public boolean isFail() {
|
||||||
|
return fail;
|
||||||
|
}
|
||||||
|
public StructureDefinition getIncluded() {
|
||||||
|
return included;
|
||||||
|
}
|
||||||
|
public List<Rule> getRules() {
|
||||||
|
return rules;
|
||||||
|
}
|
||||||
|
public StructureDefinition getSource() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
public void setSource(StructureDefinition source) {
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
public StructureDefinition getExpected() {
|
||||||
|
return expected;
|
||||||
|
}
|
||||||
|
public void setExpected(StructureDefinition expected) {
|
||||||
|
this.expected = expected;
|
||||||
|
}
|
||||||
|
public StructureDefinition getOutput() {
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
public void setOutput(StructureDefinition output) {
|
||||||
|
this.output = output;
|
||||||
|
}
|
||||||
|
public void load() throws FHIRFormatError, FileNotFoundException, IOException {
|
||||||
|
if (TestingUtilitiesX.findTestResource("rX", "snapshot-generation", id+"-input.json"))
|
||||||
|
source = (StructureDefinition) new JsonParser().parse(TestingUtilitiesX.loadTestResourceStream("rX", "snapshot-generation", id+"-input.json"));
|
||||||
|
else
|
||||||
|
source = (StructureDefinition) new XmlParser().parse(TestingUtilitiesX.loadTestResourceStream("rX", "snapshot-generation", id+"-input.xml"));
|
||||||
|
if (!fail)
|
||||||
|
expected = (StructureDefinition) new XmlParser().parse(TestingUtilitiesX.loadTestResourceStream("rX", "snapshot-generation", id+"-expected.xml"));
|
||||||
|
if (!Utilities.noString(include))
|
||||||
|
included = (StructureDefinition) new XmlParser().parse(TestingUtilitiesX.loadTestResourceStream("rX", "snapshot-generation", include+".xml"));
|
||||||
|
if (!Utilities.noString(register)) {
|
||||||
|
if (TestingUtilitiesX.findTestResource("rX", "snapshot-generation", register+".xml")) {
|
||||||
|
included = (StructureDefinition) new XmlParser().parse(TestingUtilitiesX.loadTestResourceStream("rX", "snapshot-generation", register+".xml"));
|
||||||
|
} else {
|
||||||
|
included = (StructureDefinition) new JsonParser().parse(TestingUtilitiesX.loadTestResourceStream("rX", "snapshot-generation", register+".json"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public boolean isNewSliceProcessing() {
|
||||||
|
return newSliceProcessing;
|
||||||
|
}
|
||||||
|
public boolean isDebug() {
|
||||||
|
return debug;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestPKP implements ProfileKnowledgeProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDatatype(String name) {
|
||||||
|
StructureDefinition sd = TestingUtilitiesX.context(version).fetchTypeDefinition(name);
|
||||||
|
return (sd != null) && (sd.getDerivation() == TypeDerivationRule.SPECIALIZATION) && (sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE || sd.getKind() == StructureDefinitionKind.COMPLEXTYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isResource(String typeSimple) {
|
||||||
|
StructureDefinition sd = TestingUtilitiesX.context(version).fetchTypeDefinition(typeSimple);
|
||||||
|
return (sd != null) && (sd.getDerivation() == TypeDerivationRule.SPECIALIZATION) && (sd.getKind() == StructureDefinitionKind.RESOURCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasLinkFor(String typeSimple) {
|
||||||
|
return isDatatype(typeSimple);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLinkFor(String corePath, String typeSimple) {
|
||||||
|
return Utilities.pathURL(corePath, "datatypes.html#"+typeSimple);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BindingResolution resolveBinding(StructureDefinition def, ElementDefinitionBindingComponent binding, String path) throws FHIRException {
|
||||||
|
BindingResolution br = new BindingResolution();
|
||||||
|
br.url = path+"/something.html";
|
||||||
|
br.display = "something";
|
||||||
|
return br;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BindingResolution resolveBinding(StructureDefinition def, String url, String path) throws FHIRException {
|
||||||
|
BindingResolution br = new BindingResolution();
|
||||||
|
br.url = path+"/something.html";
|
||||||
|
br.display = "something";
|
||||||
|
return br;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLinkForProfile(StructureDefinition profile, String url) {
|
||||||
|
StructureDefinition sd = TestingUtilitiesX.context(version).fetchResource(StructureDefinition.class, url);
|
||||||
|
if (sd == null)
|
||||||
|
return url+"|"+url;
|
||||||
|
else
|
||||||
|
return sd.getId()+".html|"+sd.present();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean prependLinks() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLinkForUrl(String corePath, String s) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SnapShotGenerationTestsContext implements IEvaluationContext {
|
||||||
|
public List<TestDetails> tests = new ArrayList<>();
|
||||||
|
|
||||||
|
public Resource fetchFixture(String id) {
|
||||||
|
TestFetchMode mode = TestFetchMode.INPUT;
|
||||||
|
if (id.equals("patient"))
|
||||||
|
return TestingUtilitiesX.context(version).fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/Patient");
|
||||||
|
if (id.equals("valueset"))
|
||||||
|
return TestingUtilitiesX.context(version).fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/ValueSet");
|
||||||
|
if (id.equals("organization"))
|
||||||
|
return TestingUtilitiesX.context(version).fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/Organization");
|
||||||
|
if (id.equals("operationoutcome"))
|
||||||
|
return TestingUtilitiesX.context(version).fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/OperationOutcome");
|
||||||
|
if (id.equals("parameters"))
|
||||||
|
return TestingUtilitiesX.context(version).fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/Parameters");
|
||||||
|
|
||||||
|
if (id.contains("-")) {
|
||||||
|
String[] p = id.split("\\-");
|
||||||
|
id = p[0];
|
||||||
|
if (p[1].equals("output"))
|
||||||
|
mode = TestFetchMode.OUTPUT;
|
||||||
|
else if (p[1].equals("include"))
|
||||||
|
mode = TestFetchMode.INCLUDE;
|
||||||
|
}
|
||||||
|
for (TestDetails td : tests) {
|
||||||
|
if (td.getId().equals(id))
|
||||||
|
switch (mode) {
|
||||||
|
case INPUT: return td.getSource();
|
||||||
|
case OUTPUT: if (td.getOutput() == null)
|
||||||
|
throw new FHIRException("Not generated yet");
|
||||||
|
else
|
||||||
|
return td.getOutput();
|
||||||
|
case INCLUDE:
|
||||||
|
return td.getIncluded();
|
||||||
|
default:
|
||||||
|
throw new FHIRException("Not done yet");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FHIRPath methods
|
||||||
|
@Override
|
||||||
|
public Base resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException {
|
||||||
|
throw new Error("Not implemented yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeDetails resolveConstantType(Object appContext, String name) throws PathEngineException {
|
||||||
|
throw new Error("Not implemented yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean log(String argument, List<Base> focus) {
|
||||||
|
System.out.println(argument+": "+fp.convertToString(focus));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FunctionDetails resolveFunction(String functionName) {
|
||||||
|
if ("fixture".equals(functionName))
|
||||||
|
return new FunctionDetails("Access a fixture defined in the testing context", 0, 1);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeDetails checkFunction(Object appContext, String functionName, List<TypeDetails> parameters) throws PathEngineException {
|
||||||
|
if ("fixture".equals(functionName))
|
||||||
|
return new TypeDetails(CollectionStatus.SINGLETON, TestingUtilitiesX.context(version).getResourceNamesAsSet());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Base> executeFunction(Object appContext, String functionName, List<List<Base>> parameters) {
|
||||||
|
if ("fixture".equals(functionName)) {
|
||||||
|
String id = fp.convertToString(parameters.get(0));
|
||||||
|
Resource res = fetchFixture(id);
|
||||||
|
if (res != null) {
|
||||||
|
List<Base> list = new ArrayList<Base>();
|
||||||
|
list.add(res);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
throw new Error("Could not resolve "+id);
|
||||||
|
}
|
||||||
|
throw new Error("Not implemented yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Base resolveReference(Object appContext, String url, Base refContext) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean conformsToProfile(Object appContext, Base item, String url) throws FHIRException {
|
||||||
|
IResourceValidator val = TestingUtilitiesX.context(version).newValidator();
|
||||||
|
List<ValidationMessage> valerrors = new ArrayList<ValidationMessage>();
|
||||||
|
if (item instanceof Resource) {
|
||||||
|
val.validate(appContext, valerrors, (Resource) item, url);
|
||||||
|
boolean ok = true;
|
||||||
|
for (ValidationMessage v : valerrors)
|
||||||
|
ok = ok && v.getLevel().isError();
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
throw new NotImplementedException("Not done yet (IGPublisherHostServices.SnapShotGenerationTestsContext), when item is element");
|
||||||
|
}
|
||||||
|
|
||||||
|
public StructureDefinition getByUrl(String url) {
|
||||||
|
if (url == null)
|
||||||
|
return null;
|
||||||
|
for (TestDetails t : tests) {
|
||||||
|
if (t.expected != null && url.equals(t.expected.getUrl()))
|
||||||
|
return t.expected;
|
||||||
|
if (t.included != null && url.equals(t.included.getUrl()))
|
||||||
|
return t.included;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValueSet resolveValueSet(Object appContext, String url) {
|
||||||
|
throw new Error("Not implemented yet");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FHIRPathEngine fp;
|
||||||
|
|
||||||
|
@Parameters(name = "{index}: file {0}")
|
||||||
|
public static Iterable<Object[]> data() throws ParserConfigurationException, IOException, FHIRFormatError, SAXException {
|
||||||
|
|
||||||
|
SnapShotGenerationTestsContext context = new SnapShotGenerationTestsContext();
|
||||||
|
Document tests = XMLUtil.parseToDom(TestingUtilitiesX.loadTestResource("rX", "snapshot-generation", "manifest.xml"));
|
||||||
|
Element test = XMLUtil.getFirstChild(tests.getDocumentElement());
|
||||||
|
List<Object[]> objects = new ArrayList<Object[]>();
|
||||||
|
while (test != null && test.getNodeName().equals("test")) {
|
||||||
|
TestDetails t = new TestDetails(test);
|
||||||
|
context.tests.add(t);
|
||||||
|
t.load();
|
||||||
|
objects.add(new Object[] {t.getId(), t, context });
|
||||||
|
test = XMLUtil.getNextSibling(test);
|
||||||
|
}
|
||||||
|
return objects;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private final TestDetails test;
|
||||||
|
private SnapShotGenerationTestsContext context;
|
||||||
|
private List<ValidationMessage> messages;
|
||||||
|
private static String version;
|
||||||
|
|
||||||
|
public SnapShotGenerationTestsX(String id, TestDetails test, SnapShotGenerationTestsContext context) {
|
||||||
|
this.test = test;
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
@Test
|
||||||
|
public void test() throws Exception {
|
||||||
|
version = test.version;
|
||||||
|
if (fp == null)
|
||||||
|
fp = new FHIRPathEngine(TestingUtilitiesX.context(version));
|
||||||
|
fp.setHostServices(context);
|
||||||
|
messages = new ArrayList<ValidationMessage>();
|
||||||
|
|
||||||
|
if (test.isFail()) {
|
||||||
|
try {
|
||||||
|
if (test.isGen())
|
||||||
|
testGen(true);
|
||||||
|
else
|
||||||
|
testSort();
|
||||||
|
Assert.assertTrue("Should have failed", false);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
System.out.println("Error running test: "+e.getMessage());
|
||||||
|
if (!Utilities.noString(test.regex)) {
|
||||||
|
Assert.assertTrue("correct error message", e.getMessage().matches(test.regex));
|
||||||
|
} else if ("Should have failed".equals(e.getMessage())) {
|
||||||
|
throw e;
|
||||||
|
} else {
|
||||||
|
Assert.assertTrue("all ok", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else if (test.isGen())
|
||||||
|
testGen(false);
|
||||||
|
else
|
||||||
|
testSort();
|
||||||
|
for (Rule r : test.getRules()) {
|
||||||
|
StructureDefinition sdn = new StructureDefinition();
|
||||||
|
boolean ok = fp.evaluateToBoolean(sdn, sdn, sdn, r.expression);
|
||||||
|
Assert.assertTrue(r.description, ok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void testSort() throws DefinitionException, FHIRException, IOException {
|
||||||
|
StructureDefinition base = getSD(test.getSource().getBaseDefinition());
|
||||||
|
test.setOutput(test.getSource().copy());
|
||||||
|
ProfileUtilities pu = new ProfileUtilities(TestingUtilitiesX.context(version), null, null);
|
||||||
|
pu.setIds(test.getSource(), false);
|
||||||
|
List<String> errors = new ArrayList<String>();
|
||||||
|
pu.sortDifferential(base, test.getOutput(), test.getOutput().getUrl(), errors, false);
|
||||||
|
if (!errors.isEmpty())
|
||||||
|
throw new FHIRException(errors.get(0));
|
||||||
|
IOUtils.copy(TestingUtilitiesX.loadTestResourceStream("rX", "snapshot-generation", test.getId()+"-expected.xml"), new FileOutputStream(TestingUtilitiesX.tempFile("snapshot", test.getId()+"-expected.xml")));
|
||||||
|
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(TestingUtilitiesX.tempFile("snapshot", test.getId()+"-actual.xml")), test.getOutput());
|
||||||
|
Assert.assertTrue("Output does not match expected", test.expected.equalsDeep(test.output));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testGen(boolean fail) throws Exception {
|
||||||
|
if (!Utilities.noString(test.register)) {
|
||||||
|
List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
|
||||||
|
ProfileUtilities pu = new ProfileUtilities(TestingUtilitiesX.context(version), messages, null);
|
||||||
|
pu.setNewSlicingProcessing(true);
|
||||||
|
pu.setIds(test.included, false);
|
||||||
|
StructureDefinition base = TestingUtilitiesX.context(version).fetchResource(StructureDefinition.class, test.included.getBaseDefinition());
|
||||||
|
if (base != null) {
|
||||||
|
pu.generateSnapshot(base, test.included, test.included.getUrl(), "http://test.org/profile", test.included.getName());
|
||||||
|
}
|
||||||
|
if (!TestingUtilitiesX.context(version).hasResource(StructureDefinition.class, test.included.getUrl()))
|
||||||
|
TestingUtilitiesX.context(version).cacheResource(test.included);
|
||||||
|
int ec = 0;
|
||||||
|
for (ValidationMessage vm : messages) {
|
||||||
|
if (vm.getLevel() == IssueSeverity.ERROR) {
|
||||||
|
System.out.println(vm.summary());
|
||||||
|
ec++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ec > 0)
|
||||||
|
throw new FHIRException("register gen failed: "+messages.toString());
|
||||||
|
}
|
||||||
|
StructureDefinition base = getSD(test.getSource().getBaseDefinition());
|
||||||
|
if (!base.getUrl().equals(test.getSource().getBaseDefinition()))
|
||||||
|
throw new Exception("URL mismatch on base: "+base.getUrl()+" wanting "+test.getSource().getBaseDefinition());
|
||||||
|
|
||||||
|
StructureDefinition output = test.getSource().copy();
|
||||||
|
ProfileUtilities pu = new ProfileUtilities(TestingUtilitiesX.context(version), messages , new TestPKP());
|
||||||
|
pu.setNewSlicingProcessing(test.isNewSliceProcessing());
|
||||||
|
pu.setThrowException(false);
|
||||||
|
pu.setDebug(test.isDebug());
|
||||||
|
pu.setIds(test.getSource(), false);
|
||||||
|
if (test.isSort()) {
|
||||||
|
List<String> errors = new ArrayList<String>();
|
||||||
|
int lastCount = output.getDifferential().getElement().size();
|
||||||
|
pu.sortDifferential(base, output, test.getSource().getName(), errors, false);
|
||||||
|
if (errors.size() > 0)
|
||||||
|
throw new FHIRException("Sort failed: "+errors.toString());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
messages.clear();
|
||||||
|
pu.generateSnapshot(base, output, test.getSource().getUrl(), "http://test.org/profile", test.getSource().getName());
|
||||||
|
List<ValidationMessage> ml = new ArrayList<>();
|
||||||
|
for (ValidationMessage vm : messages) {
|
||||||
|
if (vm.getLevel() == IssueSeverity.ERROR) {
|
||||||
|
ml.add(vm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ml.size() > 0) {
|
||||||
|
throw new FHIRException("Snapshot Generation failed: "+ml.toString());
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
System.out.println("\r\nException: "+e.getMessage());
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
if (output.getDifferential().hasElement())
|
||||||
|
new NarrativeGenerator("", "http://hl7.org/fhir", TestingUtilitiesX.context(version)).setPkp(new TestPKP()).generate(output, null);
|
||||||
|
if (!fail) {
|
||||||
|
test.output = output;
|
||||||
|
TestingUtilitiesX.context(version).cacheResource(output);
|
||||||
|
File dst = new File(TestingUtilitiesX.tempFile("snapshot", test.getId()+"-expected.xml"));
|
||||||
|
if (dst.exists())
|
||||||
|
dst.delete();
|
||||||
|
IOUtils.copy(TestingUtilitiesX.loadTestResourceStream("rX", "snapshot-generation", test.getId()+"-expected.xml"), new FileOutputStream(dst));
|
||||||
|
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(TestingUtilitiesX.tempFile("snapshot", test.getId()+"-actual.xml")), output);
|
||||||
|
StructureDefinition t1 = test.expected.copy();
|
||||||
|
t1.setText(null);
|
||||||
|
StructureDefinition t2 = test.output.copy();
|
||||||
|
t2.setText(null);
|
||||||
|
Assert.assertTrue("Output does not match expected", t1.equalsDeep(t2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private StructureDefinition getSD(String url) throws DefinitionException, FHIRException, IOException {
|
||||||
|
StructureDefinition sd = context.getByUrl(url);
|
||||||
|
if (sd == null)
|
||||||
|
sd = TestingUtilitiesX.context(version).fetchResource(StructureDefinition.class, url);
|
||||||
|
if (!sd.hasSnapshot()) {
|
||||||
|
StructureDefinition base = getSD(sd.getBaseDefinition());
|
||||||
|
ProfileUtilities pu = new ProfileUtilities(TestingUtilitiesX.context(version), messages , new TestPKP());
|
||||||
|
pu.setNewSlicingProcessing(true);
|
||||||
|
List<String> errors = new ArrayList<String>();
|
||||||
|
pu.sortDifferential(base, sd, url, errors, false);
|
||||||
|
if (!errors.isEmpty())
|
||||||
|
throw new FHIRException(errors.get(0));
|
||||||
|
pu.setIds(sd, false);
|
||||||
|
pu.generateSnapshot(base, sd, sd.getUrl(), "http://test.org/profile", sd.getName());
|
||||||
|
}
|
||||||
|
return sd;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,556 @@
|
||||||
|
package org.hl7.fhir.conversion.tests;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.binary.Base64;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.fhir.ucum.UcumEssenceService;
|
||||||
|
import org.hl7.fhir.convertors.R2016MayToR5Loader;
|
||||||
|
import org.hl7.fhir.convertors.R2ToR5Loader;
|
||||||
|
import org.hl7.fhir.convertors.R3ToR5Loader;
|
||||||
|
import org.hl7.fhir.convertors.R4ToR5Loader;
|
||||||
|
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||||
|
import org.hl7.fhir.r5.context.SimpleWorkerContext;
|
||||||
|
import org.hl7.fhir.r5.context.SimpleWorkerContext.IContextResourceLoader;
|
||||||
|
import org.hl7.fhir.r5.model.Parameters;
|
||||||
|
import org.hl7.fhir.utilities.CSFile;
|
||||||
|
import org.hl7.fhir.utilities.TextFile;
|
||||||
|
import org.hl7.fhir.utilities.Utilities;
|
||||||
|
import org.hl7.fhir.utilities.VersionUtilities;
|
||||||
|
import org.hl7.fhir.utilities.cache.PackageCacheManager;
|
||||||
|
import org.hl7.fhir.utilities.cache.ToolsVersion;
|
||||||
|
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
import org.w3c.dom.NamedNodeMap;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonNull;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonPrimitive;
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
|
||||||
|
public class TestingUtilitiesX {
|
||||||
|
private static final boolean SHOW_DIFF = true;
|
||||||
|
|
||||||
|
static public Map<String, IWorkerContext> fcontexts;
|
||||||
|
|
||||||
|
public static IWorkerContext context(String version) {
|
||||||
|
if (fcontexts == null) {
|
||||||
|
fcontexts = new HashMap<>();
|
||||||
|
}
|
||||||
|
if (!fcontexts.containsKey(version)) {
|
||||||
|
PackageCacheManager pcm;
|
||||||
|
try {
|
||||||
|
pcm = new PackageCacheManager(true, ToolsVersion.TOOLS_VERSION);
|
||||||
|
IWorkerContext fcontext = SimpleWorkerContext.fromPackage(pcm.loadPackage(VersionUtilities.packageForVersion(version), version), loaderForVersion(version));
|
||||||
|
fcontext.setUcumService(new UcumEssenceService(TestingUtilitiesX.loadTestResourceStream("ucum", "ucum-essence.xml")));
|
||||||
|
fcontext.setExpansionProfile(new Parameters());
|
||||||
|
fcontexts.put(version, fcontext);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new Error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fcontexts.get(version);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IContextResourceLoader loaderForVersion(String version) {
|
||||||
|
if (Utilities.noString(version))
|
||||||
|
return null;
|
||||||
|
if (version.startsWith("1.0"))
|
||||||
|
return new R2ToR5Loader(new String[] { "Conformance", "StructureDefinition", "ValueSet", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"});
|
||||||
|
if (version.startsWith("1.4"))
|
||||||
|
return new R2016MayToR5Loader(new String[] { "Conformance", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"}); // special case
|
||||||
|
if (version.startsWith("3.0"))
|
||||||
|
return new R3ToR5Loader(new String[] { "CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"});
|
||||||
|
if (version.startsWith("4.0"))
|
||||||
|
return new R4ToR5Loader(new String[] { "CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"});
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static public boolean silent;
|
||||||
|
|
||||||
|
static public String fixedpath;
|
||||||
|
static public String contentpath;
|
||||||
|
|
||||||
|
public static String home() {
|
||||||
|
if (fixedpath != null)
|
||||||
|
return fixedpath;
|
||||||
|
String s = System.getenv("FHIR_HOME");
|
||||||
|
if (!Utilities.noString(s))
|
||||||
|
return s;
|
||||||
|
s = "C:\\work\\org.hl7.fhir\\build";
|
||||||
|
// FIXME: change this back
|
||||||
|
s = "/Users/jamesagnew/git/fhir";
|
||||||
|
if (new File(s).exists())
|
||||||
|
return s;
|
||||||
|
throw new Error("FHIR Home directory not configured");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String content() throws IOException {
|
||||||
|
if (contentpath != null)
|
||||||
|
return contentpath;
|
||||||
|
String s = "R:\\fhir\\publish";
|
||||||
|
if (new File(s).exists())
|
||||||
|
return s;
|
||||||
|
return Utilities.path(home(), "publish");
|
||||||
|
}
|
||||||
|
|
||||||
|
// diretory that contains all the US implementation guides
|
||||||
|
public static String us() {
|
||||||
|
if (fixedpath != null)
|
||||||
|
return fixedpath;
|
||||||
|
String s = System.getenv("FHIR_HOME");
|
||||||
|
if (!Utilities.noString(s))
|
||||||
|
return s;
|
||||||
|
s = "C:\\work\\org.hl7.fhir.us";
|
||||||
|
if (new File(s).exists())
|
||||||
|
return s;
|
||||||
|
throw new Error("FHIR US directory not configured");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String checkXMLIsSame(InputStream f1, InputStream f2) throws Exception {
|
||||||
|
String result = compareXml(f1, f2);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String checkXMLIsSame(String f1, String f2) throws Exception {
|
||||||
|
String result = compareXml(f1, f2);
|
||||||
|
if (result != null && SHOW_DIFF) {
|
||||||
|
String diff = Utilities.path(System.getenv("ProgramFiles(X86)"), "WinMerge", "WinMergeU.exe");
|
||||||
|
List<String> command = new ArrayList<String>();
|
||||||
|
command.add("\"" + diff + "\" \"" + f1 + "\" \"" + f2 + "\"");
|
||||||
|
|
||||||
|
ProcessBuilder builder = new ProcessBuilder(command);
|
||||||
|
builder.directory(new CSFile("c:\\temp"));
|
||||||
|
builder.start();
|
||||||
|
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String compareXml(InputStream f1, InputStream f2) throws Exception {
|
||||||
|
return compareElements("", loadXml(f1).getDocumentElement(), loadXml(f2).getDocumentElement());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String compareXml(String f1, String f2) throws Exception {
|
||||||
|
return compareElements("", loadXml(f1).getDocumentElement(), loadXml(f2).getDocumentElement());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String compareElements(String path, Element e1, Element e2) {
|
||||||
|
if (!e1.getNamespaceURI().equals(e2.getNamespaceURI()))
|
||||||
|
return "Namespaces differ at "+path+": "+e1.getNamespaceURI()+"/"+e2.getNamespaceURI();
|
||||||
|
if (!e1.getLocalName().equals(e2.getLocalName()))
|
||||||
|
return "Names differ at "+path+": "+e1.getLocalName()+"/"+e2.getLocalName();
|
||||||
|
path = path + "/"+e1.getLocalName();
|
||||||
|
String s = compareAttributes(path, e1.getAttributes(), e2.getAttributes());
|
||||||
|
if (!Utilities.noString(s))
|
||||||
|
return s;
|
||||||
|
s = compareAttributes(path, e2.getAttributes(), e1.getAttributes());
|
||||||
|
if (!Utilities.noString(s))
|
||||||
|
return s;
|
||||||
|
|
||||||
|
Node c1 = e1.getFirstChild();
|
||||||
|
Node c2 = e2.getFirstChild();
|
||||||
|
c1 = skipBlankText(c1);
|
||||||
|
c2 = skipBlankText(c2);
|
||||||
|
while (c1 != null && c2 != null) {
|
||||||
|
if (c1.getNodeType() != c2.getNodeType())
|
||||||
|
return "node type mismatch in children of "+path+": "+Integer.toString(e1.getNodeType())+"/"+Integer.toString(e2.getNodeType());
|
||||||
|
if (c1.getNodeType() == Node.TEXT_NODE) {
|
||||||
|
if (!normalise(c1.getTextContent()).equals(normalise(c2.getTextContent())))
|
||||||
|
return "Text differs at "+path+": "+normalise(c1.getTextContent()) +"/"+ normalise(c2.getTextContent());
|
||||||
|
}
|
||||||
|
else if (c1.getNodeType() == Node.ELEMENT_NODE) {
|
||||||
|
s = compareElements(path, (Element) c1, (Element) c2);
|
||||||
|
if (!Utilities.noString(s))
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
c1 = skipBlankText(c1.getNextSibling());
|
||||||
|
c2 = skipBlankText(c2.getNextSibling());
|
||||||
|
}
|
||||||
|
if (c1 != null)
|
||||||
|
return "node mismatch - more nodes in source in children of "+path;
|
||||||
|
if (c2 != null)
|
||||||
|
return "node mismatch - more nodes in target in children of "+path;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Object normalise(String text) {
|
||||||
|
String result = text.trim().replace('\r', ' ').replace('\n', ' ').replace('\t', ' ');
|
||||||
|
while (result.contains(" "))
|
||||||
|
result = result.replace(" ", " ");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String compareAttributes(String path, NamedNodeMap src, NamedNodeMap tgt) {
|
||||||
|
for (int i = 0; i < src.getLength(); i++) {
|
||||||
|
|
||||||
|
Node sa = src.item(i);
|
||||||
|
String sn = sa.getNodeName();
|
||||||
|
if (! (sn.equals("xmlns") || sn.startsWith("xmlns:"))) {
|
||||||
|
Node ta = tgt.getNamedItem(sn);
|
||||||
|
if (ta == null)
|
||||||
|
return "Attributes differ at "+path+": missing attribute "+sn;
|
||||||
|
if (!normalise(sa.getTextContent()).equals(normalise(ta.getTextContent()))) {
|
||||||
|
byte[] b1 = unBase64(sa.getTextContent());
|
||||||
|
byte[] b2 = unBase64(ta.getTextContent());
|
||||||
|
if (!sameBytes(b1, b2))
|
||||||
|
return "Attributes differ at "+path+": value "+normalise(sa.getTextContent()) +"/"+ normalise(ta.getTextContent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean sameBytes(byte[] b1, byte[] b2) {
|
||||||
|
if (b1.length == 0 || b2.length == 0)
|
||||||
|
return false;
|
||||||
|
if (b1.length != b2.length)
|
||||||
|
return false;
|
||||||
|
for (int i = 0; i < b1.length; i++)
|
||||||
|
if (b1[i] != b2[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] unBase64(String text) {
|
||||||
|
return Base64.decodeBase64(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Node skipBlankText(Node node) {
|
||||||
|
while (node != null && (((node.getNodeType() == Node.TEXT_NODE) && Utilities.isWhitespace(node.getTextContent())) || (node.getNodeType() == Node.COMMENT_NODE)))
|
||||||
|
node = node.getNextSibling();
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Document loadXml(String fn) throws Exception {
|
||||||
|
return loadXml(new FileInputStream(fn));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Document loadXml(InputStream fn) throws Exception {
|
||||||
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||||
|
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||||
|
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
|
||||||
|
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
|
||||||
|
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
|
||||||
|
factory.setXIncludeAware(false);
|
||||||
|
factory.setExpandEntityReferences(false);
|
||||||
|
|
||||||
|
factory.setNamespaceAware(true);
|
||||||
|
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||||
|
return builder.parse(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String checkJsonSrcIsSame(String s1, String s2) throws JsonSyntaxException, FileNotFoundException, IOException {
|
||||||
|
return checkJsonSrcIsSame(s1,s2,true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String checkJsonSrcIsSame(String s1, String s2, boolean showDiff) throws JsonSyntaxException, FileNotFoundException, IOException {
|
||||||
|
String result = compareJsonSrc(s1, s2);
|
||||||
|
if (result != null && SHOW_DIFF && showDiff) {
|
||||||
|
String diff = null;
|
||||||
|
if (System.getProperty("os.name").contains("Linux"))
|
||||||
|
diff = Utilities.path("/", "usr", "bin", "meld");
|
||||||
|
else {
|
||||||
|
if (Utilities.checkFile("WinMerge", Utilities.path(System.getenv("ProgramFiles(X86)"), "WinMerge"), "\\WinMergeU.exe", null))
|
||||||
|
diff = Utilities.path(System.getenv("ProgramFiles(X86)"), "WinMerge", "WinMergeU.exe");
|
||||||
|
else if (Utilities.checkFile("WinMerge", Utilities.path(System.getenv("ProgramFiles(X86)"), "Meld"), "\\Meld.exe", null))
|
||||||
|
diff = Utilities.path(System.getenv("ProgramFiles(X86)"), "Meld", "Meld.exe");
|
||||||
|
}
|
||||||
|
if (diff == null || diff.isEmpty())
|
||||||
|
return result;
|
||||||
|
|
||||||
|
List<String> command = new ArrayList<String>();
|
||||||
|
String f1 = Utilities.path("[tmp]", "input" + s1.hashCode() + ".json");
|
||||||
|
String f2 = Utilities.path("[tmp]", "output" + s2.hashCode() + ".json");
|
||||||
|
TextFile.stringToFile(s1, f1);
|
||||||
|
TextFile.stringToFile(s2, f2);
|
||||||
|
command.add(diff);
|
||||||
|
if (diff.toLowerCase().contains("meld"))
|
||||||
|
command.add("--newtab");
|
||||||
|
command.add(f1);
|
||||||
|
command.add(f2);
|
||||||
|
|
||||||
|
ProcessBuilder builder = new ProcessBuilder(command);
|
||||||
|
builder.directory(new CSFile(Utilities.path("[tmp]")));
|
||||||
|
builder.start();
|
||||||
|
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
public static String checkJsonIsSame(String f1, String f2) throws JsonSyntaxException, FileNotFoundException, IOException {
|
||||||
|
String result = compareJson(f1, f2);
|
||||||
|
if (result != null && SHOW_DIFF) {
|
||||||
|
String diff = Utilities.path(System.getenv("ProgramFiles(X86)"), "WinMerge", "WinMergeU.exe");
|
||||||
|
List<String> command = new ArrayList<String>();
|
||||||
|
command.add("\"" + diff + "\" \"" + f1 + "\" \"" + f2 + "\"");
|
||||||
|
|
||||||
|
ProcessBuilder builder = new ProcessBuilder(command);
|
||||||
|
builder.directory(new CSFile("c:\\temp"));
|
||||||
|
builder.start();
|
||||||
|
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String compareJsonSrc(String f1, String f2) throws JsonSyntaxException, FileNotFoundException, IOException {
|
||||||
|
JsonObject o1 = (JsonObject) new com.google.gson.JsonParser().parse(f1);
|
||||||
|
JsonObject o2 = (JsonObject) new com.google.gson.JsonParser().parse(f2);
|
||||||
|
return compareObjects("", o1, o2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String compareJson(String f1, String f2) throws JsonSyntaxException, FileNotFoundException, IOException {
|
||||||
|
JsonObject o1 = (JsonObject) new com.google.gson.JsonParser().parse(TextFile.fileToString(f1));
|
||||||
|
JsonObject o2 = (JsonObject) new com.google.gson.JsonParser().parse(TextFile.fileToString(f2));
|
||||||
|
return compareObjects("", o1, o2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String compareObjects(String path, JsonObject o1, JsonObject o2) {
|
||||||
|
for (Map.Entry<String, JsonElement> en : o1.entrySet()) {
|
||||||
|
String n = en.getKey();
|
||||||
|
if (!n.equals("fhir_comments")) {
|
||||||
|
if (o2.has(n)) {
|
||||||
|
String s = compareNodes(path+'.'+n, en.getValue(), o2.get(n));
|
||||||
|
if (!Utilities.noString(s))
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return "properties differ at "+path+": missing property "+n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Map.Entry<String, JsonElement> en : o2.entrySet()) {
|
||||||
|
String n = en.getKey();
|
||||||
|
if (!n.equals("fhir_comments")) {
|
||||||
|
if (!o1.has(n))
|
||||||
|
return "properties differ at "+path+": missing property "+n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String compareNodes(String path, JsonElement n1, JsonElement n2) {
|
||||||
|
if (n1.getClass() != n2.getClass())
|
||||||
|
return "properties differ at "+path+": type "+n1.getClass().getName()+"/"+n2.getClass().getName();
|
||||||
|
else if (n1 instanceof JsonPrimitive) {
|
||||||
|
JsonPrimitive p1 = (JsonPrimitive) n1;
|
||||||
|
JsonPrimitive p2 = (JsonPrimitive) n2;
|
||||||
|
if (p1.isBoolean() && p2.isBoolean()) {
|
||||||
|
if (p1.getAsBoolean() != p2.getAsBoolean())
|
||||||
|
return "boolean property values differ at "+path+": type "+p1.getAsString()+"/"+p2.getAsString();
|
||||||
|
} else if (p1.isString() && p2.isString()) {
|
||||||
|
String s1 = p1.getAsString();
|
||||||
|
String s2 = p2.getAsString();
|
||||||
|
if (!(s1.contains("<div") && s2.contains("<div")))
|
||||||
|
if (!s1.equals(s2))
|
||||||
|
if (!sameBytes(unBase64(s1), unBase64(s2)))
|
||||||
|
return "string property values differ at "+path+": type "+s1+"/"+s2;
|
||||||
|
} else if (p1.isNumber() && p2.isNumber()) {
|
||||||
|
if (!p1.getAsString().equals(p2.getAsString()))
|
||||||
|
return "number property values differ at "+path+": type "+p1.getAsString()+"/"+p2.getAsString();
|
||||||
|
} else
|
||||||
|
return "property types differ at "+path+": type "+p1.getAsString()+"/"+p2.getAsString();
|
||||||
|
}
|
||||||
|
else if (n1 instanceof JsonObject) {
|
||||||
|
String s = compareObjects(path, (JsonObject) n1, (JsonObject) n2);
|
||||||
|
if (!Utilities.noString(s))
|
||||||
|
return s;
|
||||||
|
} else if (n1 instanceof JsonArray) {
|
||||||
|
JsonArray a1 = (JsonArray) n1;
|
||||||
|
JsonArray a2 = (JsonArray) n2;
|
||||||
|
|
||||||
|
if (a1.size() != a2.size())
|
||||||
|
return "array properties differ at "+path+": count "+Integer.toString(a1.size())+"/"+Integer.toString(a2.size());
|
||||||
|
for (int i = 0; i < a1.size(); i++) {
|
||||||
|
String s = compareNodes(path+"["+Integer.toString(i)+"]", a1.get(i), a2.get(i));
|
||||||
|
if (!Utilities.noString(s))
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (n1 instanceof JsonNull) {
|
||||||
|
|
||||||
|
} else
|
||||||
|
return "unhandled property "+n1.getClass().getName();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String temp() {
|
||||||
|
if (new File("c:\\temp").exists())
|
||||||
|
return "c:\\temp";
|
||||||
|
return System.getProperty("java.io.tmpdir");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String checkTextIsSame(String s1, String s2) throws JsonSyntaxException, FileNotFoundException, IOException {
|
||||||
|
return checkTextIsSame(s1,s2,true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String checkTextIsSame(String s1, String s2, boolean showDiff) throws JsonSyntaxException, FileNotFoundException, IOException {
|
||||||
|
String result = compareText(s1, s2);
|
||||||
|
if (result != null && SHOW_DIFF && showDiff) {
|
||||||
|
String diff = null;
|
||||||
|
if (System.getProperty("os.name").contains("Linux"))
|
||||||
|
diff = Utilities.path("/", "usr", "bin", "meld");
|
||||||
|
else {
|
||||||
|
if (Utilities.checkFile("WinMerge", Utilities.path(System.getenv("ProgramFiles(X86)"), "WinMerge"), "\\WinMergeU.exe", null))
|
||||||
|
diff = Utilities.path(System.getenv("ProgramFiles(X86)"), "WinMerge", "WinMergeU.exe");
|
||||||
|
else if (Utilities.checkFile("WinMerge", Utilities.path(System.getenv("ProgramFiles(X86)"), "Meld"), "\\Meld.exe", null))
|
||||||
|
diff = Utilities.path(System.getenv("ProgramFiles(X86)"), "Meld", "Meld.exe");
|
||||||
|
}
|
||||||
|
if (diff == null || diff.isEmpty())
|
||||||
|
return result;
|
||||||
|
|
||||||
|
List<String> command = new ArrayList<String>();
|
||||||
|
String f1 = Utilities.path("[tmp]", "input" + s1.hashCode() + ".json");
|
||||||
|
String f2 = Utilities.path("[tmp]", "output" + s2.hashCode() + ".json");
|
||||||
|
TextFile.stringToFile(s1, f1);
|
||||||
|
TextFile.stringToFile(s2, f2);
|
||||||
|
command.add(diff);
|
||||||
|
if (diff.toLowerCase().contains("meld"))
|
||||||
|
command.add("--newtab");
|
||||||
|
command.add(f1);
|
||||||
|
command.add(f2);
|
||||||
|
|
||||||
|
ProcessBuilder builder = new ProcessBuilder(command);
|
||||||
|
builder.directory(new CSFile(Utilities.path("[tmp]")));
|
||||||
|
builder.start();
|
||||||
|
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static String compareText(String s1, String s2) {
|
||||||
|
for (int i = 0; i < Integer.min(s1.length(), s2.length()); i++) {
|
||||||
|
if (s1.charAt(i) != s2.charAt(i))
|
||||||
|
return "Strings differ at character "+Integer.toString(i)+": '"+s1.charAt(i) +"' vs '"+s2.charAt(i)+"'";
|
||||||
|
}
|
||||||
|
if (s1.length() != s2.length())
|
||||||
|
return "Strings differ in length: "+Integer.toString(s1.length())+" vs "+Integer.toString(s2.length())+" but match to the end of the shortest";
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean findTestResource(String... paths) throws IOException {
|
||||||
|
if (new File("../../fhir-test-cases").exists() && isTryToLoadFromFileSystem()) {
|
||||||
|
String n = Utilities.path(System.getProperty("user.dir"), "..", "..", "fhir-test-cases", Utilities.path(paths));
|
||||||
|
return new File(n).exists();
|
||||||
|
} else {
|
||||||
|
String classpath = ("/org/hl7/fhir/testcases/"+ Utilities.pathURL(paths));
|
||||||
|
try {
|
||||||
|
InputStream inputStream = TestingUtilitiesX.class.getResourceAsStream(classpath);
|
||||||
|
return inputStream != null;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: JA need to figure out how to detect that we're running in maven
|
||||||
|
private static boolean isTryToLoadFromFileSystem() {
|
||||||
|
return !"true".equals(System.getProperty("dont_load_from_filesystem"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String loadTestResource(String... paths) throws IOException {
|
||||||
|
if (new File("../../fhir-test-cases").exists() && isTryToLoadFromFileSystem()) {
|
||||||
|
String n = Utilities.path(System.getProperty("user.dir"), "..", "..", "fhir-test-cases", Utilities.path(paths));
|
||||||
|
// ok, we'll resolve this locally
|
||||||
|
return TextFile.fileToString(new File(n));
|
||||||
|
} else {
|
||||||
|
// resolve from the package
|
||||||
|
String contents;
|
||||||
|
String classpath = ("/org/hl7/fhir/testcases/"+ Utilities.pathURL(paths));
|
||||||
|
try (InputStream inputStream = TestingUtilitiesX.class.getResourceAsStream(classpath)) {
|
||||||
|
if (inputStream == null) {
|
||||||
|
throw new IOException("Can't find file on classpath: " + classpath);
|
||||||
|
}
|
||||||
|
contents = IOUtils.toString(inputStream, java.nio.charset.StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
return contents;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InputStream loadTestResourceStream(String... paths) throws IOException {
|
||||||
|
if (new File("../../fhir-test-cases").exists() && isTryToLoadFromFileSystem()) {
|
||||||
|
String n = Utilities.path(System.getProperty("user.dir"), "..", "..", "fhir-test-cases", Utilities.path(paths));
|
||||||
|
return new FileInputStream(n);
|
||||||
|
} else {
|
||||||
|
String classpath = ("/org/hl7/fhir/testcases/"+ Utilities.pathURL(paths));
|
||||||
|
InputStream s = TestingUtilitiesX.class.getResourceAsStream(classpath);
|
||||||
|
if (s == null) {
|
||||||
|
throw new Error("unable to find resource "+classpath);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] loadTestResourceBytes(String... paths) throws IOException {
|
||||||
|
if (new File("../../fhir-test-cases").exists() && isTryToLoadFromFileSystem()) {
|
||||||
|
String n = Utilities.path(System.getProperty("user.dir"), "..", "..", "fhir-test-cases", Utilities.path(paths));
|
||||||
|
return TextFile.fileToBytes(n);
|
||||||
|
} else {
|
||||||
|
String classpath = ("/org/hl7/fhir/testcases/"+ Utilities.pathURL(paths));
|
||||||
|
InputStream s = TestingUtilitiesX.class.getResourceAsStream(classpath);
|
||||||
|
if (s == null) {
|
||||||
|
throw new Error("unable to find resource "+classpath);
|
||||||
|
}
|
||||||
|
return TextFile.streamToBytes(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String tempFile(String folder, String name) throws IOException {
|
||||||
|
String tmp = tempFolder(folder);
|
||||||
|
return Utilities.path(tmp, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String tempFolder(String name) throws IOException {
|
||||||
|
File tmp = new File("C:\\temp");
|
||||||
|
if (tmp.exists() && tmp.isDirectory()) {
|
||||||
|
String path = Utilities.path("C:\\temp", name);
|
||||||
|
Utilities.createDirectory(path);
|
||||||
|
return path;
|
||||||
|
} else if (new File("/tmp").exists()) {
|
||||||
|
String path = Utilities.path("/tmp", name);
|
||||||
|
Utilities.createDirectory(path);
|
||||||
|
return path;
|
||||||
|
} else {
|
||||||
|
String path = Utilities.path(System.getProperty("java.io.tmpdir"), name);
|
||||||
|
Utilities.createDirectory(path);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue