/*
* 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 java.util.Arrays.asList;
import static java.util.Collections.min;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.libreplan.business.workingday.EffortDuration.hours;
import static org.libreplan.business.workingday.EffortDuration.minutes;
import static org.libreplan.business.workingday.EffortDuration.seconds;
import static org.libreplan.business.workingday.EffortDuration.zero;
import java.math.BigDecimal;
import java.util.EnumMap;
import org.junit.Test;
import org.libreplan.business.workingday.EffortDuration;
import org.libreplan.business.workingday.EffortDuration.Granularity;
public class EffortDurationTest {
@Test
public void itCanExpressTheDurationAsHoursMinutesAndSeconds() {
EffortDuration duration = EffortDuration.hours(4);
assertThat(duration.getHours(), equalTo(4));
assertThat(duration.getMinutes(), equalTo(240));
assertThat(duration.getSeconds(), equalTo(240 * 60));
}
@Test
public void unitsCannotBeNegative() {
Granularity[] granularities = EffortDuration.Granularity.values();
for (Granularity each : granularities) {
try {
EffortDuration.elapsing(-1, each);
fail("it should throw IllegalArgumentException");
} catch (IllegalArgumentException e) {
// ok
}
}
}
@Test
public void hoursCanBeZero() {
EffortDuration.hours(0);
}
@Test
public void minutesAreTranslatedToHours() {
assertThat(EffortDuration.minutes(120).getHours(), equalTo(2));
assertThat(minutes(119).getHours(), equalTo(1));
assertThat(minutes(121).getHours(), equalTo(2));
}
@Test
public void canBeTranslatedToAnyGranularity(){
assertThat(hours(3).convertTo(Granularity.MINUTES), equalTo(180));
}
@Test
public void canSpecifyADurationWithSeveralUnits() {
assertThat(
hours(2).and(30, Granularity.MINUTES)
.convertTo(Granularity.MINUTES), equalTo(150));
}
private static final EffortDuration oneHourAndAHalf = hours(1).and(30,
Granularity.MINUTES);
private static final EffortDuration ninetyMinutes = minutes(90);
@Test
public void twoDurationWithTheSameSecondsAreEqual(){
assertThat(oneHourAndAHalf, equalTo(ninetyMinutes));
}
@Test
public void twoEqualDurationsHaveTheSameHashCode() {
assertThat(oneHourAndAHalf.hashCode(),
equalTo(ninetyMinutes.hashCode()));
}
@Test
public void anEffortDurationCanBeDecomposedIntoElements() {
EffortDuration duration = hours(1).and(90, Granularity.MINUTES);
EnumMap<Granularity, Integer> values = duration.decompose();
assertThat(values.get(Granularity.HOURS), equalTo(2));
assertThat(values.get(Granularity.MINUTES), equalTo(30));
assertThat(values.get(Granularity.SECONDS), equalTo(0));
}
@Test
public void anZeroDurationHasZeroElements() {
EffortDuration duration = EffortDuration.zero();
EnumMap<Granularity, Integer> values = duration.decompose();
assertThat(values.get(Granularity.HOURS), equalTo(0));
assertThat(values.get(Granularity.MINUTES), equalTo(0));
assertThat(values.get(Granularity.SECONDS), equalTo(0));
}
@Test
public void aZeroDurationIsZero() {
EffortDuration duration = EffortDuration.zero();
assertTrue(duration.isZero());
}
@Test
public void effortDurationImplementsComparable() {
assertTrue(hours(3).compareTo(minutes(180)) == 0);
assertTrue(hours(3).compareTo(minutes(178)) > 0);
assertTrue(hours(3).compareTo(minutes(181)) < 0);
assertTrue(hours(3).compareTo(minutes(190)) < 0);
EffortDuration min = min(asList(hours(2), hours(3), seconds(10),
seconds(5).and(1, Granularity.HOURS)));
assertThat(min, equalTo(seconds(10)));
}
@Test
public void effortDurationsCanBePlused() {
EffortDuration a = EffortDuration.hours(1).and(30, Granularity.MINUTES);
EffortDuration b = EffortDuration.minutes(30);
assertThat(a.plus(b), equalTo(EffortDuration.hours(2)));
}
@Test
public void effortDurationCanBeDivided() {
assertThat(hours(4).divideBy(4), equalTo(hours(1)));
assertThat(hours(3).divideBy(2),
equalTo(hours(1).and(30, Granularity.MINUTES)));
assertThat(hours(3).divideBy(4), equalTo(minutes(45)));
}
@Test
public void effortDurationCanBeDividedByAnotherEffortDuration() {
assertThat(hours(4).divideBy(hours(2)), equalTo(2));
assertThat(hours(4).remainderFor(hours(2)), equalTo(zero()));
assertThat(hours(5).divideBy(hours(2)), equalTo(2));
assertThat(hours(5).remainderFor(hours(2)), equalTo(hours(1)));
assertThat(hours(2).divideBy(hours(4)), equalTo(0));
assertThat(hours(2).remainderFor(hours(4)), equalTo(hours(2)));
assertThat(hours(1).and(30, Granularity.MINUTES).divideBy(minutes(30)),
equalTo(3));
}
@Test(expected = IllegalArgumentException.class)
public void effortDurationCannotBeSubstractedIfMinuedIsSmallerThanSubtrahend() {
EffortDuration threeHours = hours(3);
threeHours.minus(threeHours.and(1, Granularity.SECONDS));
}
@Test
public void effortDurationCanBeSubstracted() {
assertThat(hours(2).minus(minutes(120)), equalTo(EffortDuration.zero()));
assertThat(hours(2).minus(minutes(60)), equalTo(hours(1)));
}
@Test
public void canConvertToDecimalHours() {
EffortDuration duration = hours(1).and(30, Granularity.MINUTES);
assertThat(duration.toHoursAsDecimalWithScale(1), equalTo(new BigDecimal("1.5")));
}
@Test
public void theScaleIsTheOneProvided() {
EffortDuration duration = hours(1).and(30, Granularity.MINUTES);
assertThat(duration.toHoursAsDecimalWithScale(1).scale(), equalTo(1));
assertThat(duration.toHoursAsDecimalWithScale(2).scale(), equalTo(2));
assertThat(duration.toHoursAsDecimalWithScale(3).scale(), equalTo(3));
}
@Test
public void anHalfUpRoundIsDone() {
// 3601/3600 = 1.000277778
EffortDuration duration = hours(1).and(1, Granularity.SECONDS);
assertThat(duration.toHoursAsDecimalWithScale(6), equalTo(new BigDecimal(
"1.000278")));
assertThat(duration.toHoursAsDecimalWithScale(5),
equalTo(new BigDecimal("1.00028")));
assertThat(duration.toHoursAsDecimalWithScale(4),
equalTo(new BigDecimal("1.0003")));
}
@Test
public void theDurationCanBeRoundedToIntegerHours() {
assertThat(hours(0).roundToHours(), equalTo(0));
assertThat(hours(1).roundToHours(), equalTo(1));
assertThat(hours(2).roundToHours(), equalTo(2));
}
@Test
public void theTypeOfRoundDoneIsHalfUpWhenTheHoursAreAtLeastOne() {
assertThat(hours(1).and(20, Granularity.MINUTES).roundToHours(),
equalTo(1));
assertThat(hours(1).and(30, Granularity.MINUTES).roundToHours(),
equalTo(2));
}
@Test
public void ifDurationNotZeroIsAlwaysRoundedToAtLeastOne() {
assertThat(seconds(1).roundToHours(), equalTo(1));
assertThat(minutes(29).roundToHours(), equalTo(1));
assertThat(minutes(30).roundToHours(), equalTo(1));
}
}