001: /*
002: * Copyright 2006-2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.opensource.org/licenses/ecl1.php
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.kuali.module.gl;
017:
018: import java.io.PrintStream;
019: import java.math.BigDecimal;
020: import java.util.ArrayList;
021: import java.util.Arrays;
022: import java.util.Collection;
023: import java.util.Collections;
024: import java.util.Comparator;
025: import java.util.Date;
026: import java.util.Iterator;
027: import java.util.List;
028: import java.util.Map;
029:
030: import org.kuali.core.service.ConfigurableDateService;
031: import org.kuali.core.service.KualiConfigurationService;
032: import org.kuali.core.service.PersistenceService;
033: import org.kuali.core.util.UnitTestSqlDao;
034: import org.kuali.kfs.KFSConstants;
035: import org.kuali.kfs.context.KualiTestBase;
036: import org.kuali.kfs.context.SpringContext;
037: import org.kuali.kfs.context.TestUtils;
038: import org.kuali.core.dbplatform.RawSQL;
039: import org.kuali.module.chart.bo.OffsetDefinition;
040: import org.kuali.module.financial.bo.Bank;
041: import org.kuali.module.gl.bo.OriginEntryFull;
042: import org.kuali.module.gl.bo.OriginEntryGroup;
043: import org.kuali.module.gl.dao.OriginEntryDao;
044: import org.kuali.module.gl.service.OriginEntryGroupService;
045: import org.kuali.module.gl.service.OriginEntryService;
046:
047: /**
048: * OriginEntryTestBase...the uberpowerful base of a lot of GL tests. Basically, this class provides
049: * many convenience methods for writing tests that test against large batches of origin entries.
050: */
051: @RawSQL
052: public class OriginEntryTestBase extends KualiTestBase {
053: private static org.apache.log4j.Logger LOG = org.apache.log4j.Logger
054: .getLogger(OriginEntryTestBase.class);
055:
056: protected ConfigurableDateService dateTimeService;
057: protected PersistenceService persistenceService;
058: protected UnitTestSqlDao unitTestSqlDao = null;
059: protected OriginEntryGroupService originEntryGroupService = null;
060: protected OriginEntryService originEntryService = null;
061: protected OriginEntryDao originEntryDao = null;
062: protected KualiConfigurationService kualiConfigurationService = null;
063: protected Date date;
064:
065: /**
066: * Constructs a OriginEntryTestBase instance
067: */
068: public OriginEntryTestBase() {
069: super ();
070: }
071:
072: /**
073: * Sets up this test base; that means getting some services from Spring and reseting the
074: * enhancement flags.
075: * @see junit.framework.TestCase#setUp()
076: */
077: @Override
078: protected void setUp() throws Exception {
079: super .setUp();
080:
081: LOG.debug("setUp() starting");
082:
083: dateTimeService = SpringContext
084: .getBean(ConfigurableDateService.class);
085: date = dateTimeService.getCurrentDate();
086:
087: // Other objects needed for the tests
088: persistenceService = SpringContext
089: .getBean(PersistenceService.class);
090: unitTestSqlDao = SpringContext.getBean(UnitTestSqlDao.class);
091: originEntryService = SpringContext
092: .getBean(OriginEntryService.class);
093: originEntryDao = SpringContext.getBean(OriginEntryDao.class);
094: originEntryGroupService = SpringContext
095: .getBean(OriginEntryGroupService.class);
096: kualiConfigurationService = SpringContext
097: .getBean(KualiConfigurationService.class);
098:
099: // Set all enhancements to off
100: resetAllEnhancementFlags();
101: }
102:
103: /**
104: * An inner class to point to a specific entry in a group
105: */
106: protected class EntryHolder {
107: public String groupCode;
108: public String transactionLine;
109:
110: /**
111: * Constructs a OriginEntryTestBase.EntryHolder
112: * @param groupCode the group that the entry to point to is in
113: * @param transactionLine the line number of the entry
114: */
115: public EntryHolder(String groupCode, String transactionLine) {
116: this .groupCode = groupCode;
117: this .transactionLine = transactionLine;
118: }
119: }
120:
121: /**
122: * Given a group source code and a bunch of transactions, creates a new group and adds all
123: * the transactions to that group
124: *
125: * @param groupCode the source code of the new group
126: * @param transactions an array of String-formatted entries to save into the group
127: * @param date the creation date of the new group
128: */
129: protected void loadInputTransactions(String groupCode,
130: String[] transactions, Date date) {
131: OriginEntryGroup group = originEntryGroupService.createGroup(
132: new java.sql.Date(date.getTime()), groupCode, true,
133: true, true);
134: loadTransactions(transactions, group);
135: }
136:
137: /**
138: * Given a group source code and a bunch of transactions, creates a new group and adds all
139: * the transactions to that group; sets the group creation date to today
140: *
141: * @param groupCode the source code of the new group
142: * @param transactions an array of String-formatted entries to save into the group
143: */
144: protected void loadInputTransactions(String groupCode,
145: String[] transactions) {
146: OriginEntryGroup group = originEntryGroupService.createGroup(
147: new java.sql.Date(dateTimeService.getCurrentDate()
148: .getTime()), groupCode, true, true, true);
149: loadTransactions(transactions, group);
150: }
151:
152: /**
153: * Loads an array of String formatted entries into the given origin entry group
154: *
155: * @param transactions an array of String formatted entries
156: * @param group the group to save those entries into
157: */
158: protected void loadTransactions(String[] transactions,
159: OriginEntryGroup group) {
160: for (int i = 0; i < transactions.length; i++) {
161: OriginEntryFull e = new OriginEntryFull(transactions[i]);
162: originEntryService.createEntry(e, group);
163: }
164:
165: persistenceService.clearCache();
166: }
167:
168: /**
169: * Deletes everything in the expenditure transaction table
170: */
171: protected void clearExpenditureTable() {
172: unitTestSqlDao.sqlCommand("delete from gl_expend_trn_t");
173: }
174:
175: /**
176: * Deletes everything in the sufficient fund balance table
177: */
178: protected void clearSufficientFundBalanceTable() {
179: unitTestSqlDao.sqlCommand("delete from gl_sf_balances_t");
180: }
181:
182: /**
183: * Deletes all entries in the entry table with the given chart code and account number
184: *
185: * @param fin_coa_cd the chart code of entries to delete
186: * @param account_nbr the account number of entries to delete
187: */
188: protected void clearGlEntryTable(String fin_coa_cd,
189: String account_nbr) {
190: unitTestSqlDao
191: .sqlCommand("delete from gl_entry_t where fin_coa_cd = '"
192: + fin_coa_cd
193: + "' and account_nbr = '"
194: + account_nbr + "'");
195: }
196:
197: /**
198: * Deletes everything in the gl reversal table
199: */
200: protected void clearReversalTable() {
201: unitTestSqlDao.sqlCommand("delete from gl_reversal_t");
202: }
203:
204: /**
205: * Deletes everything in the gl balance table
206: */
207: protected void clearGlBalanceTable() {
208: unitTestSqlDao.sqlCommand("delete from gl_balance_t");
209: }
210:
211: /**
212: * Deletes everything in the gl encumbrance table.
213: */
214: protected void clearEncumbranceTable() {
215: unitTestSqlDao.sqlCommand("delete from gl_encumbrance_t");
216: }
217:
218: /**
219: * Deletes everything in the gl account balance table
220: */
221: protected void clearGlAccountBalanceTable() {
222: unitTestSqlDao.sqlCommand("delete from gl_acct_balances_t");
223: }
224:
225: /**
226: * Deletes everything in the gl origin entry table and the gl origin entry group table
227: */
228: protected void clearOriginEntryTables() {
229: unitTestSqlDao.sqlCommand("delete from gl_origin_entry_t");
230: unitTestSqlDao.sqlCommand("delete from gl_origin_entry_grp_t");
231: }
232:
233: /**
234: * Check all the entries in gl_origin_entry_t against the data passed in EntryHolder[]. If any of them are different, assert an
235: * error.
236: *
237: * @param groupCount the expected size of the group
238: * @param requiredEntries an array of expected String-formatted entries to check against
239: */
240: protected void assertOriginEntries(int groupCount,
241: EntryHolder[] requiredEntries) {
242: persistenceService.clearCache();
243:
244: final List groups = unitTestSqlDao
245: .sqlSelect("select * from gl_origin_entry_grp_t order by origin_entry_grp_src_cd");
246: assertEquals("Number of groups is wrong", groupCount, groups
247: .size());
248:
249: Collection<OriginEntryFull> c = originEntryDao
250: .testingGetAllEntries();
251:
252: // now, sort the lines here to avoid any DB sorting issues
253: Comparator<OriginEntryFull> originEntryComparator = new Comparator<OriginEntryFull>() {
254: public int compare(OriginEntryFull o1, OriginEntryFull o2) {
255: int groupCompareResult = o1.getEntryGroupId()
256: .compareTo(o2.getEntryGroupId());
257: if (groupCompareResult == 0) {
258: return o1.getLine().compareTo(o2.getLine());
259: } else {
260: return groupCompareResult;
261: }
262: }
263: };
264: Comparator<EntryHolder> entryHolderComparator = new Comparator<EntryHolder>() {
265: public int compare(EntryHolder o1, EntryHolder o2) {
266: int groupCompareResult = String.valueOf(
267: getGroup(groups, o1.groupCode)).compareTo(
268: String.valueOf(getGroup(groups, o2.groupCode)));
269: if (groupCompareResult == 0) {
270: return o1.transactionLine
271: .compareTo(o2.transactionLine);
272: } else {
273: return groupCompareResult;
274: }
275: }
276: };
277: ArrayList<OriginEntryFull> sortedEntryTransactions = new ArrayList<OriginEntryFull>(
278: c);
279: Collections
280: .sort(sortedEntryTransactions, originEntryComparator);
281: Arrays.sort(requiredEntries, entryHolderComparator);
282:
283: // This is for debugging purposes - change to true for output
284: if (true) {
285: System.err.println("Groups:");
286: for (Iterator iter = groups.iterator(); iter.hasNext();) {
287: Map element = (Map) iter.next();
288: System.err.println("G:"
289: + element.get("ORIGIN_ENTRY_GRP_ID") + " "
290: + element.get("ORIGIN_ENTRY_GRP_SRC_CD"));
291: }
292:
293: System.err.println("Transactions:");
294: for (OriginEntryFull element : sortedEntryTransactions) {
295: System.err.println("L:" + element.getEntryGroupId()
296: + " " + element.getLine());
297: }
298: System.err.println("Expected Transactions:");
299: for (EntryHolder element : requiredEntries) {
300: System.err.println("L:"
301: + getGroup(groups, element.groupCode) + " "
302: + element.transactionLine);
303: }
304: }
305:
306: assertEquals("Wrong number of transactions in Origin Entry",
307: requiredEntries.length, c.size());
308:
309: int count = 0;
310: for (Iterator iter = sortedEntryTransactions.iterator(); iter
311: .hasNext();) {
312: OriginEntryFull foundTransaction = (OriginEntryFull) iter
313: .next();
314:
315: // Check group
316: int group = getGroup(groups,
317: requiredEntries[count].groupCode);
318:
319: assertEquals("Group for transaction "
320: + foundTransaction.getEntryId() + " is wrong",
321: group, foundTransaction.getEntryGroupId()
322: .intValue());
323:
324: // Check transaction - this is done this way so that Anthill prints the two transactions to make
325: // resolving the issue easier.
326:
327: String expected = requiredEntries[count].transactionLine
328: .substring(0, 173);// trim();
329: String found = foundTransaction.getLine().substring(0, 173);// trim();
330:
331: if (!found.equals(expected)) {
332: System.err.println("Expected transaction: " + expected);
333: System.err.println("Found transaction: " + found);
334:
335: fail("Transaction " + foundTransaction.getEntryId()
336: + " doesn't match expected output");
337: }
338: count++;
339: }
340: }
341:
342: /**
343: * Given a list of origin entry groups and a group source code, returns the id of the group with that source code
344: *
345: * @param groups a List of groups to selectg a group from
346: * @param groupCode the source code of the group to select
347: * @return the id of the first group in the list with that source code, or -1 if no groups with that source code were found
348: */
349: protected int getGroup(List groups, String groupCode) {
350: for (Iterator iter = groups.iterator(); iter.hasNext();) {
351: Map element = (Map) iter.next();
352:
353: String sourceCode = (String) element
354: .get("ORIGIN_ENTRY_GRP_SRC_CD");
355: if (groupCode.equals(sourceCode)) {
356: BigDecimal groupId = (BigDecimal) element
357: .get("ORIGIN_ENTRY_GRP_ID");
358: return groupId.intValue();
359: }
360: }
361: return -1;
362: }
363:
364: protected static Object[] FLEXIBLE_OFFSET_ENABLED_FLAG = {
365: OffsetDefinition.class,
366: KFSConstants.SystemGroupParameterNames.FLEXIBLE_OFFSET_ENABLED_FLAG };
367: protected static Object[] FLEXIBLE_CLAIM_ON_CASH_BANK_ENABLED_FLAG = {
368: Bank.class,
369: KFSConstants.SystemGroupParameterNames.FLEXIBLE_CLAIM_ON_CASH_BANK_ENABLED_FLAG };
370:
371: /**
372: * Resets the flexible offset and flexible claim on cash parameters, so that processes running as unit tests have consistent behaviors
373: * @throws Exception if the parameters could not be reset for some reason
374: */
375: protected void resetAllEnhancementFlags() throws Exception {
376: setApplicationConfigurationFlag(
377: (Class) FLEXIBLE_OFFSET_ENABLED_FLAG[0],
378: (String) FLEXIBLE_OFFSET_ENABLED_FLAG[1], false);
379: setApplicationConfigurationFlag(
380: (Class) FLEXIBLE_CLAIM_ON_CASH_BANK_ENABLED_FLAG[0],
381: (String) FLEXIBLE_CLAIM_ON_CASH_BANK_ENABLED_FLAG[1],
382: false);
383: }
384:
385: /**
386: * Resets a parameter for the sake of the unit test
387: *
388: * @param componentClass the module class of the parameter
389: * @param name the name of the parameter to reset
390: * @param value the new value for the parameter
391: * @throws Exception thrown if some vague thing goes wrong
392: */
393: protected void setApplicationConfigurationFlag(
394: Class componentClass, String name, boolean value)
395: throws Exception {
396: TestUtils.setSystemParameter(componentClass, name, value ? "Y"
397: : "N");
398: }
399:
400: /**
401: * Outputs the entire contents of a List to System.out
402: *
403: * @param list a List, presumably of Origin entries, but really, it could be anything
404: * @param name the name of the list to display in the output
405: */
406: protected void traceList(List list, String name) {
407: trace(
408: "StartList " + name + "( " + list.size()
409: + " elements): ", 0);
410:
411: for (Iterator iterator = list.iterator(); iterator.hasNext();) {
412: trace(iterator.next(), 1);
413: }
414:
415: trace("EndList " + name + ": ", 0);
416: trace("", 0);
417: }
418:
419: /**
420: * Writes an object to standard out
421: *
422: * @param o the object to output, after..
423: * @param tabIndentCount the number of tabs to push the object output
424: */
425: protected void trace(Object o, int tabIndentCount) {
426: PrintStream out = System.out;
427:
428: for (int i = 0; i < tabIndentCount; i++) {
429: out.print("\t");
430: }
431:
432: out.println(null == o ? "NULL" : o.toString());
433: }
434:
435: }
|