org.jacoco
jacoco-maven-plugin
diff --git a/hapi-fhir-storage/src/test/java/ca/uhn/fhir/jpa/dao/BaseDateSearchDaoTests.java b/hapi-fhir-storage/src/test/java/ca/uhn/fhir/jpa/dao/BaseDateSearchDaoTests.java
new file mode 100644
index 00000000000..6b36749cb7c
--- /dev/null
+++ b/hapi-fhir-storage/src/test/java/ca/uhn/fhir/jpa/dao/BaseDateSearchDaoTests.java
@@ -0,0 +1,137 @@
+package ca.uhn.fhir.jpa.dao;
+
+import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
+import ca.uhn.fhir.jpa.conformance.DateSearchTestCase;
+import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
+import ca.uhn.fhir.rest.api.server.IBundleProvider;
+import ca.uhn.fhir.rest.param.DateParam;
+import ca.uhn.fhir.test.utilities.ITestDataBuilder;
+import org.hl7.fhir.instance.model.api.IBaseResource;
+import org.hl7.fhir.instance.model.api.IIdType;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Run the tests defined in {@link DateSearchTestCase} in a DAO test as a @Nested suite.
+ */
+public abstract class BaseDateSearchDaoTests {
+ private static final Logger ourLog = LoggerFactory.getLogger(BaseDateSearchDaoTests.class);
+
+ /**
+ * Id of test Observation
+ */
+ IIdType myObservationId;
+
+
+ /**
+ * Test for our date search operators.
+ *
+ * Be careful - date searching is defined by set relations over intervals, not a simple number comparison.
+ * See http://hl7.org/fhir/search.html#prefix for details.
+ *
+ * To debug, uncomment the @CsvSource line and comment @MethodSource to run a single case
+ *
+ *
+ * @param theResourceDate the date to use as Observation effective date
+ * @param theQuery the query parameter value including prefix (e.g. eq2020-01-01)
+ * @param theExpectedMatch true if theQuery should match theResourceDate.
+ * @param theFileName source file for test case
+ * @param theLineNumber source file line number for test case (-1 for inline tests)
+ */
+ @ParameterizedTest
+ // use @CsvSource to debug individual cases.
+ //@CsvSource("2019-12-31T08:00:00,eq2020,false,inline,1")
+ @MethodSource("dateSearchCases")
+ public void testDateSearchMatching(String theResourceDate, String theQuery, boolean theExpectedMatch, String theFileName, int theLineNumber) {
+ Fixture fixture = getFixture();
+ if (isShouldSkip(theResourceDate, theQuery)) {
+ return;
+ }
+
+ // setup
+ myObservationId = fixture.createObservationWithEffectiveDate(theResourceDate);
+
+ // run the query
+ boolean matched = fixture.isObservationSearchMatch(theQuery, myObservationId);
+
+ assertExpectedMatch(theResourceDate, theQuery, theExpectedMatch, matched, theFileName, theLineNumber);
+ }
+
+
+ protected boolean isShouldSkip(String theResourceDate, String theQuery) {
+ return false;
+ }
+
+ protected static void assertExpectedMatch(String theResourceDate, String theQuery, boolean theExpectedMatch, boolean matched, String theFileName, int theLineNumber) {
+ String message =
+ "Expected " + theQuery + " to " +
+ (theExpectedMatch ? "" : "not ") + "match " + theResourceDate +
+ " (" + theFileName + ":" + theLineNumber + ")"; // wrap this in () so tools recognize the line reference.
+ assertEquals(theExpectedMatch, matched, message);
+ }
+
+
+ /**
+ * Turn the cases into expanded arguments for better reporting output and debugging
+ */
+ public static List dateSearchCases() {
+ return DateSearchTestCase.ourCases.stream()
+ .map(DateSearchTestCase::toArguments)
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Helper to provide local setup and query services.
+ *
+ * Use an abstract method instead of a constructor because JUnit has a such a funky lifecycle.
+ */
+ protected abstract Fixture getFixture();
+
+ public interface Fixture {
+ /**
+ * Create an observation and save it
+ */
+ IIdType createObservationWithEffectiveDate(String theResourceDate);
+
+ /**
+ * Does date=theQuery match theObservationId created
+ */
+ boolean isObservationSearchMatch(String theQuery, IIdType theObservationId);
+
+ }
+
+ public static class TestDataBuilderFixture implements Fixture {
+ final ITestDataBuilder myTestDataBuilder;
+ final IFhirResourceDao myObservationDao;
+
+ public TestDataBuilderFixture(ITestDataBuilder theTestDataBuilder, IFhirResourceDao theObservationDao) {
+ myTestDataBuilder = theTestDataBuilder;
+ myObservationDao = theObservationDao;
+ }
+
+ @Override
+ public IIdType createObservationWithEffectiveDate(String theResourceDate) {
+ return myTestDataBuilder.createObservation(myTestDataBuilder.withEffectiveDate(theResourceDate));
+ }
+
+ @Override
+ public boolean isObservationSearchMatch(String theQuery, IIdType theObservationId) {
+ SearchParameterMap map = SearchParameterMap.newSynchronous();
+ map.add("date", new DateParam(theQuery));
+ ourLog.info("Searching for observation {}", map);
+
+ IBundleProvider results = myObservationDao.search(map);
+
+ boolean matched = results.getAllResourceIds().contains(theObservationId.getIdPart());
+ return matched;
+ }
+ }
+}
diff --git a/hapi-fhir-storage/src/test/java/ca/uhn/fhir/jpa/dao/DaoTestDataBuilder.java b/hapi-fhir-storage/src/test/java/ca/uhn/fhir/jpa/dao/DaoTestDataBuilder.java
new file mode 100644
index 00000000000..411a366ac7d
--- /dev/null
+++ b/hapi-fhir-storage/src/test/java/ca/uhn/fhir/jpa/dao/DaoTestDataBuilder.java
@@ -0,0 +1,42 @@
+package ca.uhn.fhir.jpa.dao;
+
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
+import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
+import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
+import ca.uhn.fhir.test.utilities.ITestDataBuilder;
+import org.hl7.fhir.instance.model.api.IBaseResource;
+import org.hl7.fhir.instance.model.api.IIdType;
+
+public class DaoTestDataBuilder implements ITestDataBuilder {
+ final FhirContext myFhirCtx;
+ final DaoRegistry myDaoRegistry;
+ SystemRequestDetails mySrd;
+
+ public DaoTestDataBuilder(FhirContext theFhirCtx, DaoRegistry theDaoRegistry, SystemRequestDetails theSrd) {
+ myFhirCtx = theFhirCtx;
+ myDaoRegistry = theDaoRegistry;
+ mySrd = theSrd;
+ }
+
+ @Override
+ public IIdType doCreateResource(IBaseResource theResource) {
+ //noinspection rawtypes
+ IFhirResourceDao dao = myDaoRegistry.getResourceDao(theResource.getClass());
+ //noinspection unchecked
+ return dao.create(theResource, mySrd).getId().toUnqualifiedVersionless();
+ }
+
+ @Override
+ public IIdType doUpdateResource(IBaseResource theResource) {
+ //noinspection rawtypes
+ IFhirResourceDao dao = myDaoRegistry.getResourceDao(theResource.getClass());
+ //noinspection unchecked
+ return dao.update(theResource, mySrd).getId().toUnqualifiedVersionless();
+ }
+
+ @Override
+ public FhirContext getFhirContext() {
+ return myFhirCtx;
+ }
+}
diff --git a/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/jpa/conformance/DateSearchTestCase.java b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/jpa/conformance/DateSearchTestCase.java
index ca611defee9..33b03d34d69 100644
--- a/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/jpa/conformance/DateSearchTestCase.java
+++ b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/jpa/conformance/DateSearchTestCase.java
@@ -30,6 +30,7 @@ import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
@@ -68,17 +69,23 @@ public class DateSearchTestCase {
*/
public final static List ourCases;
static {
+ ourCases = new ArrayList<>();
+ ourCases.addAll(expandedCases());
+ ourCases.addAll(compactCases());
+ }
+
+ private static List expandedCases() {
String csv = "DateSearchTestCase.csv";
InputStream resource = DateSearchTestCase.class.getResourceAsStream(csv);
assert resource != null;
InputStreamReader inputStreamReader = new InputStreamReader(resource, StandardCharsets.UTF_8);
- ourCases = parseCsvCases(inputStreamReader, csv);
+ List cases = parseCsvCases(inputStreamReader, csv);
try {
resource.close();
} catch (IOException e) {
e.printStackTrace();
}
- ourCases.addAll(compactCases());
+ return cases;
}
static List parseCsvCases(Reader theSource, String theFileName) {
@@ -122,7 +129,7 @@ public class DateSearchTestCase {
String resourceValue = fields[0].trim();
String truePrefixes = fields[1].trim();
String queryValue = fields[2].trim();
- Set expectedTruePrefixes = Arrays.stream(truePrefixes.split(" +")).map(String::trim).collect(Collectors.toSet());
+ Set expectedTruePrefixes = Arrays.stream(truePrefixes.split("\\s+")).map(String::trim).collect(Collectors.toSet());
// expand to one test case per supportedPrefixes
return supportedPrefixes.stream()
diff --git a/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/ITestDataBuilder.java b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/ITestDataBuilder.java
index 7338eb60364..54e79c27ca9 100644
--- a/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/ITestDataBuilder.java
+++ b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/ITestDataBuilder.java
@@ -86,6 +86,13 @@ public interface ITestDataBuilder {
return t -> __setPrimitiveChild(getFhirContext(), t, "status", "code", theStatus);
}
+ /**
+ * Set Observation.effectiveDate
+ */
+ default Consumer withEffectiveDate(String theDate) {
+ return t -> __setPrimitiveChild(getFhirContext(), t, "effectiveDateTime", "dateTime", theDate);
+ }
+
/**
* Set [Resource].identifier.system and [Resource].identifier.value
*/
diff --git a/hapi-fhir-test-utilities/src/main/resources/ca/uhn/fhir/jpa/conformance/DateSearchTestCase-compact.csv b/hapi-fhir-test-utilities/src/main/resources/ca/uhn/fhir/jpa/conformance/DateSearchTestCase-compact.csv
index 49a169909a4..50ac7344212 100644
--- a/hapi-fhir-test-utilities/src/main/resources/ca/uhn/fhir/jpa/conformance/DateSearchTestCase-compact.csv
+++ b/hapi-fhir-test-utilities/src/main/resources/ca/uhn/fhir/jpa/conformance/DateSearchTestCase-compact.csv
@@ -3,3 +3,6 @@
2021, gt ge ne,2020,
2020, lt le ne,2021,
2021-01-01, ne gt ge,2020
+1965-08-09, ne gt ge, 1918-11-11
+1965-08-09, eq le ge, 1965-08-09
+1965-08-09, ne lt le, 2020-12-08
diff --git a/pom.xml b/pom.xml
index ee492b8de52..bf08df39611 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2913,7 +2913,7 @@
FASTINSTALL
- true
+ true