/* * Copyright (c) 2005-2011 Grameen Foundation USA * All rights reserved. * * Licensed under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. * * See also http://www.apache.org/licenses/LICENSE-2.0.html for an * explanation of the license and how it is applied. */ package org.mifos.framework; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.StringReader; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.math.BigDecimal; import java.util.Date; import java.util.HashSet; import java.util.Locale; import java.util.Set; import junit.framework.Assert; import org.dom4j.DocumentException; import org.dom4j.io.SAXReader; import org.joda.time.DateMidnight; import org.joda.time.DateTime; import org.joda.time.DateTimeConstants; import org.joda.time.LocalDate; import org.mifos.accounts.business.AccountActionDateEntity; import org.mifos.application.master.business.MifosCurrency; import org.mifos.application.meeting.business.MeetingBO; import org.mifos.application.meeting.util.helpers.WeekDay; import org.mifos.config.Localization; import org.mifos.customers.business.CustomerBO; import org.mifos.customers.business.CustomerScheduleEntity; import org.mifos.customers.personnel.util.helpers.PersonnelConstants; import org.mifos.customers.personnel.util.helpers.PersonnelLevel; import org.mifos.framework.util.helpers.Money; import org.mifos.schedule.ScheduledEvent; import org.mifos.schedule.ScheduledEventFactory; import org.mifos.security.rolesandpermission.util.helpers.RolesAndPermissionConstants; import org.mifos.security.util.UserContext; import org.springframework.util.ReflectionUtils; public class TestUtils { /* * Supplied in a few tests, but not actually in master data. The test might * set up the role, or more likely the test doesn't need it to exist in the * database. */ public static final int DUMMY_ROLE = 2; public static final int TEST_ROLE = 3; private static final Short TEST_LOCALE = 1; private static final Short HEAD_OFFICE = 1; public static UserContext makeUser() { return makeUser(RolesAndPermissionConstants.ADMIN_ROLE); } /** * This is a closer simulation to real life than {@link #makeUser()} in * terms of the locales. It probably could replace it, although I haven't * tried to see whether that breaks anything. */ public static UserContext makeUserWithLocales() { UserContext user = makeUser(RolesAndPermissionConstants.ADMIN_ROLE, ukLocale()); user.setLocaleId(TEST_LOCALE); user.setMfiLocale(ukLocale()); user.setMfiLocaleId(TEST_LOCALE); return user; } /** * Also see TestObjectFactory#getUserContext() which should be * slower (it involves several database accesses). */ public static UserContext makeUser(int role) { return makeUser(role, sampleLocale()); } public static UserContext makeUser(int role, Locale locale) { UserContext user = new UserContext(); user.setPreferredLocale(Locale.UK); user.setLocaleId(Localization.ENGLISH_LOCALE_ID); user.setId(PersonnelConstants.SYSTEM_USER); user.setLocaleId(TEST_LOCALE); Set<Short> set = new HashSet<Short>(); set.add((short) role); user.setRoles(set); user.setLevel(PersonnelLevel.NON_LOAN_OFFICER); user.setName("mifos"); user.setPreferredLocale(locale); user.setBranchId(HEAD_OFFICE); user.setBranchGlobalNum("0001"); return user; } public static Locale sampleLocale() { // return new Locale("en", "US"); return new Locale("en", "GB"); } /** * Corresponds to the locale one gets from * TestObjectFactory#getUserContext() */ public static Locale ukLocale() { return new Locale("EN", "GB"); } public static final MifosCurrency RUPEE = new MifosCurrency((short) 2, "RUPEE", BigDecimal.valueOf(1.0), "INR"); public static final MifosCurrency EURO = new MifosCurrency((short) 3, "EURO", BigDecimal.valueOf(0.5), "EUR"); public static void assertWellFormedFragment(String xml) throws DocumentException { assertWellFormedDocument("<root>" + xml + "</root>"); } public static void assertWellFormedDocument(String xmlDocument) throws DocumentException { SAXReader reader = new SAXReader(); reader.read(new StringReader(xmlDocument)); } public static Money createMoney(String amount) { return new Money(RUPEE, amount); } public static Money createMoney(Double amount) { return new Money(RUPEE, BigDecimal.valueOf(amount)); } public static Money createMoney(int amount) { // TODO Auto-generated method stub return new Money(RUPEE, BigDecimal.valueOf(amount)); } public static Money createMoney() { return new Money(RUPEE); } /* end equals testing methods */ public static void assertCanSerialize(Object object) throws IOException { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(object); objectOutputStream.close(); Assert.assertTrue(byteArrayOutputStream.toByteArray().length > 0); } public static void showMemory() { System.out.println("free: " + Runtime.getRuntime().freeMemory() / 1000000.0 + " MB"); System.out.println("max: " + Runtime.getRuntime().maxMemory() / 1000000.0 + " MB"); System.out.println("total: " + Runtime.getRuntime().totalMemory() / 1000000.0 + " MB"); System.out.println(); } public static Date generateNearestMondayOnOrAfterToday() { // start from today's date and then add enough days to make it a Monday DateTime dateTime = new DateTime(); Date startDate = null; DateTime dateTimeMonday = null; int dayOfWeek = dateTime.getDayOfWeek(); if (dayOfWeek == DateTimeConstants.MONDAY) { startDate = dateTime.toDate(); dateTimeMonday = dateTime; } else { dateTimeMonday = dateTime.plusDays(7 - (dayOfWeek - DateTimeConstants.MONDAY)); startDate = dateTimeMonday.toDate(); } return startDate; } /** * x != notx <br/><br/> * x = y = z (but different objects) * * @param x * @param notx * @param y * @param z */ public static void assertEqualsAndHashContract(Object x, Object notx, Object y, Object z) { assertEqual_ToSelf(x); assertPassIncompatibleType_isFalse(x); assertNullReference_isFalse(x); assertEquals_isReflexive_isSymmetric(x, y); assertEquals_isTransitive(x, y, z); assertEquals_isConsistent(x, y, notx); assertHashcode_isConsistent(x); assertHashcode_twoEqualsObjects_produceSameNumber(x, y); assertHashcode_twoUnEqualObjects_produceDifferentNumber(x, notx); } /** * A class is equal to itself. */ private static void assertEqual_ToSelf(Object x) { Assert.assertTrue("Class equal to itself.", x.equals(x)); } /** * x.equals(WrongType) must return false; */ private static void assertPassIncompatibleType_isFalse(Object x) { Assert.assertFalse("Passing incompatible object to equals should return false", x.equals("string")); } /** * x.equals(null) must return false; */ private static void assertNullReference_isFalse(Object x) { Assert.assertFalse("Passing null to equals should return false", x.equals(null)); } /** * 1. x, x.equals(x) must return true. 2. x and y, x.equals(y) must return true if and only if y.equals(x) returns * true. */ private static void assertEquals_isReflexive_isSymmetric(Object x, Object y) { Assert.assertTrue("Reflexive test fail x,y", x.equals(y)); Assert.assertTrue("Symmetric test fail y", y.equals(x)); } /** * 1. x.equals(y) returns true 2. y.equals(z) returns true 3. x.equals(z) must return true */ private static void assertEquals_isTransitive(Object x, Object y, Object z) { Assert.assertTrue("Transitive test fails x,y", x.equals(y)); Assert.assertTrue("Transitive test fails y,z", y.equals(z)); Assert.assertTrue("Transitive test fails x,z", x.equals(z)); } /** * Repeated calls to equals consistently return true or false. */ private static void assertEquals_isConsistent(Object x, Object y, Object notx) { Assert.assertTrue("Consistent test fail x,y", x.equals(y)); Assert.assertTrue("Consistent test fail x,y", x.equals(y)); Assert.assertTrue("Consistent test fail x,y", x.equals(y)); Assert.assertFalse("Consistent test fail x,notx", notx.equals(x)); Assert.assertFalse("Consistent test fail x,notx", notx.equals(x)); Assert.assertFalse("Consistent test fail x,notx", notx.equals(x)); } /** * Repeated calls to hashcode should consistently return the same integer. */ private static void assertHashcode_isConsistent(Object x) { int initial_hashcode = x.hashCode(); Assert.assertEquals("Consistent hashcode test fails", initial_hashcode, x.hashCode()); Assert.assertEquals("Consistent hashcode test fails", initial_hashcode, x.hashCode()); } /** * Objects that are equal using the equals method should return the same integer. */ private static void assertHashcode_twoEqualsObjects_produceSameNumber(Object x, Object y) { int xhashcode = x.hashCode(); int yhashcode = y.hashCode(); Assert.assertEquals("Equal object, return equal hashcode test fails", xhashcode, yhashcode); } /** * A more optimal implementation of hashcode ensures that if the objects are unequal different integers are * produced. */ private static void assertHashcode_twoUnEqualObjects_produceDifferentNumber(Object x, Object notx) { int xhashcode = x.hashCode(); int yhashcode = notx.hashCode(); Assert.assertTrue("Equal object, return unequal hashcode test fails", !(xhashcode == yhashcode)); } public static DateTime nearestDateMatchingPeriodStartingOn(DateTime inclusiveOf, MeetingBO period) { ScheduledEvent scheduledEvent = ScheduledEventFactory.createScheduledEventFrom(period); return scheduledEvent.nearestMatchingDateBeginningAt(inclusiveOf); } public static void assertThatAllCustomerSchedulesOccuringBeforeOrOnCurrentInstallmentPeriodRemainUnchanged(CustomerBO customer, WeekDay expectedDayOfWeek) { Set<AccountActionDateEntity> customerSchedules = customer.getCustomerAccount().getAccountActionDates(); for (AccountActionDateEntity accountActionDateEntity : customerSchedules) { CustomerScheduleEntity customerSchedule = (CustomerScheduleEntity) accountActionDateEntity; LocalDate scheduledDate = new LocalDate(customerSchedule.getActionDate()); DateTime endOfCurrentInstallmentPeriod = TestUtils.nearestDateMatchingPeriodStartingOn(new DateMidnight().toDateTime(), customer.getCustomerMeetingValue()); LocalDate endOfCurrentInstallmentPeriodLocalDate = new LocalDate(endOfCurrentInstallmentPeriod); if (scheduledDate.isBefore(endOfCurrentInstallmentPeriodLocalDate)) { assertThat(scheduledDate.dayOfWeek().get(), is(WeekDay.getJodaDayOfWeekThatMatchesMifosWeekDay(expectedDayOfWeek.getValue()))); } } } public static void assertThatAllCustomerSchedulesOccuringAfterCurrentInstallmentPeriodFallOnDayOfWeek(CustomerBO customer, WeekDay expectedDayOfWeek) { Set<AccountActionDateEntity> customerSchedules = customer.getCustomerAccount().getAccountActionDates(); for (AccountActionDateEntity accountActionDateEntity : customerSchedules) { CustomerScheduleEntity customerSchedule = (CustomerScheduleEntity) accountActionDateEntity; LocalDate scheduledDate = new LocalDate(customerSchedule.getActionDate()); DateTime endOfCurrentInstallmentPeriod = TestUtils.nearestDateMatchingPeriodStartingOn(new DateMidnight().toDateTime(), customer.getCustomerMeetingValue()); if (scheduledDate.isAfter(new LocalDate(endOfCurrentInstallmentPeriod))) { assertThat(scheduledDate.dayOfWeek().get(), is(WeekDay.getJodaDayOfWeekThatMatchesMifosWeekDay(expectedDayOfWeek.getValue()))); } } } public static void dereferenceObjects(final Object testCase) { ReflectionUtils.doWithFields(testCase.getClass(), new ReflectionUtils.FieldCallback() { @SuppressWarnings("cast") @Override public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { field.setAccessible(true); try { if (Modifier.isStatic(field.getModifiers()) || field.getType().isPrimitive()) { return; } if (field.get(testCase) instanceof Object) { field.set(testCase, null); } } finally { field.setAccessible(false); } } }, new ReflectionUtils.FieldFilter() { @Override public boolean matches(Field field) { return field.getDeclaringClass().equals(testCase.getClass()); } }); } public static Date getDate(int date, int month, int year) { DateMidnight dateMidnight = new DateMidnight(year, month, date); return dateMidnight.toDate(); } public static DateTime getDateTime(int date, int month, int year) { DateMidnight dateMidnight = new DateMidnight(year, month, date); return dateMidnight.toDateTime(); } public static java.sql.Date getSqlDate(int date, int month, int year) { return new java.sql.Date(getDate(date, month, year).getTime()); } }