diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/client/FHIRToolingClient.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/client/FHIRToolingClient.java index d052f681a..268f3c814 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/client/FHIRToolingClient.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/client/FHIRToolingClient.java @@ -171,10 +171,13 @@ public class FHIRToolingClient { public TerminologyCapabilities getTerminologyCapabilities() { TerminologyCapabilities capabilities = null; - capabilities = getCapabilities(resourceAddress.resolveMetadataTxCaps(), + try { + capabilities = getCapabilities(resourceAddress.resolveMetadataTxCaps(), "TerminologyCapabilities", "Error fetching the server's terminology capabilities"); - + } catch (ClassCastException e) { + throw new FHIRException("Unexpected response format for Terminology Capability metadata", e); + } return capabilities; } diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/utils/client/FHIRToolingClientTest.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/utils/client/FHIRToolingClientTest.java index 07b9fea61..4706a1e0e 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/utils/client/FHIRToolingClientTest.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/utils/client/FHIRToolingClientTest.java @@ -32,8 +32,7 @@ import okhttp3.Headers; import okhttp3.Request; import okhttp3.internal.http2.Header; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.times; class FHIRToolingClientTest { @@ -162,6 +161,20 @@ class FHIRToolingClientTest { checkHeaders(argumentCaptorValue); } + @Test + void getTerminologyCapabilitiesNotSupported() throws IOException { + Mockito.when(mockClient.issueGetResourceRequest(Mockito.any(URI.class), Mockito.anyString(), + Mockito.any(Headers.class), Mockito.eq("TerminologyCapabilities"), Mockito.anyLong())) + .thenReturn(new ResourceRequest<>(new CapabilityStatement(), 200, "location")); + + ArgumentCaptor headersArgumentCaptor = ArgumentCaptor.forClass(Headers.class); + toolingClient.setClientHeaders(getHeaders()); + Exception exception = assertThrows(FHIRException.class, () -> { + toolingClient.getTerminologyCapabilities(); + }); + assertEquals(exception.getCause().getClass(), ClassCastException.class); + } + @Test void getTerminologyCapabilitiesFailsForJSON() throws IOException { Mockito.when(mockClient.issueGetResourceRequest(Mockito.any(URI.class), Mockito.anyString(), diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/DurationUtil.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/DurationUtil.java new file mode 100644 index 000000000..1123a225e --- /dev/null +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/DurationUtil.java @@ -0,0 +1,29 @@ +package org.hl7.fhir.utilities; + +import java.util.concurrent.TimeUnit; + +public class DurationUtil { + public static String presentDuration(long duration) { + duration = duration / 1000000; + String res = ""; // ; + long days = TimeUnit.MILLISECONDS.toDays(duration); + long hours = TimeUnit.MILLISECONDS.toHours(duration) - + TimeUnit.DAYS.toHours(TimeUnit.MILLISECONDS.toDays(duration)); + long minutes = TimeUnit.MILLISECONDS.toMinutes(duration) - + TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(duration)); + long seconds = TimeUnit.MILLISECONDS.toSeconds(duration) - + TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration)); + long millis = TimeUnit.MILLISECONDS.toMillis(duration) - + TimeUnit.SECONDS.toMillis(TimeUnit.MILLISECONDS.toSeconds(duration)); + + if (days > 0) + res = String.format("%dd %02d:%02d:%02d.%03d", days, hours, minutes, seconds, millis); + else if (hours > 0) + res = String.format("%02d:%02d:%02d.%03d", hours, minutes, seconds, millis); + else // + res = String.format("%02d:%02d.%03d", minutes, seconds, millis); +// else +// res = String.format("%02d.%04d", seconds, millis); + return res; + } +} diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/TimeTracker.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/TimeTracker.java index def73143d..79c236907 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/TimeTracker.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/TimeTracker.java @@ -1,11 +1,7 @@ package org.hl7.fhir.utilities; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; - -import org.hl7.fhir.utilities.TimeTracker.Counter; public class TimeTracker { @@ -72,29 +68,29 @@ public class TimeTracker { CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); for (Counter c : records) { if (c.count == 1) { - b.append(c.name+": "+Utilities.presentDuration(c.length)); + b.append(c.name+": "+ DurationUtil.presentDuration(c.length)); } } for (Counter c : records) { if (c.count > 1) { - b.append(c.name+": "+Utilities.presentDuration(c.length)+" (#"+c.count+")"); + b.append(c.name+": "+ DurationUtil.presentDuration(c.length)+" (#"+c.count+")"); } } return "Times: "+b.toString(); } public String clock() { - return Utilities.presentDuration(System.nanoTime() - globalStart); + return DurationUtil.presentDuration(System.nanoTime() - globalStart); } public String instant() { - return Utilities.presentDuration(System.nanoTime() - globalStart); + return DurationUtil.presentDuration(System.nanoTime() - globalStart); } public String milestone() { long start = milestone == 0 ? globalStart : milestone ; milestone = System.nanoTime(); - return Utilities.presentDuration(milestone - start); + return DurationUtil.presentDuration(milestone - start); } } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java index 5f29390ad..8bb68f5b7 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java @@ -22,14 +22,12 @@ import java.nio.file.StandardCopyOption; import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; -import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.UUID; -import java.util.concurrent.TimeUnit; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -92,7 +90,7 @@ public class Utilities { * * @param word the word that is to be pluralized. * @return the pluralized form of the word, or the word itself if it could not be pluralized - * @see #singularize(Object) + * @see Inflector#singularize(Object) */ public static String pluralizeMe(String word) { Inflector inf = new Inflector(); @@ -1423,30 +1421,6 @@ public class Utilities { return byteArrays; } - - public static String presentDuration(long duration) { - duration = duration / 1000000; - String res = ""; // ; - long days = TimeUnit.MILLISECONDS.toDays(duration); - long hours = TimeUnit.MILLISECONDS.toHours(duration) - - TimeUnit.DAYS.toHours(TimeUnit.MILLISECONDS.toDays(duration)); - long minutes = TimeUnit.MILLISECONDS.toMinutes(duration) - - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(duration)); - long seconds = TimeUnit.MILLISECONDS.toSeconds(duration) - - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration)); - long millis = TimeUnit.MILLISECONDS.toMillis(duration) - - TimeUnit.SECONDS.toMillis(TimeUnit.MILLISECONDS.toSeconds(duration)); - - if (days > 0) - res = String.format("%dd %02d:%02d:%02d.%04d", days, hours, minutes, seconds, millis); - else if (hours > 0) - res = String.format("%02d:%02d:%02d.%04d", hours, minutes, seconds, millis); - else // - res = String.format("%02d:%02d.%04d", minutes, seconds, millis); -// else -// res = String.format("%02d.%04d", seconds, millis); - return res; - } public static void unzip(InputStream zip, Path target) throws IOException { try (ZipInputStream zis = new ZipInputStream(zip)) { diff --git a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/DurationUtilTest.java b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/DurationUtilTest.java new file mode 100644 index 000000000..838ae860f --- /dev/null +++ b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/DurationUtilTest.java @@ -0,0 +1,44 @@ +package org.hl7.fhir.utilities; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.xml.sax.SAXException; + +import javax.xml.parsers.ParserConfigurationException; +import java.io.IOException; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; + + +public class DurationUtilTest { + + + public static Stream data() throws ParserConfigurationException, SAXException, IOException { + List objects = new ArrayList<>(); + objects.add(Arguments.of("PT0.001S", "00:00.001")); + objects.add(Arguments.of("PT0.012S", "00:00.012")); + objects.add(Arguments.of("PT0.123S", "00:00.123")); + objects.add(Arguments.of("PT0.999S", "00:00.999")); + objects.add(Arguments.of("PT1.001S", "00:01.001")); + objects.add(Arguments.of("PT1M1.001S", "01:01.001")); + objects.add(Arguments.of("PT59M1.001S", "59:01.001")); + objects.add(Arguments.of("PT1H1M1.001S", "01:01:01.001")); + objects.add(Arguments.of("PT23H1M1.001S", "23:01:01.001")); + objects.add(Arguments.of("P1DT23H1M1.001S", "1d 23:01:01.001")); + objects.add(Arguments.of("P12DT23H1M1.001S", "12d 23:01:01.001")); + return objects.stream(); + } + + @ParameterizedTest + @MethodSource("data") + public void testPresentDuration(String iso8601String, String expectedPresentation) { + assertEquals(expectedPresentation, DurationUtil.presentDuration(Duration.parse(iso8601String).toNanos())); + } + + +} diff --git a/org.hl7.fhir.validation/src/main/resources/help.txt b/org.hl7.fhir.validation/src/main/resources/help.txt index 14c3c9265..a0dde8db1 100644 --- a/org.hl7.fhir.validation/src/main/resources/help.txt +++ b/org.hl7.fhir.validation/src/main/resources/help.txt @@ -13,6 +13,9 @@ schematron checking is performed, then some additional checks are performed. If requested, instances will also be verified against the appropriate schema W3C XML Schema, JSON schema or ShEx, as appropriate +Default Usage +============= + Usage: java -jar [validator].jar (parameters) The following parameters are supported: @@ -111,9 +114,11 @@ proxy Parameters can appear in any order -Alternatively, you can use the validator to execute a transformation as -described by a structure map. To do this, you must provide some additional -parameters: +Transforms +========== + +You can use the validator to execute a transformation as described by a +structure map. To do this, you must provide some additional parameters: -transform [map] @@ -124,24 +129,33 @@ Any other dependency maps have to be loaded through an -ig reference -transform uses the parameters -defn, -txserver, -ig (at least one with the map files), and -output -Alternatively, you can use the validator to generate narrative for a resource. -To do this, you must provide a specific parameter: +Narratives +========== + +You can use the validator to generate narrative for a resource. To do this, you +must provide a specific parameter: -narrative -narrative requires the parameters -defn, -txserver, -source, and -output. ig and profile may be used -Alternatively, you can use the validator to convert a resource or logical model. -To do this, you must provide a specific parameter: +Conversion +========== + +You can use the validator to convert a resource or logical model. To do this, +you must provide a specific parameter: -convert -convert requires the parameters -source and -output. ig may be used to provide a logical model -Alternatively, you can use the validator to evaluate a FHIRPath expression on a -resource or logical model. To do this, you must provide a specific parameter: +FHIRPath +======== + +You can use the validator to evaluate a FHIRPath expression on a resource or +logical model. To do this, you must provide a specific parameter: -fhirpath [FHIRPath] @@ -150,10 +164,41 @@ resource or logical model. To do this, you must provide a specific parameter: -fhirpath requires the parameters -source. ig may be used to provide a logical model -Finally, you can use the validator to generate a snapshot for a profile. -To do this, you must provide a specific parameter: +Snapshots +========= + +You can use the validator to generate a snapshot for a profile. To do this, you +must provide a specific parameter: -snapshot -snapshot requires the parameters -defn, -txserver, -source, and -output. ig may -be used to provide necessary base profiles \ No newline at end of file +be used to provide necessary base profiles + +Tests +===== + +The validator can be run in test mode, which executes all JUnit tests for the +FHIR core library against a set of test cases in a local directory. To do this, +you must provide a specific parameter with a directory value: + + -test [directory] + +The directory must follow the same conventions as the reference test cases found +at https://github.com/FHIR/fhir-test-cases. This mode must also be executed with +the Java property java.locale.providers set to COMPAT as below: + + java -Djava.locale.providers=COMPAT -jar validator_cli.jar -tests + ./my/path/to/fhir-test-cases + +This parameter is compatible with -txCache, -test-modules, and +-test-classname-filter parameters. + +The following test-specific parameters can be used to limit which tests are run: +-test-modules [module-names] A comma delimited list of Java module names for + which to run JUnit tests. By default, all modules are used to run tests. + Example: -test-modules org.hl7.fhir.dstu2,org.hl7.fhir.dstu2016may + +-test-classname-filter [regex] A regex filter applied to test Java class names + for selecting which JUnit tests to run. By default, all tests are run. + Example: -test-classname-filter .*ShexGeneratorTests \ No newline at end of file