/* * 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)); } }