/**
* The contents of this file are subject to the OpenMRS Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://license.openmrs.org
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* Copyright (C) OpenMRS, LLC. All Rights Reserved.
*/
package org.openmrs.util;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;
import java.util.SortedSet;
import java.util.TreeSet;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.openmrs.GlobalProperty;
import org.openmrs.PatientIdentifier;
import org.openmrs.PatientIdentifierType;
import org.openmrs.User;
import org.openmrs.api.InvalidCharactersPasswordException;
import org.openmrs.api.ShortPasswordException;
import org.openmrs.api.WeakPasswordException;
import org.openmrs.api.context.Context;
import org.openmrs.test.BaseContextSensitiveTest;
import org.openmrs.test.TestUtil;
import org.openmrs.test.Verifies;
/**
* Tests the methods in {@link OpenmrsUtil} TODO: finish adding tests for all methods
*/
public class OpenmrsUtilTest extends BaseContextSensitiveTest {
private static GlobalProperty luhnGP = new GlobalProperty(
OpenmrsConstants.GLOBAL_PROPERTY_DEFAULT_PATIENT_IDENTIFIER_VALIDATOR,
OpenmrsConstants.LUHN_IDENTIFIER_VALIDATOR);
/**
* @see org.springframework.test.AbstractTransactionalSpringContextTests#onSetUpInTransaction()
*/
@Before
public void runBeforeEachTest() throws Exception {
initializeInMemoryDatabase();
authenticate();
Context.getAdministrationService().saveGlobalProperty(luhnGP);
}
/**
* Test the check digit method
*
* @see {@link OpenmrsUtil#getCheckDigit(String)}
*/
@Test
@Verifies(value = "should get valid check digits", method = "getCheckDigit(String)")
public void getCheckDigit_shouldGetValidCheckDigits() throws Exception {
String[] ids = { "9", "99", "999", "123MT", "asdf" };
int[] cds = { 1, 2, 3, 2, 8 };
for (int i = 0; i < ids.length; i++) {
assertEquals(OpenmrsUtil.getCheckDigit(ids[i]), cds[i]);
}
}
/**
* Test check digit validation methods
*
* @see {@link OpenmrsUtil#isValidCheckDigit(String)}
*/
@Test
@Verifies(value = "should validate correct check digits", method = "isValidCheckDigit(String)")
public void isValidCheckDigit_shouldValidateCorrectCheckDigits() throws Exception {
String[] ids2 = { "9-1", "99-2", "999-3", "123MT-2", "asdf-8", "12abd-7" };
String[] ids2Char = { "9-b", "99-c", "999-d", "123MT-c", "asdf-i", "12abd-h" };
for (int i = 0; i < ids2.length; i++) {
assertTrue(OpenmrsUtil.isValidCheckDigit(ids2[i]));
assertTrue(OpenmrsUtil.isValidCheckDigit(ids2Char[i]));
}
}
/**
* @see {@link OpenmrsUtil#isValidCheckDigit(String)}
*/
@Test
@Verifies(value = "should not validate invalid check digits", method = "isValidCheckDigit(String)")
public void isValidCheckDigit_shouldNotValidateInvalidCheckDigits() throws Exception {
String[] ids3 = { "asdf-7", "9-2", "9-4" };
for (int i = 0; i < ids3.length; i++) {
assertFalse(OpenmrsUtil.isValidCheckDigit(ids3[i]));
}
}
/**
* @see {@link OpenmrsUtil#isValidCheckDigit(String)}
*/
@Test
@Verifies(value = "should throw error if given an invalid character in id", method = "isValidCheckDigit(String)")
public void isValidCheckDigit_shouldThrowErrorIfGivenAnInvalidCharacterInId() throws Exception {
String[] ids4 = { "#@!", "234-3-3", "-3", "2134" };
for (int i = 0; i < ids4.length; i++) {
try {
OpenmrsUtil.isValidCheckDigit(ids4[i]);
fail("An exception was not thrown for invalid identifier: " + ids4[i]);
}
catch (Exception e) {}
}
}
/**
* test the collection contains method
*
* @see {@link OpenmrsUtil#collectionContains(Collection<*>,Object)}
*/
@Test
@Verifies(value = "should use equals method for comparison instead of compareTo given List collection", method = "collectionContains(Collection<*>,Object)")
public void collectionContains_shouldUseEqualsMethodForComparisonInsteadOfCompareToGivenListCollection()
throws Exception {
ArrayList<PatientIdentifier> identifiers = new ArrayList<PatientIdentifier>();
PatientIdentifier pi = new PatientIdentifier();
pi.setIdentifier("123");
pi.setIdentifierType(new PatientIdentifierType(1));
pi.setDateCreated(new Date());
pi.setCreator(new User(1));
identifiers.add(pi);
// sanity check
identifiers.add(pi);
assertFalse("Lists should accept more than one object", identifiers.size() == 1);
pi.setDateCreated(null);
pi.setCreator(null);
assertTrue("Just because the date is null, doesn't make it not in the list anymore", OpenmrsUtil.collectionContains(
identifiers, pi));
}
/**
* test the collection contains method
*
* @see {@link OpenmrsUtil#collectionContains(Collection<*>,Object)}
*/
@Test
@Verifies(value = "should use equals method for comparison instead of compareTo given SortedSet collection", method = "collectionContains(Collection<*>,Object)")
public void collectionContains_shouldUseEqualsMethodForComparisonInsteadOfCompareToGivenSortedSetCollection()
throws Exception {
SortedSet<PatientIdentifier> identifiers = new TreeSet<PatientIdentifier>();
PatientIdentifier pi = new PatientIdentifier();
pi.setIdentifier("123");
pi.setIdentifierType(new PatientIdentifierType(1));
pi.setDateCreated(new Date());
pi.setCreator(new User(1));
identifiers.add(pi);
// sanity check
identifiers.add(pi);
assertTrue("There should still be only 1 identifier in the patient object now", identifiers.size() == 1);
pi.setDateCreated(null);
pi.setCreator(null);
assertTrue("Just because the date is null, doesn't make it not in the list anymore", OpenmrsUtil.collectionContains(
identifiers, pi));
}
/**
* When given a null parameter, the {@link OpenmrsUtil#url2file(java.net.URL)} method should
* quietly fail by returning null
*
* @see {@link OpenmrsUtil#url2file(URL)}
*/
@Test
@Verifies(value = "should return null given null parameter", method = "url2file(URL)")
public void url2file_shouldReturnNullGivenNullParameter() throws Exception {
assertNull(OpenmrsUtil.url2file(null));
}
/**
* @see {@link OpenmrsUtil#validatePassword(String,String,String)}
*/
@Test(expected = InvalidCharactersPasswordException.class)
@Verifies(value = "should fail with digit only password by default", method = "validatePassword(String,String,String)")
public void validatePassword_shouldFailWithDigitOnlyPasswordByDefault() throws Exception {
OpenmrsUtil.validatePassword("admin", "12345678", "1-8");
}
/**
* @see {@link OpenmrsUtil#validatePassword(String,String,String)}
*/
@Test(expected = InvalidCharactersPasswordException.class)
@Verifies(value = "should fail with digit only password if not allowed", method = "validatePassword(String,String,String)")
public void validatePassword_shouldFailWithDigitOnlyPasswordIfNotAllowed() throws Exception {
TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_REQUIRES_NON_DIGIT, "true");
OpenmrsUtil.validatePassword("admin", "12345678", "1-8");
}
/**
* @see {@link OpenmrsUtil#validatePassword(String,String,String)}
*/
@Test
@Verifies(value = "should pass with digit only password if allowed", method = "validatePassword(String,String,String)")
public void validatePassword_shouldPassWithDigitOnlyPasswordIfAllowed() throws Exception {
TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_REQUIRES_NON_DIGIT, "false");
TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_REQUIRES_UPPER_AND_LOWER_CASE, "false");
OpenmrsUtil.validatePassword("admin", "12345678", "1-8");
}
/**
* @see {@link OpenmrsUtil#validatePassword(String,String,String)}
*/
@Test(expected = InvalidCharactersPasswordException.class)
@Verifies(value = "should fail with char only password by default", method = "validatePassword(String,String,String)")
public void validatePassword_shouldFailWithCharOnlyPasswordByDefault() throws Exception {
OpenmrsUtil.validatePassword("admin", "testonly", "1-8");
}
/**
* @see {@link OpenmrsUtil#validatePassword(String,String,String)}
*/
@Test(expected = InvalidCharactersPasswordException.class)
@Verifies(value = "should fail with char only password if not allowed", method = "validatePassword(String,String,String)")
public void validatePassword_shouldFailWithCharOnlyPasswordIfNotAllowed() throws Exception {
TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_REQUIRES_DIGIT, "true");
OpenmrsUtil.validatePassword("admin", "testonly", "1-8");
}
/**
* @see {@link OpenmrsUtil#validatePassword(String,String,String)}
*/
@Test
@Verifies(value = "should pass with char only password if allowed", method = "validatePassword(String,String,String)")
public void validatePassword_shouldPassWithCharOnlyPasswordIfAllowed() throws Exception {
TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_REQUIRES_DIGIT, "false");
TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_REQUIRES_UPPER_AND_LOWER_CASE, "false");
OpenmrsUtil.validatePassword("admin", "testonly", "1-8");
}
/**
* @see {@link OpenmrsUtil#validatePassword(String,String,String)}
*/
@Test(expected = InvalidCharactersPasswordException.class)
@Verifies(value = "should fail without upper and lower case password by default", method = "validatePassword(String,String,String)")
public void validatePassword_shouldFailWithoutUpperAndLowerCasePasswordByDefault() throws Exception {
OpenmrsUtil.validatePassword("admin", "test0nl1", "1-8");
}
/**
* @see {@link OpenmrsUtil#validatePassword(String,String,String)}
*/
@Test(expected = InvalidCharactersPasswordException.class)
@Verifies(value = "should fail without upper and lower case password if not allowed", method = "validatePassword(String,String,String)")
public void validatePassword_shouldFailWithoutUpperAndLowerCasePasswordIfNotAllowed() throws Exception {
TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_REQUIRES_UPPER_AND_LOWER_CASE, "true");
OpenmrsUtil.validatePassword("admin", "test0nl1", "1-8");
}
/**
* @see {@link OpenmrsUtil#validatePassword(String,String,String)}
*/
@Test
@Verifies(value = "should pass without upper and lower case password if allowed", method = "validatePassword(String,String,String)")
public void validatePassword_shouldPassWithoutUpperAndLowerCasePasswordIfAllowed() throws Exception {
TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_REQUIRES_UPPER_AND_LOWER_CASE, "false");
OpenmrsUtil.validatePassword("admin", "test0nl1", "1-8");
}
/**
* @see {@link OpenmrsUtil#validatePassword(String,String,String)}
*/
@Test(expected = WeakPasswordException.class)
@Verifies(value = "should fail with password equals to user name by default", method = "validatePassword(String,String,String)")
public void validatePassword_shouldFailWithPasswordEqualsToUserNameByDefault() throws Exception {
OpenmrsUtil.validatePassword("Admin1234", "Admin1234", "1-8");
}
/**
* @see {@link OpenmrsUtil#validatePassword(String,String,String)}
*/
@Test(expected = WeakPasswordException.class)
@Verifies(value = "should fail with password equals to user name if not allowed", method = "validatePassword(String,String,String)")
public void validatePassword_shouldFailWithPasswordEqualsToUserNameIfNotAllowed() throws Exception {
TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_CANNOT_MATCH_USERNAME_OR_SYSTEMID, "true");
OpenmrsUtil.validatePassword("Admin1234", "Admin1234", "1-8");
}
/**
* @see {@link OpenmrsUtil#validatePassword(String,String,String)}
*/
@Test
@Verifies(value = "should pass with password equals to user name if allowed", method = "validatePassword(String,String,String)")
public void validatePassword_shouldPassWithPasswordEqualsToUserNameIfAllowed() throws Exception {
TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_CANNOT_MATCH_USERNAME_OR_SYSTEMID, "false");
OpenmrsUtil.validatePassword("Admin1234", "Admin1234", "1-8");
}
/**
* @see {@link OpenmrsUtil#validatePassword(String,String,String)}
*/
@Test(expected = WeakPasswordException.class)
@Verifies(value = "should fail with password equals to system id by default", method = "validatePassword(String,String,String)")
public void validatePassword_shouldFailWithPasswordEqualsToSystemIdByDefault() throws Exception {
OpenmrsUtil.validatePassword("admin", "Admin1234", "Admin1234");
}
/**
* @see {@link OpenmrsUtil#validatePassword(String,String,String)}
*/
@Test(expected = WeakPasswordException.class)
@Verifies(value = "should fail with password equals to system id if not allowed", method = "validatePassword(String,String,String)")
public void validatePassword_shouldFailWithPasswordEqualsToSystemIdIfNotAllowed() throws Exception {
TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_CANNOT_MATCH_USERNAME_OR_SYSTEMID, "true");
OpenmrsUtil.validatePassword("admin", "Admin1234", "Admin1234");
}
/**
* @see {@link OpenmrsUtil#validatePassword(String,String,String)}
*/
@Test
@Verifies(value = "should pass with password equals to system id if allowed", method = "validatePassword(String,String,String)")
public void validatePassword_shouldPassWithPasswordEqualsToSystemIdIfAllowed() throws Exception {
TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_CANNOT_MATCH_USERNAME_OR_SYSTEMID, "false");
OpenmrsUtil.validatePassword("admin", "Admin1234", "Admin1234");
}
/**
* @see {@link OpenmrsUtil#validatePassword(String,String,String)}
*/
@Test(expected = ShortPasswordException.class)
@Verifies(value = "should fail with short password by default", method = "validatePassword(String,String,String)")
public void validatePassword_shouldFailWithShortPasswordByDefault() throws Exception {
OpenmrsUtil.validatePassword("admin", "1234567", "1-8");
}
/**
* @see {@link OpenmrsUtil#validatePassword(String,String,String)}
*/
@Test(expected = ShortPasswordException.class)
@Verifies(value = "should fail with short password if not allowed", method = "validatePassword(String,String,String)")
public void validatePassword_shouldFailWithShortPasswordIfNotAllowed() throws Exception {
TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_MINIMUM_LENGTH, "6");
OpenmrsUtil.validatePassword("admin", "12345", "1-8");
}
/**
* @see {@link OpenmrsUtil#validatePassword(String,String,String)}
*/
@Test
@Verifies(value = "should pass with short password if allowed", method = "validatePassword(String,String,String)")
public void validatePassword_shouldPassWithShortPasswordIfAllowed() throws Exception {
TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_MINIMUM_LENGTH, "0");
OpenmrsUtil.validatePassword("admin", "H4t", "1-8");
}
/**
* @see {@link OpenmrsUtil#validatePassword(String,String,String)}
*/
@Test(expected = InvalidCharactersPasswordException.class)
@Verifies(value = "should fail with password not matching configured regex", method = "validatePassword(String,String,String)")
public void validatePassword_shouldFailWithPasswordNotMatchingConfiguredRegex() throws Exception {
TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_CUSTOM_REGEX,
"[A-Z][a-z][0-9][0-9][a-z][A-Z][a-z][a-z][a-z][a-z]");
OpenmrsUtil.validatePassword("admin", "he11oWorld", "1-8");
}
/**
* @see {@link OpenmrsUtil#validatePassword(String,String,String)}
*/
@Test
@Verifies(value = "should pass with password matching configured regex", method = "validatePassword(String,String,String)")
public void validatePassword_shouldPassWithPasswordMatchingConfiguredRegex() throws Exception {
TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_CUSTOM_REGEX,
"[A-Z][a-z][0-9][0-9][a-z][A-Z][a-z][a-z][a-z][a-z]");
OpenmrsUtil.validatePassword("admin", "He11oWorld", "1-8");
}
/**
* @see {@link OpenmrsUtil#validatePassword(String,String,String)}
*/
@Test
@Verifies(value = "should allow password to contain non alphanumeric characters", method = "validatePassword(String,String,String)")
public void validatePassword_shouldAllowPasswordToContainNonAlphanumericCharacters() throws Exception {
OpenmrsUtil.validatePassword("admin", "Test1234?", "1-8");
}
/**
* @see {@link OpenmrsUtil#validatePassword(String,String,String)}
*/
@Test
@Verifies(value = "should allow password to contain white spaces", method = "validatePassword(String,String,String)")
public void validatePassword_shouldAllowPasswordToContainWhiteSpaces() throws Exception {
OpenmrsUtil.validatePassword("admin", "Test *&^ 1234? ", "1-8");
}
/**
* @see {@link OpenmrsUtil#getDateFormat(Locale)}
*/
@Test
@Verifies(value = "should return a pattern with four y characters in it", method = "getDateFormat(Locale)")
public void getDateFormat_shouldReturnAPatternWithFourYCharactersInIt() throws Exception {
Assert.assertEquals("MM/dd/yyyy", OpenmrsUtil.getDateFormat(Locale.US).toLocalizedPattern());
Assert.assertEquals("dd/MM/yyyy", OpenmrsUtil.getDateFormat(Locale.UK).toLocalizedPattern());
Assert.assertEquals("tt.MM.uuuu", OpenmrsUtil.getDateFormat(Locale.GERMAN).toLocalizedPattern());
Assert.assertEquals("dd-MM-yyyy", OpenmrsUtil.getDateFormat(new Locale("pt", "pt")).toLocalizedPattern());
}
/**
* @see {@link OpenmrsUtil#containsUpperAndLowerCase(String)}
*/
@Test
@Verifies(value = "should return true if string contains upper and lower case", method = "containsUpperAndLowerCase(String)")
public void containsUpperAndLowerCase_shouldReturnTrueIfStringContainsUpperAndLowerCase() throws Exception {
Assert.assertTrue(OpenmrsUtil.containsUpperAndLowerCase("Hello"));
Assert.assertTrue(OpenmrsUtil.containsUpperAndLowerCase("methodName"));
Assert.assertTrue(OpenmrsUtil.containsUpperAndLowerCase("the letter K"));
Assert.assertTrue(OpenmrsUtil.containsUpperAndLowerCase("The number 10"));
}
/**
* @see {@link OpenmrsUtil#containsUpperAndLowerCase(String)}
*/
@Test
@Verifies(value = "should return false if string does not contain lower case characters", method = "containsUpperAndLowerCase(String)")
public void containsUpperAndLowerCase_shouldReturnFalseIfStringDoesNotContainLowerCaseCharacters() throws Exception {
Assert.assertFalse(OpenmrsUtil.containsUpperAndLowerCase("HELLO"));
Assert.assertFalse(OpenmrsUtil.containsUpperAndLowerCase("THE NUMBER 10?"));
Assert.assertFalse(OpenmrsUtil.containsUpperAndLowerCase(""));
Assert.assertFalse(OpenmrsUtil.containsUpperAndLowerCase(null));
}
/**
* @see {@link OpenmrsUtil#containsUpperAndLowerCase(String)}
*/
@Test
@Verifies(value = "should return false if string does not contain upper case characters", method = "containsUpperAndLowerCase(String)")
public void containsUpperAndLowerCase_shouldReturnFalseIfStringDoesNotContainUpperCaseCharacters() throws Exception {
Assert.assertFalse(OpenmrsUtil.containsUpperAndLowerCase("hello"));
Assert.assertFalse(OpenmrsUtil.containsUpperAndLowerCase("the number 10?"));
Assert.assertFalse(OpenmrsUtil.containsUpperAndLowerCase(""));
Assert.assertFalse(OpenmrsUtil.containsUpperAndLowerCase(null));
}
/**
* @see {@link OpenmrsUtil#containsOnlyDigits(String)}
*/
@Test
@Verifies(value = "should return true if string contains only digits", method = "containsOnlyDigits(String)")
public void containsOnlyDigits_shouldReturnTrueIfStringContainsOnlyDigits() throws Exception {
Assert.assertTrue(OpenmrsUtil.containsOnlyDigits("1234567890"));
}
/**
* @see {@link OpenmrsUtil#containsOnlyDigits(String)}
*/
@Test
@Verifies(value = "should return false if string contains any non-digits", method = "containsOnlyDigits(String)")
public void containsOnlyDigits_shouldReturnFalseIfStringContainsAnyNonDigits() throws Exception {
Assert.assertFalse(OpenmrsUtil.containsOnlyDigits("1.23"));
Assert.assertFalse(OpenmrsUtil.containsOnlyDigits("123A"));
Assert.assertFalse(OpenmrsUtil.containsOnlyDigits("12 3"));
Assert.assertFalse(OpenmrsUtil.containsOnlyDigits(""));
Assert.assertFalse(OpenmrsUtil.containsOnlyDigits(null));
}
/**
* @see {@link OpenmrsUtil#containsDigit(String)}
*/
@Test
@Verifies(value = "should return true if string contains any digits", method = "containsDigit(String)")
public void containsDigit_shouldReturnTrueIfStringContainsAnyDigits() throws Exception {
Assert.assertTrue(OpenmrsUtil.containsDigit("There is 1 digit here."));
}
/**
* @see {@link OpenmrsUtil#containsDigit(String)}
*/
@Test
@Verifies(value = "should return false if string contains no digits", method = "containsDigit(String)")
public void containsDigit_shouldReturnFalseIfStringContainsNoDigits() throws Exception {
Assert.assertFalse(OpenmrsUtil.containsDigit("ABC .$!@#$%^&*()-+=/?><.,~`|[]"));
Assert.assertFalse(OpenmrsUtil.containsDigit(""));
Assert.assertFalse(OpenmrsUtil.containsDigit(null));
}
/**
* The validate password method should be in a separate jvm here so that the Context and
* services are not available to the validatePassword (similar to how its used in the
* initialization wizard), but that is not possible to set up on a test-by-test basis, so we
* settle by making the user context not available.
*
* @see {@link OpenmrsUtil#validatePassword(String,String,String)}
*/
@Test
@Verifies(value = "should still work without an open session", method = "validatePassword(String,String,String)")
public void validatePassword_shouldStillWorkWithoutAnOpenSession() throws Exception {
Context.closeSession();
OpenmrsUtil.validatePassword("admin", "1234Password", "systemId");
}
}