package se.cambio.cds.gdl.converters.drools;
import com.google.gson.Gson;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.joda.time.DateTime;
import org.junit.Test;
import org.openehr.rm.datatypes.basic.DataValue;
import org.openehr.rm.datatypes.quantity.DvCount;
import org.openehr.rm.datatypes.quantity.DvOrdinal;
import org.openehr.rm.datatypes.quantity.datetime.DvDateTime;
import org.openehr.rm.datatypes.text.DvCodedText;
import se.cambio.cds.controller.cds.CDSManager;
import se.cambio.cds.controller.guide.GuideManager;
import se.cambio.cds.gdl.model.expression.OperatorKind;
import se.cambio.cds.model.facade.execution.vo.PredicateGeneratedElementInstance;
import se.cambio.cds.model.facade.execution.vo.RuleExecutionResult;
import se.cambio.cds.model.facade.execution.vo.RuleReference;
import se.cambio.cds.model.instance.ArchetypeReference;
import se.cambio.cds.model.instance.ElementInstance;
import se.cambio.cds.util.export.ArchetypeReferenceGsonFactory;
import se.cambio.openehr.util.exceptions.InternalErrorException;
import se.cambio.openehr.util.exceptions.PatientNotFoundException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import static org.junit.Assert.*;
public class BasicGDLTest extends GDLTestCase{
private RuleExecutionResult rer;
public BasicGDLTest(){
super();
}
@Test
public void shouldCountMedications(){
Collection<ArchetypeReference> ars = new ArrayList<ArchetypeReference>();
ars.add(generateOngoingMedicationArchetypeReference("A10BX03"));
ars.add(generateOngoingMedicationArchetypeReference("N02AX02"));
Collection<ElementInstance> elementInstances = getElementInstances(ars);
RuleExecutionResult rer = executeGuides(Collections.singleton("count_test.v1"), elementInstances);
assertEquals(1, rer.getArchetypeReferences().size());
ArchetypeReference arResult = rer.getArchetypeReferences().iterator().next();
assertEquals(1, arResult.getElementInstancesMap().size());
ElementInstance ei = arResult.getElementInstancesMap().get("openEHR-EHR-OBSERVATION.chadsvas_score.v1/data[at0002]/events[at0003]/data[at0001]/items[at0099]");
assertNotNull(ei);
assertTrue(ei.getDataValue() instanceof DvCount);
assertEquals(2, ((DvCount)ei.getDataValue()).getMagnitude().intValue());
}
@Test
public void shouldFindThatElementDoesNotExist(){
ArchetypeReference ar = generateOngoingMedicationArchetypeReference("A10BX03");
Collection<ElementInstance> elementInstances = getElementInstances(Collections.singleton(ar));
RuleExecutionResult rer = executeGuides(Collections.singleton("not_exists_test.v1"), elementInstances);
assertEquals(2, rer.getFiredRules().size());
assertTrue(rer.getFiredRules().contains(new RuleReference("not_exists_test.v1", "gt0045")));
assertTrue(rer.getFiredRules().contains(new RuleReference("not_exists_test.v1","gt0039")));
}
@Test
public void shouldAllowToDefineOrsWithPredicates(){
ArchetypeReference ar = generateOngoingMedicationArchetypeReference("A01AA01");
Collection<ElementInstance> elementInstances = getElementInstances(Collections.singleton(ar));
RuleExecutionResult rer = executeGuides(Collections.singleton("test_or_predicates.v1"), elementInstances);
assertEquals(4, rer.getFiredRules().size());
assertTrue(rer.getFiredRules().contains(new RuleReference("test_or_predicates.v1", "gt0002")));
assertTrue(rer.getFiredRules().contains(new RuleReference("test_or_predicates.v1", "gt0012")));
assertTrue(rer.getFiredRules().contains(new RuleReference("test_or_predicates.v1","gt0013")));
assertTrue(rer.getFiredRules().contains(new RuleReference("test_or_predicates.v1","gt0014")));
}
@Test
public void shouldCreateSeveralElements(){
ArchetypeReference ar = generateOngoingMedicationArchetypeReference("A01AA01");
Collection<ElementInstance> elementInstances = getElementInstances(Collections.singleton(ar));
Collection<String> guideIds = new ArrayList<String>();
guideIds.add("test_creation_and_order_1");
guideIds.add("test_creation_and_order_2");
RuleExecutionResult rer = executeGuides(guideIds, elementInstances);
assertEquals(4, rer.getFiredRules().size());
assertTrue(rer.getFiredRules().get(0).equals(new RuleReference("test_creation_and_order_2","gt0002")));
assertTrue(rer.getFiredRules().get(1).equals(new RuleReference("test_creation_and_order_2","gt0005")));
assertTrue(rer.getFiredRules().get(2).equals(new RuleReference("test_creation_and_order_1","gt0005")));
assertTrue(rer.getFiredRules().get(3).equals(new RuleReference("test_creation_and_order_1","gt0002")));
}
@Test
public void shouldCountCDSElements(){
Collection<ArchetypeReference> ars = new ArrayList<ArchetypeReference>();
ars.add(generateOngoingMedicationArchetypeReference("A10BX03"));
ars.add(generateOngoingMedicationArchetypeReference("A10BX02"));
ars.add(generateOngoingMedicationArchetypeReference("N02AX02"));
ars.add(generateContactArchetypeReference(new DateTime().plus(-100000)));
ars.add(generateContactArchetypeReference(new DateTime().plus(100000)));
ars.add(generateContactArchetypeReference(new DateTime().plus(-200000)));
Collection<ElementInstance> elementInstances = getElementInstances(ars);
Collection<String> guideIds = new ArrayList<String>();
guideIds.add("cds_count");
RuleExecutionResult rer = executeGuides(guideIds, elementInstances);
assertEquals(4, rer.getFiredRules().size());
assertTrue(rer.getFiredRules().get(0).equals(new RuleReference("cds_count","gt0006")));
assertTrue(rer.getFiredRules().get(1).equals(new RuleReference("cds_count","gt0006")));
assertTrue(rer.getFiredRules().get(2).equals(new RuleReference("cds_count","gt0006")));
assertTrue(rer.getFiredRules().get(3).equals(new RuleReference("cds_count","gt0011")));
}
@Test
public void shouldFindMissingElements(){
Collection<ArchetypeReference> ars = new ArrayList<ArchetypeReference>();
ArchetypeReference ar = generateOngoingMedicationArchetypeReference("A10BX03");
ar.getElementInstancesMap().remove(GDLTestCase.MEDICATION_DATE_END_ELEMENT_ID); //Remove end elements
ars.add(ar);
ar = generateOngoingMedicationArchetypeReference("A10BX02");
ar.getElementInstancesMap().remove(GDLTestCase.MEDICATION_DATE_END_ELEMENT_ID);
ars.add(ar);
ar = generateOngoingMedicationArchetypeReference("N02AX02");
ar.getElementInstancesMap().remove(GDLTestCase.MEDICATION_DATE_END_ELEMENT_ID);
ars.add(ar);
Collection<String> guideIds = new ArrayList<String>();
guideIds.add("test_med_definition");
GuideManager guideManager = generateGuideManager(guideIds);
try {
Collection<ElementInstance> elementInstances =
CDSManager.getElementInstances(null, guideIds, ars, guideManager, Calendar.getInstance());
assertEquals(9,elementInstances.size());
} catch (PatientNotFoundException e) {
e.printStackTrace();
} catch (InternalErrorException e) {
e.printStackTrace();
}
}
@Test
public void shouldAllowToDefinePredicates(){
Collection<ArchetypeReference> ars = new ArrayList<ArchetypeReference>();
ArchetypeReference ar = generateOngoingMedicationArchetypeReference("A10BX03");
ar.getElementInstancesMap().remove(GDLTestCase.MEDICATION_DATE_END_ELEMENT_ID); //Remove end elements
ars.add(ar);
ar = generateOngoingMedicationArchetypeReference("A01AB06");
ar.getElementInstancesMap().remove(GDLTestCase.MEDICATION_DATE_END_ELEMENT_ID);
ars.add(ar);
ar = generateOngoingMedicationArchetypeReference("N02AX02");
ar.getElementInstancesMap().remove(GDLTestCase.MEDICATION_DATE_END_ELEMENT_ID);
ars.add(ar);
Collection<String> guideIds = new ArrayList<String>();
guideIds.add("test_med_definition_with_predicates1");
guideIds.add("test_med_definition_with_predicates2");
GuideManager guideManager = generateGuideManager(guideIds);
try {
Collection<ElementInstance> elementInstances =
CDSManager.getElementInstances(null, guideIds, ars, guideManager, Calendar.getInstance());
assertEquals(18,elementInstances.size());
boolean predicateForBValuesExists = false;
boolean predicateForGenericEqualsNullValuesExists = false;
boolean predicateForMinLastAdministrationExists = false;
for(ElementInstance elementInstance: elementInstances){
if (elementInstance instanceof PredicateGeneratedElementInstance){
PredicateGeneratedElementInstance pgei = (PredicateGeneratedElementInstance)elementInstance;
if (MEDICATION_CODE_ELEMENT_ID.equals(pgei.getId())){
if(OperatorKind.INEQUAL.equals(pgei.getOperatorKind())){
if (pgei.getDataValue()==null){
fail("Predicate medication generic name!=null should not be generated!");
}
}else if(OperatorKind.EQUALITY.equals(pgei.getOperatorKind())){
if (pgei.getDataValue()==null){
predicateForGenericEqualsNullValuesExists = true;
}
}else if(OperatorKind.IS_A.equals(pgei.getOperatorKind())){
if (pgei.getDataValue() instanceof DvCodedText){
DvCodedText dvCodedText = (DvCodedText)pgei.getDataValue();
String code = dvCodedText.getCode();
if (code.equals("A01AB06")){
fail("Predicate medication generic name is_a 'A01AB06' should not be generated!");
}else if (code.startsWith("B01")){
predicateForBValuesExists =true;
}
}
}
}else if (MEDICATION_DATE_INIT_ELEMENT_ID.equals(pgei.getId())){
if(OperatorKind.MAX.equals(pgei.getOperatorKind())){
fail("Predicate medication generic name!=null should not be generated!");
}
}else if (MEDICATION_DATE_END_ELEMENT_ID.equals(pgei.getId())){
if(OperatorKind.MIN.equals(pgei.getOperatorKind())){
predicateForMinLastAdministrationExists=true;
}
}
}
}
assertTrue(predicateForBValuesExists);
assertTrue(predicateForGenericEqualsNullValuesExists);
assertTrue(predicateForMinLastAdministrationExists);
} catch (PatientNotFoundException e) {
e.printStackTrace();
} catch (InternalErrorException e) {
e.printStackTrace();
}
}
@Test
public void shouldAllowMultpleResults(){
Collection<ArchetypeReference> ars = new ArrayList<ArchetypeReference>();
ArchetypeReference ar = generateOngoingMedicationArchetypeReference("A10BX03");
ar.getElementInstancesMap().remove(GDLTestCase.MEDICATION_DATE_END_ELEMENT_ID); //Remove end elements
ars.add(ar);
ar = generateOngoingMedicationArchetypeReference("A10BX02");
ar.getElementInstancesMap().remove(GDLTestCase.MEDICATION_DATE_END_ELEMENT_ID);
ars.add(ar);
ar = generateOngoingMedicationArchetypeReference("N02AX02");
ars.add(ar);
ar.getElementInstancesMap().remove(GDLTestCase.MEDICATION_DATE_END_ELEMENT_ID);
ars.add(generateContactArchetypeReference(new DateTime().plus(100000)));
Collection<ElementInstance> elementInstances = getElementInstances(ars);
Collection<String> guideIds = new ArrayList<String>();
guideIds.add("multiple_results_test");
RuleExecutionResult rer = executeGuides(guideIds, elementInstances);
assertEquals(7, rer.getArchetypeReferences().size());
assertEquals(4, rer.getFiredRules().size());
assertEquals(4, ars.size());
for(ArchetypeReference arAux: ars){
if (GDLTestCase.MEDICATION_ARCHETYPE_ID.equals(arAux.getIdArchetype())){
assertEquals(3, arAux.getElementInstancesMap().size()); //End date is generated in CDSManager
}
}
}
@Test
public void shouldAllowCDSInitiallization(){
Collection<ArchetypeReference> ars = new ArrayList<ArchetypeReference>();
Collection<ElementInstance> elementInstances = getElementInstances(ars);
Collection<String> guideIds = new ArrayList<String>();
guideIds.add("test_cds_init1");
guideIds.add("test_cds_init2");
RuleExecutionResult rer = executeGuides(guideIds, elementInstances);
assertEquals(1, rer.getArchetypeReferences().size());
}
@Test
public void shouldTestDateOperations(){
Collection<ArchetypeReference> ars = new ArrayList<ArchetypeReference>();
Collection<ElementInstance> elementInstances = getElementInstances(ars);
Collection<String> guideIds = new ArrayList<String>();
guideIds.add("test_date_operation");
RuleExecutionResult rer = executeGuides(guideIds, elementInstances);
assertEquals(1, rer.getArchetypeReferences().size());
assertEquals(1, rer.getFiredRules().size());
ArchetypeReference ar = rer.getArchetypeReferences().iterator().next();
assertEquals(1, ar.getElementInstancesMap().size());
ElementInstance contactEndElement = ar.getElementInstancesMap().get(CONTACT_DATE_END_ELEMENT_ID);
assertNotNull(contactEndElement);
DataValue dv = contactEndElement.getDataValue();
assertTrue(dv instanceof DvDateTime);
assertEquals(Calendar.getInstance().get(Calendar.YEAR)-1,((DvDateTime)dv).getYear());
}
/* TODO Disabled until we are able to implement the functionality
@Test
public void testPredicateAsDefaultCDSValues(){
Collection<ArchetypeReference> ars = new ArrayList<ArchetypeReference>();
Collection<ElementInstance> elementInstances = getElementInstances(ars);
Collection<String> guideIds = new ArrayList<String>();
assertEquals(5, rer.getFiredRules().size());
}
*/
@Test
public void shouldPerformCDSLinking(){
Collection<ArchetypeReference> ars = new ArrayList<ArchetypeReference>();
Calendar birthdate = Calendar.getInstance();
birthdate.add(Calendar.YEAR, -75);
ars.add(generateBasicDemographicsArchetypeReference(birthdate, Gender.FEMALE));
ars.add(generateICD10DiagnosisArchetypeReference("I48"));
Collection<ElementInstance> elementInstances = getElementInstances(ars);
Collection<String> guideIds = new ArrayList<String>();
guideIds.add("CHA2DS2VASc_Score_calculation.v1.1");
guideIds.add("Stroke_risks.v2");
guideIds.add("CHA2DS2VASc_diagnosis_review.v1");
guideIds.add("Stroke_prevention_compliance_checking_in_AF.v2");
guideIds.add("Stroke_prevention_alert.v1.1");
guideIds.add("Stroke_prevention_medication_recommendation.v1");
int medicationCount = 0;
rer = executeGuides(guideIds, elementInstances);
assertEquals(9, rer.getArchetypeReferences().size());
assertEquals(11, rer.getFiredRules().size());
boolean strokeARFound = false;
for(ArchetypeReference ar: rer.getArchetypeReferences()){
if (ar.getIdArchetype().equals("openEHR-EHR-OBSERVATION.stroke_risk.v1")){
strokeARFound = true;
assertEquals(1, ar.getElementInstancesMap().size());
ElementInstance strokeRiskElement = ar.getElementInstancesMap().get("openEHR-EHR-OBSERVATION.stroke_risk.v1/data[at0001]/events[at0002]/data[at0003]/items[at0004]");
assertNotNull(strokeRiskElement);
DataValue dv = strokeRiskElement.getDataValue();
assertTrue(dv instanceof DvOrdinal);
assertEquals(3, ((DvOrdinal)dv).getValue());
}else if (ar.getIdArchetype().equals("openEHR-EHR-INSTRUCTION.medication.v1")){
medicationCount++;
}
}
assertTrue(strokeARFound);
assertEquals(4,medicationCount);
}
@Test
public void shouldPerformRountripJSONSerializationOfRuleExecutionResults(){
Gson gson = new ArchetypeReferenceGsonFactory().create();
if (rer == null){
shouldAllowCDSInitiallization();
}
String json = gson.toJson(rer);
RuleExecutionResult auxRer = gson.fromJson(json, RuleExecutionResult.class);
boolean equalRER = EqualsBuilder.reflectionEquals(rer, auxRer);
assertTrue(equalRER);
}
}