/*
* Copyright (c) 2014. The Trustees of Indiana University.
*
* This version of the code is licensed under the MPL 2.0 Open Source license with additional
* healthcare disclaimer. If the user is an entity intending to commercialize any application
* that uses this code in a for-profit venture, please contact the copyright holder.
*/
package com.muzima.service;
import com.muzima.api.model.Concept;
import com.muzima.api.model.Encounter;
import com.muzima.api.model.EncounterType;
import com.muzima.api.model.Location;
import com.muzima.api.model.Observation;
import com.muzima.api.model.Patient;
import com.muzima.api.model.Person;
import com.muzima.controller.ConceptController;
import com.muzima.controller.EncounterController;
import com.muzima.controller.ObservationController;
import com.muzima.controller.PatientController;
import com.muzima.utils.DateUtils;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.xmlpull.mxp1.MXParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.util.List;
import java.util.Scanner;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.junit.matchers.JUnitMatchers.containsString;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
public class FormParserTest {
private FormParser formParser;
private String formDataUuid;
@Mock
private PatientController patientController;
@Mock
private ConceptController conceptController;
@Mock
private EncounterController encounterController;
@Mock
private ObservationController observationController;
@Before
public void setUp() {
initMocks(this);
formDataUuid = "formDataUuid";
}
@Test
public void shouldCreateMultipleObservations() throws IOException, XmlPullParserException, ParseException,
PatientController.PatientLoadException, ConceptController.ConceptFetchException,
ConceptController.ConceptSaveException, ConceptController.ConceptParseException,
ObservationController.ParseObservationException{
String xml = readFile("xml/histo_xml_payload.xml");
formParser = new FormParser(new MXParser(), patientController, conceptController, encounterController, observationController);
List<Observation> observations = formParser.parseAndSaveObservations(xml,formDataUuid);
assertThat(observations.size(), is(6));
}
@Test
public void shouldAssociateCorrectConceptForObservation() throws IOException, XmlPullParserException,
ParseException, PatientController.PatientLoadException, ConceptController.ConceptFetchException,
ConceptController.ConceptSaveException, ConceptController.ConceptParseException,
ObservationController.ParseObservationException{
String xml = readFile("xml/one_date_observation.xml");
formParser = new FormParser(new MXParser(), patientController, conceptController, encounterController, observationController);
Concept aConcept = mock(Concept.class);
String conceptName = "RETURN VISIT DATE";
when(conceptController.getConceptByName(conceptName)).thenReturn(aConcept);
List<Observation> observations = formParser.parseAndSaveObservations(xml,formDataUuid);
verify(conceptController).getConceptByName(conceptName);
assertThat(observations.get(0).getConcept(), is(aConcept));
}
@Test
public void shouldParseObservationOfTypeConcept() throws IOException, XmlPullParserException, ParseException,
PatientController.PatientLoadException, ConceptController.ConceptFetchException,
ConceptController.ConceptSaveException, ConceptController.ConceptParseException,
ObservationController.ParseObservationException{
String xml = readFile("xml/value_concept_observation.xml");
formParser = new FormParser(new MXParser(), patientController, conceptController, encounterController, observationController);
Concept aConcept = mock(Concept.class);
Concept observedConcept = mock(Concept.class);
when(conceptController.getConceptByName("BODY PART")).thenReturn(aConcept);
when(conceptController.getConceptByName("CERVIX")).thenReturn(observedConcept);
when(aConcept.isCoded()).thenReturn(true);
List<Observation> observations = formParser.parseAndSaveObservations(xml,formDataUuid);
Observation observation = observations.get(0);
assertThat(observation.getValueCoded(), is(observedConcept));
}
@Test
public void shouldParsePayloadWithMultipleSelectObservations() throws IOException, XmlPullParserException,
ParseException, PatientController.PatientLoadException, ConceptController.ConceptFetchException,
ConceptController.ConceptSaveException, ConceptController.ConceptParseException,
ObservationController.ParseObservationException{
String xml = readFile("xml/multiple_select_value_concept_observation.xml");
formParser = new FormParser(new MXParser(), patientController, conceptController, encounterController, observationController);
Concept aConcept = mock(Concept.class);
when(conceptController.getConceptByName(anyString())).thenReturn(aConcept);
List<Observation> observations = formParser.parseAndSaveObservations(xml,formDataUuid);
assertThat(observations.size(), is(6));
assertThat(observations.get(0).getValueText(), is("testing"));
assertThat(observations.get(1).getValueText(), is("5963^SHORTNESS OF BREATH WITH EXERTION^99DCT"));
assertThat(observations.get(4).getValueText(), is("1470^CHRONIC COUGH^99DCT"));
assertThat(observations.get(5).getValueText(), is("2014-03-01"));
}
@Test
public void shouldParsePayloadWithMultipleSelectObservationsAndNoneSelected() throws IOException,
XmlPullParserException, ParseException, PatientController.PatientLoadException,
ConceptController.ConceptFetchException, ConceptController.ConceptSaveException,
ConceptController.ConceptParseException, ObservationController.ParseObservationException{
String xml = readFile("xml/multiple_select_value_concept_observation_with_no_selection.xml");
formParser = new FormParser(new MXParser(), patientController, conceptController, encounterController, observationController);
Concept aConcept = mock(Concept.class);
when(conceptController.getConceptByName(anyString())).thenReturn(aConcept);
List<Observation> observations = formParser.parseAndSaveObservations(xml,formDataUuid);
assertThat(observations.size(), is(0));
}
@Test(expected = ObservationController.ParseObservationException.class)
public void shouldNotCreateObservationWithEmptyValue() throws ConceptController.ConceptFetchException,
XmlPullParserException, PatientController.PatientLoadException, ParseException, IOException,
ConceptController.ConceptSaveException, ConceptController.ConceptParseException,
ObservationController.ParseObservationException{
String xml = readFile("xml/observation_with_empty_value.xml");
formParser = new FormParser(new MXParser(), patientController, conceptController, encounterController, observationController);
Concept aConcept = mock(Concept.class);
when(conceptController.getConceptByName("BODY PART")).thenReturn(aConcept);
List<Observation> observations = formParser.parseAndSaveObservations(xml,formDataUuid);
assertThat(observations.size(), is(0));
}
@Test
public void shouldParseNonPreciseNumericObservation() throws ConceptController.ConceptFetchException,
XmlPullParserException, PatientController.PatientLoadException, ParseException, IOException,
ConceptController.ConceptSaveException, ConceptController.ConceptParseException,
ObservationController.ParseObservationException{
String xml = readFile("xml/numeric_observation.xml");
formParser = new FormParser(new MXParser(), patientController, conceptController, encounterController, observationController);
Concept aConcept = mock(Concept.class);
when(conceptController.getConceptByName("WEIGHT (KG)")).thenReturn(aConcept);
when(aConcept.isNumeric()).thenReturn(true);
when(aConcept.isPrecise()).thenReturn(false);
List<Observation> observations = formParser.parseAndSaveObservations(xml,formDataUuid);
Observation observation = observations.get(0);
assertThat(observation.getValueNumeric().intValue(), is(42));
}
@Test
public void shouldParsePreciseNumericObservationToTwoDecimalPlaces() throws ConceptController.ConceptFetchException,
XmlPullParserException, PatientController.PatientLoadException, ParseException, IOException,
ConceptController.ConceptSaveException, ConceptController.ConceptParseException,
ObservationController.ParseObservationException{
String xml = readFile("xml/numeric_observation.xml");
formParser = new FormParser(new MXParser(), patientController, conceptController, encounterController, observationController);
Concept aConcept = mock(Concept.class);
when(conceptController.getConceptByName("BODY SURFACE AREA")).thenReturn(aConcept);
when(aConcept.isNumeric()).thenReturn(true);
when(aConcept.isPrecise()).thenReturn(false);
List<Observation> observations = formParser.parseAndSaveObservations(xml,formDataUuid);
Observation observation = observations.get(1);
assertThat(observation.getValueNumeric(), is(1.45));
}
@Test
public void shouldBuildDummyConceptForObservationOfTypeConcept() throws IOException, XmlPullParserException,
ParseException, PatientController.PatientLoadException, ConceptController.ConceptFetchException,
ConceptController.ConceptSaveException, ConceptController.ConceptParseException,
ObservationController.ParseObservationException{
String xml = readFile("xml/value_concept_observation.xml");
formParser = new FormParser(new MXParser(), patientController, conceptController, encounterController, observationController);
Concept aConcept = mock(Concept.class);
when(conceptController.getConceptByName("BODY PART")).thenReturn(aConcept);
String observedConceptName = "CERVIX";
when(conceptController.getConceptByName(observedConceptName)).thenReturn(null);
when(aConcept.isCoded()).thenReturn(true);
List<Observation> observations = formParser.parseAndSaveObservations(xml,formDataUuid);
Observation observation = observations.get(0);
Concept actuallyObservedConcept = observation.getValueCoded();
assertThat(actuallyObservedConcept.getName(), is(observedConceptName));
assertThat(actuallyObservedConcept.getConceptType() != null, is(true));
}
@Test
public void shouldPrefixCreatedObservationsUuidWithCustomPrefix() throws IOException, XmlPullParserException,
ParseException, PatientController.PatientLoadException, ConceptController.ConceptFetchException,
ConceptController.ConceptSaveException, ConceptController.ConceptParseException,
ObservationController.ParseObservationException{
String xml = readFile("xml/one_date_observation.xml");
formParser = new FormParser(new MXParser(), patientController, conceptController, encounterController, observationController);
List<Observation> observations = formParser.parseAndSaveObservations(xml,formDataUuid);
assertThat(observations.get(0).getUuid(), containsString("observationFromPhoneUuid"));
}
@Test
public void shouldAssociateCorrectEncounterForObservation() throws IOException, XmlPullParserException,
ParseException, PatientController.PatientLoadException, ConceptController.ConceptFetchException,
ConceptController.ConceptSaveException, ConceptController.ConceptParseException,
ObservationController.ParseObservationException {
String xml = readFile("xml/one_date_observation.xml");
formParser = new FormParser(new MXParser(), patientController, conceptController, encounterController, observationController);
List<Observation> observations = formParser.parseAndSaveObservations(xml,formDataUuid);
assertThat(observations.get(0).getEncounter().getEncounterDatetime(), is(DateUtils.parse("2014-02-01")));
}
@Test
public void shouldSetAssociateEncounterTimeAsObservationDateTime() throws ConceptController.ConceptFetchException,
XmlPullParserException, PatientController.PatientLoadException, ParseException, IOException,
ConceptController.ConceptSaveException, ConceptController.ConceptParseException,
ObservationController.ParseObservationException {
String xml = readFile("xml/one_date_observation.xml");
formParser = new FormParser(new MXParser(), patientController, conceptController, encounterController, observationController);
List<Observation> observations = formParser.parseAndSaveObservations(xml,formDataUuid);
assertThat(observations.get(0).getObservationDatetime(), is(DateUtils.parse("2014-02-01")));
}
@Test
public void shouldAssociateEncountersToDummyProvider() throws ConceptController.ConceptFetchException,
XmlPullParserException, PatientController.PatientLoadException, ParseException, IOException,
ConceptController.ConceptSaveException, ConceptController.ConceptParseException,
ObservationController.ParseObservationException {
String xml = readFile("xml/one_date_observation.xml");
formParser = new FormParser(new MXParser(), patientController, conceptController, encounterController, observationController);
List<Observation> observations = formParser.parseAndSaveObservations(xml,formDataUuid);
Person provider = observations.get(0).getEncounter().getProvider();
assertThat(provider.getUuid(), is("providerForObservationsCreatedOnPhone"));
assertThat(provider.getGender(), is("NA"));
assertThat(provider.getFamilyName(), is("Taken"));
assertThat(provider.getGivenName(), is(" on"));
assertThat(provider.getMiddleName(), is("phone"));
}
@Test
public void shouldAssociateEncountersToDummyLocation() throws ConceptController.ConceptFetchException,
XmlPullParserException, PatientController.PatientLoadException, ParseException, IOException,
ConceptController.ConceptSaveException, ConceptController.ConceptParseException,
ObservationController.ParseObservationException{
String xml = readFile("xml/one_date_observation.xml");
formParser = new FormParser(new MXParser(), patientController, conceptController, encounterController, observationController);
List<Observation> observations = formParser.parseAndSaveObservations(xml,formDataUuid);
Location location = observations.get(0).getEncounter().getLocation();
assertThat(location.getUuid(), is("locationForObservationsCreatedOnPhone"));
assertThat(location.getName(), is("Created On Phone"));
}
@Test
public void shouldAssociateEncountersToDummyEncounterType() throws ConceptController.ConceptFetchException,
XmlPullParserException, PatientController.PatientLoadException, ParseException, IOException,
ConceptController.ConceptSaveException, ConceptController.ConceptParseException,
ObservationController.ParseObservationException {
String xml = readFile("xml/one_date_observation.xml");
formParser = new FormParser(new MXParser(), patientController, conceptController, encounterController, observationController);
List<Observation> observations = formParser.parseAndSaveObservations(xml,formDataUuid);
EncounterType encounterType = observations.get(0).getEncounter().getEncounterType();
assertThat(encounterType.getUuid(), is("encounterTypeForObservationsCreatedOnPhone"));
assertThat(encounterType.getName(), is("encounterTypeForObservationsCreatedOnPhone"));
}
@Test
public void shouldSaveAssociateCorrectEncounterForObservation() throws IOException, XmlPullParserException,
ParseException, PatientController.PatientLoadException, ConceptController.ConceptFetchException,
EncounterController.SaveEncounterException, ConceptController.ConceptSaveException,
ConceptController.ConceptParseException, ObservationController.ParseObservationException{
String xml = readFile("xml/one_date_observation.xml");
formParser = new FormParser(new MXParser(), patientController, conceptController, encounterController, observationController);
List<Observation> observations = formParser.parseAndSaveObservations(xml,formDataUuid);
final Encounter encounter = observations.get(0).getEncounter();
assertThat(encounter.getEncounterDatetime(), is(DateUtils.parse("2014-02-01")));
verify(encounterController).saveEncounter(encounter);
}
@Test
public void shouldSaveCreatedObservation() throws IOException, XmlPullParserException, ParseException,
ObservationController.SaveObservationException, PatientController.PatientLoadException,
ConceptController.ConceptFetchException, ConceptController.ConceptSaveException,
ConceptController.ConceptParseException, ObservationController.ParseObservationException{
String xml = readFile("xml/histo_xml_payload.xml");
formParser = new FormParser(new MXParser(), patientController, conceptController, encounterController, observationController);
List<Observation> observations = formParser.parseAndSaveObservations(xml,formDataUuid);
verify(observationController).saveObservations(observations);
}
@Test
public void shouldAssociateCorrectPatient() throws IOException, XmlPullParserException, ParseException,
PatientController.PatientLoadException, ConceptController.ConceptFetchException,
ConceptController.ConceptSaveException, ConceptController.ConceptParseException,
ObservationController.ParseObservationException {
String xml = readFile("xml/histo_xml_payload.xml");
formParser = new FormParser(new MXParser(), patientController, conceptController, encounterController, observationController);
Patient patient = new Patient();
String patientUuid = "dd7963a8-1691-11df-97a5-7038c432aabf";
when(patientController.getPatientByUuid(patientUuid)).thenReturn(patient);
List<Observation> observations = formParser.parseAndSaveObservations(xml,formDataUuid);
verify(patientController).getPatientByUuid(patientUuid);
assertThat(observations.get(0).getEncounter().getPatient(), is(patient));
assertThat(observations.get(0).getPerson(), is((Person)patient));
}
private String readFile(String fileName) {
InputStream fileStream = getClass().getClassLoader().getResourceAsStream(fileName);
Scanner s = new Scanner(fileStream).useDelimiter("\\A");
return s.hasNext() ? s.next() : "{}";
}
}