add narrative generation tests

This commit is contained in:
Grahame Grieve 2019-12-11 20:52:25 +11:00
parent 1fb2da565b
commit e6ecc998ea
5 changed files with 242 additions and 12 deletions

View File

@ -23,7 +23,9 @@ package org.hl7.fhir.r5.terminologies;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
@ -47,6 +49,90 @@ import org.hl7.fhir.utilities.Utilities;
public class CodeSystemUtilities {
public static class CodeSystemNavigator {
private CodeSystem cs;
private boolean restructure;
private Set<String> processed = new HashSet<>();
public CodeSystemNavigator(CodeSystem cs) {
this.cs = cs;
restructure = hasExtraRelationships(cs.getConcept());
}
public boolean isRestructure() {
return restructure;
}
private boolean hasExtraRelationships(List<ConceptDefinitionComponent> concept) {
for (ConceptDefinitionComponent cd : concept) {
if (getSubsumedBy(cd) != null) {
return true;
}
for (ConceptDefinitionComponent cdc : cd.getConcept()) {
if (hasExtraRelationships(cdc.getConcept())) {
return true;
}
}
}
return false;
}
public List<ConceptDefinitionComponent> getConcepts(ConceptDefinitionComponent context) {
if (context == null) {
if (restructure) {
List<ConceptDefinitionComponent> res = new ArrayList<>();
for (ConceptDefinitionComponent cd : cs.getConcept()) {
if (getSubsumedBy(cd) == null) {
res.add(cd);
processed.add(cd.getCode());
}
}
return res;
} else {
return cs.getConcept();
}
} else {
if (restructure) {
List<ConceptDefinitionComponent> res = new ArrayList<>();
for (ConceptDefinitionComponent cd : context.getConcept()) {
res.add(cd);
processed.add(cd.getCode());
}
for (ConceptDefinitionComponent cd : cs.getConcept()) {
if (context.getCode().equals(getSubsumedBy(cd)) && !processed.contains(cd.getCode())) {
res.add(cd);
processed.add(cd.getCode());
}
}
return res;
} else {
return context.getConcept();
}
}
}
private String getSubsumedBy(ConceptDefinitionComponent cd) {
for (ConceptPropertyComponent cp : cd.getProperty()) {
if (cp.getCode().equals("subsumedBy")) {
return cp.getValue().primitiveValue();
}
}
return null;
}
public List<ConceptDefinitionComponent> getOtherChildren(ConceptDefinitionComponent context) {
List<ConceptDefinitionComponent> res = new ArrayList<>();
for (ConceptDefinitionComponent cd : cs.getConcept()) {
if (context.getCode().equals(getSubsumedBy(cd)) && processed.contains(cd.getCode())) {
res.add(cd);
}
}
return res;
}
}
public static boolean isNotSelectable(CodeSystem cs, ConceptDefinitionComponent def) {
for (ConceptPropertyComponent p : def.getProperty()) {
if (p.getCode().equals("notSelectable") && p.hasValue() && p.getValue() instanceof BooleanType)

View File

@ -177,6 +177,7 @@ import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionParameterComponent;
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities.CodeSystemNavigator;
import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
import org.hl7.fhir.r5.utils.LiquidEngine.LiquidDocument;
@ -317,6 +318,9 @@ public class NarrativeGenerator implements INarrativeGenerator {
return res;
}
public boolean generate(DomainResource r) throws EOperationOutcome, FHIRException, IOException {
return generate(null, r, new HashSet<>());
}
public boolean generate(DomainResource r, Set<String> outputTracker) throws EOperationOutcome, FHIRException, IOException {
return generate(null, r, outputTracker);
}
@ -2667,7 +2671,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
if (header) {
XhtmlNode h = x.h2();
h.addText(cs.hasTitle() ? cs.getTitle() : cs.getName());
addMarkdown(x, cs.getDescription());
// .... addMarkdown(x, cs.getDescription());
if (cs.hasCopyright())
generateCopyright(x, cs, lang);
}
@ -2768,9 +2772,10 @@ public class NarrativeGenerator implements INarrativeGenerator {
version = version || conceptsHaveVersion(c);
hierarchy = hierarchy || c.hasConcept();
}
CodeSystemNavigator csNav = new CodeSystemNavigator(cs);
addMapHeaders(addTableHeaderRowStandard(t, hierarchy, display, true, commentS, version, deprecated, lang, properties), maps);
for (ConceptDefinitionComponent c : cs.getConcept()) {
hasExtensions = addDefineRowToTable(t, c, 0, hierarchy, display, commentS, version, deprecated, maps, cs.getUrl(), cs, lang, properties) || hasExtensions;
for (ConceptDefinitionComponent c : csNav.getConcepts(null)) {
hasExtensions = addDefineRowToTable(t, c, 0, hierarchy || csNav.isRestructure(), display, commentS, version, deprecated, maps, cs.getUrl(), cs, lang, properties, csNav) || hasExtensions;
}
// if (langs.size() > 0) {
// Collections.sort(langs);
@ -2799,10 +2804,19 @@ public class NarrativeGenerator implements INarrativeGenerator {
private boolean showPropertyInTable(PropertyComponent cp) {
if (cp.hasCode()) {
if (cp.hasExtension(ToolingExtensions.EXT_RENDERED_VALUE)) {
return true;
}
String uri = cp.getUri();
if (Utilities.noString(uri)){
return false;
}
if (uri.contains("#")) {
uri = uri.substring(0, uri.indexOf("#"));
}
return
Utilities.existsInList(cp.getUri(), "http://hl7.org/fhir/concept-properties") ||
codeSystemPropList.contains(cp.getUri()) ||
cp.hasExtension(ToolingExtensions.EXT_RENDERED_VALUE);
Utilities.existsInList(uri, "http://hl7.org/fhir/concept-properties") ||
codeSystemPropList.contains(uri);
}
return false;
}
@ -3449,7 +3463,7 @@ public class NarrativeGenerator implements INarrativeGenerator {
return "??Lang";
}
private boolean addDefineRowToTable(XhtmlNode t, ConceptDefinitionComponent c, int i, boolean hasHierarchy, boolean hasDisplay, boolean comment, boolean version, boolean deprecated, List<UsedConceptMap> maps, String system, CodeSystem cs, String lang, List<PropertyComponent> properties) throws FHIRFormatError, DefinitionException, IOException {
private boolean addDefineRowToTable(XhtmlNode t, ConceptDefinitionComponent c, int i, boolean hasHierarchy, boolean hasDisplay, boolean comment, boolean version, boolean deprecated, List<UsedConceptMap> maps, String system, CodeSystem cs, String lang, List<PropertyComponent> properties, CodeSystemNavigator csNav) throws FHIRFormatError, DefinitionException, IOException {
boolean hasExtensions = false;
XhtmlNode tr = t.tr();
XhtmlNode td = tr.td();
@ -3618,16 +3632,16 @@ public class NarrativeGenerator implements INarrativeGenerator {
td.i().tx("("+mapping.comp.getComment()+")");
}
}
for (String e : CodeSystemUtilities.getOtherChildren(cs, c)) {
for (ConceptDefinitionComponent cc : csNav.getOtherChildren(c)) {
tr = t.tr();
td = tr.td();
String s = Utilities.padLeft("", '.', i*2);
td.addText(s);
a = td.ah("#"+Utilities.nmtokenize(e));
a = td.ah("#"+Utilities.nmtokenize(cc.getCode()));
a.addText(c.getCode());
}
for (ConceptDefinitionComponent cc : c.getConcept()) {
hasExtensions = addDefineRowToTable(t, cc, i+1, hasHierarchy, hasDisplay, comment, version, deprecated, maps, system, cs, lang, properties) || hasExtensions;
for (ConceptDefinitionComponent cc : csNav.getConcepts(c)) {
hasExtensions = addDefineRowToTable(t, cc, i+1, hasHierarchy, hasDisplay, comment, version, deprecated, maps, system, cs, lang, properties, csNav) || hasExtensions;
}
return hasExtensions;
}

View File

@ -15,6 +15,7 @@ import org.junit.runners.Suite.SuiteClasses;
GraphQLEngineTests.class,
LiquidEngineTests.class,
FHIRPathTests.class,
NarrativeGenerationTests.class,
NarrativeGeneratorTests.class,
ShexGeneratorTests.class,
BaseDateTimeTypeTest.class,

View File

@ -0,0 +1,129 @@
package org.hl7.fhir.r5.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.NotImplementedException;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.exceptions.PathEngineException;
import org.hl7.fhir.r5.conformance.ProfileUtilities;
import org.hl7.fhir.r5.conformance.ProfileUtilities.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.context.SimpleWorkerContext;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
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.Coding;
import org.hl7.fhir.r5.model.DomainResource;
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent;
import org.hl7.fhir.r5.model.ExpressionNode.CollectionStatus;
import org.hl7.fhir.r5.model.MetadataResource;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r5.model.StructureDefinition.TypeDerivationRule;
import org.hl7.fhir.r5.model.TestScript;
import org.hl7.fhir.r5.model.TestScript.AssertionResponseTypes;
import org.hl7.fhir.r5.model.TestScript.SetupActionAssertComponent;
import org.hl7.fhir.r5.model.TestScript.SetupActionOperationComponent;
import org.hl7.fhir.r5.model.TestScript.TestActionComponent;
import org.hl7.fhir.r5.model.TestScript.TestScriptFixtureComponent;
import org.hl7.fhir.r5.model.TestScript.TestScriptTestComponent;
import org.hl7.fhir.r5.test.utils.TestingUtilities;
import org.hl7.fhir.r5.model.TypeDetails;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.utils.CodingUtilities;
import org.hl7.fhir.r5.utils.EOperationOutcome;
import org.hl7.fhir.r5.utils.FHIRPathEngine;
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
import org.hl7.fhir.r5.utils.IResourceValidator;
import org.hl7.fhir.r5.utils.NarrativeGenerator;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.cache.PackageCacheManager;
import org.hl7.fhir.utilities.cache.ToolsVersion;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.xhtml.XhtmlComposer;
import org.hl7.fhir.utilities.xml.XMLUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
import ca.uhn.fhir.rest.api.Constants;
import junit.framework.Assert;
@RunWith(Parameterized.class)
public class NarrativeGenerationTests {
public static class TestDetails {
private String id;
public TestDetails(Element test) {
super();
id = test.getAttribute("id");
}
public String getId() {
return id;
}
}
private static FHIRPathEngine fp;
@Parameters(name = "{index}: file {0}")
public static Iterable<Object[]> data() throws ParserConfigurationException, IOException, FHIRFormatError, SAXException {
Document tests = XMLUtil.parseToDom(TestingUtilities.loadTestResource("r5", "narrative", "manifest.xml"));
Element test = XMLUtil.getFirstChild(tests.getDocumentElement());
List<Object[]> objects = new ArrayList<Object[]>();
while (test != null && test.getNodeName().equals("test")) {
TestDetails t = new TestDetails(test);
objects.add(new Object[] {t.getId(), t});
test = XMLUtil.getNextSibling(test);
}
return objects;
}
private final TestDetails test;
private IWorkerContext context;
private List<ValidationMessage> messages;
public NarrativeGenerationTests(String id, TestDetails test) {
this.test = test;
this.context = TestingUtilities.context();
}
@SuppressWarnings("deprecation")
@Test
public void test() throws Exception {
NarrativeGenerator gen = new NarrativeGenerator("", "http://hl7.org/fhir", context);
IOUtils.copy(TestingUtilities.loadTestResourceStream("r5", "narrative", test.getId()+"-expected.xml"), new FileOutputStream(TestingUtilities.tempFile("narrative", test.getId()+"-expected.xml")));
DomainResource source = (DomainResource) new XmlParser().parse(TestingUtilities.loadTestResourceStream("r5", "narrative", test.getId()+"-input.xml"));
DomainResource target = (DomainResource) new XmlParser().parse(TestingUtilities.loadTestResourceStream("r5", "narrative", test.getId()+"-expected.xml"));
gen.generate(source);
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(TestingUtilities.tempFile("narrative", test.getId()+"-actual.xml")), source);
Assert.assertTrue("Output does not match expected", source.equalsDeep(target));
}
}

View File

@ -17,7 +17,7 @@
<properties>
<hapi_fhir_version>4.1.0</hapi_fhir_version>
<validator_test_case_version>1.0.14-SNAPSHOT</validator_test_case_version>
<validator_test_case_version>1.0.15-SNAPSHOT</validator_test_case_version>
</properties>
<artifactId>org.hl7.fhir.core</artifactId>