From e79b2bf199d2df517fa9a59964d009297363a2f0 Mon Sep 17 00:00:00 2001 From: dotasek Date: Thu, 25 Aug 2022 10:02:13 -0400 Subject: [PATCH] Return lists for FHIRPath constants in r4 (#902) * Test for r5 * Test for r4b * r4 test + fix Co-authored-by: dotasek --- .../org/hl7/fhir/r4/utils/FHIRPathEngine.java | 42 ++++++------ .../org/hl7/fhir/r4/utils/LiquidEngine.java | 65 +++++++++---------- .../fhir/r4/utils/StructureMapUtilities.java | 7 +- .../org/hl7/fhir/r4/test/FHIRPathTests.java | 42 +++++++++--- .../fhir/r4/test/SnapShotGenerationTests.java | 2 +- .../org/hl7/fhir/r4b/test/FHIRPathTests.java | 42 ++++++++---- .../org/hl7/fhir/r5/test/FHIRPathTests.java | 50 +++++++++----- 7 files changed, 153 insertions(+), 97 deletions(-) diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRPathEngine.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRPathEngine.java index 67391afa3..e057967b4 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRPathEngine.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/FHIRPathEngine.java @@ -199,7 +199,7 @@ public class FHIRPathEngine { * @param beforeContext - whether this is being called before the name is resolved locally, or not * @return the value of the reference (or null, if it's not valid, though can throw an exception if desired) */ - public Base resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException; + public List resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException; public TypeDetails resolveConstantType(Object appContext, String name) throws PathEngineException; /** @@ -1162,9 +1162,9 @@ public class FHIRPathEngine { work.addAll(work2); break; case Constant: - Base b = resolveConstant(context, exp.getConstant(), false, exp); + List b = resolveConstant(context, exp.getConstant(), false, exp); if (b != null) - work.add(b); + work.addAll(b); break; case Group: work2 = execute(context, focus, exp.getGroup(), atEntry); @@ -1292,14 +1292,14 @@ public class FHIRPathEngine { return result; } - private Base resolveConstant(ExecutionContext context, Base constant, boolean beforeContext, ExpressionNode expr) throws PathEngineException { + private List resolveConstant(ExecutionContext context, Base constant, boolean beforeContext, ExpressionNode expr) throws PathEngineException { if (!(constant instanceof FHIRConstant)) - return constant; + return new ArrayList<>(Arrays.asList(constant)); FHIRConstant c = (FHIRConstant) constant; if (c.getValue().startsWith("%")) { return resolveConstant(context, c.getValue(), beforeContext, expr); } else if (c.getValue().startsWith("@")) { - return processDateConstant(context.appInfo, c.getValue().substring(1)); + return new ArrayList<>(Arrays.asList(processDateConstant(context.appInfo, c.getValue().substring(1)))); } else throw new PathEngineException("Invaild FHIR Constant "+c.getValue(), expr.getStart(), expr.toString()); } @@ -1323,31 +1323,31 @@ public class FHIRPathEngine { } - private Base resolveConstant(ExecutionContext context, String s, boolean beforeContext, ExpressionNode expr) throws PathEngineException { + private List resolveConstant(ExecutionContext context, String s, boolean beforeContext, ExpressionNode expr) throws PathEngineException { if (s.equals("%sct")) - return new StringType("http://snomed.info/sct").noExtensions(); + return new ArrayList<>(Arrays.asList(new StringType("http://snomed.info/sct").noExtensions())); else if (s.equals("%loinc")) - return new StringType("http://loinc.org").noExtensions(); + return new ArrayList<>(Arrays.asList(new StringType("http://loinc.org").noExtensions())); else if (s.equals("%ucum")) - return new StringType("http://unitsofmeasure.org").noExtensions(); + return new ArrayList<>(Arrays.asList(new StringType("http://unitsofmeasure.org").noExtensions())); else if (s.equals("%resource")) { if (context.focusResource == null) throw new PathEngineException("Cannot use %resource in this context", expr.getStart(), expr.toString()); - return context.focusResource; + return new ArrayList<>(Arrays.asList(context.focusResource)); } else if (s.equals("%rootResource")) { if (context.rootResource == null) throw new PathEngineException("Cannot use %rootResource in this context", expr.getStart(), expr.toString()); - return context.rootResource; + return new ArrayList<>(Arrays.asList(context.rootResource)); } else if (s.equals("%context")) { - return context.context; + return new ArrayList<>(Arrays.asList(context.context)); } else if (s.equals("%us-zip")) - return new StringType("[0-9]{5}(-[0-9]{4}){0,1}").noExtensions(); + return new ArrayList<>(Arrays.asList(new StringType("[0-9]{5}(-[0-9]{4}){0,1}").noExtensions())); else if (s.startsWith("%`vs-")) - return new StringType("http://hl7.org/fhir/ValueSet/"+s.substring(5, s.length()-1)+"").noExtensions(); + return new ArrayList<>(Arrays.asList(new StringType("http://hl7.org/fhir/ValueSet/"+s.substring(5, s.length()-1)+"").noExtensions())); else if (s.startsWith("%`cs-")) - return new StringType("http://hl7.org/fhir/"+s.substring(5, s.length()-1)+"").noExtensions(); + return new ArrayList<>(Arrays.asList(new StringType("http://hl7.org/fhir/"+s.substring(5, s.length()-1)+"").noExtensions())); else if (s.startsWith("%`ext-")) - return new StringType("http://hl7.org/fhir/StructureDefinition/"+s.substring(6, s.length()-1)).noExtensions(); + return new ArrayList<>(Arrays.asList(new StringType("http://hl7.org/fhir/StructureDefinition/"+s.substring(6, s.length()-1)).noExtensions())); else if (hostServices == null) throw new PathEngineException("Unknown fixed constant '"+s+"'", expr.getStart(), expr.toString()); else @@ -2401,9 +2401,9 @@ public class FHIRPathEngine { List result = new ArrayList(); if (atEntry && context.appInfo != null && hostServices != null) { // we'll see if the name matches a constant known by the context. - Base temp = hostServices.resolveConstant(context.appInfo, exp.getName(), true); + List temp = hostServices.resolveConstant(context.appInfo, exp.getName(), true); if (temp != null) { - result.add(temp); + result.addAll(temp); return result; } } @@ -2415,9 +2415,9 @@ public class FHIRPathEngine { if (atEntry && context.appInfo != null && hostServices != null && result.isEmpty()) { // well, we didn't get a match on the name - we'll see if the name matches a constant known by the context. // (if the name does match, and the user wants to get the constant value, they'll have to try harder... - Base temp = hostServices.resolveConstant(context.appInfo, exp.getName(), false); + List temp = hostServices.resolveConstant(context.appInfo, exp.getName(), false); if (temp != null) { - result.add(temp); + result.addAll(temp); } } return result; diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/LiquidEngine.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/LiquidEngine.java index 6a307b8ca..63deeda3f 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/LiquidEngine.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/LiquidEngine.java @@ -1,38 +1,35 @@ package org.hl7.fhir.r4.utils; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; -/* - Copyright (c) 2011+, HL7, Inc. - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, - are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of HL7 nor the names of its contributors may be used to - endorse or promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. - - */ +/* + Copyright (c) 2011+, HL7, Inc. + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of HL7 nor the names of its contributors may be used to + endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + */ import org.hl7.fhir.exceptions.FHIRException; @@ -365,10 +362,10 @@ public class LiquidEngine implements IEvaluationContext { } @Override - public Base resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException { + public List resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException { LiquidEngineContext ctxt = (LiquidEngineContext) appContext; if (ctxt.vars.containsKey(name)) - return ctxt.vars.get(name); + return new ArrayList<>(Arrays.asList(ctxt.vars.get(name))); if (externalHostServices == null) return null; return externalHostServices.resolveConstant(ctxt.externalContext, name, beforeContext); diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/StructureMapUtilities.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/StructureMapUtilities.java index 65286544b..01e3dfdf3 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/StructureMapUtilities.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/utils/StructureMapUtilities.java @@ -168,12 +168,15 @@ public class StructureMapUtilities { private class FFHIRPathHostServices implements IEvaluationContext{ - public Base resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException { + public List resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException { Variables vars = (Variables) appContext; Base res = vars.get(VariableMode.INPUT, name); if (res == null) res = vars.get(VariableMode.OUTPUT, name); - return res; + List result = new ArrayList(); + if (res != null) + result.add(res); + return result; } @Override diff --git a/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/FHIRPathTests.java b/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/FHIRPathTests.java index 357f8e143..6dd98e693 100644 --- a/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/FHIRPathTests.java +++ b/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/FHIRPathTests.java @@ -11,10 +11,7 @@ import org.hl7.fhir.r4.utils.FHIRPathEngine; import org.hl7.fhir.r4.utils.FHIRPathEngine.IEvaluationContext; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.xml.XMLUtil; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.*; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -27,24 +24,24 @@ import javax.xml.parsers.ParserConfigurationException; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Stream; -@Disabled +import static org.junit.jupiter.api.Assertions.assertEquals; + + public class FHIRPathTests { public class FHIRPathTestEvaluationServices implements IEvaluationContext { @Override - public Base resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException { + public List resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException { throw new NotImplementedException("Not done yet (FHIRPathTestEvaluationServices.resolveConstant), when item is element"); } @Override public TypeDetails resolveConstantType(Object appContext, String name) throws PathEngineException { + throw new NotImplementedException("Not done yet (FHIRPathTestEvaluationServices.resolveConstantType), when item is element"); } @@ -136,9 +133,11 @@ public class FHIRPathTests { @SuppressWarnings("deprecation") + @Disabled @ParameterizedTest(name = "{index}: file {0}") @MethodSource("data") public void test(String name, Element test) throws FileNotFoundException, IOException, FHIRException, org.hl7.fhir.exceptions.FHIRException, UcumException { + fp.setHostServices(new FHIRPathTestEvaluationServices()); String input = test.getAttribute("inputfile"); String expression = XMLUtil.getNamedChild(test, "expression").getTextContent(); @@ -211,4 +210,27 @@ public class FHIRPathTests { } } } + + @Test + @DisplayName("resolveConstant returns a list of Base") + public void resolveConstantReturnsList() { + final String DUMMY_CONSTANT_1 = "dummyConstant1"; + final String DUMMY_CONSTANT_2 = "dummyConstant2"; + fp.setHostServices(new FHIRPathTestEvaluationServices() { + @Override + public List resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException { + + return Arrays.asList( + new StringType(DUMMY_CONSTANT_1).noExtensions(), + new StringType(DUMMY_CONSTANT_2).noExtensions()); + } + }); + + ExpressionNode expressionNode = fp.parse("%dummyConstant"); + + List result = fp.evaluate(null, expressionNode); + assertEquals(2, result.size()); + assertEquals(DUMMY_CONSTANT_1, result.get(0).primitiveValue()); + assertEquals(DUMMY_CONSTANT_2, result.get(1).primitiveValue()); + } } \ No newline at end of file diff --git a/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/SnapShotGenerationTests.java b/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/SnapShotGenerationTests.java index 2b4a32a44..d646bcd4e 100644 --- a/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/SnapShotGenerationTests.java +++ b/org.hl7.fhir.r4/src/test/java/org/hl7/fhir/r4/test/SnapShotGenerationTests.java @@ -286,7 +286,7 @@ public class SnapShotGenerationTests { // FHIRPath methods @Override - public Base resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException { + public List resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException { throw new Error("Not implemented yet"); } diff --git a/org.hl7.fhir.r4b/src/test/java/org/hl7/fhir/r4b/test/FHIRPathTests.java b/org.hl7.fhir.r4b/src/test/java/org/hl7/fhir/r4b/test/FHIRPathTests.java index d7a3645c5..fc5891eba 100644 --- a/org.hl7.fhir.r4b/src/test/java/org/hl7/fhir/r4b/test/FHIRPathTests.java +++ b/org.hl7.fhir.r4b/src/test/java/org/hl7/fhir/r4b/test/FHIRPathTests.java @@ -2,11 +2,7 @@ package org.hl7.fhir.r4b.test; import java.io.FileNotFoundException; import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.TimeZone; +import java.util.*; import java.util.stream.Stream; import javax.xml.parsers.ParserConfigurationException; @@ -17,14 +13,7 @@ import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.PathEngineException; import org.hl7.fhir.r4b.formats.JsonParser; import org.hl7.fhir.r4b.formats.XmlParser; -import org.hl7.fhir.r4b.model.Base; -import org.hl7.fhir.r4b.model.BooleanType; -import org.hl7.fhir.r4b.model.ExpressionNode; -import org.hl7.fhir.r4b.model.PrimitiveType; -import org.hl7.fhir.r4b.model.Quantity; -import org.hl7.fhir.r4b.model.Resource; -import org.hl7.fhir.r4b.model.TypeDetails; -import org.hl7.fhir.r4b.model.ValueSet; +import org.hl7.fhir.r4b.model.*; import org.hl7.fhir.r4b.test.FHIRPathTests.TestResultType; import org.hl7.fhir.r4b.test.utils.TestingUtilities; import org.hl7.fhir.r4b.utils.FHIRPathEngine; @@ -33,6 +22,8 @@ import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.xml.XMLUtil; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -41,6 +32,8 @@ import org.w3c.dom.Element; import org.w3c.dom.Node; import org.xml.sax.SAXException; +import static org.junit.jupiter.api.Assertions.assertEquals; + public class FHIRPathTests { public enum TestResultType {OK, SYNTAX, SEMANTICS, EXECUTION} @@ -273,4 +266,27 @@ public class FHIRPathTests { } } } + + @Test + @DisplayName("resolveConstant returns a list of Base") + public void resolveConstantReturnsList() { + final String DUMMY_CONSTANT_1 = "dummyConstant1"; + final String DUMMY_CONSTANT_2 = "dummyConstant2"; + fp.setHostServices(new FHIRPathTestEvaluationServices() { + @Override + public List resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException { + + return Arrays.asList( + new StringType(DUMMY_CONSTANT_1).noExtensions(), + new StringType(DUMMY_CONSTANT_2).noExtensions()); + } + }); + + ExpressionNode expressionNode = fp.parse("%dummyConstant"); + + List result = fp.evaluate(null, expressionNode); + assertEquals(2, result.size()); + assertEquals(DUMMY_CONSTANT_1, result.get(0).primitiveValue()); + assertEquals(DUMMY_CONSTANT_2, result.get(1).primitiveValue()); + } } \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java index d1f6d8aa4..53bcadcd4 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/FHIRPathTests.java @@ -2,11 +2,7 @@ package org.hl7.fhir.r5.test; import java.io.FileNotFoundException; import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.TimeZone; +import java.util.*; import java.util.stream.Stream; import javax.xml.parsers.ParserConfigurationException; @@ -17,14 +13,7 @@ import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.PathEngineException; 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.BooleanType; -import org.hl7.fhir.r5.model.ExpressionNode; -import org.hl7.fhir.r5.model.PrimitiveType; -import org.hl7.fhir.r5.model.Quantity; -import org.hl7.fhir.r5.model.Resource; -import org.hl7.fhir.r5.model.TypeDetails; -import org.hl7.fhir.r5.model.ValueSet; +import org.hl7.fhir.r5.model.*; import org.hl7.fhir.r5.test.utils.TestingUtilities; import org.hl7.fhir.r5.utils.FHIRPathEngine; import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext; @@ -32,6 +21,8 @@ import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.xml.XMLUtil; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -40,6 +31,10 @@ import org.w3c.dom.Element; import org.w3c.dom.Node; import org.xml.sax.SAXException; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + public class FHIRPathTests { public enum TestResultType {OK, SYNTAX, SEMANTICS, EXECUTION} @@ -229,7 +224,7 @@ public class FHIRPathTests { List expected = new ArrayList(); XMLUtil.getNamedChildren(test, "output", expected); - Assertions.assertEquals(outcome.size(), expected.size(), String.format("Expected %d objects but found %d for expression %s", expected.size(), outcome.size(), expression)); + assertEquals(outcome.size(), expected.size(), String.format("Expected %d objects but found %d for expression %s", expected.size(), outcome.size(), expression)); if ("false".equals(test.getAttribute("ordered"))) { for (int i = 0; i < Math.min(outcome.size(), expected.size()); i++) { String tn = outcome.get(i).fhirType(); @@ -252,7 +247,7 @@ public class FHIRPathTests { for (int i = 0; i < Math.min(outcome.size(), expected.size()); i++) { String tn = expected.get(i).getAttribute("type"); if (!Utilities.noString(tn)) { - Assertions.assertEquals(tn, outcome.get(i).fhirType(), String.format("Outcome %d: Type should be %s but was %s", i, tn, outcome.get(i).fhirType())); + assertEquals(tn, outcome.get(i).fhirType(), String.format("Outcome %d: Type should be %s but was %s", i, tn, outcome.get(i).fhirType())); } String v = expected.get(i).getTextContent(); if (!Utilities.noString(v)) { @@ -265,11 +260,34 @@ public class FHIRPathTests { System.out.println(name); System.out.println(String.format("Outcome %d: Value should be %s but was %s for expression %s", i, v, ((PrimitiveType) outcome.get(i)).fpValue(), expression)); } - Assertions.assertEquals(v, ((PrimitiveType) outcome.get(i)).fpValue(), String.format("Outcome %d: Value should be %s but was %s for expression %s", i, v, ((PrimitiveType) outcome.get(i)).fpValue(), expression)); + assertEquals(v, ((PrimitiveType) outcome.get(i)).fpValue(), String.format("Outcome %d: Value should be %s but was %s for expression %s", i, v, ((PrimitiveType) outcome.get(i)).fpValue(), expression)); } } } } } } + + @Test + @DisplayName("resolveConstant returns a list of Base") + public void resolveConstantReturnsList() { + final String DUMMY_CONSTANT_1 = "dummyConstant1"; + final String DUMMY_CONSTANT_2 = "dummyConstant2"; + fp.setHostServices(new FHIRPathTestEvaluationServices() { + @Override + public List resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException { + + return Arrays.asList( + new StringType(DUMMY_CONSTANT_1).noExtensions(), + new StringType(DUMMY_CONSTANT_2).noExtensions()); + } + }); + + ExpressionNode expressionNode = fp.parse("%dummyConstant"); + + List result = fp.evaluate(null, expressionNode); + assertEquals(2, result.size()); + assertEquals(DUMMY_CONSTANT_1, result.get(0).primitiveValue()); + assertEquals(DUMMY_CONSTANT_2, result.get(1).primitiveValue()); + } } \ No newline at end of file