package org.libreplan.business.test.planner.chart; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.nullValue; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.List; import java.util.Objects; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.hamcrest.Matcher; import org.joda.time.Days; import org.joda.time.LocalDate; import org.junit.Test; import org.libreplan.business.planner.chart.ContiguousDaysLine; import org.libreplan.business.planner.chart.ContiguousDaysLine.IValueTransformer; import org.libreplan.business.planner.chart.ContiguousDaysLine.OnDay; public class ContiguousDaysLineTest { private static final LocalDate someDate = new LocalDate(2002, 2, 10); @Test(expected = IllegalArgumentException.class) public void aLineCannotBeCreatedWithAStartBeforeTheEnd() { ContiguousDaysLine.create(someDate, someDate.minusDays(1)); } @Test public void aLineWithTheSameStartAndEndIsEmpty() { ContiguousDaysLine<?> line = ContiguousDaysLine.create( someDate, someDate); assertTrue(line.isEmpty()); assertThat(line.size(), equalTo(0)); } @Test public void theSizeIsEqualToTheDaysBetweenTheDates() { for (int i = 0; i < 10; i++) { LocalDate end = someDate.plusDays(i); ContiguousDaysLine<?> line = ContiguousDaysLine.create( someDate, end); assertThat(line.getEndExclusive(), equalTo(end)); assertThat(line.size(), equalTo(Days.daysBetween(someDate, end) .getDays())); } } @Test public void initiallyTheValuesAreNull() { for (OnDay<String> onDay : ContiguousDaysLine.create(someDate, someDate.plusDays(2), String.class)) { assertThat(onDay.getValue(), nullValue()); } } @Test public void theInitialValueCanBeChanged() { ContiguousDaysLine<String> line = ContiguousDaysLine.create( someDate, someDate.plusDays(2), String.class); line.setValueForAll("foo"); assertThat(line, allValuesEqualTo("foo")); } private <T> Matcher<ContiguousDaysLine<T>> allValuesEqualTo(final T value) { return new BaseMatcher<ContiguousDaysLine<T>>() { @Override public boolean matches(Object object) { if (object instanceof ContiguousDaysLine) { ContiguousDaysLine<?> line = (ContiguousDaysLine) object; for (OnDay<?> each : line) { if(! Objects.equals(value, each.getValue())){ return false; } } return true; } return false; } @Override public void describeTo(Description description) { description .appendText("all the values of the line has as value: " + value); } }; } @Test public void linesCanBeIndexedByLocalDates() { ContiguousDaysLine<String> line = ContiguousDaysLine.create( someDate, someDate.plusDays(2), String.class); assertThat(line.get(someDate), nullValue()); assertThat(line.get(someDate.plusDays(1)), nullValue()); line.setValueForAll("foo"); assertThat(line.get(someDate), equalTo("foo")); assertThat(line.get(someDate.plusDays(1)), equalTo("foo")); } @Test(expected = IndexOutOfBoundsException.class) public void aLocalDateIndexBeyondTheLineCausesException() { ContiguousDaysLine<String> line = ContiguousDaysLine.create( someDate, someDate.plusDays(2), String.class); line.get(someDate.plusDays(2)); } @Test public void aLineCanBeTransformedInSitu() { ContiguousDaysLine<String> line = ContiguousDaysLine.create( someDate, someDate.plusDays(2), String.class); line.setValueForAll("foo"); line.transformInSitu(doubleTransformer()); assertThat(line, allValuesEqualTo("foofoo")); } @Test public void aLineCanBeTransformedIntoAnotherOne() { ContiguousDaysLine<String> line = ContiguousDaysLine.create( someDate, someDate.plusDays(2), String.class); line.setValueForAll("foo"); ContiguousDaysLine<String> another = line .transform(doubleTransformer()); assertThat("the original line remains the same", line, allValuesEqualTo("foo")); assertThat(another, allValuesEqualTo("foofoo")); } @Test public void aSubIntervalOfAnInvalidLineIsInvalid() { ContiguousDaysLine<Object> invalid = ContiguousDaysLine.invalid(); assertTrue(invalid.subInterval(someDate, someDate.plusDays(2)) .isNotValid()); } @Test public void ifTheRangeIsOutsideInvalidIsReturned() { ContiguousDaysLine<String> line = ContiguousDaysLine.create(someDate, someDate.plusDays(2), String.class); line.setValueForAll("foo"); assertTrue(line.subInterval(someDate.minusDays(2), someDate.minusDays(1)).isNotValid()); } @Test public void ifTheRangeIsCompletelyInsideThatPartIsReturned() { ContiguousDaysLine<String> line = ContiguousDaysLine.create(someDate, someDate.plusDays(4), String.class); line.setValueForAll("foo"); ContiguousDaysLine<String> newLine = line.subInterval( someDate.plusDays(1), someDate.plusDays(3)); assertThat(newLine.getStart(), equalTo(someDate.plusDays(1))); assertThat(newLine.getEndExclusive(), equalTo(someDate.plusDays(3))); } @Test public void ifTheRangeIsPartOutsideAndPartInsideTheIntersectionIsReturned() { ContiguousDaysLine<String> line = ContiguousDaysLine.create(someDate, someDate.plusDays(4), String.class); line.setValueForAll("foo"); ContiguousDaysLine<String> newLine = line.subInterval( someDate.minusDays(1), someDate.plusDays(7)); assertThat(newLine.getStart(), equalTo(someDate)); assertThat(newLine, hasSameValuesAs(line)); assertThat(newLine.getEndExclusive(), equalTo(someDate.plusDays(4))); } private Matcher<ContiguousDaysLine<?>> hasSameValuesAs( final ContiguousDaysLine<?> line) { return new BaseMatcher<ContiguousDaysLine<?>>() { @Override public boolean matches(Object object) { if (object instanceof ContiguousDaysLine) { ContiguousDaysLine<?> another = (ContiguousDaysLine<?>) object; for (OnDay<?> each : line) { if (!Objects.equals(each.getValue(), another.get(each.getDay()))) { return false; } } return true; } return false; } @Override public void describeTo(Description description) { List<Object> values = new ArrayList<Object>(); for (OnDay<?> each : line) { values.add(each.getValue()); } description.appendText("the line has values: " + values); } }; } private IValueTransformer<String, String> doubleTransformer() { return new IValueTransformer<String, String>() { @Override public String transform(LocalDate day, String previousValue) { return previousValue + previousValue; } }; } }