/**
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
* the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
*
* Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
* graphic logo is a trademark of OpenMRS Inc.
*/
package org.openmrs;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNot.not;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.lang.reflect.Field;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.apache.commons.beanutils.BeanUtils;
import org.junit.Assert;
import org.junit.Test;
import org.openmrs.api.APIException;
import org.openmrs.obs.ComplexData;
import org.openmrs.util.Reflect;
/**
* This class tests all methods that are not getter or setters in the Obs java object TODO: finish
* this test class for Obs
*
* @see Obs
*/
public class ObsTest {
private static final String VERO = "Vero";
private static final String FORM_NAMESPACE_PATH_SEPARATOR = "^";
//ignore these fields, groupMembers and formNamespaceAndPath field are taken care of by other tests
private static final List<String> IGNORED_FIELDS = Arrays.asList("dirty", "log", "serialVersionUID",
"DATE_TIME_PATTERN", "TIME_PATTERN", "DATE_PATTERN", "FORM_NAMESPACE_PATH_SEPARATOR",
"FORM_NAMESPACE_PATH_MAX_LENGTH", "obsId", "groupMembers", "uuid", "changedBy", "dateChanged", "voided", "voidedBy",
"voidReason", "dateVoided", "formNamespaceAndPath", "$jacocoData");
private void resetObs(Obs obs) throws Exception {
Field field = Obs.class.getDeclaredField("dirty");
field.setAccessible(true);
try {
field.set(obs, false);
}
finally {
field.setAccessible(false);
}
assertFalse(obs.isDirty());
}
private Obs createObs(Integer id) throws Exception {
Obs obs = new Obs(id);
List<Field> fields = Reflect.getAllFields(Obs.class);
for (Field field : fields) {
if (IGNORED_FIELDS.contains(field.getName())) {
continue;
}
setFieldValue(obs, field, false);
}
assertFalse(obs.isDirty());
return obs;
}
private void setFieldValue(Obs obs, Field field, boolean setAlternateValue) throws Exception {
final boolean accessible = field.isAccessible();
if (!accessible) {
field.setAccessible(true);
}
try {
Object oldFieldValue = field.get(obs);
Object newFieldValue = generateValue(field, setAlternateValue);
//sanity check
if (setAlternateValue) {
assertNotEquals("The old and new values should be different for field: Obs." + field.getName(),
oldFieldValue, newFieldValue);
}
field.set(obs, newFieldValue);
}
finally {
field.setAccessible(accessible);
}
}
private Object generateValue(Field field, boolean setAlternateValue) throws Exception {
Object fieldValue;
if (field.getType().equals(Boolean.class)) {
fieldValue = setAlternateValue ? true : false;
} else if (field.getType().equals(Integer.class)) {
fieldValue = setAlternateValue ? 10 : 17;
} else if (field.getType().equals(Double.class)) {
fieldValue = setAlternateValue ? 5.0 : 7.0;
} else if (field.getType().equals(Date.class)) {
fieldValue = new Date();
if (setAlternateValue) {
Calendar c = Calendar.getInstance();
c.add(Calendar.MINUTE, 2);
fieldValue = c.getTime();
}
} else if (field.getType().equals(String.class)) {
fieldValue = setAlternateValue ? "old" : "new";
} else if (field.getType().equals(Person.class)) {
//setPerson updates the personId, so we want the personIds to match for the tests to be valid
fieldValue = new Person(setAlternateValue ? 10 : 17);
} else if (field.getType().equals(ComplexData.class)) {
fieldValue = new ComplexData(setAlternateValue ? "some complex data" : "Some other value", new Object());
} else if (field.getType().equals(Obs.Interpretation.class)) {
fieldValue = setAlternateValue ? Obs.Interpretation.ABNORMAL : Obs.Interpretation.CRITICALLY_ABNORMAL;
} else if (field.getType().equals(Obs.Status.class)) {
fieldValue = setAlternateValue ? Obs.Status.AMENDED : Obs.Status.PRELIMINARY;
} else {
fieldValue = field.getType().newInstance();
}
assertNotNull("Failed to generate a value for field: Obs." + field.getName());
return fieldValue;
}
/**
* Tests the addToGroup method in ObsGroup
*
* @throws Exception
*/
@Test
public void shouldAddandRemoveObsToGroup() throws Exception {
Obs obs = new Obs(1);
Obs obsGroup = new Obs(755);
// These methods should not fail even with null attributes on the obs
assertFalse(obsGroup.isObsGrouping());
assertFalse(obsGroup.hasGroupMembers(false));
assertFalse(obsGroup.hasGroupMembers(true)); // Check both flags for false
// adding an obs when the obs group has no other obs
// should not throw an error
obsGroup.addGroupMember(obs);
assertEquals(1, obsGroup.getGroupMembers().size());
// check duplicate add. should only be one
obsGroup.addGroupMember(obs);
assertTrue(obsGroup.hasGroupMembers(false));
assertEquals("Duplicate add should not increase the grouped obs size", 1, obsGroup.getGroupMembers().size());
Obs obs2 = new Obs(2);
obsGroup.removeGroupMember(obs2);
assertTrue(obsGroup.hasGroupMembers(false));
assertEquals("Removing a non existent obs should not decrease the number of grouped obs", 1, obsGroup
.getGroupMembers().size());
// testing removing an obs from a group that has a null obs list
new Obs().removeGroupMember(obs2);
obsGroup.removeGroupMember(obs);
assertEquals(0, obsGroup.getGroupMembers().size());
// try to add an obs group to itself
try {
obsGroup.addGroupMember(obsGroup);
fail("An APIException about adding an obsGroup should have been thrown");
}
catch (APIException e) {
// this exception is expected
}
}
/**
* tests the getRelatedObservations method:
*/
@Test
public void shouldGetRelatedObservations() throws Exception {
// create a child Obs
Obs o = new Obs();
o.setDateCreated(new Date());
o.setLocation(new Location(1));
o.setObsDatetime(new Date());
o.setPerson(new Patient(2));
o.setValueText("childObs");
// create its sibling
Obs oSibling = new Obs();
oSibling.setDateCreated(new Date());
oSibling.setLocation(new Location(1));
oSibling.setObsDatetime(new Date());
oSibling.setValueText("childObs2");
oSibling.setPerson(new Patient(2));
// create a parent Obs
Obs oParent = new Obs();
oParent.setDateCreated(new Date());
oParent.setLocation(new Location(1));
oParent.setObsDatetime(new Date());
oSibling.setValueText("parentObs");
oParent.setPerson(new Patient(2));
// create a grandparent obs
Obs oGrandparent = new Obs();
oGrandparent.setDateCreated(new Date());
oGrandparent.setLocation(new Location(1));
oGrandparent.setObsDatetime(new Date());
oGrandparent.setPerson(new Patient(2));
oSibling.setValueText("grandParentObs");
oParent.addGroupMember(o);
oParent.addGroupMember(oSibling);
oGrandparent.addGroupMember(oParent);
// create a leaf observation at the grandparent level
Obs o2 = new Obs();
o2.setDateCreated(new Date());
o2.setLocation(new Location(1));
o2.setObsDatetime(new Date());
o2.setPerson(new Patient(2));
o2.setValueText("grandparentLeafObs");
oGrandparent.addGroupMember(o2);
/**
* test to make sure that if the original child obs calls getRelatedObservations, it returns
* itself and its siblings: original obs is one of two groupMembers, so relatedObservations
* should return a size of set 2 then, make sure that if oParent calls
* getRelatedObservations, it returns its own children as well as the leaf obs attached to
* the grandparentObs oParent has two members, and one leaf ancestor -- so a set of size 3
* should be returned.
*/
assertEquals(o.getRelatedObservations().size(), 2);
assertEquals(oParent.getRelatedObservations().size(), 3);
// create a great-grandparent obs
Obs oGGP = new Obs();
oGGP.setDateCreated(new Date());
oGGP.setLocation(new Location(1));
oGGP.setObsDatetime(new Date());
oGGP.setPerson(new Patient(2));
oGGP.setValueText("grandParentObs");
oGGP.addGroupMember(oGrandparent);
// create a leaf great-grandparent obs
Obs oGGPleaf = new Obs();
oGGPleaf.setDateCreated(new Date());
oGGPleaf.setLocation(new Location(1));
oGGPleaf.setObsDatetime(new Date());
oGGPleaf.setPerson(new Patient(2));
oGGPleaf.setValueText("grandParentObs");
oGGP.addGroupMember(oGGPleaf);
/**
* now run the previous assertions again. this time there are two ancestor leaf obs, so the
* first assertion should still return a set of size 2, but the second assertion sould
* return a set of size 4.
*/
assertEquals(o.getRelatedObservations().size(), 2);
assertEquals(oParent.getRelatedObservations().size(), 4);
// remove the grandparent leaf observation:
oGrandparent.removeGroupMember(o2);
// now the there is only one ancestor leaf obs:
assertEquals(o.getRelatedObservations().size(), 2);
assertEquals(oParent.getRelatedObservations().size(), 3);
/**
* finally, test a non-obsGroup and non-member Obs to the function Obs o2 is now not
* connected to our heirarchy: an empty set should be returned:
*/
assertNotNull(o2.getRelatedObservations());
assertEquals(o2.getRelatedObservations().size(), 0);
}
/**
* @see Obs#isComplex()
*/
@Test
public void isComplex_shouldReturnTrueIfTheConceptIsComplex() throws Exception {
ConceptDatatype cd = new ConceptDatatype();
cd.setName("Complex");
cd.setHl7Abbreviation("ED");
ConceptComplex complexConcept = new ConceptComplex();
complexConcept.setDatatype(cd);
Obs obs = new Obs();
obs.setConcept(complexConcept);
Assert.assertTrue(obs.isComplex());
}
/**
* @see Obs#setValueAsString(String)
*/
@Test(expected = RuntimeException.class)
public void setValueAsString_shouldFailIfTheValueOfTheStringIsEmpty() throws Exception {
Obs obs = new Obs();
obs.setValueAsString("");
}
/**
* @see Obs#setValueAsString(String)
*/
@Test(expected = RuntimeException.class)
public void setValueAsString_shouldFailIfTheValueOfTheStringIsNull() throws Exception {
Obs obs = new Obs();
obs.setValueAsString(null);
}
/**
* @see Obs#getValueAsBoolean()
*/
@Test
public void getValueAsBoolean_shouldReturnFalseForValue_numericConceptsIfValueIs0() throws Exception {
Obs obs = new Obs();
obs.setValueNumeric(0.0);
Assert.assertEquals(false, obs.getValueAsBoolean());
}
/**
* @see Obs#getValueAsBoolean()
*/
@Test
public void getValueAsBoolean_shouldReturnNullForValue_numericConceptsIfValueIsNeither1Nor0() throws Exception {
Obs obs = new Obs();
obs.setValueNumeric(24.8);
Assert.assertNull(obs.getValueAsBoolean());
}
@Test
public void getValueAsString_shouldReturnNonPreciseValuesForNumericConcepts() throws Exception {
Obs obs = new Obs();
obs.setValueNumeric(25.125);
ConceptNumeric cn = new ConceptNumeric();
ConceptDatatype cdt = new ConceptDatatype();
cdt.setHl7Abbreviation("NM");
cn.setDatatype(cdt);
cn.setAllowDecimal(false);
obs.setConcept(cn);
String str = "25";
Assert.assertEquals(str, obs.getValueAsString(Locale.US));
}
@Test
public void getValueAsString_shouldNotReturnLongDecimalNumbersAsScientificNotation() throws Exception {
Obs obs = new Obs();
obs.setValueNumeric(123456789.0);
String str = "123456789.0";
Assert.assertEquals(str, obs.getValueAsString(Locale.US));
}
@Test
public void getValueAsString_shouldReturnDateInCorrectFormat() throws Exception {
Obs obs = new Obs();
obs.setValueDatetime(new Date());
Concept cn = new Concept();
ConceptDatatype cdt = new ConceptDatatype();
cdt.setHl7Abbreviation("DT");
cn.setDatatype(cdt);
obs.setConcept(cn);
Date utilDate = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
String dateString = dateFormat.format(utilDate);
Assert.assertEquals(dateString, obs.getValueAsString(Locale.US));
}
/**
* @see Obs#getValueAsBoolean()
*/
@Test
public void getValueAsBoolean_shouldReturnTrueForValue_numericConceptsIfValueIs1() throws Exception {
Obs obs = new Obs();
obs.setValueNumeric(1.0);
Assert.assertEquals(true, obs.getValueAsBoolean());
}
/**
* @see Obs#getGroupMembers(boolean)
*/
@Test
public void getGroupMembers_shouldGetAllGroupMembersIfPassedTrueAndNonvoidedIfPassedFalse() throws Exception {
Obs parent = new Obs(1);
Set<Obs> members = new HashSet<>();
members.add(new Obs(101));
members.add(new Obs(103));
Obs voided = new Obs(99);
voided.setVoided(true);
members.add(voided);
parent.setGroupMembers(members);
members = parent.getGroupMembers(true);
assertEquals("set of all members should have length of 3", 3, members.size());
members = parent.getGroupMembers(false);
assertEquals("set of non-voided should have length of 2", 2, members.size());
members = parent.getGroupMembers(); // should be same as false
assertEquals("default should return non-voided with length of 2", 2, members.size());
}
/**
* @see Obs#hasGroupMembers(boolean)
*/
@Test
public void hasGroupMembers_shouldReturnTrueIfThisObsHasGroupMembersBasedOnParameter() throws Exception {
Obs parent = new Obs(5);
Obs child = new Obs(33);
child.setVoided(true);
parent.addGroupMember(child); // Only contains 1 voided child
assertTrue("When checking for all members, should return true", parent.hasGroupMembers(true));
assertFalse("When checking for non-voided, should return false", parent.hasGroupMembers(false));
assertFalse("Default should check for non-voided", parent.hasGroupMembers());
}
/**
* @see Obs#isObsGrouping()
*/
@Test
public void isObsGrouping_shouldIncludeVoidedObs() throws Exception {
Obs parent = new Obs(5);
Obs child = new Obs(33);
child.setVoided(true);
parent.addGroupMember(child);
assertTrue("When checking for Obs grouping, should include voided Obs", parent.isObsGrouping());
}
/**
* @see Obs#getValueAsString(Locale)
*/
@Test
public void getValueAsString_shouldUseCommasOrDecimalPlacesDependingOnLocale() throws Exception {
Obs obs = new Obs();
obs.setValueNumeric(123456789.3);
String str = "123456789,3";
Assert.assertEquals(str, obs.getValueAsString(Locale.GERMAN));
}
/**
* @see Obs#getValueAsString(Locale)
*/
@Test
public void getValueAsString_shouldNotUseThousandSeparator() throws Exception {
Obs obs = new Obs();
obs.setValueNumeric(123456789.0);
String str = "123456789.0";
Assert.assertEquals(str, obs.getValueAsString(Locale.ENGLISH));
}
/**
* @see Obs#getValueAsString(Locale)
*/
@Test
public void getValueAsString_shouldReturnRegularNumberForSizeOfZeroToOrGreaterThanTenDigits() throws Exception {
Obs obs = new Obs();
obs.setValueNumeric(1234567890.0);
String str = "1234567890.0";
Assert.assertEquals(str, obs.getValueAsString(Locale.ENGLISH));
}
/**
* @see Obs#getValueAsString(Locale)
*/
@Test
public void getValueAsString_shouldReturnRegularNumberIfDecimalPlacesAreAsHighAsSix() throws Exception {
Obs obs = new Obs();
obs.setValueNumeric(123456789.012345);
String str = "123456789.012345";
Assert.assertEquals(str, obs.getValueAsString(Locale.ENGLISH));
}
@Test
public void getValueAsString_shouldReturnLocalizedCodedConcept() throws Exception {
ConceptDatatype cdt = new ConceptDatatype();
cdt.setHl7Abbreviation("CWE");
Concept cn = new Concept();
cn.setDatatype(cdt);
cn.addName(new ConceptName(VERO, Locale.ITALIAN));
Obs obs = new Obs();
obs.setValueCoded(cn);
obs.setConcept(cn);
obs.setValueCodedName(new ConceptName("True", Locale.US));
Assert.assertEquals(VERO, obs.getValueAsString(Locale.ITALIAN));
}
/**
* @see Obs#setFormField(String,String)
*/
@Test
public void setFormField_shouldSetTheUnderlyingFormNamespaceAndPathInTheCorrectPattern() throws Exception {
final String ns = "my ns";
final String path = "my path";
Obs obs = new Obs();
obs.setFormField(ns, path);
java.lang.reflect.Field formNamespaceAndPathProperty = Obs.class.getDeclaredField("formNamespaceAndPath");
formNamespaceAndPathProperty.setAccessible(true);
Assert.assertEquals(ns + FORM_NAMESPACE_PATH_SEPARATOR + path, formNamespaceAndPathProperty.get(obs));
}
/**
* @see Obs#getFormFieldNamespace()
*/
@Test
public void getFormFieldNamespace_shouldReturnNullIfTheNamespaceIsNotSpecified() throws Exception {
Obs obs = new Obs();
obs.setFormField("", "my path");
Assert.assertNull(obs.getFormFieldNamespace());
}
/**
* @see Obs#getFormFieldNamespace()
*/
@Test
public void getFormFieldNamespace_shouldReturnTheCorrectNamespaceForAFormFieldWithAPath() throws Exception {
final String ns = "my ns";
final String path = "my path";
Obs obs = new Obs();
obs.setFormField(ns, path);
Assert.assertEquals(ns, obs.getFormFieldNamespace());
}
/**
* @see Obs#getFormFieldNamespace()
*/
@Test
public void getFormFieldNamespace_shouldReturnTheNamespaceForAFormFieldThatHasNoPath() throws Exception {
final String ns = "my ns";
Obs obs = new Obs();
obs.setFormField(ns, null);
Assert.assertEquals(ns, obs.getFormFieldNamespace());
}
/**
* @see Obs#getFormFieldPath()
*/
@Test
public void getFormFieldPath_shouldReturnNullIfThePathIsNotSpecified() throws Exception {
Obs obs = new Obs();
obs.setFormField("my ns", "");
Assert.assertNull(obs.getFormFieldPath());
}
/**
* @see Obs#getFormFieldPath()
*/
@Test
public void getFormFieldPath_shouldReturnTheCorrectPathForAFormFieldWithANamespace() throws Exception {
final String ns = "my ns";
final String path = "my path";
Obs obs = new Obs();
obs.setFormField(ns, path);
Assert.assertEquals(path, obs.getFormFieldPath());
}
/**
* @see Obs#getFormFieldPath()
*/
@Test
public void getFormFieldPath_shouldReturnThePathForAFormFieldThatHasNoNamespace() throws Exception {
final String path = "my path";
Obs obs = new Obs();
obs.setFormField("", path);
Assert.assertEquals(path, obs.getFormFieldPath());
}
/**
* @see Obs#setFormField(String,String)
*/
@Test(expected = APIException.class)
public void setFormField_shouldRejectANamepaceAndPathCombinationLongerThanTheMaxLength() throws Exception {
StringBuffer nsBuffer = new StringBuffer(125);
for (int i = 0; i < 125; i++) {
nsBuffer.append("n");
}
StringBuffer pathBuffer = new StringBuffer(130);
for (int i = 0; i < 130; i++) {
nsBuffer.append("p");
}
final String ns = nsBuffer.toString();
final String path = pathBuffer.toString();
Obs obs = new Obs();
obs.setFormField(ns, path);
}
/**
* @see Obs#setFormField(String,String)
*/
@Test(expected = APIException.class)
public void setFormField_shouldRejectANamepaceContainingTheSeparator() throws Exception {
final String ns = "my ns" + FORM_NAMESPACE_PATH_SEPARATOR;
Obs obs = new Obs();
obs.setFormField(ns, "");
}
/**
* @see Obs#setFormField(String,String)
*/
@Test(expected = APIException.class)
public void setFormField_shouldRejectAPathContainingTheSeparator() throws Exception {
final String path = FORM_NAMESPACE_PATH_SEPARATOR + "my path";
Obs obs = new Obs();
obs.setFormField("", path);
}
/**
* @see Obs#isDirty()
*/
@Test
public void isDirty_shouldReturnFalseWhenNoChangeHasBeenMade() throws Exception {
assertFalse(new Obs().isDirty());
//Should also work if setters are called with same values as the original
Obs obs = createObs(2);
obs.setGroupMembers(new LinkedHashSet<>());
obs.getConcept().setDatatype(new ConceptDatatype());
assertFalse(obs.isDirty());
BeanUtils.copyProperties(obs, BeanUtils.cloneBean(obs));
assertFalse(obs.isDirty());
obs = createObs(null);
obs.setGroupMembers(new LinkedHashSet<>());
obs.getConcept().setDatatype(new ConceptDatatype());
assertFalse(obs.isDirty());
BeanUtils.copyProperties(obs, BeanUtils.cloneBean(obs));
assertFalse(obs.isDirty());
}
/**
* @see Obs#isDirty()
*/
@Test
public void isDirty_shouldReturnTrueWhenAnyImmutableFieldHasBeenChangedForEditedObs() throws Exception {
Obs obs = createObs(2);
assertFalse(obs.isDirty());
updateImmutableFieldsAndAssert(obs, true);
}
/**
* @see Obs#isDirty()
*/
@Test
public void isDirty_shouldReturnFalseWhenAnyImmutableFieldHasBeenChangedForNewObs() throws Exception {
Obs obs = createObs(null);
assertFalse(obs.isDirty());
updateImmutableFieldsAndAssert(obs, false);
}
private void updateImmutableFieldsAndAssert(Obs obs, boolean assertion) throws Exception {
//Set all fields to some random values via reflection
List<Field> fields = Reflect.getAllFields(Obs.class);
final Integer originalPersonId = obs.getPersonId();
//call each setter and check that dirty has been set to true for each
for (Field field : fields) {
String fieldName = field.getName();
if (IGNORED_FIELDS.contains(fieldName)) {
continue;
}
if ("personId".equals(fieldName)) {
//call setPersonId because it is protected so BeanUtils.setProperty won't work
obs.setPersonId((Integer) generateValue(field, true));
} else {
BeanUtils.setProperty(obs, fieldName, generateValue(field, true));
}
assertEquals("Obs was not marked as dirty after changing: " + fieldName, obs.isDirty(), assertion);
if ("person".equals(fieldName)) {
//Because setPerson updates the personId we need to reset personId to its original value
//that matches that of person otherwise the test will fail for the personId field
obs.setPersonId(originalPersonId);
}
//reset for next field
resetObs(obs);
}
}
/**
* @see Obs#isDirty()
*/
@Test
public void isDirty_shouldReturnFalseWhenOnlyMutableFieldsAreChanged() throws Exception {
Obs obs = new Obs();
obs.setVoided(true);
obs.setVoidedBy(new User(1000));
obs.setVoidReason("some other reason");
obs.setDateVoided(new Date());
assertFalse(obs.isDirty());
Obs obsEdited = new Obs(5);
obsEdited.setVoided(true);
obsEdited.setVoidedBy(new User(1000));
obsEdited.setVoidReason("some other reason");
obsEdited.setDateVoided(new Date());
assertFalse(obsEdited.isDirty());
}
/**
* @see Obs#isDirty()
*/
@Test
public void isDirty_shouldReturnTrueWhenAnImmutableFieldIsChangedFromANonNullToANullValueForEditedObs() throws Exception {
Obs obs = createObs(2);
assertNotNull(obs.getComment());
obs.setComment(null);
assertTrue(obs.isDirty());
}
/**
* @see Obs#isDirty()
*/
@Test
public void isDirty_shouldReturnFalsWhenAnImmutableFieldIsChangedFromANonNullToANullValueForNewObs() throws Exception {
Obs obs = createObs(null);
assertNotNull(obs.getComment());
obs.setComment(null);
assertFalse(obs.isDirty());
}
/**
* @see Obs#isDirty()
*/
@Test
public void isDirty_shouldReturnTrueWhenAnImmutableFieldIsChangedFromANullToANonNullValueInExistingObs() throws Exception {
Obs obs = new Obs(5);
assertNull(obs.getComment());
obs.setComment("some non null value");
assertTrue(obs.isDirty());
}
/**
* @see Obs#isDirty()
*/
@Test
public void isDirty_shouldReturnFalseWhenAnImmutableFieldIsChangedFromANullToANonNullValueInNewObs() throws Exception {
Obs obs = new Obs();
assertNull(obs.getComment());
obs.setComment("some non null value");
assertFalse(obs.isDirty());
}
/**
* @see Obs#setFormField(String,String)
*/
@Test
public void setFormField_shouldNotMarkTheObsAsDirtyWhenTheValueHasNotBeenChanged() throws Exception {
Obs obs = createObs(3);
obs.setFormField(obs.getFormFieldNamespace(), obs.getFormFieldPath());
assertFalse(obs.isDirty());
}
/**
* @see Obs#setFormField(String,String)
*/
@Test
public void setFormField_shouldMarkTheObsAsDirtyWhenTheValueHasBeenChanged() throws Exception {
Obs obs = createObs(5);
final String newNameSpace = "someNameSpace";
final String newPath = "somePath";
assertNotEquals(newPath, obs.getFormFieldNamespace());
assertNotEquals(newNameSpace, obs.getFormFieldPath());
obs.setFormField(newNameSpace, newPath);
assertTrue(obs.isDirty());
}
/**
* @see Obs#setFormField(String,String)
*/
@Test
public void setFormField_shouldMarkTheObsAsDirtyWhenTheValueIsChangedFromANonNullToANullValue() throws Exception {
Obs obs = new Obs(2);
obs.setFormField("someNameSpace", "somePath");
resetObs(obs);
assertFalse(obs.isDirty());
assertNotNull(obs.getFormFieldNamespace());
assertNotNull(obs.getFormFieldPath());
obs.setFormField(null, null);
assertTrue(obs.isDirty());
}
/**
* @see Obs#setFormField(String,String)
*/
@Test
public void setFormField_shouldMarkTheObsAsDirtyWhenTheValueIsChangedFromANullToANonNullValue() throws Exception {
Obs obs = new Obs(5);
assertNull(obs.getFormFieldNamespace());
assertNull(obs.getFormFieldPath());
obs.setFormField("someNameSpace", "somePath");
assertTrue(obs.isDirty());
}
/**
* @see Obs#addGroupMember(Obs)
*/
@Test
public void addGroupMember_shouldReturnFalseWhenADuplicateObsIsAddedAsAMember() throws Exception {
Obs obs = new Obs(2);
Obs member = new Obs();
obs.addGroupMember(member);
assertFalse(obs.isDirty());
resetObs(obs);
obs.addGroupMember(member);
assertFalse(obs.isDirty());
}
/**
* @see Obs#addGroupMember(Obs)
*/
@Test
public void addGroupMember_shouldReturnFalseWhenADuplicateObsIsAddedAsAMemberToNewObs() throws Exception {
Obs obs = new Obs();
Obs member = new Obs();
obs.addGroupMember(member);
assertFalse(obs.isDirty());
resetObs(obs);
obs.addGroupMember(member);
assertFalse(obs.isDirty());
}
/**
* @see Obs#addGroupMember(Obs)
*/
@Test
public void addGroupMember_shouldReturnFalseWhenANewObsIsAddedAsAMember() throws Exception {
Obs obs = new Obs(2);
Obs member1 = new Obs();
obs.addGroupMember(member1);
assertFalse(obs.isDirty());
resetObs(obs);
Obs member2 = new Obs();
obs.addGroupMember(member2);
assertFalse(obs.isDirty());
}
/**
* @see Obs#removeGroupMember(Obs)
*/
@Test
public void removeGroupMember_shouldReturnFalseWhenANonExistentObsIsRemoved() throws Exception {
Obs obs = new Obs();
obs.removeGroupMember(new Obs());
assertFalse(obs.isDirty());
}
/**
* @see Obs#removeGroupMember(Obs)
*/
@Test
public void removeGroupMember_shouldReturnDirtyFalseWhenAnObsIsRemoved() throws Exception {
Obs obs = new Obs(2);
Obs member = new Obs();
obs.addGroupMember(member);
assertFalse(obs.isDirty());
resetObs(obs);
obs.removeGroupMember(member);
assertFalse(obs.isDirty());
}
/**
* @see Obs#removeGroupMember(Obs)
*/
@Test
public void removeGroupMember_shouldReturnFalseForDirtyFlagWhenAnObsIsRemovedFromGroup() throws Exception {
Obs obs = new Obs();
Obs member = new Obs();
obs.addGroupMember(member);
assertFalse(obs.isDirty());
resetObs(obs);
obs.removeGroupMember(member);
assertFalse(obs.isDirty());
}
/**
* @see Obs#setGroupMembers(Set)
*/
@Test
public void setGroupMembers_shouldNotMarkTheExistingObsAsDirtyWhenTheSetIsChangedFromNullToANonEmptyOne() throws Exception {
Obs obs = new Obs(5);
assertNull(Obs.class.getDeclaredField("groupMembers").get(obs));
Set<Obs> members = new HashSet<>();
members.add(new Obs());
obs.setGroupMembers(members);
assertFalse(obs.isDirty());
}
/**
* @see Obs#setGroupMembers(Set)
*/
@Test
public void setGroupMembers_shouldNotMarkNewObsAsDirtyWhenTheSetIsChangedFromNullToANonEmptyOne() throws Exception {
Obs obs = new Obs();
assertNull(Obs.class.getDeclaredField("groupMembers").get(obs));
Set<Obs> members = new HashSet<>();
members.add(new Obs());
obs.setGroupMembers(members);
assertFalse(obs.isDirty());
}
/**
* @see Obs#setGroupMembers(Set)
*/
@Test
public void setGroupMembers_shouldNotMarkTheExistingObsAsDirtyWhenTheSetIsReplacedWithAnotherWithDifferentMembers()
throws Exception {
Obs obs = new Obs(2);
Set<Obs> members1 = new HashSet<>();
members1.add(new Obs());
obs.setGroupMembers(members1);
resetObs(obs);
Set<Obs> members2 = new HashSet<>();
members2.add(new Obs());
obs.setGroupMembers(members2);
assertFalse(obs.isDirty());
}
/**
* @see Obs#setGroupMembers(Set)
*/
@Test
public void setGroupMembers_shouldNotMarkTheNewObsAsDirtyWhenTheSetIsReplacedWithAnotherWithDifferentMembers()
throws Exception {
Obs obs = new Obs();
Set<Obs> members1 = new HashSet<>();
members1.add(new Obs());
obs.setGroupMembers(members1);
assertFalse(obs.isDirty());
Set<Obs> members2 = new HashSet<>();
members2.add(new Obs());
obs.setGroupMembers(members2);
assertFalse(obs.isDirty());
}
/**
* @see Obs#setGroupMembers(Set)
*/
@Test
public void setGroupMembers_shouldNotMarkTheObsAsDirtyWhenTheSetIsChangedFromNullToAnEmptyOne() throws Exception {
Obs obs = new Obs();
assertNull(Obs.class.getDeclaredField("groupMembers").get(obs));
obs.setGroupMembers(new HashSet<>());
assertFalse(obs.isDirty());
}
/**
* @see Obs#setGroupMembers(Set)
*/
@Test
public void setGroupMembers_shouldNotMarkTheObsAsDirtyWhenTheSetIsReplacedWithAnotherWithSameMembers() throws Exception {
Obs obs = new Obs();
Obs o = new Obs();
Set<Obs> members1 = new HashSet<>();
members1.add(o);
obs.setGroupMembers(members1);
resetObs(obs);
Set<Obs> members2 = new HashSet<>();
members2.add(o);
obs.setGroupMembers(members2);
assertFalse(obs.isDirty());
}
/**
* @see Obs#setObsDatetime(Date)
*/
@Test
public void setObsDateTime_shouldNotMarkTheObsAsDirtyWhenDateIsNotChangedAndExistingValueIsOfTimeStampType(){
Obs obs = new Obs();
Date date = new Date();
Timestamp timestamp = new Timestamp(date.getTime());
obs.setObsDatetime(timestamp);
obs.setId(1);
assertFalse(obs.isDirty());
obs.setObsDatetime(date);
assertFalse(obs.isDirty());
}
@Test
public void shouldSetFinalStatusOnNewObsByDefault() throws Exception {
Obs obs = new Obs();
assertThat(obs.getStatus(), is(Obs.Status.FINAL));
}
@Test
public void newInstance_shouldCopyMostFields() throws Exception {
Obs obs = new Obs();
obs.setStatus(Obs.Status.PRELIMINARY);
obs.setInterpretation(Obs.Interpretation.LOW);
obs.setConcept(new Concept());
obs.setValueNumeric(1.2);
Obs copy = Obs.newInstance(obs);
// these fields are not copied
assertThat(copy.getObsId(), nullValue());
assertThat(copy.getUuid(), not(obs.getUuid()));
// other fields are copied
assertThat(copy.getConcept(), is(obs.getConcept()));
assertThat(copy.getValueNumeric(), is(obs.getValueNumeric()));
assertThat(copy.getStatus(), is(obs.getStatus()));
assertThat(copy.getInterpretation(), is(obs.getInterpretation()));
// TODO test that the rest of the fields are set
}
@Test
public void shouldSupportInterpretationProperty() throws Exception {
Obs obs = new Obs();
assertThat(obs.getInterpretation(), nullValue());
obs.setInterpretation(Obs.Interpretation.NORMAL);
assertThat(obs.getInterpretation(), is(Obs.Interpretation.NORMAL));
}
}