Package org.libreplan.business.test.planner.entities

Source Code of org.libreplan.business.test.planner.entities.SpecificResourceAllocationTest

/*
* This file is part of LibrePlan
*
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
*                         Desenvolvemento Tecnolóxico de Galicia
* Copyright (C) 2010-2011 Igalia, S.L.
*
* 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.libreplan.business.test.planner.entities;

import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.isA;
import static org.easymock.EasyMock.verify;
import static org.easymock.classextension.EasyMock.createNiceMock;
import static org.easymock.classextension.EasyMock.replay;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.libreplan.business.test.planner.entities.DayAssignmentMatchers.consecutiveDays;
import static org.libreplan.business.test.planner.entities.DayAssignmentMatchers.from;
import static org.libreplan.business.test.planner.entities.DayAssignmentMatchers.haveHours;
import static org.libreplan.business.test.planner.entities.DayAssignmentMatchers.haveResourceAllocation;
import static org.libreplan.business.workingday.EffortDuration.hours;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.easymock.IAnswer;
import org.easymock.classextension.EasyMock;
import org.joda.time.LocalDate;
import org.junit.Test;
import org.libreplan.business.calendars.entities.AvailabilityTimeLine;
import org.libreplan.business.calendars.entities.BaseCalendar;
import org.libreplan.business.calendars.entities.Capacity;
import org.libreplan.business.calendars.entities.ResourceCalendar;
import org.libreplan.business.planner.entities.DayAssignment;
import org.libreplan.business.planner.entities.ResourceAllocation.DetachDayAssignmentOnRemoval;
import org.libreplan.business.planner.entities.ResourceAllocation.IOnDayAssignmentRemoval;
import org.libreplan.business.planner.entities.SpecificDayAssignment;
import org.libreplan.business.planner.entities.SpecificResourceAllocation;
import org.libreplan.business.planner.entities.Task;
import org.libreplan.business.resources.entities.Worker;
import org.libreplan.business.workingday.EffortDuration;
import org.libreplan.business.workingday.IntraDayDate;
import org.libreplan.business.workingday.IntraDayDate.PartialDay;
import org.libreplan.business.workingday.ResourcesPerDay;

public class SpecificResourceAllocationTest {

    public static IntraDayDate date(int year, int monthOfYear, int dayOfMonth) {
        return IntraDayDate.startOfDay(new LocalDate(year, monthOfYear,
                dayOfMonth));
    }

    public static IntraDayDate plusDays(IntraDayDate date, int days) {
        return IntraDayDate.create(date.getDate().plusDays(days),
                date.getEffortDuration());
    }

    public static IntraDayDate minusDays(IntraDayDate date, int days) {
        return IntraDayDate.create(date.getDate().minusDays(days),
                date.getEffortDuration());
    }

    public static IntraDayDate plusDaysAndEffort(IntraDayDate date, int days,
            EffortDuration effort) {
        return IntraDayDate.create(date.getDate().plusDays(days), date
                .getEffortDuration().plus(effort));
    }

    private BaseCalendar baseCalendar;

    private Task task;

    private SpecificResourceAllocation specificResourceAllocation;

    private Worker worker;

    private ResourceCalendar calendar;

    private void givenResourceCalendarAlwaysReturning(final int hours) {
        this.calendar = createResourceCalendarAlwaysReturning(hours);
    }

    public static ResourceCalendar createResourceCalendarAlwaysReturning(final int hours) {
        ResourceCalendar workerCalendar;
        workerCalendar = createNiceMock(ResourceCalendar.class);
        expect(workerCalendar.getCapacityOn(isA(PartialDay.class)))
        .andReturn(EffortDuration.hours(hours)).anyTimes();
        IAnswer<? extends EffortDuration> asDurationAnswer = asDurationOnAnswer(hours(hours));
        expect(
                workerCalendar.asDurationOn(isA(PartialDay.class),
                        isA(ResourcesPerDay.class)))
                        .andAnswer(asDurationAnswer).anyTimes();
        expect(workerCalendar.getCapacityWithOvertime(isA(LocalDate.class)))
        .andReturn(
                Capacity.create(hours(hours))
                .overAssignableWithoutLimit()).anyTimes();
        expect(workerCalendar.getAvailability()).andReturn(
                AvailabilityTimeLine.allValid()).anyTimes();
        replay(workerCalendar);
        return workerCalendar;
    }

    private static IAnswer<? extends EffortDuration> asDurationOnAnswer(
            final EffortDuration duration) {
        return new IAnswer<EffortDuration>() {

            @Override
            public EffortDuration answer() throws Throwable {
                ResourcesPerDay perDay = (ResourcesPerDay) EasyMock
                        .getCurrentArguments()[1];
                return perDay.asDurationGivenWorkingDayOf(duration);
            }
        };
    }

    private void givenResourceCalendar(final Capacity defaultAnswer,
            final Map<LocalDate, Capacity> answersForDates) {
        this.calendar = createNiceMock(ResourceCalendar.class);
        expect(this.calendar.getCapacityOn(isA(PartialDay.class)))
                .andAnswer(new IAnswer<EffortDuration>() {

                    @Override
                    public EffortDuration answer() throws Throwable {
                        PartialDay day = (PartialDay) EasyMock
                                .getCurrentArguments()[0];
                        LocalDate date = day.getDate();
                        if (answersForDates.containsKey(date)) {
                            return day.limitWorkingDay(answersForDates
                                    .get(date).getStandardEffort());
                        }
                        return day.limitWorkingDay(defaultAnswer
                                .getStandardEffort());
                    }
                }).anyTimes();

        expect(this.calendar.getCapacityWithOvertime(isA(LocalDate.class)))
                .andAnswer(new IAnswer<Capacity>() {

                    @Override
                    public Capacity answer() throws Throwable {
                        LocalDate date = (LocalDate) EasyMock
                                .getCurrentArguments()[0];
                        if (answersForDates.containsKey(date)) {
                            return answersForDates.get(date);
                        }
                        return defaultAnswer;
                    }
                }).anyTimes();
        final IAnswer<EffortDuration> effortAnswer = new IAnswer<EffortDuration>() {

            @Override
            public EffortDuration answer() throws Throwable {
                PartialDay day = (PartialDay) EasyMock
                        .getCurrentArguments()[0];
                ResourcesPerDay resourcesPerDay = (ResourcesPerDay) EasyMock
                        .getCurrentArguments()[1];

                LocalDate date = day.getDate();
                Capacity capacity = answersForDates.containsKey(date) ? answersForDates
                        .get(date) : defaultAnswer;

                EffortDuration oneResourcePerDayWorkingDuration = day
                        .limitWorkingDay(capacity.getStandardEffort());
                EffortDuration amountRequestedDuration = resourcesPerDay
                        .asDurationGivenWorkingDayOf(oneResourcePerDayWorkingDuration);
                return capacity.limitDuration(amountRequestedDuration);
            }
        };
        expect(
                this.calendar.asDurationOn(isA(PartialDay.class),
                        isA(ResourcesPerDay.class))).andAnswer(effortAnswer)
                .anyTimes();
        expect(this.calendar.getAvailability()).andReturn(
                AvailabilityTimeLine.allValid()).anyTimes();
        replay(this.calendar);
    }

    private void givenWorker() {
        this.worker = createNiceMock(Worker.class);
        expect(this.worker.getCalendar()).andReturn(calendar).anyTimes();
        replay(this.worker);
    }

    private void givenTask(IntraDayDate start, IntraDayDate end) {
        task = createNiceMock(Task.class);
        expect(task.getCalendar()).andReturn(baseCalendar).anyTimes();
        expect(task.getStartDate()).andReturn(
                start.toDateTimeAtStartOfDay().toDate()).anyTimes();
        expect(task.getIntraDayStartDate()).andReturn(start).anyTimes();
        expect(task.getEndDate()).andReturn(
                end.toDateTimeAtStartOfDay().toDate()).anyTimes();
        expect(task.getIntraDayEndDate()).andReturn(end).anyTimes();
        expect(task.getFirstDayNotConsolidated()).andReturn(start).anyTimes();
        replay(task);
    }

    private void givenSpecificResourceAllocation(IntraDayDate start,
            IntraDayDate end) {
        givenWorker();
        givenTask(start, end);
        specificResourceAllocation = SpecificResourceAllocation.create(task);
        specificResourceAllocation.setResource(worker);
    }

    private void givenSpecificResourceAllocation(IntraDayDate start, int days) {
        givenSpecificResourceAllocation(start, plusDays(start, days));
    }

    @Test
    public void theAllocationsDoneAreOrderedByDay() {
        givenSpecificResourceAllocation(date(2000, 2, 4), 2);
        specificResourceAllocation.allocate(ResourcesPerDay.amount(1));
        assertThat(specificResourceAllocation.getAssignments(),
                consecutiveDays(2));
    }

    @Test
    public void theAllocationsDoneHaveAsParentTheAllocation() {
        givenSpecificResourceAllocation(date(2000, 2, 4), 2);
        specificResourceAllocation.allocate(ResourcesPerDay.amount(1));
        assertThat(specificResourceAllocation.getAssignments(),
                haveResourceAllocation(specificResourceAllocation));
    }

    @Test
    public void theAllocationStartsAtTheStartDate() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 2);
        specificResourceAllocation.allocate(ResourcesPerDay.amount(1));
        assertThat(specificResourceAllocation.getAssignments(), from(start));
    }

    @Test
    public void theAllocationIsDoneEvenIfThereisOvertimeIfCapacitiesAreOverAssignable() {
        givenResourceCalendar(Capacity.create(hours(4))
                .overAssignableWithoutLimit(),
                Collections.<LocalDate, Capacity> emptyMap());
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 2);
        specificResourceAllocation.allocate(ResourcesPerDay.amount(2));
        assertThat(specificResourceAllocation.getAssignments(), haveHours(8, 8));
    }

    @Test
    public void ifNotOverassignableItOnlyDoesExtraEffortSpecified() {
        givenResourceCalendar(
                Capacity.create(hours(4)).withAllowedExtraEffort(hours(2)),
                Collections.<LocalDate, Capacity> emptyMap());
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 2);
        specificResourceAllocation.allocate(ResourcesPerDay.amount(2));
        assertThat(specificResourceAllocation.getAssignments(), haveHours(6, 6));
    }

    @Test
    public void canAllocateUntilSomeEndDate() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.resourcesPerDayUntil(plusDays(start, 3))
                .allocate(ResourcesPerDay.amount(1));
        assertThat(specificResourceAllocation.getAssignments(), haveHours(8, 8,
                8));
    }

    @Test
    public void initiallyTheIntendedResourcesPerDayAreNull() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        assertThat(specificResourceAllocation.getIntendedResourcesPerDay(),
                nullValue());
    }

    @Test
    public void afterAllocatingSomeResourcesPerDayTheIntendedResourcesPerDayAreNotNull() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        ResourcesPerDay specified = ResourcesPerDay.amount(1);
        specificResourceAllocation.resourcesPerDayUntil(plusDays(start, 3))
                .allocate(specified);
        assertThat(specificResourceAllocation.getIntendedResourcesPerDay(),
                equalTo(specified));
    }

    @Test
    public void theIntendedAndTheRealResourcesPerDayCanBeDifferent() {
        givenResourceCalendar(
                Capacity.create(hours(8)).withAllowedExtraEffort(hours(2)),
                Collections.<LocalDate, Capacity> emptyMap());

        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);

        specificResourceAllocation.resourcesPerDayUntil(plusDays(start, 3))
                .allocate(ResourcesPerDay.amount(2));

        BigDecimal intentededAmount = specificResourceAllocation
                .getIntendedResourcesPerDay().getAmount();
        BigDecimal realAmount = specificResourceAllocation.getResourcesPerDay()
                .getAmount();
        assertTrue(intentededAmount.compareTo(realAmount) > 0);
    }

    @Test
    public void canAllocateFromEndUntilSomeStartDate() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.resourcesPerDayFromEndUntil(start).allocate(
                ResourcesPerDay.amount(1));
        assertThat(specificResourceAllocation.getAssignments(),
                haveHours(8, 8, 8, 8));
    }

    @Test
    public void canAllocateFromEndInTheMiddleOfTheDayToStartDate() {
        IntraDayDate start = date(2000, 2, 4);
        IntraDayDate end = plusDaysAndEffort(start, 3, hours(3));
        givenSpecificResourceAllocation(start, end);
        specificResourceAllocation.resourcesPerDayFromEndUntil(start).allocate(
                ResourcesPerDay.amount(1));
        assertThat(specificResourceAllocation.getAssignments(),
                haveHours(8, 8, 8, 3));
        assertThat(specificResourceAllocation.getResourcesPerDay(),
                equalTo(ResourcesPerDay.amount(1)));
    }

    @Test
    public void theResourcesPerDayAreConvertedTakingIntoAccountTheWorkerCalendar() {
        givenResourceCalendarAlwaysReturning(4);
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 2);
        specificResourceAllocation.allocate(ResourcesPerDay.amount(1));
        assertThat(specificResourceAllocation.getAssignments(), haveHours(4, 4));
    }

    @Test(expected = IllegalArgumentException.class)
    public void cantAllocateOnAnWrongInterval() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        IntraDayDate dayBefore = minusDays(start, 1);
        specificResourceAllocation.onIntervalWithinTask(start, dayBefore).allocateHours(
                10);
    }

    @Test
    public void canAllocateZeroHours() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.onIntervalWithinTask(start,
                plusDays(start, 2))
                .allocateHours(0);
    }

    @Test(expected = IllegalArgumentException.class)
    public void cantAllocateNegativeHours() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.onIntervalWithinTask(start,
                plusDays(start, 1))
                .allocateHours(-1);
    }

    @Test
    public void someHoursInAnIntervalCanBeAssigned() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.onIntervalWithinTask(start,
                plusDays(start, 2))
                .allocateHours(10);
        assertThat(specificResourceAllocation.getAssignments(), haveHours(5, 5));
    }

    @Test
    public void theHoursForEachDayCanBeAssigned() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.onIntervalWithinTask(start,
                plusDays(start, 4)).allocate(
                Arrays.asList(hours(4), hours(8), hours(4), hours(8)));
        assertThat(specificResourceAllocation.getAssignments(),
                haveHours(4, 8, 4, 8));
    }

    @Test
    public void ifLessDaysAreSpecifiedTheInitialDaysAreAllocated() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.onIntervalWithinTask(start,
                plusDays(start, 4)).allocate(
                Arrays.asList(hours(4), hours(8), hours(4)));
        assertThat(specificResourceAllocation.getAssignments(),
                haveHours(4, 8, 4));
    }

    @Test
    public void ifMoreDaysAreSpecifiedTheInitialDaysAreAllocated() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.onIntervalWithinTask(start,
                plusDays(start, 4))
                .allocate(
                        Arrays.asList(hours(4), hours(8), hours(4), hours(4),
                                hours(3)));
        assertThat(specificResourceAllocation.getAssignments(),
                haveHours(4, 8, 4, 4));
    }

    @Test
    public void theDaysSpecifiedOutsideBoundsAreDiscarded() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.onIntervalWithinTask(minusDays(start, 2),
                plusDays(start, 1)).allocate(
                Arrays.asList(hours(2), hours(3), hours(4)));
        assertThat(specificResourceAllocation.getAssignments(), haveHours(4));
    }

    @Test
    public void combineOutsideBoundsAndZeroPadding() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.onIntervalWithinTask(minusDays(start, 2),
                plusDays(start, 1)).allocate(Arrays.asList(hours(2), hours(3)));
        assertThat(specificResourceAllocation.getAssignments(), haveHours());
    }

    @Test
    public void theDaysSpecifiedOutsideTheTaskAreDiscarded() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.onIntervalWithinTask(minusDays(start, 1),
                plusDays(start, 4)).allocate(
                Arrays.asList(hours(10), hours(4), hours(8), hours(4),
                        hours(4), hours(3)));
        List<SpecificDayAssignment> assigments = specificResourceAllocation
                .getAssignments();
        assertThat(assigments, haveHours(4, 8, 4, 4));
    }

    @Test
    public void theIntervalWithinTaskCanBeMadeOfIntraDayDates() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        IntraDayDate startInterval = start;
        IntraDayDate endInterval = plusDaysAndEffort(start, 2,
                EffortDuration.hours(4));
        specificResourceAllocation.onIntervalWithinTask(startInterval,
                endInterval).allocateHours(12);
        List<SpecificDayAssignment> assignments = specificResourceAllocation
                .getAssignments();
        assertThat(DayAssignment.sum(assignments), equalTo(hours(12)));
        assertTrue(assignments.get(0).getDuration()
                .compareTo(assignments.get(2).getDuration()) > 0);
        assertTrue(assignments.get(1).getDuration()
                .compareTo(assignments.get(2).getDuration()) > 0);
    }

    @Test
    public void thePartOfTheIntervalUsedIsTheOneOverlapping() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.onIntervalWithinTask(plusDays(start, 1),
                plusDays(start, 6)).allocateHours(12);
        assertThat(specificResourceAllocation.getAssignments(),
                haveHours(4, 4, 4));
    }

    @Test
    public void ifTheProvidedIntervalIsAfterTheTaskDoesntAllocateAnything() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.onIntervalWithinTask(plusDays(start, 5),
                plusDays(start, 6)).allocateHours(12);
        assertTrue(specificResourceAllocation.getAssignments().isEmpty());
    }

    @Test
    public void ifTheProvidedIntervalIsBeforeTheTaskDoesntAllocateAnything() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.onIntervalWithinTask(minusDays(start, 5),
                minusDays(start, 2)).allocateHours(12);
        assertTrue(specificResourceAllocation.getAssignments().isEmpty());
    }

    @Test
    public void thePartOfTheIntervalUsedIsTheOneOverlappingWithTheTask() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);

        specificResourceAllocation.fromStartUntil(plusDays(start, 2))
                .allocateHours(16);
        specificResourceAllocation.onIntervalWithinTask(start,
                plusDays(start, 6))
                .allocateHours(12);

        assertThat(specificResourceAllocation.getAssignments(),
                haveHours(3, 3, 3, 3));
    }

    @Test
    public void theEndIsNotChangedIfAZeroAllocationIsDoneInTheLastDay() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        IntraDayDate end = plusDays(start, 4);

        specificResourceAllocation.fromStartUntil(end).allocateHours(32);
        specificResourceAllocation
                .onIntervalWithinTask(plusDays(start, 3), end)
                .allocateHours(0);

        assertThat(specificResourceAllocation.getIntraDayEndDate(),
                equalTo(end));
    }

    @Test
    public void theEndCanGrowUntilReachingTheEndOfTheTask() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        IntraDayDate end = plusDays(start, 4);

        specificResourceAllocation.fromStartUntil(minusDays(end, 1))
                .allocateHours(24);
        assertThat(specificResourceAllocation.getIntraDayEndDate(),
                equalTo(minusDays(end, 1)));

        specificResourceAllocation.onIntervalWithinTask(start, end).allocateHours(32);
        assertThat(specificResourceAllocation.getAssignments(),
                haveHours(8, 8, 8, 8));
        assertThat(specificResourceAllocation.getIntraDayEndDate(),
                equalTo(end));
    }

    @Test
    public void theStartIsNotChangedIfAZeroAllocationIsDoneInTheFirstDay() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.fromStartUntil(plusDays(start, 4))
                .allocateHours(32);
        specificResourceAllocation.onIntervalWithinTask(start,
                plusDays(start, 1))
                .allocateHours(0);
        assertThat(specificResourceAllocation.getIntraDayStartDate(),
                equalTo(start));
    }

    @Test
    public void thereIsAWayForAllocatingOutsideTheBoundsOfTheTask() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.fromStartUntil(plusDays(start, 4))
                .allocateHours(32);

        specificResourceAllocation.onInterval(plusDays(start, 5),
                plusDays(start, 6)).allocateHours(8);

        assertThat(specificResourceAllocation.getIntraDayEndDate(),
                equalTo(plusDays(start, 6)));
        assertThat(specificResourceAllocation.getAssignments(),
                haveHours(8, 8, 8, 8, 8));
    }

    @Test
    public void canAllocateOutsideTheBoundsUsingAnIntervalMadeOfIntraDayDates() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.onInterval(start,
                IntraDayDate.create(start.getDate().plusDays(4), hours(4)))
                .allocateHours(36);
        assertThat(specificResourceAllocation.getAssignments(),
                haveHours(8, 8, 8, 8, 4));
    }

    @Test
    public void canAllocateOutsideTheBoundsSpecifyingTheHoursForEachDay() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.onInterval(minusDays(start, 1),
                plusDaysAndEffort(start, 4, hours(4)))
                .allocate(
                        Arrays.asList(hours(8), hours(2), hours(8), hours(8),
                                hours(8),
                        hours(4)));
        assertThat(specificResourceAllocation.getAssignments(),
                haveHours(8, 2, 8, 8, 8, 4));
    }

    @Test
    public void allocatingZeroHoursAtTheEndShrinksTheAllocation() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.fromStartUntil(plusDays(start, 4))
                .allocateHours(32);

        specificResourceAllocation.onInterval(plusDays(start, 3),
                plusDays(start, 4)).allocateHours(0);

        assertThat(specificResourceAllocation.getIntraDayEndDate(),
                equalTo(plusDays(start, 3)));
        assertThat(specificResourceAllocation.getAssignments(),
                haveHours(8, 8, 8));
    }

    @Test
    public void allocatingZeroHoursAtTheStartShrinksTheAllocation() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.fromStartUntil(plusDays(start, 4))
                .allocateHours(32);

        specificResourceAllocation.onInterval(start, plusDays(start, 1))
                .allocateHours(0);

        assertThat(specificResourceAllocation.getIntraDayStartDate(),
                equalTo(plusDays(start, 1)));
        assertThat(specificResourceAllocation.getAssignments(),
                haveHours(8, 8, 8));
    }

    @Test
    public void canAssignFromStartUntilEnd() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.fromStartUntil(plusDays(start, 4))
                .allocateHours(32);
        assertThat(specificResourceAllocation.getAssignments(),
                haveHours(8, 8, 8, 8));
        assertThat(specificResourceAllocation.getResourcesPerDay(),
                equalTo(ResourcesPerDay.amount(1)));
    }

    @Test
    public void canAssignFromEndUntilStart() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.fromEndUntil(start).allocateHours(32);
        assertThat(specificResourceAllocation.getAssignments(),
                haveHours(8, 8, 8, 8));
        assertThat(specificResourceAllocation.getResourcesPerDay(),
                equalTo(ResourcesPerDay.amount(1)));
    }

    @Test
    public void ifEndIsInTheMiddleOfADayFromEndUntilStartCalculatesResourcesPerDayCorrectly() {
        IntraDayDate start = date(2000, 2, 4);
        IntraDayDate end = plusDaysAndEffort(start, 3, hours(4));
        givenSpecificResourceAllocation(start, end);
        specificResourceAllocation.fromEndUntil(start).allocateHours(28);
        assertThat(specificResourceAllocation.getAssignments(),
                haveHours(8, 8, 8, 4));
        assertThat(specificResourceAllocation.getResourcesPerDay(),
                equalTo(ResourcesPerDay.amount(1)));
    }

    @Test
    public void canBeNotifiedWhenADayAssignmentIsRemoved() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.onIntervalWithinTask(start,
                plusDays(start, 2))
                .allocateHours(10);
        List<SpecificDayAssignment> currentAssignments = specificResourceAllocation
                .getAssignments();
        IOnDayAssignmentRemoval dayAssignmentRemovalMock = createMock(IOnDayAssignmentRemoval.class);
        for (SpecificDayAssignment each : currentAssignments) {
            dayAssignmentRemovalMock
                    .onRemoval(specificResourceAllocation, each);
            expectLastCall().once();
        }
        specificResourceAllocation
                .setOnDayAssignmentRemoval(dayAssignmentRemovalMock);
        replay(dayAssignmentRemovalMock);
        specificResourceAllocation.onIntervalWithinTask(start,
                plusDays(start, 2))
                .allocateHours(10);
        verify(dayAssignmentRemovalMock);
    }

    @Test
    public void canAutomaticallyDetachDayAssignmentsWhenRemoved() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.onIntervalWithinTask(start,
                plusDays(start, 2))
                .allocateHours(10);
        List<SpecificDayAssignment> assignments = specificResourceAllocation
                .getAssignments();
        for (SpecificDayAssignment each : assignments) {
            assertThat(each.getSpecificResourceAllocation(), notNullValue());
        }

        specificResourceAllocation
                .setOnDayAssignmentRemoval(new DetachDayAssignmentOnRemoval());
        specificResourceAllocation.onIntervalWithinTask(start,
                plusDays(start, 2))
                .allocateHours(10);

        for (SpecificDayAssignment each : assignments) {
            assertThat(each.getSpecificResourceAllocation(), nullValue());
        }
    }

    @Test
    public void thePreviousAssignmentsAreReplacedWhenAllocationHoursOnInterval() {
        givenResourceCalendarAlwaysReturning(3);
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.allocate(ResourcesPerDay.amount(1));
        specificResourceAllocation.onIntervalWithinTask(start,
                plusDays(start, 2))
                .allocateHours(10);
        assertThat(specificResourceAllocation.getAssignments(), haveHours(5, 5,
                3, 3));
    }

    @Test
    public void allocatingZeroHoursOnIntervalRemovesThem() {
        givenResourceCalendarAlwaysReturning(3);
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.allocate(ResourcesPerDay.amount(1));
        specificResourceAllocation.onIntervalWithinTask(start,
                plusDays(start, 2))
                .allocateHours(0);
        assertThat(specificResourceAllocation.getAssignments(),
                from(plusDays(start, 2)));
    }

    @Test
    public void theResourcesPerDayAreRecalculatedWhenAllocationHoursOnInterval() {
        givenResourceCalendarAlwaysReturning(3);
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 4);
        ResourcesPerDay original = ResourcesPerDay.amount(1);
        specificResourceAllocation.allocate(original);
        specificResourceAllocation.onIntervalWithinTask(start,
                plusDays(start, 2))
                .allocateHours(10);
        ResourcesPerDay newResourcesPerDay = specificResourceAllocation
                .getResourcesPerDay();
        assertTrue("Expecting that the resources per day is increased",
                newResourcesPerDay
                .getAmount().compareTo(original.getAmount()) > 0);
    }

    @Test
    @SuppressWarnings("serial")
    public void theResourcesPerDayAreTheOnesSpecifiedEvenIfInTheLastDayNoAllocationCanBeDone() {
        final IntraDayDate start = date(2000, 2, 4);
        givenResourceCalendar(Capacity.create(hours(8))
                .overAssignableWithoutLimit(),
                new HashMap<LocalDate, Capacity>() {
            {
                        put(plusDays(start, 3).getDate(),
                                Capacity.create(hours(8))
                                .notOverAssignableWithoutLimit());
            }
        });
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.resourcesPerDayUntil(plusDays(start, 4))
                .allocate(ResourcesPerDay.amount(1));
        assertThat(specificResourceAllocation.getResourcesPerDay(),
                equalTo(ResourcesPerDay.amount(1)));
    }

    @Test
    public void theResourcesPerDayAreTheOnesSpecifiedEvenIfTheStartIsInTheMiddleOfTheDay() {
        final IntraDayDate start = IntraDayDate.create(
                new LocalDate(2000, 2, 4), hours(4));
        givenResourceCalendarAlwaysReturning(8);
        IntraDayDate end = IntraDayDate.startOfDay(start.getDate().plusDays(4));
        givenSpecificResourceAllocation(start, end);
        specificResourceAllocation.resourcesPerDayUntil(end)
                .allocate(ResourcesPerDay.amount(1));
        assertThat(specificResourceAllocation.getResourcesPerDay(),
                equalTo(ResourcesPerDay.amount(1)));
    }

    @Test
    public void theHoursAreDistributedTakingIntoAccountTheWorkableHours() {
        final IntraDayDate start = date(2000, 2, 4);
        givenResourceCalendar(Capacity.create(hours(8))
                .overAssignableWithoutLimit(),
                new HashMap<LocalDate, Capacity>() {
            {
                        put(start.getDate(), Capacity.create(hours(2))
                                .notOverAssignableWithoutLimit());
            }
        });
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.onIntervalWithinTask(start,
                plusDays(start, 2))
                .allocateHours(10);
        assertThat(specificResourceAllocation.getAssignments(), haveHours(2, 8));
    }

    @SuppressWarnings("serial")
    @Test
    public void youCanAllocateHoursPreservingTheCurrentShape() {
        final IntraDayDate start = date(2000, 2, 4);
        givenResourceCalendar(Capacity.create(hours(8))
                .overAssignableWithoutLimit(),
                new HashMap<LocalDate, Capacity>() {
            {
                        put(start.getDate(), Capacity.create(hours(2))
                                .notOverAssignableWithoutLimit());
                        put(plusDays(start, 1).getDate(),
                                Capacity.create(hours(4))
                                .notOverAssignableWithoutLimit());
                        put(plusDays(start, 3).getDate(),
                                Capacity.create(hours(6))
                                .notOverAssignableWithoutLimit());
            }
        });
        givenSpecificResourceAllocation(start, 4);
        specificResourceAllocation.onIntervalWithinTask(start,
                plusDays(start, 4))
                .allocateHours(20);
        assertThat(specificResourceAllocation.getAssignments(), haveHours(2, 4,
                8, 6));

        specificResourceAllocation.allocateWholeAllocationKeepingProportions(
                EffortDuration.hours(18), plusDays(start, 2));

        assertThat(specificResourceAllocation.getAssignments(),
                haveHours(6, 12));
    }

    @Test
    public void theEndDateOfTheAllocationIsExclusive() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 2);
        specificResourceAllocation.allocate(ResourcesPerDay.amount(1));
        assertThat(specificResourceAllocation.getIntraDayEndDate(),
                equalTo(date(2000, 2, 6)));
    }

    @Test
    public void theAllocationIsFinishedByEndDate() {
        IntraDayDate start = date(2000, 2, 4);
        givenSpecificResourceAllocation(start, 2);
        specificResourceAllocation.allocate(ResourcesPerDay.amount(1));
        assertTrue(specificResourceAllocation
                .isAlreadyFinishedBy(specificResourceAllocation.getEndDate()));
    }

}
TOP

Related Classes of org.libreplan.business.test.planner.entities.SpecificResourceAllocationTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.