/*
* 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.workingday;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.libreplan.business.workingday.EffortDuration.hours;
import static org.libreplan.business.workingday.EffortDuration.seconds;
import static org.libreplan.business.workingday.EffortDuration.zero;
import java.math.BigDecimal;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.junit.Test;
import org.libreplan.business.workingday.EffortDuration;
import org.libreplan.business.workingday.EffortDuration.Granularity;
import org.libreplan.business.workingday.ResourcesPerDay;
import org.libreplan.business.workingday.ResourcesPerDay.ResourcesPerDayDistributor;
public class ResourcesPerDayTest {
@Test(expected = IllegalArgumentException.class)
public void cannotHaveANegativeNumberOfUnits() {
ResourcesPerDay.amount(-1);
}
@Test
public void theUnitsAmoutCanBeRetrieved() {
ResourcesPerDay units = ResourcesPerDay.amount(2);
assertThat(units, readsAs(2, 0));
}
private Matcher<ResourcesPerDay> readsAs(final int integerPart,
final int decimalPart) {
return new BaseMatcher<ResourcesPerDay>() {
@Override
public boolean matches(Object arg) {
if (arg instanceof ResourcesPerDay) {
ResourcesPerDay r = (ResourcesPerDay) arg;
return r.getAmount().intValue() == integerPart
&& getDecimalPart(r) == decimalPart;
}
return false;
}
private int getDecimalPart(ResourcesPerDay r) {
BigDecimal onlyDecimal = r.getAmount().subtract(
new BigDecimal(r.getAmount().intValue()));
BigDecimal decimalPartAsInt = onlyDecimal.movePointRight(4);
int result = decimalPartAsInt.intValue();
return result;
}
@Override
public void describeTo(Description description) {
description.appendText("must have an integer part of "
+ integerPart + " and ");
description.appendText("must have " + decimalPart
+ " as decimal part");
}
};
}
@Test
public void theUnitsAmountCanBeADecimalValue() {
ResourcesPerDay resourcesPerDay = ResourcesPerDay
.amount(new BigDecimal(2.2));
assertThat(resourcesPerDay, readsAs(2, 2000));
}
@Test
public void theAmountIsConvertedToABigDecimalOfScale4() {
ResourcesPerDay resourcesPerDay = ResourcesPerDay
.amount(new BigDecimal(2.2));
assertThat(resourcesPerDay.getAmount().scale(), equalTo(4));
}
@Test
public void ifTheAmountSpecifiedHasBiggerScaleThan4ItIsRoundedHalfUp() {
BigDecimal[] examples = { new BigDecimal(2.11236),
new BigDecimal(211235).movePointLeft(5),
new BigDecimal(2.1124), new BigDecimal(2.112449) };
for (BigDecimal example : examples) {
ResourcesPerDay resourcesPerDay = ResourcesPerDay.amount(example);
assertThat(resourcesPerDay.getAmount().scale(), equalTo(4));
assertThat(resourcesPerDay, readsAs(2, 1124));
}
}
@Test
public void canBeConvertedToDurationsGivenTheWorkingDayInDifferentGranularities() {
ResourcesPerDay units = ResourcesPerDay.amount(2);
for (Granularity each : Granularity.values()) {
assertThat(units.asDurationGivenWorkingDayOf(EffortDuration
.elapsing(8, each)), equalTo(EffortDuration.elapsing(16,
each)));
}
}
@Test
public void ifTheAmountIsDecimalTheSecondsAreMultiplied() {
ResourcesPerDay resourcesPerDay = ResourcesPerDay
.amount(new BigDecimal(2.4));
assertThat(resourcesPerDay.asDurationGivenWorkingDayOf(hours(8)),
equalTo(hours(19).and(12, Granularity.MINUTES)));
assertThat(resourcesPerDay.asDurationGivenWorkingDayOf(hours(10)),
equalTo(hours(24)));
assertThat(resourcesPerDay.asDurationGivenWorkingDayOf(hours(2)),
equalTo(hours(4).and(48, Granularity.MINUTES)));
}
@Test
public void theSecondsAreRoundedHalfUpUnlessItIsMinusThanOneSecond() {
ResourcesPerDay resourcesPerDay = ResourcesPerDay
.amount(new BigDecimal(2.4));
assertThat(resourcesPerDay.asDurationGivenWorkingDayOf(seconds(1)),
equalTo(seconds(2)));
assertThat(resourcesPerDay.asDurationGivenWorkingDayOf(seconds(2)),
equalTo(seconds(5)));
}
@Test
public void asSecondsMustReturnOneIfResultingAmountFromMultiplicationIsGreaterThanZero() {
ResourcesPerDay resourcesPerDay = ResourcesPerDay
.amount(new BigDecimal(0.1));
assertThat(resourcesPerDay.asDurationGivenWorkingDayOf(seconds(1)),
equalTo(seconds(1)));
}
@Test
public void twoResourcesPerDayAreEqualsIfNormalizeToTheSameAmount() {
ResourcesPerDay a = ResourcesPerDay.amount(new BigDecimal(2.00001));
ResourcesPerDay b = ResourcesPerDay.amount(2);
assertEquals(a.hashCode(), b.hashCode());
assertEquals(a, b);
}
@Test
public void ifTheAmountIsZeroMustReturnZero() {
ResourcesPerDay amount = ResourcesPerDay.amount(BigDecimal.ZERO);
EffortDuration result = amount.asDurationGivenWorkingDayOf(hours(8));
assertThat(result, equalTo(zero()));
}
@Test
public void isZeroIfHaveZeroValue() {
BigDecimal[] examples = { new BigDecimal(0.00001), new BigDecimal(0),
new BigDecimal(00), new BigDecimal(0.00) };
for (BigDecimal example : examples) {
assertTrue(ResourcesPerDay.amount(example).isZero());
}
}
@Test
public void notZeroIfNoZeroValue() {
BigDecimal[] examples = { new BigDecimal(0.0001),
new BigDecimal(0.00009), new BigDecimal(1),
new BigDecimal(0.1000) };
for (BigDecimal example : examples) {
assertFalse(ResourcesPerDay.amount(example).isZero());
}
}
@SuppressWarnings("unchecked")
@Test
public void canCalculateTheResourcesPerDayFromTheWorkingEffortAndTheWorkableEffort() {
Object[] periodicalNumber = {
ResourcesPerDay.calculateFrom(seconds(10), seconds(3)),
readsAs(3, 3333) };
Object[][] examples = {
{ ResourcesPerDay.calculateFrom(seconds(1000), seconds(1000)),
readsAs(1, 0000) },
{ ResourcesPerDay.calculateFrom(seconds(2000), seconds(1000)),
readsAs(2, 0000) },
{ ResourcesPerDay.calculateFrom(seconds(500), seconds(1000)),
readsAs(0, 5000) },
{ ResourcesPerDay.calculateFrom(seconds(651), seconds(1000)),
readsAs(0, 6510) },
{ ResourcesPerDay.calculateFrom(seconds(1986), seconds(1000)),
readsAs(1, 9860) },
periodicalNumber };
for (Object[] pair : examples) {
ResourcesPerDay first = (ResourcesPerDay) pair[0];
Matcher<ResourcesPerDay> matcher = (Matcher<ResourcesPerDay>) pair[1];
assertThat(first, matcher);
}
}
@SuppressWarnings("unchecked")
@Test
public void canDistributeResourcesPerDay() {
ResourcesPerDayDistributor distributor = ResourcesPerDay.distributor(
ResourcesPerDay.amount(new BigDecimal(0.8)), ResourcesPerDay
.amount(new BigDecimal(0.2)));
Object[][] examples = {
{ ResourcesPerDay.amount(10),
readsAs(8, 0), readsAs(2, 0) },
{ ResourcesPerDay.amount(1),
readsAs(0, 8000), readsAs(0, 2000) },
{ ResourcesPerDay.amount(new BigDecimal(0.5)),
readsAs(0, 4000),readsAs(0, 1000) } };
for (Object[] eachExample : examples) {
ResourcesPerDay toDistribute = (ResourcesPerDay) eachExample[0];
Matcher<ResourcesPerDay> firstMatcher = (Matcher<ResourcesPerDay>) eachExample[1];
Matcher<ResourcesPerDay> secondMatcher = (Matcher<ResourcesPerDay>) eachExample[2];
ResourcesPerDay[] distribute = distributor.distribute(toDistribute);
assertThat(distribute[0], firstMatcher);
assertThat(distribute[1], secondMatcher);
}
}
}