From e2d2eec9483be23cb372f613766f0d06cd5eabdf Mon Sep 17 00:00:00 2001 From: Prasanna Hegde Date: Thu, 28 Jul 2022 00:39:57 +0530 Subject: [PATCH] issue #3805 - fix FHIRPath evaluator string function error handling Signed-off-by: Prasanna Hegde --- .../json/spec/appointment-example3.json | 105 +++++++++ .../fhir/path/function/ContainsFunction.java | 7 +- .../fhir/path/function/EndsWithFunction.java | 7 +- .../fhir/path/function/LengthFunction.java | 7 +- .../fhir/path/function/MatchesFunction.java | 7 +- .../fhir/path/function/ReplaceFunction.java | 7 +- .../path/function/ReplaceMatchesFunction.java | 7 +- .../path/function/StartsWithFunction.java | 7 +- .../fhir/path/function/SubstringFunction.java | 8 +- .../fhir/path/function/ToStringFunction.java | 6 +- .../com/ibm/fhir/path/util/FHIRPathUtil.java | 18 ++ .../test/FHIRPathStringManipulationTest.java | 209 ++++++++++++++++++ 12 files changed, 351 insertions(+), 44 deletions(-) create mode 100644 fhir-examples/src/main/resources/json/spec/appointment-example3.json create mode 100644 fhir-path/src/test/java/com/ibm/fhir/path/test/FHIRPathStringManipulationTest.java diff --git a/fhir-examples/src/main/resources/json/spec/appointment-example3.json b/fhir-examples/src/main/resources/json/spec/appointment-example3.json new file mode 100644 index 00000000000..121d13b240e --- /dev/null +++ b/fhir-examples/src/main/resources/json/spec/appointment-example3.json @@ -0,0 +1,105 @@ +{ + "resourceType": "Appointment", + "id": "examplereq", + "text": { + "status": "generated", + "div": "
Brian MRI results discussion
" + }, + "identifier": [ + { + "system": "http://example.org/sampleappointment-identifier", + "value": "123" + } + ], + "status": "proposed", + "serviceCategory": [ + { + "coding": [ + { + "system": "http://example.org/service-category", + "code": "gp", + "display": "General Practice" + } + ] + } + ], + "specialty": [ + { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "394814009", + "display": "General practice" + } + ] + } + ], + "appointmentType": { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v2-0276", + "code": "WALKIN", + "display": "A previously unscheduled walk-in visit" + } + ] + }, + "reasonCode": [ + { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "413095006" + } + ], + "text": "Clinical Review" + } + ], + "priority": 5, + "description": "Discussion on the results of your recent MRI", + "minutesDuration": 15, + "slot": [ + { + "reference": "Slot/example" + } + ], + "created": "2015-12-02", + "comment": "Further expand on the results of the MRI and determine the next actions that may be appropriate.", + "participant": [ + { + "actor": { + "reference": "Patient/example", + "display": "Peter James Chalmers" + }, + "required": "required", + "status": "needs-action" + }, + { + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-ParticipationType", + "code": "ATND" + } + ] + } + ], + "required": "required", + "status": "needs-action" + }, + { + "actor": { + "reference": "Location/1", + "display": "South Wing, second floor" + }, + "required": "required", + "status": "accepted" + } + ], + "requestedPeriod": [ + { + "start": "2016-06-02", + "end": "2016-06-09" + } + ] +} diff --git a/fhir-path/src/main/java/com/ibm/fhir/path/function/ContainsFunction.java b/fhir-path/src/main/java/com/ibm/fhir/path/function/ContainsFunction.java index becb018abe5..53a496ee9c6 100644 --- a/fhir-path/src/main/java/com/ibm/fhir/path/function/ContainsFunction.java +++ b/fhir-path/src/main/java/com/ibm/fhir/path/function/ContainsFunction.java @@ -8,9 +8,8 @@ import static com.ibm.fhir.path.evaluator.FHIRPathEvaluator.SINGLETON_FALSE; import static com.ibm.fhir.path.evaluator.FHIRPathEvaluator.SINGLETON_TRUE; -import static com.ibm.fhir.path.util.FHIRPathUtil.empty; import static com.ibm.fhir.path.util.FHIRPathUtil.getStringValue; -import static com.ibm.fhir.path.util.FHIRPathUtil.hasStringValue; +import static com.ibm.fhir.path.util.FHIRPathUtil.checkStringValue; import java.util.Collection; import java.util.List; @@ -36,9 +35,7 @@ public int getMaxArity() { @Override public Collection apply(EvaluationContext evaluationContext, Collection context, List> arguments) { - if (!hasStringValue(context)) { - return empty(); - } + checkStringValue(context); return getStringValue(context).contains(getStringValue(arguments.get(0))) ? SINGLETON_TRUE : SINGLETON_FALSE; } } diff --git a/fhir-path/src/main/java/com/ibm/fhir/path/function/EndsWithFunction.java b/fhir-path/src/main/java/com/ibm/fhir/path/function/EndsWithFunction.java index 33fe1e5f9a8..9aaa1011304 100644 --- a/fhir-path/src/main/java/com/ibm/fhir/path/function/EndsWithFunction.java +++ b/fhir-path/src/main/java/com/ibm/fhir/path/function/EndsWithFunction.java @@ -8,9 +8,8 @@ import static com.ibm.fhir.path.evaluator.FHIRPathEvaluator.SINGLETON_FALSE; import static com.ibm.fhir.path.evaluator.FHIRPathEvaluator.SINGLETON_TRUE; -import static com.ibm.fhir.path.util.FHIRPathUtil.empty; +import static com.ibm.fhir.path.util.FHIRPathUtil.checkStringValue; import static com.ibm.fhir.path.util.FHIRPathUtil.getStringValue; -import static com.ibm.fhir.path.util.FHIRPathUtil.hasStringValue; import java.util.Collection; import java.util.List; @@ -36,9 +35,7 @@ public int getMaxArity() { @Override public Collection apply(EvaluationContext evaluationContext, Collection context, List> arguments) { - if (!hasStringValue(context)) { - return empty(); - } + checkStringValue(context); return getStringValue(context).endsWith(getStringValue(arguments.get(0))) ? SINGLETON_TRUE : SINGLETON_FALSE; } } diff --git a/fhir-path/src/main/java/com/ibm/fhir/path/function/LengthFunction.java b/fhir-path/src/main/java/com/ibm/fhir/path/function/LengthFunction.java index 65859331ba5..8b436e9c7b8 100644 --- a/fhir-path/src/main/java/com/ibm/fhir/path/function/LengthFunction.java +++ b/fhir-path/src/main/java/com/ibm/fhir/path/function/LengthFunction.java @@ -7,9 +7,8 @@ package com.ibm.fhir.path.function; import static com.ibm.fhir.path.FHIRPathIntegerValue.integerValue; -import static com.ibm.fhir.path.util.FHIRPathUtil.empty; +import static com.ibm.fhir.path.util.FHIRPathUtil.checkStringValue; import static com.ibm.fhir.path.util.FHIRPathUtil.getStringValue; -import static com.ibm.fhir.path.util.FHIRPathUtil.hasStringValue; import static com.ibm.fhir.path.util.FHIRPathUtil.singleton; import java.util.Collection; @@ -36,9 +35,7 @@ public int getMaxArity() { @Override public Collection apply(EvaluationContext evaluationContext, Collection context, List> arguments) { - if (!hasStringValue(context)) { - return empty(); - } + checkStringValue(context); return singleton(integerValue(getStringValue(context).length())); } } diff --git a/fhir-path/src/main/java/com/ibm/fhir/path/function/MatchesFunction.java b/fhir-path/src/main/java/com/ibm/fhir/path/function/MatchesFunction.java index 3368c20f169..e9da6b22ab4 100644 --- a/fhir-path/src/main/java/com/ibm/fhir/path/function/MatchesFunction.java +++ b/fhir-path/src/main/java/com/ibm/fhir/path/function/MatchesFunction.java @@ -8,9 +8,8 @@ import static com.ibm.fhir.path.evaluator.FHIRPathEvaluator.SINGLETON_FALSE; import static com.ibm.fhir.path.evaluator.FHIRPathEvaluator.SINGLETON_TRUE; -import static com.ibm.fhir.path.util.FHIRPathUtil.empty; +import static com.ibm.fhir.path.util.FHIRPathUtil.checkStringValue; import static com.ibm.fhir.path.util.FHIRPathUtil.getStringValue; -import static com.ibm.fhir.path.util.FHIRPathUtil.hasStringValue; import java.util.Collection; import java.util.List; @@ -37,9 +36,7 @@ public int getMaxArity() { @Override public Collection apply(EvaluationContext evaluationContext, Collection context, List> arguments) { - if (!hasStringValue(context)) { - return empty(); - } + checkStringValue(context); FHIRPathStringValue string = getStringValue(context); FHIRPathStringValue regex = getStringValue(arguments.get(0)); diff --git a/fhir-path/src/main/java/com/ibm/fhir/path/function/ReplaceFunction.java b/fhir-path/src/main/java/com/ibm/fhir/path/function/ReplaceFunction.java index 9bf5c9693fd..54122d6fd05 100644 --- a/fhir-path/src/main/java/com/ibm/fhir/path/function/ReplaceFunction.java +++ b/fhir-path/src/main/java/com/ibm/fhir/path/function/ReplaceFunction.java @@ -6,9 +6,8 @@ package com.ibm.fhir.path.function; -import static com.ibm.fhir.path.util.FHIRPathUtil.empty; +import static com.ibm.fhir.path.util.FHIRPathUtil.checkStringValue; import static com.ibm.fhir.path.util.FHIRPathUtil.getStringValue; -import static com.ibm.fhir.path.util.FHIRPathUtil.hasStringValue; import static com.ibm.fhir.path.util.FHIRPathUtil.singleton; import java.util.Collection; @@ -35,9 +34,7 @@ public int getMaxArity() { @Override public Collection apply(EvaluationContext evaluationContext, Collection context, List> arguments) { - if (!hasStringValue(context)) { - return empty(); - } + checkStringValue(context); return singleton(getStringValue(context).replace(getStringValue(arguments.get(0)), getStringValue(arguments.get(1)))); } } diff --git a/fhir-path/src/main/java/com/ibm/fhir/path/function/ReplaceMatchesFunction.java b/fhir-path/src/main/java/com/ibm/fhir/path/function/ReplaceMatchesFunction.java index 4cb90b6c2a8..3e058c33309 100644 --- a/fhir-path/src/main/java/com/ibm/fhir/path/function/ReplaceMatchesFunction.java +++ b/fhir-path/src/main/java/com/ibm/fhir/path/function/ReplaceMatchesFunction.java @@ -6,9 +6,8 @@ package com.ibm.fhir.path.function; -import static com.ibm.fhir.path.util.FHIRPathUtil.empty; +import static com.ibm.fhir.path.util.FHIRPathUtil.checkStringValue; import static com.ibm.fhir.path.util.FHIRPathUtil.getStringValue; -import static com.ibm.fhir.path.util.FHIRPathUtil.hasStringValue; import static com.ibm.fhir.path.util.FHIRPathUtil.singleton; import java.util.Collection; @@ -35,9 +34,7 @@ public int getMaxArity() { @Override public Collection apply(EvaluationContext evaluationContext, Collection context, List> arguments) { - if (!hasStringValue(context)) { - return empty(); - } + checkStringValue(context); return singleton(getStringValue(context).replaceMatches(getStringValue(arguments.get(0)), getStringValue(arguments.get(1)))); } } diff --git a/fhir-path/src/main/java/com/ibm/fhir/path/function/StartsWithFunction.java b/fhir-path/src/main/java/com/ibm/fhir/path/function/StartsWithFunction.java index ab72996e1fb..383429caa7e 100644 --- a/fhir-path/src/main/java/com/ibm/fhir/path/function/StartsWithFunction.java +++ b/fhir-path/src/main/java/com/ibm/fhir/path/function/StartsWithFunction.java @@ -8,9 +8,8 @@ import static com.ibm.fhir.path.evaluator.FHIRPathEvaluator.SINGLETON_FALSE; import static com.ibm.fhir.path.evaluator.FHIRPathEvaluator.SINGLETON_TRUE; -import static com.ibm.fhir.path.util.FHIRPathUtil.empty; +import static com.ibm.fhir.path.util.FHIRPathUtil.checkStringValue; import static com.ibm.fhir.path.util.FHIRPathUtil.getStringValue; -import static com.ibm.fhir.path.util.FHIRPathUtil.hasStringValue; import java.util.Collection; import java.util.List; @@ -36,9 +35,7 @@ public int getMaxArity() { @Override public Collection apply(EvaluationContext evaluationContext, Collection context, List> arguments) { - if (!hasStringValue(context)) { - return empty(); - } + checkStringValue(context); return getStringValue(context).startsWith(getStringValue(arguments.get(0))) ? SINGLETON_TRUE : SINGLETON_FALSE; } } diff --git a/fhir-path/src/main/java/com/ibm/fhir/path/function/SubstringFunction.java b/fhir-path/src/main/java/com/ibm/fhir/path/function/SubstringFunction.java index 8927bb04117..df7e6571f89 100644 --- a/fhir-path/src/main/java/com/ibm/fhir/path/function/SubstringFunction.java +++ b/fhir-path/src/main/java/com/ibm/fhir/path/function/SubstringFunction.java @@ -9,9 +9,8 @@ import static com.ibm.fhir.path.util.FHIRPathUtil.empty; import static com.ibm.fhir.path.util.FHIRPathUtil.getInteger; import static com.ibm.fhir.path.util.FHIRPathUtil.getStringValue; -import static com.ibm.fhir.path.util.FHIRPathUtil.hasStringValue; import static com.ibm.fhir.path.util.FHIRPathUtil.singleton; - +import static com.ibm.fhir.path.util.FHIRPathUtil.checkStringValue; import java.util.Collection; import java.util.List; @@ -37,9 +36,8 @@ public int getMaxArity() { @Override public Collection apply(EvaluationContext evaluationContext, Collection context, List> arguments) { - if (!hasStringValue(context)) { - return empty(); - } + + checkStringValue(context); FHIRPathStringValue value = getStringValue(context); diff --git a/fhir-path/src/main/java/com/ibm/fhir/path/function/ToStringFunction.java b/fhir-path/src/main/java/com/ibm/fhir/path/function/ToStringFunction.java index e609dfdc7ab..bdadfd0e49f 100644 --- a/fhir-path/src/main/java/com/ibm/fhir/path/function/ToStringFunction.java +++ b/fhir-path/src/main/java/com/ibm/fhir/path/function/ToStringFunction.java @@ -7,10 +7,10 @@ package com.ibm.fhir.path.function; import static com.ibm.fhir.path.FHIRPathStringValue.stringValue; +import static com.ibm.fhir.path.util.FHIRPathUtil.checkStringValue; import static com.ibm.fhir.path.util.FHIRPathUtil.empty; import static com.ibm.fhir.path.util.FHIRPathUtil.getSystemValue; import static com.ibm.fhir.path.util.FHIRPathUtil.hasSystemValue; -import static com.ibm.fhir.path.util.FHIRPathUtil.isSingleton; import static com.ibm.fhir.path.util.FHIRPathUtil.singleton; import java.util.Collection; @@ -38,9 +38,7 @@ public int getMaxArity() { @Override public Collection apply(EvaluationContext evaluationContext, Collection context, List> arguments) { - if (!isSingleton(context)) { - return empty(); - } + checkStringValue(context); if (hasSystemValue(context)) { FHIRPathSystemValue value = getSystemValue(context); return singleton(stringValue(value.toString())); diff --git a/fhir-path/src/main/java/com/ibm/fhir/path/util/FHIRPathUtil.java b/fhir-path/src/main/java/com/ibm/fhir/path/util/FHIRPathUtil.java index e9d3f2ed74f..77feef557a8 100644 --- a/fhir-path/src/main/java/com/ibm/fhir/path/util/FHIRPathUtil.java +++ b/fhir-path/src/main/java/com/ibm/fhir/path/util/FHIRPathUtil.java @@ -1238,4 +1238,22 @@ public static com.ibm.fhir.model.type.String getDisplay(FHIRPathTree tree, FHIRP } return null; } + + /** + * Check if the given collection item is of type String. + * @param nodes + * @return + * @throws IllegalArgumentException if the given collection item has more than one item or if the given collection item is not of type String + */ + public static boolean checkStringValue(Collection nodes) { + if(!isSingleton(nodes)) { + throw new IllegalArgumentException("Input collection must not contain more than one item, but found " + nodes.size()); + + } else if(!hasStringValue(nodes)) { + FHIRPathNode node = getSingleton(nodes); + throw new IllegalArgumentException("Input collection item must be of type String, but found '"+node.type().getName()+ "'"); + + } + return true; + } } \ No newline at end of file diff --git a/fhir-path/src/test/java/com/ibm/fhir/path/test/FHIRPathStringManipulationTest.java b/fhir-path/src/test/java/com/ibm/fhir/path/test/FHIRPathStringManipulationTest.java new file mode 100644 index 00000000000..30261981138 --- /dev/null +++ b/fhir-path/src/test/java/com/ibm/fhir/path/test/FHIRPathStringManipulationTest.java @@ -0,0 +1,209 @@ +/* + * (C) Copyright IBM Corp. 2020 + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package com.ibm.fhir.path.test; + +import static com.ibm.fhir.path.evaluator.FHIRPathEvaluator.SINGLETON_TRUE; +import static org.testng.Assert.assertEquals; +import static com.ibm.fhir.path.util.FHIRPathUtil.getStringValue; +import static com.ibm.fhir.path.util.FHIRPathUtil.getIntegerValue; + +import java.io.Reader; +import java.util.Collection; + +import org.testng.annotations.Test; + +import com.ibm.fhir.examples.ExamplesUtil; +import com.ibm.fhir.model.format.Format; +import com.ibm.fhir.model.parser.FHIRParser; +import com.ibm.fhir.model.resource.Appointment; +import com.ibm.fhir.path.FHIRPathNode; +import com.ibm.fhir.path.evaluator.FHIRPathEvaluator; +import com.ibm.fhir.path.exception.FHIRPathException; + +public class FHIRPathStringManipulationTest { + private static final Appointment appointment = readAppointment(); + + @Test + public void testContainsFunctionForCollectionWithString() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + Collection result = evaluator.evaluate(appointment, "Appointment.status.contains('proposed')"); + assertEquals(result, SINGLETON_TRUE); + } + + @Test(expectedExceptions = FHIRPathException.class, expectedExceptionsMessageRegExp = ".*Input collection must not contain more than one item.*" ) + public void testContainsFunctionForCollectionWithMultipleItems() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + evaluator.evaluate(appointment, "Appointment.participant.contains('random')"); + } + + @Test(expectedExceptions = FHIRPathException.class, expectedExceptionsMessageRegExp = ".*Input collection item must be of type String, but found 'Identifier'*" ) + public void testContainsFunctionForCollectionWithNonStringType() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + evaluator.evaluate(appointment, "Appointment.identifier.contains('random')"); + } + + @Test + public void testSubstringFunctionForCollectionWithString() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + Collection result = evaluator.evaluate(appointment, "Appointment.status.substring(3)"); + assertEquals(getStringValue(result).toString(), "posed"); + } + + @Test(expectedExceptions = FHIRPathException.class, expectedExceptionsMessageRegExp = ".*Input collection must not contain more than one item.*" ) + public void testSubstringFunctionForCollectionWithMultipleItems() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + evaluator.evaluate(appointment, "Appointment.participant.substring(3)"); + } + + @Test(expectedExceptions = FHIRPathException.class, expectedExceptionsMessageRegExp = ".*Input collection item must be of type String, but found 'Identifier'*" ) + public void testSubstringFunctionForCollectionWithNonStringType() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + evaluator.evaluate(appointment, "Appointment.identifier.substring(3)"); + } + + @Test + public void testStartsWithFunctionForCollectionWithString() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + Collection result = evaluator.evaluate(appointment, "Appointment.status.startsWith('pro')"); + assertEquals(result, SINGLETON_TRUE); + } + + @Test(expectedExceptions = FHIRPathException.class, expectedExceptionsMessageRegExp = ".*Input collection must not contain more than one item.*" ) + public void testStartsWithFunctionForCollectionWithMultipleItems() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + evaluator.evaluate(appointment, "Appointment.participant.startsWith('random')"); + } + + @Test(expectedExceptions = FHIRPathException.class, expectedExceptionsMessageRegExp = ".*Input collection item must be of type String, but found 'Identifier'*" ) + public void testStartsWithFunctionForCollectionWithNonStringType() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + evaluator.evaluate(appointment, "Appointment.identifier.startsWith('random')"); + } + + @Test + public void testEndsWithFunctionForCollectionWithString() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + Collection result = evaluator.evaluate(appointment, "Appointment.status.endsWith('ed')"); + assertEquals(result, SINGLETON_TRUE); + } + + @Test(expectedExceptions = FHIRPathException.class, expectedExceptionsMessageRegExp = ".*Input collection must not contain more than one item.*" ) + public void testEndsWithFunctionForCollectionWithMultipleItems() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + evaluator.evaluate(appointment, "Appointment.participant.endsWith('random')"); + } + + @Test(expectedExceptions = FHIRPathException.class, expectedExceptionsMessageRegExp = ".*Input collection item must be of type String, but found 'Identifier'*" ) + public void testEndsWithFunctionForCollectionWithNonStringType() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + evaluator.evaluate(appointment, "Appointment.identifier.endsWith('random')"); + } + + @Test + public void testReplaceFunctionForCollectionWithString() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + Collection result = evaluator.evaluate(appointment, "Appointment.status.replace('proposed', 'booked')"); + assertEquals(getStringValue(result).toString(), "booked"); + } + + @Test(expectedExceptions = FHIRPathException.class, expectedExceptionsMessageRegExp = ".*Input collection must not contain more than one item.*" ) + public void testReplaceFunctionForCollectionWithMultipleItems() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + evaluator.evaluate(appointment, "Appointment.participant.replace('random1', 'random2')"); + } + + @Test(expectedExceptions = FHIRPathException.class, expectedExceptionsMessageRegExp = ".*Input collection item must be of type String, but found 'Identifier'*" ) + public void testReplaceFunctionForCollectionWithNonStringType() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + evaluator.evaluate(appointment, "Appointment.identifier.replace('random1', 'random2')"); + } + + @Test + public void testMatchesFunctionForCollectionWithString() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + Collection result = evaluator.evaluate(appointment, "Appointment.status.matches('.*')"); + assertEquals(result, SINGLETON_TRUE); + } + + @Test(expectedExceptions = FHIRPathException.class, expectedExceptionsMessageRegExp = ".*Input collection must not contain more than one item.*" ) + public void testMatchesFunctionForCollectionWithMultipleItems() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + evaluator.evaluate(appointment, "Appointment.participant.matches('.*')"); + } + + @Test(expectedExceptions = FHIRPathException.class, expectedExceptionsMessageRegExp = ".*Input collection item must be of type String, but found 'Identifier'*" ) + public void testMatchesFunctionForCollectionWithNonStringType() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + evaluator.evaluate(appointment, "Appointment.identifier.matches('.*')"); + } + + @Test + public void testReplaceMatchesFunctionForCollectionWithString() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + Collection result = evaluator.evaluate(appointment, "Appointment.status.replaceMatches('.', 'a')"); + assertEquals(getStringValue(result).toString(), "aaaaaaaa"); + } + + @Test(expectedExceptions = FHIRPathException.class, expectedExceptionsMessageRegExp = ".*Input collection must not contain more than one item.*" ) + public void testReplaceMatchesFunctionForCollectionWithMultipleItems() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + evaluator.evaluate(appointment, "Appointment.participant.replaceMatches('.*', 'booked')"); + } + + @Test(expectedExceptions = FHIRPathException.class, expectedExceptionsMessageRegExp = ".*Input collection item must be of type String, but found 'Identifier'*" ) + public void testReplaceMatchesFunctionForCollectionWithNonStringType() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + evaluator.evaluate(appointment, "Appointment.identifier.replaceMatches('.*', 'booked')"); + } + + @Test + public void testLengthFunctionForCollectionWithString() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + Collection result = evaluator.evaluate(appointment, "Appointment.status.length()"); + assertEquals(getIntegerValue(result).toString(), "8"); + } + + @Test(expectedExceptions = FHIRPathException.class, expectedExceptionsMessageRegExp = ".*Input collection must not contain more than one item.*" ) + public void testLengthFunctionForCollectionWithMultipleItems() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + evaluator.evaluate(appointment, "Appointment.participant.length()"); + } + + @Test(expectedExceptions = FHIRPathException.class, expectedExceptionsMessageRegExp = ".*Input collection item must be of type String, but found 'Identifier'*" ) + public void testLengthFunctionForCollectionWithNonStringType() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + evaluator.evaluate(appointment, "Appointment.identifier.length()"); + } + + @Test + public void testToStringFunctionForCollectionWithString() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + Collection result = evaluator.evaluate(appointment, "Appointment.status.toString()"); + assertEquals(getStringValue(result).toString(), "proposed"); + } + + @Test(expectedExceptions = FHIRPathException.class, expectedExceptionsMessageRegExp = ".*Input collection must not contain more than one item.*" ) + public void testToStringFunctionForCollectionWithMultipleItems() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + evaluator.evaluate(appointment, "Appointment.participant.toString()"); + } + + @Test(expectedExceptions = FHIRPathException.class, expectedExceptionsMessageRegExp = ".*Input collection item must be of type String, but found 'Identifier'*" ) + public void testToStringFunctionForCollectionWithNonStringType() throws Exception { + FHIRPathEvaluator evaluator = FHIRPathEvaluator.evaluator(); + evaluator.evaluate(appointment, "Appointment.identifier.toString()"); + } + + + private static Appointment readAppointment() { + try (Reader reader = ExamplesUtil.resourceReader("json/spec/appointment-example3.json")) { + return FHIRParser.parser(Format.JSON).parse(reader); + } catch (Exception e) { + throw new Error(e); + } + } +}