Merge pull request #1614 from Boereck/fix/canonical_split_base_validator
Fix/canonical split base validator
This commit is contained in:
commit
4b32505953
|
@ -1,26 +1,82 @@
|
||||||
package org.hl7.fhir.utilities;
|
package org.hl7.fhir.utilities;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstraction that splits a canonical in form of {@code <url>|<version>} into a URL and a version part.
|
||||||
|
*/
|
||||||
public class CanonicalPair {
|
public class CanonicalPair {
|
||||||
|
|
||||||
private String url;
|
private final String url;
|
||||||
private String version;
|
private final String version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static factory method, that invokes the {@link CanonicalPair#CanonicalPair(String) CanonicalPair constructor}
|
||||||
|
* with the given argument.
|
||||||
|
* @param target the canonical to be split. May be {@code null}.
|
||||||
|
* @return new instance of CanonicalPair
|
||||||
|
*/
|
||||||
|
public static CanonicalPair of(String target) {
|
||||||
|
return new CanonicalPair(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the given canonical and if needed splits off the version part.<p>
|
||||||
|
* The given parameter {@code target} is expected to be a canonical.
|
||||||
|
* @param target canonical to create a url, version pair from. May be {@code null}.
|
||||||
|
*/
|
||||||
public CanonicalPair(String target) {
|
public CanonicalPair(String target) {
|
||||||
if (target != null && target.contains("|")) {
|
int pipeIndex = target != null ? target.indexOf('|') : -1;
|
||||||
this.url = target.substring(0, target.indexOf("|"));
|
if (pipeIndex >= 0) {
|
||||||
this.version = target.substring(target.indexOf("|")+1);
|
this.url = target.substring(0, pipeIndex);
|
||||||
|
this.version = target.substring(pipeIndex+1);
|
||||||
} else {
|
} else {
|
||||||
this.url = target;
|
this.url = target;
|
||||||
this.version = null;
|
this.version = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the URL part of the canonical (everything before the {@code "|"} character, or the complete
|
||||||
|
* canonical if the character is not present). If the source
|
||||||
|
* @return URL part of the source canonical. May be {@code null}, if source canonical was {@code null}
|
||||||
|
*/
|
||||||
public String getUrl() {
|
public String getUrl() {
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the version part of the source canonical (everything after the {@code "|"} character.
|
||||||
|
* @return version part of the canonical, may be {@code null}, if canonical was {@code null}, or canonical contains no
|
||||||
|
* {@code "|"} character.
|
||||||
|
*/
|
||||||
public String getVersion() {
|
public String getVersion() {
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the version part of the canonical is not {@code null}
|
||||||
|
* @return {@code true} if version is not {@code null}, otherwise {@code false}
|
||||||
|
*/
|
||||||
|
public boolean hasVersion() {
|
||||||
|
return version != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the version of this pair, or the parameter {@code alternative},
|
||||||
|
* if the version of this pair is {@code null}.
|
||||||
|
* @param alternative to be returned from this method if the encapsulated version is {@code null}.
|
||||||
|
* @return either the held version, or {@code alternative}, if version is {@code null}
|
||||||
|
*/
|
||||||
|
public String getVersionOr(String alternative) {
|
||||||
|
return hasVersion() ? version : alternative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the encapsulated version of this pair is not {@code null} and not an empty string.
|
||||||
|
* @return {@code true} if the version of this pair is not {@code null} and not an empty string, {@code false} otherwise
|
||||||
|
*/
|
||||||
|
public boolean hasNonEmptyVersion() {
|
||||||
|
return StringUtils.isNotEmpty(version);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
package org.hl7.fhir.utilities;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
class CanonicalPairTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCanonicalNull() {
|
||||||
|
var canonical = new CanonicalPair(null);
|
||||||
|
assertNull(canonical.getUrl());
|
||||||
|
assertNull(canonical.getVersion());
|
||||||
|
assertFalse(canonical.hasVersion());
|
||||||
|
assertFalse(canonical.hasNonEmptyVersion());
|
||||||
|
String expectedVer = "1.0";
|
||||||
|
String actualVer = canonical.getVersionOr(expectedVer);
|
||||||
|
assertEquals(expectedVer, actualVer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCanonicalEmpty() {
|
||||||
|
var url = "";
|
||||||
|
var canonical = new CanonicalPair(url);
|
||||||
|
assertEquals(url, canonical.getUrl());
|
||||||
|
assertFalse(canonical.hasVersion());
|
||||||
|
assertFalse(canonical.hasNonEmptyVersion());
|
||||||
|
String expectedVer = "1.0";
|
||||||
|
String actualVer = canonical.getVersionOr(expectedVer);
|
||||||
|
assertEquals(expectedVer, actualVer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCanonicalWithoutVersion() {
|
||||||
|
var url = "https://www.test.org";
|
||||||
|
var canonical = new CanonicalPair(url);
|
||||||
|
assertEquals(url, canonical.getUrl());
|
||||||
|
assertNull(canonical.getVersion());
|
||||||
|
assertFalse(canonical.hasVersion());
|
||||||
|
assertFalse(canonical.hasNonEmptyVersion());
|
||||||
|
String expectedVer = "1.0";
|
||||||
|
String actualVer = canonical.getVersionOr(expectedVer);
|
||||||
|
assertEquals(expectedVer, actualVer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCanonicalWithEmptyVersion() {
|
||||||
|
var expectedUrl = "https://www.test.org";
|
||||||
|
var url = expectedUrl + "|";
|
||||||
|
var canonical = new CanonicalPair(url);
|
||||||
|
assertEquals(expectedUrl, canonical.getUrl());
|
||||||
|
assertEquals("", canonical.getVersion());
|
||||||
|
assertTrue(canonical.hasVersion());
|
||||||
|
assertFalse(canonical.hasNonEmptyVersion());
|
||||||
|
String alternativeVer = "1.0";
|
||||||
|
String actualVer = canonical.getVersionOr(alternativeVer);
|
||||||
|
assertEquals("", actualVer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCanonicalWithVersion() {
|
||||||
|
var expectedUrl = "https://www.test.org";
|
||||||
|
var expectedVersion = "2.6";
|
||||||
|
var url = expectedUrl + "|" + expectedVersion;
|
||||||
|
var canonical = new CanonicalPair(url);
|
||||||
|
assertEquals(expectedUrl, canonical.getUrl());
|
||||||
|
assertEquals(expectedVersion, canonical.getVersion());
|
||||||
|
assertTrue(canonical.hasVersion());
|
||||||
|
assertTrue(canonical.hasNonEmptyVersion());
|
||||||
|
String alternativeVer = "1.0";
|
||||||
|
String actualVer = canonical.getVersionOr(alternativeVer);
|
||||||
|
assertEquals(expectedVersion, actualVer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testCanonicalWithVersionIncludingPipe() {
|
||||||
|
var expectedUrl = "https://www.test.org";
|
||||||
|
var expectedVersion = "2024|05";
|
||||||
|
var url = expectedUrl + "|" + expectedVersion;
|
||||||
|
var canonical = new CanonicalPair(url);
|
||||||
|
assertEquals(expectedUrl, canonical.getUrl());
|
||||||
|
assertEquals(expectedVersion, canonical.getVersion());
|
||||||
|
assertTrue(canonical.hasVersion());
|
||||||
|
assertTrue(canonical.hasNonEmptyVersion());
|
||||||
|
String alternativeVer = "1.0";
|
||||||
|
String actualVer = canonical.getVersionOr(alternativeVer);
|
||||||
|
assertEquals(expectedVersion, actualVer);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1428,25 +1428,7 @@ public class BaseValidator implements IValidationContextResourceLoader {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String versionFromCanonical(String system) {
|
|
||||||
if (system == null) {
|
|
||||||
return null;
|
|
||||||
} else if (system.contains("|")) {
|
|
||||||
return system.substring(0, system.indexOf("|"));
|
|
||||||
} else {
|
|
||||||
return system;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String systemFromCanonical(String system) {
|
|
||||||
if (system == null) {
|
|
||||||
return null;
|
|
||||||
} else if (system.contains("|")) {
|
|
||||||
return system.substring(system.indexOf("|")+1);
|
|
||||||
} else {
|
|
||||||
return system;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Resource loadContainedResource(List<ValidationMessage> errors, String path, Element resource, String id, Class<? extends Resource> class1) throws FHIRException {
|
public Resource loadContainedResource(List<ValidationMessage> errors, String path, Element resource, String id, Class<? extends Resource> class1) throws FHIRException {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import org.hl7.fhir.r5.model.CodeSystem;
|
||||||
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
|
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
|
||||||
import org.hl7.fhir.r5.model.ValueSet;
|
import org.hl7.fhir.r5.model.ValueSet;
|
||||||
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
|
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
|
||||||
|
import org.hl7.fhir.utilities.CanonicalPair;
|
||||||
import org.hl7.fhir.utilities.Utilities;
|
import org.hl7.fhir.utilities.Utilities;
|
||||||
import org.hl7.fhir.utilities.VersionUtilities;
|
import org.hl7.fhir.utilities.VersionUtilities;
|
||||||
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
||||||
|
@ -620,7 +621,8 @@ public class CodeSystemValidator extends BaseValidator {
|
||||||
private boolean validateSupplementConcept(List<ValidationMessage> errors, Element concept, NodeStack stack, String supp, ValidationOptions options) {
|
private boolean validateSupplementConcept(List<ValidationMessage> errors, Element concept, NodeStack stack, String supp, ValidationOptions options) {
|
||||||
String code = concept.getChildValue("code");
|
String code = concept.getChildValue("code");
|
||||||
if (!Utilities.noString(code)) {
|
if (!Utilities.noString(code)) {
|
||||||
org.hl7.fhir.r5.terminologies.utilities.ValidationResult res = context.validateCode(options, systemFromCanonical(supp), versionFromCanonical(supp), code, null);
|
var canonical = new CanonicalPair(supp);
|
||||||
|
org.hl7.fhir.r5.terminologies.utilities.ValidationResult res = context.validateCode(options, canonical.getUrl(), canonical.getVersion(), code, null);
|
||||||
return rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), res.isOk(), I18nConstants.CODESYSTEM_CS_SUPP_INVALID_CODE, supp, code);
|
return rule(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack.getLiteralPath(), res.isOk(), I18nConstants.CODESYSTEM_CS_SUPP_INVALID_CODE, supp, code);
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
package org.hl7.fhir.validation;
|
package org.hl7.fhir.validation;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.hamcrest.Matchers.empty;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -10,6 +14,7 @@ import org.hl7.fhir.r5.formats.XmlParser;
|
||||||
import org.hl7.fhir.r5.model.Resource;
|
import org.hl7.fhir.r5.model.Resource;
|
||||||
import org.hl7.fhir.r5.test.utils.TestingUtilities;
|
import org.hl7.fhir.r5.test.utils.TestingUtilities;
|
||||||
import org.hl7.fhir.utilities.FhirPublication;
|
import org.hl7.fhir.utilities.FhirPublication;
|
||||||
|
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
||||||
import org.hl7.fhir.utilities.settings.FhirSettings;
|
import org.hl7.fhir.utilities.settings.FhirSettings;
|
||||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||||
import org.hl7.fhir.validation.instance.InstanceValidator;
|
import org.hl7.fhir.validation.instance.InstanceValidator;
|
||||||
|
@ -25,7 +30,7 @@ public class ResourceValidationTests {
|
||||||
private static InstanceValidator val;
|
private static InstanceValidator val;
|
||||||
|
|
||||||
|
|
||||||
private void runTest(String filename) throws IOException, FileNotFoundException, Exception {
|
private List<ValidationMessage> runTest(String filename) throws IOException, FileNotFoundException, Exception {
|
||||||
TestingUtilities.injectCorePackageLoader();
|
TestingUtilities.injectCorePackageLoader();
|
||||||
if (val == null) {
|
if (val == null) {
|
||||||
ctxt = TestingUtilities.getSharedWorkerContext();
|
ctxt = TestingUtilities.getSharedWorkerContext();
|
||||||
|
@ -37,6 +42,7 @@ public class ResourceValidationTests {
|
||||||
Resource res = (Resource) new XmlParser().parse(TestingUtilities.loadTestResourceStream("r5", filename));
|
Resource res = (Resource) new XmlParser().parse(TestingUtilities.loadTestResourceStream("r5", filename));
|
||||||
val.validate(val, errors, res);
|
val.validate(val, errors, res);
|
||||||
Assertions.assertNotNull(errors);
|
Assertions.assertNotNull(errors);
|
||||||
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -123,4 +129,26 @@ public class ResourceValidationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCodesystemSupplementsVersion() throws Exception {
|
||||||
|
List<ValidationMessage> errors = runTest("codesystem-example-supplement-version.xml");
|
||||||
|
assertNoErrors(errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void assertNoErrors(List<ValidationMessage> errors) {
|
||||||
|
List<String> errorMessages = new ArrayList<>();
|
||||||
|
for(ValidationMessage message : errors) {
|
||||||
|
// we will skip the message that WG citation is needed
|
||||||
|
if(I18nConstants.VALIDATION_HL7_WG_NEEDED.equals(message.getMessageId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(message.getLevel().isError()) {
|
||||||
|
errorMessages.add(message.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertThat("No error message expected in validation outcome.", errorMessages, is(empty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue