/*
* The Kuali Financial System, a comprehensive financial management system for higher education.
*
* Copyright 2005-2014 The Kuali Foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kuali.kfs.module.bc.report;
import static org.kuali.kfs.sys.fixture.UserNameFixture.khuntley;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import org.kuali.kfs.coa.service.OrganizationService;
import org.kuali.kfs.module.bc.BCConstants;
import org.kuali.kfs.module.bc.businessobject.BudgetConstructionOrganizationReports;
import org.kuali.kfs.module.bc.businessobject.BudgetConstructionPullup;
import org.kuali.kfs.module.bc.report.ReportControlListBuildHelper.BuildState;
import org.kuali.kfs.sys.ConfigureContext;
import org.kuali.kfs.sys.context.KualiTestBase;
import org.kuali.kfs.sys.context.SpringContext;
import org.kuali.rice.krad.service.BusinessObjectService;
@ConfigureContext(session = khuntley)
public class ReportControlListBuildHelperTest extends KualiTestBase {
// this arraylist differs includes all of arrayListForTest but has one additional set of organizations: it is a superset of
// arrayListForTest
private Collection<BudgetConstructionPullup> arrayListSuperSetOfForTest = new ArrayList(4);
// these two have the same Pullup objects with the same content, but in different collection formats
private Collection<BudgetConstructionPullup> arrayListForTest = new ArrayList(3);
private Collection<BudgetConstructionPullup> hashSetMatchingArrayList = new HashSet(3);
// same content as arrayListForTest, but with different PullupObjects
private Collection<BudgetConstructionPullup> arrayListForTestDifferentObjects = new ArrayList(3);
// these two have different Pullup objects, but with the same content, in the same collection format
private Collection<BudgetConstructionPullup> hashSetForTest = new HashSet(3);
private Collection<BudgetConstructionPullup> sameHashSetDataDifferentObjects = new HashSet(3);
//
private BuildState currentState = null;
private BuildState requestedState = null;
private String firstPointOfView = null;
private String secondPointOfView = null;
private String userIdString = new String("1234567890");
private boolean testDataValid;
private BusinessObjectService businessObjectService;
private OrganizationService organizationService;
private Integer pullupFlag = new Integer(0);
private Long versionNumber = new Long(0);
StringBuilder messageBuffer = new StringBuilder("Testing ReportControlListBuilder.isBuildNeeded: ");
/*
* verify the check to see whether the data in a requested report needs to be refreshed. if a new user requests the same report
* as a previous user, the structures will be reset and the isBuildNeeded routine will return true. So, we only need to check
* whether the same user has requested the same organizations for the same "mode" (the source table for the report data).
*/
@Override
public void setUp() throws Exception {
super.setUp();
businessObjectService = SpringContext.getBean(BusinessObjectService.class);
organizationService = SpringContext.getBean(OrganizationService.class);
// one of the points of view will be the top-level organization
String[] rootOrganization = organizationService.getRootOrganizationCode();
firstPointOfView = setUpAPointOfView(rootOrganization[0], rootOrganization[1]);
// set up the test cases
testDataValid = setUpTestOrganizations();
}
// did we have enough test data?
public void testAdequateData() {
assertTrue(ourAssertMessage("insufficient test data exists"), testDataValid);
}
// uninitialized call--no current state and no request state
public void testUniitializedCall() {
ReportControlListBuildHelper buildHelper = new ReportControlListBuildHelper();
assertFalse(ourAssertMessage("the control list builder is not initialized from the database"), buildHelper.isBuildNeeded());
}
// first call for a report--a null current state and a new requested state should signal a build is needed
public void testFirstCall() {
// on the first call, the currentState should have been initialized to null by the helper
ReportControlListBuildHelper buildHelper = new ReportControlListBuildHelper();
requestedState = buildHelper.new BuildState(firstPointOfView, arrayListForTest, BCConstants.Report.BuildMode.PBGL);
buildHelper.setRequestedState(requestedState);
// a build should be required
assertTrue(ourAssertMessage("first call with a null current state and a valid requested state"), buildHelper.isBuildNeeded());
}
// repeated call for a given report--the content of the pullup objects is the same, but a new set of pullup objects with that
// same content have been fetched from the database
public void testSameCallDifferentDBObjectsInHashSets() {
ReportControlListBuildHelper buildHelper = new ReportControlListBuildHelper();
requestedState = buildHelper.new BuildState(firstPointOfView, hashSetForTest, BCConstants.Report.BuildMode.PBGL);
buildHelper.setRequestedState(requestedState);
currentState = buildHelper.new BuildState(firstPointOfView, sameHashSetDataDifferentObjects, BCConstants.Report.BuildMode.PBGL);
buildHelper.setCurrentState(currentState);
// the comparison should look at the content of the objects and not the objects themselves, and no build should be required
assertFalse(ourAssertMessage("same content in two different sets of DB objects--two hashSets"), buildHelper.isBuildNeeded());
}
// now do the same thing with an array list
public void testSameCallDifferentDBObjectsInArrayLists() {
ReportControlListBuildHelper buildHelper = new ReportControlListBuildHelper();
requestedState = buildHelper.new BuildState(secondPointOfView, arrayListForTestDifferentObjects, BCConstants.Report.BuildMode.BCAF);
buildHelper.setRequestedState(requestedState);
currentState = buildHelper.new BuildState(secondPointOfView, arrayListForTest, BCConstants.Report.BuildMode.BCAF);
buildHelper.setCurrentState(currentState);
// the comparison should look at the content of the objects and not the objects themselves, and no build should be required
assertFalse(ourAssertMessage("same content in two different sets of DB objects--two arrayLists"), buildHelper.isBuildNeeded());
}
public void testDifferentPointOfView() {
ReportControlListBuildHelper buildHelper = new ReportControlListBuildHelper();
requestedState = buildHelper.new BuildState(secondPointOfView, hashSetForTest, BCConstants.Report.BuildMode.PBGL);
buildHelper.setRequestedState(requestedState);
currentState = buildHelper.new BuildState(firstPointOfView, sameHashSetDataDifferentObjects, BCConstants.Report.BuildMode.PBGL);
buildHelper.setCurrentState(currentState);
// a new build should be required, because the same person is asking for the same data but from a different place in the
// security hierarchy
assertTrue(ourAssertMessage("same content in two different sets of DB objects, but a different point of view"), buildHelper.isBuildNeeded());
}
public void testDifferentBuildMode() {
ReportControlListBuildHelper buildHelper = new ReportControlListBuildHelper();
requestedState = buildHelper.new BuildState(firstPointOfView, hashSetForTest, BCConstants.Report.BuildMode.MONTH);
buildHelper.setRequestedState(requestedState);
currentState = buildHelper.new BuildState(firstPointOfView, sameHashSetDataDifferentObjects, BCConstants.Report.BuildMode.PBGL);
buildHelper.setCurrentState(currentState);
// a new build is required because the target report differs, even though the user and the organizations involved are the
// same
assertTrue(ourAssertMessage("same content in two different sets of DB objects, but a different build mode"), buildHelper.isBuildNeeded());
}
// repeated call for a given report--the DB objects and their content are the same, but they are in different collection formats
public void testDifferentCollectionFormats() {
ReportControlListBuildHelper buildHelper = new ReportControlListBuildHelper();
requestedState = buildHelper.new BuildState(firstPointOfView, arrayListForTest, BCConstants.Report.BuildMode.BCAF);
buildHelper.setRequestedState(requestedState);
currentState = buildHelper.new BuildState(firstPointOfView, hashSetMatchingArrayList, BCConstants.Report.BuildMode.BCAF);
buildHelper.setCurrentState(currentState);
// the comparison should look at the content of the objects and not the objects themselves, and no build should be required
assertFalse(ourAssertMessage("same content in collections with different formats--hash Set vs. arrayList"), buildHelper.isBuildNeeded());
}
// different organizations (only of one three is the same) requested by the same person: both collections are hash sets
public void testDifferentReportsSameCollectionFormat() {
ReportControlListBuildHelper buildHelper = new ReportControlListBuildHelper();
requestedState = buildHelper.new BuildState(firstPointOfView, hashSetForTest, BCConstants.Report.BuildMode.BCAF);
buildHelper.setRequestedState(requestedState);
currentState = buildHelper.new BuildState(firstPointOfView, hashSetMatchingArrayList, BCConstants.Report.BuildMode.BCAF);
buildHelper.setCurrentState(currentState);
// the fact that the collection format is the same should not affect the fact that a new build is required
assertTrue(ourAssertMessage("same collection format but different data content"), buildHelper.isBuildNeeded());
}
// different organizations (only one of the three is the same) requested by the same person in different collection formats
public void testDifferentReportsDifferentCollectionFormats() {
ReportControlListBuildHelper buildHelper = new ReportControlListBuildHelper();
requestedState = buildHelper.new BuildState(firstPointOfView, hashSetForTest, BCConstants.Report.BuildMode.BCAF);
buildHelper.setRequestedState(requestedState);
currentState = buildHelper.new BuildState(firstPointOfView, arrayListForTest, BCConstants.Report.BuildMode.BCAF);
buildHelper.setCurrentState(currentState);
// only the requesting ID is the same
assertTrue(ourAssertMessage("different data content and different collection formats"), buildHelper.isBuildNeeded());
}
// current state is a superset of the requested state
public void testCurrentStateSuperSetOfRequestState() {
ReportControlListBuildHelper buildHelper = new ReportControlListBuildHelper();
requestedState = buildHelper.new BuildState(firstPointOfView, arrayListForTest, BCConstants.Report.BuildMode.BCAF);
buildHelper.setRequestedState(requestedState);
currentState = buildHelper.new BuildState(firstPointOfView, arrayListSuperSetOfForTest, BCConstants.Report.BuildMode.BCAF);
buildHelper.setCurrentState(currentState);
//
assertTrue(ourAssertMessage("current state is a superset of the requested state"), buildHelper.isBuildNeeded());
}
// requested state is a superset of the current state
public void testRequestStateSuperSetOfCurrentState() {
ReportControlListBuildHelper buildHelper = new ReportControlListBuildHelper();
requestedState = buildHelper.new BuildState(firstPointOfView, arrayListSuperSetOfForTest, BCConstants.Report.BuildMode.BCAF);
buildHelper.setRequestedState(requestedState);
currentState = buildHelper.new BuildState(firstPointOfView, arrayListForTest, BCConstants.Report.BuildMode.BCAF);
buildHelper.setCurrentState(currentState);
//
assertTrue(ourAssertMessage("requested state is a superset of the current state"), buildHelper.isBuildNeeded());
}
private String ourAssertMessage(String messageToDisplay) {
StringBuilder msg = new StringBuilder(messageBuffer);
msg.append(messageToDisplay);
return (msg.toString());
}
private BudgetConstructionPullup newBudgetConstructionPullup(BudgetConstructionOrganizationReports organizationReports) {
BudgetConstructionPullup newMember = new BudgetConstructionPullup();
newMember.setChartOfAccountsCode(organizationReports.getChartOfAccountsCode());
newMember.setOrganizationCode(organizationReports.getOrganizationCode());
newMember.setReportsToChartOfAccountsCode(organizationReports.getReportsToChartOfAccountsCode());
newMember.setReportsToOrganizationCode(organizationReports.getReportsToOrganizationCode());
newMember.setPullFlag(pullupFlag);
newMember.setPrincipalId(userIdString);
// to spoof the pullup object's coming from the DB, we add the OBJ_ID and VER_NBR from the Organization Reports, so they
// will not be null in the Pullup object.
// doing this ensures that two pullup objects built from the same source OrganizationReports will have exactly the same
// content, as if the same Pullup object had come from the DB at two different times.
newMember.setVersionNumber(versionNumber);
newMember.setObjectId(organizationReports.getObjectId());
return (newMember);
}
private void setUpAHashSet(BudgetConstructionOrganizationReports organizationReports) {
// both have hte same collection format, but contain different objects with the same content
hashSetForTest.add(newBudgetConstructionPullup(organizationReports));
sameHashSetDataDifferentObjects.add(newBudgetConstructionPullup(organizationReports));
}
private void setUpAnArrayList(BudgetConstructionOrganizationReports organizationReports) {
BudgetConstructionPullup pullUpElement = newBudgetConstructionPullup(organizationReports);
// both contain the same elements, but in different collection formats
arrayListForTest.add(pullUpElement);
hashSetMatchingArrayList.add(pullUpElement);
arrayListSuperSetOfForTest.add(pullUpElement);
// set up an array list with different objects with the same content
BudgetConstructionPullup pullUpElementWithNewID = newBudgetConstructionPullup(organizationReports);
this.arrayListForTestDifferentObjects.add(pullUpElementWithNewID);
}
private String setUpAPointOfView(String chartOfAccounts, String organizationCode) {
// the exact structure of this string does not affect what is being tested.
// the assumed requirement is that it uniquely define an organization.
return chartOfAccounts + "-" + organizationCode;
}
private void setUpExtraArrayListRow(BudgetConstructionOrganizationReports organizationReports) {
BudgetConstructionPullup pullUpElement = newBudgetConstructionPullup(organizationReports);
arrayListSuperSetOfForTest.add(pullUpElement);
}
// we assume that each row has a unique chart of accounts and organization code.
// the method being tested should not depend on the type of collection it is fed, so we build two different states from two
// different collection classes.
// if we cannot find enough data for a test, the test fails.
// there are three members in each state. both states have the same first member, but have no other common members.
private boolean setUpTestOrganizations() {
Collection<BudgetConstructionOrganizationReports> sourceData = businessObjectService.findAll(BudgetConstructionOrganizationReports.class);
if (sourceData.size() < 6) {
// not enough test data
return false;
}
int elementsSeen = 0;
Iterator<BudgetConstructionOrganizationReports> reportSet = sourceData.iterator();
if (reportSet.hasNext()) {
elementsSeen = elementsSeen + 1;
// the first element is in both sets
BudgetConstructionOrganizationReports organizationReports = reportSet.next();
secondPointOfView = setUpAPointOfView(organizationReports.getChartOfAccountsCode(), organizationReports.getOrganizationCode());
setUpAnArrayList(organizationReports);
setUpAHashSet(organizationReports);
}
while (reportSet.hasNext()) {
elementsSeen = elementsSeen + 1;
BudgetConstructionOrganizationReports organizationReports = reportSet.next();
if (elementsSeen > 6) {
continue;
}
if (elementsSeen < 4) {
setUpAnArrayList(organizationReports);
}
else {
if (elementsSeen < 6) {
setUpAHashSet(organizationReports);
}
else {
setUpExtraArrayListRow(organizationReports);
}
}
}
return (!(elementsSeen < 6));
}
}