From eacffd11df4ee0234ce4d922943394a704fbabbf Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 17 Aug 2023 11:14:34 +1000 Subject: [PATCH] Add support for external strings for tx tests --- .../fhir/r5/test/utils/CompareUtilities.java | 171 +++++++++++------- .../org/hl7/fhir/r5/test/ParsingTests.java | 2 +- .../r5/test/utils/CompareUtilitiesTests.java | 2 +- .../utilities/json/model/JsonPrimitive.java | 4 + .../validation/cli/tasks/TxTestsTask.java | 15 +- .../hl7/fhir/validation/cli/utils/Params.java | 1 + .../hl7/fhir/validation/special/TxTester.java | 20 +- .../comparison/tests/ComparisonTests.java | 93 +++++++++- .../fhir/r5/test/StructureMappingTests.java | 2 +- .../ExternalTerminologyServiceTests.java | 8 +- .../tests/TerminologyServiceTests.java | 20 +- 11 files changed, 248 insertions(+), 90 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/CompareUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/CompareUtilities.java index 6eaa0dd6d..f1c27c413 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/CompareUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/test/utils/CompareUtilities.java @@ -2,20 +2,22 @@ package org.hl7.fhir.r5.test.utils; import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang3.StringUtils; +import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.utilities.*; import org.hl7.fhir.utilities.json.JsonUtilities; +import org.hl7.fhir.utilities.json.model.JsonArray; +import org.hl7.fhir.utilities.json.model.JsonElement; +import org.hl7.fhir.utilities.json.model.JsonNull; +import org.hl7.fhir.utilities.json.model.JsonObject; +import org.hl7.fhir.utilities.json.model.JsonPrimitive; +import org.hl7.fhir.utilities.json.model.JsonProperty; +import org.hl7.fhir.utilities.json.parser.JsonParser; import org.hl7.fhir.utilities.settings.FhirSettings; 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; import org.hl7.fhir.utilities.tests.BaseTestingUtilities; import javax.xml.parsers.DocumentBuilder; @@ -28,21 +30,52 @@ import java.util.Map; public class CompareUtilities extends BaseTestingUtilities { private static final boolean SHOW_DIFF = true; - - public static String createNotEqualMessage(final String message, final String expected, final String actual) { + private JsonObject externals; + + public String createNotEqualMessage(final String message, final String expected, final String actual) { return new StringBuilder() .append(message).append('\n') - .append("Expected :").append(expected).append('\n') - .append("Actual :").append(actual).toString(); + .append("Expected :").append(presentExpected(expected)).append('\n') + .append("Actual :").append("\""+actual+"\"").toString(); + } + + private String presentExpected(String expected) { + if (expected.startsWith("$") && expected.endsWith("$")) { + if (expected.startsWith("$choice:")) { + return "Contains one of "+readChoices(8, expected).toString(); + } else if (expected.startsWith("$fragments:")) { + List fragments = readChoices(11, expected); + return "Contains all of "+fragments.toString(); + } else if (expected.startsWith("$external:")) { + String[] cmd = expected.substring(1, expected.length() - 1).split("\\:"); + if (externals != null) { + String s = externals.asString(cmd[1]); + return "\""+s+"\" (Ext)"; + } else { + return "Contains \""+cmd[2]+"\""; + } + } else { + switch (expected) { + case "$$" : return "$$"; + case "$instant$": return "\"An Instant\""; + case "$uuid$": return "\"A Uuid\""; + default: return "Unhandled template: "+expected; + } + } + } else { + return "\""+expected+"\""; + } } public static String checkXMLIsSame(InputStream expected, InputStream actual) throws Exception { - String result = compareXml(expected, actual); + CompareUtilities self = new CompareUtilities(); + String result = self.compareXml(expected, actual); return result; } public static String checkXMLIsSame(String expected, String actual) throws Exception { - String result = compareXml(expected, actual); + CompareUtilities self = new CompareUtilities(); + String result = self.compareXml(expected, actual); if (result != null && SHOW_DIFF) { String diff = getDiffTool(); if (diff != null && new File(diff).exists() || Utilities.isToken(diff)) { @@ -52,7 +85,7 @@ public class CompareUtilities extends BaseTestingUtilities { return result; } - private static String getDiffTool() throws IOException { + private static String getDiffTool() throws IOException { if (FhirSettings.hasDiffToolPath()) { return FhirSettings.getDiffToolPath(); } else if (System.getenv("ProgramFiles") != null) { @@ -62,15 +95,15 @@ public class CompareUtilities extends BaseTestingUtilities { } } - private static String compareXml(InputStream expected, InputStream actual) throws Exception { + private String compareXml(InputStream expected, InputStream actual) throws Exception { return compareElements("", loadXml(expected).getDocumentElement(), loadXml(actual).getDocumentElement()); } - private static String compareXml(String expected, String actual) throws Exception { + private String compareXml(String expected, String actual) throws Exception { return compareElements("", loadXml(expected).getDocumentElement(), loadXml(actual).getDocumentElement()); } - private static String compareElements(String path, Element expectedElement, Element actualElement) { + private String compareElements(String path, Element expectedElement, Element actualElement) { if (!namespacesMatch(expectedElement.getNamespaceURI(), actualElement.getNamespaceURI())) return createNotEqualMessage("Namespaces differ at " + path, expectedElement.getNamespaceURI(), actualElement.getNamespaceURI()); if (!expectedElement.getLocalName().equals(actualElement.getLocalName())) @@ -109,18 +142,18 @@ public class CompareUtilities extends BaseTestingUtilities { return null; } - private static boolean namespacesMatch(String ns1, String ns2) { + private boolean namespacesMatch(String ns1, String ns2) { return ns1 == null ? ns2 == null : ns1.equals(ns2); } - private static Object normalise(String text) { + private String 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 expected, NamedNodeMap actual) { + private String compareAttributes(String path, NamedNodeMap expected, NamedNodeMap actual) { for (int i = 0; i < expected.getLength(); i++) { Node expectedNode = expected.item(i); @@ -140,7 +173,7 @@ public class CompareUtilities extends BaseTestingUtilities { return null; } - private static boolean sameBytes(byte[] b1, byte[] b2) { + private boolean sameBytes(byte[] b1, byte[] b2) { if (b1.length == 0 || b2.length == 0) return false; if (b1.length != b2.length) @@ -151,21 +184,21 @@ public class CompareUtilities extends BaseTestingUtilities { return true; } - private static byte[] unBase64(String text) { + private byte[] unBase64(String text) { return Base64.decodeBase64(text); } - private static Node skipBlankText(Node node) { + private Node skipBlankText(Node node) { while (node != null && (((node.getNodeType() == Node.TEXT_NODE) && StringUtils.isWhitespace(node.getTextContent())) || (node.getNodeType() == Node.COMMENT_NODE))) node = node.getNextSibling(); return node; } - private static Document loadXml(String fn) throws Exception { + private Document loadXml(String fn) throws Exception { return loadXml(new FileInputStream(fn)); } - private static Document loadXml(InputStream fn) throws Exception { + private 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); @@ -179,12 +212,14 @@ public class CompareUtilities extends BaseTestingUtilities { return builder.parse(fn); } - public static String checkJsonSrcIsSame(String expected, String actual) throws JsonSyntaxException, FileNotFoundException, IOException { - return checkJsonSrcIsSame(expected, actual, true); + public static String checkJsonSrcIsSame(String expected, String actual, JsonObject externals) throws FileNotFoundException, IOException { + return checkJsonSrcIsSame(expected, actual, true, externals); } - public static String checkJsonSrcIsSame(String expectedString, String actualString, boolean showDiff) throws JsonSyntaxException, FileNotFoundException, IOException { - String result = compareJsonSrc(expectedString, actualString); + public static String checkJsonSrcIsSame(String expectedString, String actualString, boolean showDiff, JsonObject externals) throws FileNotFoundException, IOException { + CompareUtilities self = new CompareUtilities(); + self.externals = externals; + String result = self.compareJsonSrc(expectedString, actualString); if (result != null && SHOW_DIFF && showDiff) { String diff = null; if (System.getProperty("os.name").contains("Linux")) @@ -217,8 +252,9 @@ public class CompareUtilities extends BaseTestingUtilities { return result; } - public static String checkJsonIsSame(String expected, String actual) throws JsonSyntaxException, FileNotFoundException, IOException { - String result = compareJson(expected, actual); + public static String checkJsonIsSame(String expected, String actual) throws FileNotFoundException, IOException { + CompareUtilities self = new CompareUtilities(); + String result = self.compareJson(expected, actual); if (result != null && SHOW_DIFF) { String diff = Utilities.path(System.getenv("ProgramFiles(X86)"), "WinMerge", "WinMergeU.exe"); List command = new ArrayList(); @@ -232,22 +268,22 @@ public class CompareUtilities extends BaseTestingUtilities { return result; } - private static String compareJsonSrc(String expected, String actual) throws JsonSyntaxException, FileNotFoundException, IOException { - JsonObject actualJsonObject = (JsonObject) new com.google.gson.JsonParser().parse(actual); - JsonObject expectedJsonObject = (JsonObject) new com.google.gson.JsonParser().parse(expected); + private String compareJsonSrc(String expected, String actual) throws FileNotFoundException, IOException { + JsonObject actualJsonObject = JsonParser.parseObject(actual); + JsonObject expectedJsonObject = JsonParser.parseObject(expected); return compareObjects("", expectedJsonObject, actualJsonObject); } - private static String compareJson(String expected, String actual) throws JsonSyntaxException, FileNotFoundException, IOException { - JsonObject actualJsonObject = (JsonObject) new com.google.gson.JsonParser().parse(TextFile.fileToString(actual)); - JsonObject expectedJsonObject = (JsonObject) new com.google.gson.JsonParser().parse(TextFile.fileToString(expected)); + private String compareJson(String expected, String actual) throws FileNotFoundException, IOException { + JsonObject actualJsonObject = JsonParser.parseObject(TextFile.fileToString(actual)); + JsonObject expectedJsonObject = JsonParser.parseObject(TextFile.fileToString(expected)); return compareObjects("", expectedJsonObject, actualJsonObject); } - private static String compareObjects(String path, JsonObject expectedJsonObject, JsonObject actualJsonObject) { + private String compareObjects(String path, JsonObject expectedJsonObject, JsonObject actualJsonObject) { List optionals = listOptionals(expectedJsonObject); - for (Map.Entry en : actualJsonObject.entrySet()) { - String n = en.getKey(); + for (JsonProperty en : actualJsonObject.getProperties()) { + String n = en.getName(); if (!n.equals("fhir_comments")) { if (expectedJsonObject.has(n)) { String s = compareNodes(path + '.' + n, expectedJsonObject.get(n), en.getValue()); @@ -257,8 +293,8 @@ public class CompareUtilities extends BaseTestingUtilities { return "properties differ at " + path + ": missing property " + n; } } - for (Map.Entry en : expectedJsonObject.entrySet()) { - String n = en.getKey(); + for (JsonProperty en : expectedJsonObject.getProperties()) { + String n = en.getName(); if (!n.equals("fhir_comments") && !n.equals("$optional$") && !optionals.contains(n)) { if (!actualJsonObject.has(n)) return "properties differ at " + path + ": missing property " + n; @@ -267,38 +303,38 @@ public class CompareUtilities extends BaseTestingUtilities { return null; } - private static List listOptionals(JsonObject expectedJsonObject) { + private List listOptionals(JsonObject expectedJsonObject) { List res = new ArrayList<>(); if (expectedJsonObject.has("$optional-properties$")) { res.add("$optional-properties$"); - for (String s : JsonUtilities.strings(expectedJsonObject.getAsJsonArray("$optional-properties$"))) { + for (String s : expectedJsonObject.getStrings("$optional-properties$")) { res.add(s); } } return res; } - private static String compareNodes(String path, JsonElement expectedJsonElement, JsonElement actualJsonElement) { + private String compareNodes(String path, JsonElement expectedJsonElement, JsonElement actualJsonElement) { if (actualJsonElement.getClass() != expectedJsonElement.getClass()) return createNotEqualMessage("properties differ at " + path, expectedJsonElement.getClass().getName(), actualJsonElement.getClass().getName()); else if (actualJsonElement instanceof JsonPrimitive) { JsonPrimitive actualJsonPrimitive = (JsonPrimitive) actualJsonElement; JsonPrimitive expectedJsonPrimitive = (JsonPrimitive) expectedJsonElement; - if (actualJsonPrimitive.isBoolean() && expectedJsonPrimitive.isBoolean()) { - if (actualJsonPrimitive.getAsBoolean() != expectedJsonPrimitive.getAsBoolean()) - return createNotEqualMessage("boolean property values differ at " + path , expectedJsonPrimitive.getAsString(), actualJsonPrimitive.getAsString()); - } else if (actualJsonPrimitive.isString() && expectedJsonPrimitive.isString()) { - String actualJsonString = actualJsonPrimitive.getAsString(); - String expectedJsonString = expectedJsonPrimitive.getAsString(); + if (actualJsonPrimitive.isJsonBoolean() && expectedJsonPrimitive.isJsonBoolean()) { + if (actualJsonPrimitive.asBoolean() != expectedJsonPrimitive.asBoolean()) + return createNotEqualMessage("boolean property values differ at " + path , expectedJsonPrimitive.asString(), actualJsonPrimitive.asString()); + } else if (actualJsonPrimitive.isJsonString() && expectedJsonPrimitive.isJsonString()) { + String actualJsonString = actualJsonPrimitive.asString(); + String expectedJsonString = expectedJsonPrimitive.asString(); if (!(actualJsonString.contains(" readChoices(int offset, String s) { + private List readChoices(int offset, String s) { List list = new ArrayList<>(); s = s.substring(offset, s.length()-1); for (String p : s.split("\\|")) { @@ -384,12 +428,13 @@ public class CompareUtilities extends BaseTestingUtilities { return list; } - public static String checkTextIsSame(String expected, String actual) throws JsonSyntaxException, FileNotFoundException, IOException { + public static String checkTextIsSame(String expected, String actual) throws FileNotFoundException, IOException { return checkTextIsSame(expected, actual, true); } - public static String checkTextIsSame(String expectedString, String actualString, boolean showDiff) throws JsonSyntaxException, FileNotFoundException, IOException { - String result = compareText(expectedString, actualString); + public static String checkTextIsSame(String expectedString, String actualString, boolean showDiff) throws FileNotFoundException, IOException { + CompareUtilities self = new CompareUtilities(); + String result = self.compareText(expectedString, actualString); if (result != null && SHOW_DIFF && showDiff) { String diff = null; if (System.getProperty("os.name").contains("Linux")) @@ -423,7 +468,7 @@ public class CompareUtilities extends BaseTestingUtilities { } - private static String compareText(String expectedString, String actualString) { + private String compareText(String expectedString, String actualString) { for (int i = 0; i < Integer.min(expectedString.length(), actualString.length()); i++) { if (expectedString.charAt(i) != actualString.charAt(i)) return createNotEqualMessage("Strings differ at character " + Integer.toString(i), String.valueOf(expectedString.charAt(i)), String.valueOf(actualString.charAt(i))); diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ParsingTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ParsingTests.java index 430754c14..3a14f83d1 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ParsingTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/ParsingTests.java @@ -60,7 +60,7 @@ public class ParsingTests { r = new XmlParser().parse(b); b = new JsonParser().setOutputStyle(OutputStyle.PRETTY).composeBytes(r); String output = new String(b); - String msg = CompareUtilities.checkJsonSrcIsSame(src, output); + String msg = CompareUtilities.checkJsonSrcIsSame(src, output, null); Assertions.assertTrue(msg == null, msg); } diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/utils/CompareUtilitiesTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/utils/CompareUtilitiesTests.java index 5e9126bbc..a2f9af1a0 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/utils/CompareUtilitiesTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/utils/CompareUtilitiesTests.java @@ -91,7 +91,7 @@ public class CompareUtilitiesTests implements ResourceLoaderTests { final String expectedJSONPath = ROOT_JSON_TEST_PATH.resolve(expectedFileName).toString(); final String actualJSONPath = ROOT_JSON_TEST_PATH.resolve(actualFileName).toString(); - final String actualOutput = CompareUtilities.checkJsonSrcIsSame(getResourceAsString(expectedJSONPath), getResourceAsString(actualJSONPath), false); + final String actualOutput = CompareUtilities.checkJsonSrcIsSame(getResourceAsString(expectedJSONPath), getResourceAsString(actualJSONPath), false, null); if (expectedOutputFileName == null) { assertNull(actualOutput); } else { diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/model/JsonPrimitive.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/model/JsonPrimitive.java index 7c1d76b77..90d85003e 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/model/JsonPrimitive.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/json/model/JsonPrimitive.java @@ -7,4 +7,8 @@ public abstract class JsonPrimitive extends JsonElement { public String toJson() { return getValue(); } + + public boolean asBoolean() { + return "true".equals(getValue()); + } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/tasks/TxTestsTask.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/tasks/TxTestsTask.java index 87da870d5..f6742cef8 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/tasks/TxTestsTask.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/tasks/TxTestsTask.java @@ -1,9 +1,13 @@ package org.hl7.fhir.validation.cli.tasks; +import java.io.IOException; import java.io.PrintStream; import org.hl7.fhir.utilities.SystemExitManager; import org.hl7.fhir.utilities.TimeTracker; +import org.hl7.fhir.utilities.json.JsonException; +import org.hl7.fhir.utilities.json.model.JsonObject; +import org.hl7.fhir.utilities.json.parser.JsonParser; import org.hl7.fhir.validation.cli.model.CliContext; import org.hl7.fhir.validation.cli.utils.Params; import org.hl7.fhir.validation.special.TxTester; @@ -41,8 +45,17 @@ public class TxTestsTask extends StandaloneTask{ final String version = Params.getParam(args, Params.VERSION); final String tx = Params.getParam(args, Params.TERMINOLOGY); final String filter = Params.getParam(args, Params.FILTER); - boolean ok = new TxTester(new TxTester.InternalTxLoader(source, output), tx, false).setOutput(output).execute(version, cliContext.getModeParams(), filter); + final String externals = Params.getParam(args, Params.EXTERNALS); + boolean ok = new TxTester(new TxTester.InternalTxLoader(source, output), tx, false, loadExternals(externals)).setOutput(output).execute(version, cliContext.getModeParams(), filter); SystemExitManager.setError(ok ? 1 : 0); SystemExitManager.finish(); } + + private JsonObject loadExternals(String externals) throws JsonException, IOException { + if (externals == null) { + return null; + } else { + return JsonParser.parseObjectFromFile(externals); + } + } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Params.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Params.java index 0e1a9a36e..047f262cd 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Params.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/utils/Params.java @@ -99,6 +99,7 @@ public class Params { public static final String SOURCE = "-source"; public static final String INPUT = "-input"; public static final String FILTER = "-filter"; + public static final String EXTERNALS = "-externals"; public static final String MODE = "-mode"; private static final String FHIR_SETTINGS_PARAM = "-fhir-settings"; private static final String WATCH_MODE_PARAM = "-watch-mode"; diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTester.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTester.java index 70ac919b2..c597332fa 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTester.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTester.java @@ -55,17 +55,19 @@ public class TxTester { private String output; private ITerminologyClient tx; private boolean tight; + private JsonObject externals; - public TxTester(ITxTesterLoader loader, String server, boolean tight) { + public TxTester(ITxTesterLoader loader, String server, boolean tight, JsonObject externals) { super(); this.server = server; this.loader = loader; this.tight = tight; + this.externals = externals; } public static void main(String[] args) throws Exception { - new TxTester(new InternalTxLoader(args[0]), args[1], "true".equals(args[2])).execute(args[2], new ArrayList<>(), args[3]); + new TxTester(new InternalTxLoader(args[0]), args[1], "true".equals(args[2]), args.length == 5 ? JsonParser.parseObjectFromFile(args[4]) : null).execute(args[2], new ArrayList<>(), args[3]); } public boolean execute(String version, List modes, String filter) throws IOException, URISyntaxException { @@ -77,6 +79,7 @@ public class TxTester { System.out.println(" Source for tests: "+loader.describe()); System.out.println(" Output Directory: "+output); System.out.println(" Term Service Url: "+server); + System.out.println(" External Strings: "+(externals != null)); System.out.println(" Test Exec Modes: "+modes.toString()); if (version != null) { System.out.println(" Tx FHIR Version: "+version); @@ -185,12 +188,13 @@ public class TxTester { if (fo.exists()) { fo.delete(); } + JsonObject ext = externals == null ? null : externals.getJsonObject(fn); String msg = null; if (test.asString("operation").equals("expand")) { - msg = expand(tx, setup, req, resp, fp, profile); + msg = expand(tx, setup, req, resp, fp, profile, ext); } else if (test.asString("operation").equals("validate-code")) { - msg = validate(tx, setup, req, resp, fp, profile); + msg = validate(tx, setup, req, resp, fp, profile, ext); } else { throw new Exception("Unknown Operation "+test.asString("operation")); } @@ -239,7 +243,7 @@ public class TxTester { return new URI(server).getHost(); } - private String expand(ITerminologyClient tx, List setup, Parameters p, String resp, String fp, Parameters profile) throws IOException { + private String expand(ITerminologyClient tx, List setup, Parameters p, String resp, String fp, Parameters profile, JsonObject ext) throws IOException { for (Resource r : setup) { p.addParameter().setName("tx-resource").setResource(r); } @@ -255,7 +259,7 @@ public class TxTester { TxTesterScrubbers.scrubOO(oo, tight); vsj = new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).composeString(oo); } - String diff = CompareUtilities.checkJsonSrcIsSame(resp, vsj); + String diff = CompareUtilities.checkJsonSrcIsSame(resp, vsj, ext); if (diff != null) { Utilities.createDirectory(Utilities.getDirectoryForFile(fp)); TextFile.stringToFile(vsj, fp); @@ -263,7 +267,7 @@ public class TxTester { return diff; } - private String validate(ITerminologyClient tx, List setup, Parameters p, String resp, String fp, Parameters profile) throws IOException { + private String validate(ITerminologyClient tx, List setup, Parameters p, String resp, String fp, Parameters profile, JsonObject ext) throws IOException { for (Resource r : setup) { p.addParameter().setName("tx-resource").setResource(r); } @@ -279,7 +283,7 @@ public class TxTester { oo.setText(null); pj = new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).composeString(oo); } - String diff = CompareUtilities.checkJsonSrcIsSame(resp, pj); + String diff = CompareUtilities.checkJsonSrcIsSame(resp, pj, ext); if (diff != null) { Utilities.createDirectory(Utilities.getDirectoryForFile(fp)); TextFile.stringToFile(pj, fp); diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/comparison/tests/ComparisonTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/comparison/tests/ComparisonTests.java index d409a276f..4f833e4ff 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/comparison/tests/ComparisonTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/comparison/tests/ComparisonTests.java @@ -14,6 +14,7 @@ import java.util.Map; import java.util.stream.Stream; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.NotImplementedException; import org.hl7.fhir.convertors.factory.VersionConvertorFactory_10_50; import org.hl7.fhir.convertors.factory.VersionConvertorFactory_14_50; import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_50; @@ -32,6 +33,8 @@ import org.hl7.fhir.r5.comparison.StructureDefinitionComparer; import org.hl7.fhir.r5.comparison.StructureDefinitionComparer.ProfileComparison; import org.hl7.fhir.r5.comparison.ValueSetComparer; import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison; +import org.hl7.fhir.r5.conformance.profile.BindingResolution; +import org.hl7.fhir.r5.conformance.profile.ProfileKnowledgeProvider; import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.context.BaseWorkerContext; import org.hl7.fhir.r5.context.IWorkerContext; @@ -45,6 +48,7 @@ import org.hl7.fhir.r5.model.Constants; import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.model.ValueSet; +import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent; import org.hl7.fhir.r5.renderers.CodeSystemRenderer; import org.hl7.fhir.r5.renderers.StructureDefinitionRenderer; import org.hl7.fhir.r5.renderers.ValueSetRenderer; @@ -155,6 +159,7 @@ public class ComparisonTests { } RenderingContext lrc = new RenderingContext(context, new MarkDownProcessor(Dialect.COMMON_MARK), null, "http://hl7.org/fhir", "", "en", ResourceRendererMode.TECHNICAL, GenerationRules.IG_PUBLISHER); lrc.setDestDir(Utilities.path("[tmp]", "comparison")); + lrc.setPkp(new TestProfileKnowledgeProvider(context)); if (left instanceof CodeSystem && right instanceof CodeSystem) { CodeSystemComparer cs = new CodeSystemComparer(session); @@ -199,14 +204,15 @@ public class ComparisonTests { // String xml3 = new XhtmlComposer(true).compose(cs.renderExpansion(csc, "", "")); TextFile.stringToFile(HEADER + hd("Messages") + xmle + BREAK + hd("Metadata") + xml1 + BREAK + hd("Structure") + xml2 + FOOTER, Utilities.path("[tmp]", "comparison", name + ".html")); checkOutcomes(csc.getMessages(), content); - - lrc.setStructureMode(StructureDefinitionRendererMode.DATA_DICT); - new StructureDefinitionRenderer(lrc).render(right); - checkOutput(content.getJsonObject("version").asString("filename-dd"), right); lrc.setStructureMode(StructureDefinitionRendererMode.SUMMARY); new StructureDefinitionRenderer(lrc).render(right); checkOutput(content.getJsonObject("version").asString("filename-tree"), right); + + + lrc.setStructureMode(StructureDefinitionRendererMode.DATA_DICT); + new StructureDefinitionRenderer(lrc).render(right); + checkOutput(content.getJsonObject("version").asString("filename-dd"), right); } else if (left instanceof CapabilityStatement && right instanceof CapabilityStatement) { CapabilityStatementComparer pc = new CapabilityStatementComparer(session); CapabilityStatementComparison csc = pc.compare((CapabilityStatement) left, (CapabilityStatement) right); @@ -322,4 +328,83 @@ public class ComparisonTests { Assertions.assertEquals(output.asInteger("infoCount"), hc, "Expected " + Integer.toString(output.asInteger("infoCount")) + " hints, but found " + Integer.toString(hc) + "."); } + + public class TestProfileKnowledgeProvider implements ProfileKnowledgeProvider { + + private IWorkerContext context; + + public TestProfileKnowledgeProvider(IWorkerContext context) { + this.context = context; + } + + @Override + public boolean isDatatype(String typeSimple) { + throw new NotImplementedException(); + } + @Override + public boolean isPrimitiveType(String typeSimple) { + throw new NotImplementedException(); + } + + @Override + public boolean isResource(String typeSimple) { + throw new NotImplementedException(); + } + + @Override + public boolean hasLinkFor(String typeSimple) { + return getLinkFor(null, typeSimple) != null; + } + + @Override + public String getLinkFor(String corePath, String typeSimple) { + StructureDefinition sd = context.fetchTypeDefinition(typeSimple); + if (sd != null) { + return sd.getWebPath(); + } + return null; + } + + @Override + public BindingResolution resolveBinding(StructureDefinition def, ElementDefinitionBindingComponent binding, String path) throws FHIRException { + ValueSet vs = context.fetchResource(ValueSet.class, binding.getValueSet()); + if (vs != null) { + return new BindingResolution(vs.present(), vs.getWebPath()); + } else { + return new BindingResolution(binding.getValueSet(), null); + } + } + + @Override + public BindingResolution resolveBinding(StructureDefinition def, String url, String path) throws FHIRException { + ValueSet vs = context.fetchResource(ValueSet.class, url); + if (vs != null) { + if (vs.hasWebPath()) { + return new BindingResolution(vs.present(), vs.getWebPath()); + } else { + return new BindingResolution(vs.present(), "valueset-"+vs.getIdBase()+".html"); + } + } + throw new NotImplementedException(); + } + + @Override + public String getLinkForProfile(StructureDefinition profile, String url) { + if ("http://hl7.org/fhir/StructureDefinition/Composition".equals(url)) { + return "http://hl7.org/fhir/composition.html|TestComposition"; + } + throw new NotImplementedException(); + } + + @Override + public boolean prependLinks() { + return false; + } + + @Override + public String getLinkForUrl(String corePath, String s) { + throw new NotImplementedException(); + } + + } } \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/r5/test/StructureMappingTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/r5/test/StructureMappingTests.java index bec2dbb95..b84d0a7fc 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/r5/test/StructureMappingTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/r5/test/StructureMappingTests.java @@ -120,7 +120,7 @@ public class StructureMappingTests { fail(e.getMessage()); } if (output.endsWith("json")) { - msg = CompareUtilities.checkJsonSrcIsSame(s.toString(), outputJson); + msg = CompareUtilities.checkJsonSrcIsSame(s.toString(), outputJson, null); } else { TextFile.bytesToFile(s.toByteArray(), fileOutputRes); TextFile.bytesToFile(outputJson.getBytes(), fileOutputResOrig); diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/ExternalTerminologyServiceTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/ExternalTerminologyServiceTests.java index 4b14810d2..00c90d9fd 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/ExternalTerminologyServiceTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/ExternalTerminologyServiceTests.java @@ -46,8 +46,8 @@ public class ExternalTerminologyServiceTests implements ITxTesterLoader { private JsonObject test; } - private static final String SERVER = FhirSettings.getTxFhirDevelopment(); -// private static final String SERVER = FhirSettings.getTxFhirLocal(); +// private static final String SERVER = FhirSettings.getTxFhirDevelopment(); + private static final String SERVER = FhirSettings.getTxFhirLocal(); // private static final String SERVER = "https://r4.ontoserver.csiro.au/fhir"; @@ -55,6 +55,7 @@ public class ExternalTerminologyServiceTests implements ITxTesterLoader { public static Iterable data() throws IOException { String contents = TestingUtilities.loadTestResource("tx", "test-cases.json"); + externals = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(TestingUtilities.loadTestResource("tx", "messages-tx.fhir.org.json")); Map examples = new HashMap(); manifest = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(contents); @@ -78,6 +79,7 @@ public class ExternalTerminologyServiceTests implements ITxTesterLoader { } private static org.hl7.fhir.utilities.json.model.JsonObject manifest; + private static org.hl7.fhir.utilities.json.model.JsonObject externals; private JsonObjectPair setup; private String version = "5.0.0"; private static TxTester tester; @@ -92,7 +94,7 @@ public class ExternalTerminologyServiceTests implements ITxTesterLoader { public void test() throws Exception { if (SERVER != null) { if (tester == null) { - tester = new TxTester(this, SERVER, true); + tester = new TxTester(this, SERVER, true, externals); } String err = tester.executeTest(setup.suite, setup.test, modes); Assertions.assertTrue(err == null, err); diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/TerminologyServiceTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/TerminologyServiceTests.java index 3957efec6..f2a732704 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/TerminologyServiceTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/TerminologyServiceTests.java @@ -76,7 +76,9 @@ public class TerminologyServiceTests { public static Iterable data() throws IOException { String contents = TestingUtilities.loadTestResource("tx", "test-cases.json"); - + String externalSource = TestingUtilities.loadTestResource("tx", "messages-tx.fhir.org.json"); + externals = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(externalSource); + Map examples = new HashMap(); manifest = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(contents); for (org.hl7.fhir.utilities.json.model.JsonObject suite : manifest.getJsonObjects("suites")) { @@ -99,6 +101,7 @@ public class TerminologyServiceTests { } private static org.hl7.fhir.utilities.json.model.JsonObject manifest; + private static org.hl7.fhir.utilities.json.model.JsonObject externals; private JsonObjectPair setup; private String version; private String name; @@ -128,6 +131,7 @@ public class TerminologyServiceTests { String fn = setup.test.asString("response"); String resp = TestingUtilities.loadTestResource("tx", fn); String fp = Utilities.path("[tmp]", "tx", fn); + JsonObject ext = externals == null ? null : externals.getJsonObject(fn); File fo = new File(fp); if (fo.exists()) { fo.delete(); @@ -138,15 +142,15 @@ public class TerminologyServiceTests { engine.getContext().setExpansionProfile((org.hl7.fhir.r5.model.Parameters) loadResource("parameters-default.json")); } if (setup.test.asString("operation").equals("expand")) { - expand(engine, req, resp, fp); + expand(engine, req, resp, fp, ext); } else if (setup.test.asString("operation").equals("validate-code")) { - validate(engine, setup.test.asString("name"), req, resp, fp); + validate(engine, setup.test.asString("name"), req, resp, fp, ext); } else { Assertions.fail("Unknown Operation "+setup.test.asString("operation")); } } - private void expand(ValidationEngine engine, Resource req, String resp, String fp) throws IOException { + private void expand(ValidationEngine engine, Resource req, String resp, String fp, JsonObject ext) throws IOException { org.hl7.fhir.r5.model.Parameters p = ( org.hl7.fhir.r5.model.Parameters) req; ValueSet vs = engine.getContext().fetchResource(ValueSet.class, p.getParameterValue("url").primitiveValue()); boolean hierarchical = p.hasParameter("excludeNested") ? p.getParameterBool("excludeNested") == false : true; @@ -162,7 +166,7 @@ public class TerminologyServiceTests { TxTesterSorters.sortValueSet(vse.getValueset()); TxTesterScrubbers.scrubVS(vse.getValueset(), false); String vsj = new JsonParser().setOutputStyle(OutputStyle.PRETTY).composeString(vse.getValueset()); - String diff = CompareUtilities.checkJsonSrcIsSame(resp, vsj); + String diff = CompareUtilities.checkJsonSrcIsSame(resp, vsj, ext); if (diff != null) { Utilities.createDirectory(Utilities.getDirectoryForFile(fp)); TextFile.stringToFile(vsj, fp); @@ -207,7 +211,7 @@ public class TerminologyServiceTests { TxTesterScrubbers.scrubOO(oo, false); String ooj = new JsonParser().setOutputStyle(OutputStyle.PRETTY).composeString(oo); - String diff = CompareUtilities.checkJsonSrcIsSame(resp, ooj); + String diff = CompareUtilities.checkJsonSrcIsSame(resp, ooj, ext); if (diff != null) { Utilities.createDirectory(Utilities.getDirectoryForFile(fp)); TextFile.stringToFile(ooj, fp); @@ -225,7 +229,7 @@ public class TerminologyServiceTests { } } - private void validate(ValidationEngine engine, String name, Resource req, String resp, String fp) throws JsonSyntaxException, FileNotFoundException, IOException { + private void validate(ValidationEngine engine, String name, Resource req, String resp, String fp, JsonObject ext) throws JsonSyntaxException, FileNotFoundException, IOException { org.hl7.fhir.r5.model.Parameters p = (org.hl7.fhir.r5.model.Parameters) req; ValueSet vs = null; if (p.hasParameter("valueSetVersion")) { @@ -299,7 +303,7 @@ public class TerminologyServiceTests { TxTesterScrubbers.scrubParams(res); String pj = new JsonParser().setOutputStyle(OutputStyle.PRETTY).composeString(res); - String diff = CompareUtilities.checkJsonSrcIsSame(resp, pj); + String diff = CompareUtilities.checkJsonSrcIsSame(resp, pj, ext); if (diff != null) { Utilities.createDirectory(Utilities.getDirectoryForFile(fp)); TextFile.stringToFile(pj, fp);