/** * Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.basics.schedule; import static com.opengamma.basics.date.BusinessDayConventions.MODIFIED_FOLLOWING; import static com.opengamma.basics.date.BusinessDayConventions.MODIFIED_PRECEDING; import static com.opengamma.basics.date.BusinessDayConventions.PRECEDING; import static com.opengamma.basics.date.HolidayCalendars.NO_HOLIDAYS; import static com.opengamma.basics.schedule.Frequency.P1M; import static com.opengamma.basics.schedule.Frequency.P2M; import static com.opengamma.basics.schedule.Frequency.P3M; import static com.opengamma.basics.schedule.Frequency.TERM; import static com.opengamma.basics.schedule.RollConventions.DAY_11; import static com.opengamma.basics.schedule.RollConventions.DAY_17; import static com.opengamma.basics.schedule.RollConventions.DAY_4; import static com.opengamma.basics.schedule.RollConventions.EOM; import static com.opengamma.basics.schedule.RollConventions.IMM; import static com.opengamma.basics.schedule.RollConventions.SFE; import static com.opengamma.basics.schedule.StubConvention.LONG_FINAL; import static com.opengamma.basics.schedule.StubConvention.LONG_INITIAL; import static com.opengamma.basics.schedule.StubConvention.SHORT_FINAL; import static com.opengamma.basics.schedule.StubConvention.SHORT_INITIAL; import static com.opengamma.collect.TestHelper.assertSerialization; import static com.opengamma.collect.TestHelper.assertThrows; import static com.opengamma.collect.TestHelper.coverImmutableBean; import static com.opengamma.collect.TestHelper.date; import static java.time.DayOfWeek.SUNDAY; import static java.time.Month.AUGUST; import static java.time.Month.FEBRUARY; import static java.time.Month.JULY; import static java.time.Month.JUNE; import static java.time.Month.MAY; import static java.time.Month.NOVEMBER; import static java.time.Month.SEPTEMBER; import static org.testng.Assert.assertEquals; import java.time.LocalDate; import java.util.List; import java.util.Optional; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import com.google.common.collect.ImmutableList; import com.opengamma.basics.date.BusinessDayAdjustment; import com.opengamma.basics.date.BusinessDayConvention; import com.opengamma.basics.date.BusinessDayConventions; import com.opengamma.basics.date.HolidayCalendar; import com.opengamma.basics.date.HolidayCalendars; /** * Test {@link PeriodicSchedule}. */ @Test public class PeriodicScheduleTest { private static final StubConvention STUB_NONE = StubConvention.NONE; private static final StubConvention STUB_BOTH = StubConvention.BOTH; private static final BusinessDayAdjustment BDA = BusinessDayAdjustment.of( MODIFIED_FOLLOWING, HolidayCalendars.SAT_SUN); private static final LocalDate NOV_30_2013 = date(2013, NOVEMBER, 30); private static final LocalDate FEB_28 = date(2014, FEBRUARY, 28); private static final LocalDate MAY_30 = date(2014, MAY, 30); private static final LocalDate MAY_31 = date(2014, MAY, 31); private static final LocalDate AUG_30 = date(2014, AUGUST, 30); private static final LocalDate AUG_31 = date(2014, AUGUST, 31); private static final LocalDate NOV_30 = date(2014, NOVEMBER, 30); private static final LocalDate JUN_03 = date(2014, JUNE, 3); private static final LocalDate JUN_04 = date(2014, JUNE, 4); private static final LocalDate JUN_17 = date(2014, JUNE, 17); private static final LocalDate JUL_04 = date(2014, JULY, 4); private static final LocalDate JUL_11 = date(2014, JULY, 11); private static final LocalDate JUL_17 = date(2014, JULY, 17); private static final LocalDate AUG_04 = date(2014, AUGUST, 4); private static final LocalDate AUG_11 = date(2014, AUGUST, 11); private static final LocalDate AUG_17 = date(2014, AUGUST, 17); private static final LocalDate AUG_18 = date(2014, AUGUST, 18); private static final LocalDate SEP_04 = date(2014, SEPTEMBER, 4); private static final LocalDate SEP_05 = date(2014, SEPTEMBER, 5); private static final LocalDate SEP_17 = date(2014, SEPTEMBER, 17); private static final LocalDate SEP_18 = date(2014, SEPTEMBER, 18); //------------------------------------------------------------------------- public void test_of_LocalDateEomFalse() { PeriodicSchedule test = PeriodicSchedule.of(JUN_04, SEP_17, P1M, BDA, SHORT_INITIAL, false); assertEquals(test.getStartDate(), JUN_04); assertEquals(test.getEndDate(), SEP_17); assertEquals(test.getFrequency(), P1M); assertEquals(test.getBusinessDayAdjustment(), BDA); assertEquals(test.getStartDateBusinessDayAdjustment(), Optional.empty()); assertEquals(test.getEndDateBusinessDayAdjustment(), Optional.empty()); assertEquals(test.getStubConvention(), Optional.of(SHORT_INITIAL)); assertEquals(test.getRollConvention(), Optional.empty()); assertEquals(test.getFirstRegularStartDate(), Optional.empty()); assertEquals(test.getLastRegularEndDate(), Optional.empty()); assertEquals(test.getEffectiveRollConvention(), DAY_17); assertEquals(test.getEffectiveFirstRegularStartDate(), JUN_04); assertEquals(test.getEffectiveLastRegularEndDate(), SEP_17); assertEquals(test.getEffectiveStartDateBusinessDayAdjustment(), BDA); assertEquals(test.getEffectiveEndDateBusinessDayAdjustment(), BDA); assertEquals(test.getAdjustedStartDate(), JUN_04); assertEquals(test.getAdjustedEndDate(), SEP_17); } public void test_of_LocalDateEomTrue() { PeriodicSchedule test = PeriodicSchedule.of(JUN_04, SEP_17, P1M, BDA, SHORT_FINAL, true); assertEquals(test.getStartDate(), JUN_04); assertEquals(test.getEndDate(), SEP_17); assertEquals(test.getFrequency(), P1M); assertEquals(test.getBusinessDayAdjustment(), BDA); assertEquals(test.getStartDateBusinessDayAdjustment(), Optional.empty()); assertEquals(test.getEndDateBusinessDayAdjustment(), Optional.empty()); assertEquals(test.getStubConvention(), Optional.of(SHORT_FINAL)); assertEquals(test.getRollConvention(), Optional.of(EOM)); assertEquals(test.getFirstRegularStartDate(), Optional.empty()); assertEquals(test.getLastRegularEndDate(), Optional.empty()); assertEquals(test.getEffectiveRollConvention(), DAY_4); assertEquals(test.getEffectiveFirstRegularStartDate(), JUN_04); assertEquals(test.getEffectiveLastRegularEndDate(), SEP_17); assertEquals(test.getEffectiveStartDateBusinessDayAdjustment(), BDA); assertEquals(test.getEffectiveEndDateBusinessDayAdjustment(), BDA); assertEquals(test.getAdjustedStartDate(), JUN_04); assertEquals(test.getAdjustedEndDate(), SEP_17); } public void test_of_LocalDateEom_null() { assertThrows(() -> PeriodicSchedule.of( null, SEP_17, P1M, BDA, SHORT_INITIAL, false), IllegalArgumentException.class); assertThrows(() -> PeriodicSchedule.of( JUN_04, null, P1M, BDA, SHORT_INITIAL, false), IllegalArgumentException.class); assertThrows(() -> PeriodicSchedule.of( JUN_04, SEP_17, null, BDA, SHORT_INITIAL, false), IllegalArgumentException.class); assertThrows(() -> PeriodicSchedule.of( JUN_04, SEP_17, P1M, null, SHORT_INITIAL, false), IllegalArgumentException.class); assertThrows(() -> PeriodicSchedule.of( JUN_04, SEP_17, P1M, BDA, null, false), IllegalArgumentException.class); } //------------------------------------------------------------------------- public void test_of_LocalDateRoll() { PeriodicSchedule test = PeriodicSchedule.of(JUN_04, SEP_17, P1M, BDA, SHORT_INITIAL, DAY_17); assertEquals(test.getStartDate(), JUN_04); assertEquals(test.getEndDate(), SEP_17); assertEquals(test.getFrequency(), P1M); assertEquals(test.getBusinessDayAdjustment(), BDA); assertEquals(test.getStartDateBusinessDayAdjustment(), Optional.empty()); assertEquals(test.getEndDateBusinessDayAdjustment(), Optional.empty()); assertEquals(test.getStubConvention(), Optional.of(SHORT_INITIAL)); assertEquals(test.getRollConvention(), Optional.of(DAY_17)); assertEquals(test.getFirstRegularStartDate(), Optional.empty()); assertEquals(test.getLastRegularEndDate(), Optional.empty()); assertEquals(test.getEffectiveRollConvention(), DAY_17); assertEquals(test.getEffectiveFirstRegularStartDate(), JUN_04); assertEquals(test.getEffectiveLastRegularEndDate(), SEP_17); assertEquals(test.getEffectiveStartDateBusinessDayAdjustment(), BDA); assertEquals(test.getEffectiveEndDateBusinessDayAdjustment(), BDA); assertEquals(test.getAdjustedStartDate(), JUN_04); assertEquals(test.getAdjustedEndDate(), SEP_17); } public void test_of_LocalDateRoll_null() { assertThrows(() -> PeriodicSchedule.of( null, SEP_17, P1M, BDA, SHORT_INITIAL, DAY_17), IllegalArgumentException.class); assertThrows(() -> PeriodicSchedule.of( JUN_04, null, P1M, BDA, SHORT_INITIAL, DAY_17), IllegalArgumentException.class); assertThrows(() -> PeriodicSchedule.of( JUN_04, SEP_17, null, BDA, SHORT_INITIAL, DAY_17), IllegalArgumentException.class); assertThrows(() -> PeriodicSchedule.of( JUN_04, SEP_17, P1M, null, SHORT_INITIAL, DAY_17), IllegalArgumentException.class); assertThrows(() -> PeriodicSchedule.of( JUN_04, SEP_17, P1M, BDA, null, DAY_17), IllegalArgumentException.class); assertThrows(() -> PeriodicSchedule.of( JUN_04, SEP_17, P1M, BDA, SHORT_INITIAL, null), IllegalArgumentException.class); } //------------------------------------------------------------------------- public void test_builder_invalidDateOrder() { // start vs end assertThrows(() -> createDates(SEP_17, SEP_17, null, null), IllegalArgumentException.class); assertThrows(() -> createDates(SEP_17, JUN_04, null, null), IllegalArgumentException.class); // first/last regular vs start/end assertThrows(() -> createDates(JUN_04, SEP_17, JUN_03, null), IllegalArgumentException.class); assertThrows(() -> createDates(JUN_04, SEP_17, null, SEP_18), IllegalArgumentException.class); // first regular vs last regular assertThrows(() -> createDates(JUN_04, SEP_17, SEP_05, SEP_05), IllegalArgumentException.class); assertThrows(() -> createDates(JUN_04, SEP_17, SEP_05, SEP_04), IllegalArgumentException.class); } private PeriodicSchedule createDates(LocalDate start, LocalDate end, LocalDate first, LocalDate last) { return PeriodicSchedule.builder() .startDate(start) .endDate(end) .frequency(P1M) .businessDayAdjustment(BDA) .firstRegularStartDate(first) .lastRegularEndDate(last) .build(); } //------------------------------------------------------------------------- @DataProvider(name = "generation") Object[][] data_generation() { return new Object[][] { // stub null {JUN_17, SEP_17, P1M, null, null, null, null, ImmutableList.of(JUN_17, JUL_17, AUG_17, SEP_17), ImmutableList.of(JUN_17, JUL_17, AUG_18, SEP_17)}, // stub NONE {JUN_17, SEP_17, P1M, STUB_NONE, null, null, null, ImmutableList.of(JUN_17, JUL_17, AUG_17, SEP_17), ImmutableList.of(JUN_17, JUL_17, AUG_18, SEP_17)}, {JUN_17, JUL_17, P1M, STUB_NONE, null, null, null, ImmutableList.of(JUN_17, JUL_17), ImmutableList.of(JUN_17, JUL_17)}, // stub SHORT_INITIAL {JUN_04, SEP_17, P1M, SHORT_INITIAL, null, null, null, ImmutableList.of(JUN_04, JUN_17, JUL_17, AUG_17, SEP_17), ImmutableList.of(JUN_04, JUN_17, JUL_17, AUG_18, SEP_17)}, {JUN_17, SEP_17, P1M, SHORT_INITIAL, null, null, null, ImmutableList.of(JUN_17, JUL_17, AUG_17, SEP_17), ImmutableList.of(JUN_17, JUL_17, AUG_18, SEP_17)}, {JUN_17, JUL_04, P1M, SHORT_INITIAL, null, null, null, ImmutableList.of(JUN_17, JUL_04), ImmutableList.of(JUN_17, JUL_04)}, {date(2011, 6, 28), date(2011, 6, 30), P1M, SHORT_INITIAL, EOM, null, null, ImmutableList.of(date(2011, 6, 28), date(2011, 6, 30)), ImmutableList.of(date(2011, 6, 28), date(2011, 6, 30))}, {date(2014, 12, 12), date(2015, 8, 24), P3M, SHORT_INITIAL, null, null, null, ImmutableList.of(date(2014, 12, 12), date(2015, 2, 24), date(2015, 5, 24), date(2015, 8, 24)), ImmutableList.of(date(2014, 12, 12), date(2015, 2, 24), date(2015, 5, 25), date(2015, 8, 24))}, {date(2014, 12, 12), date(2015, 8, 24), P3M, SHORT_INITIAL, RollConventions.NONE, null, null, ImmutableList.of(date(2014, 12, 12), date(2015, 2, 24), date(2015, 5, 24), date(2015, 8, 24)), ImmutableList.of(date(2014, 12, 12), date(2015, 2, 24), date(2015, 5, 25), date(2015, 8, 24))}, {date(2014, 11, 24), date(2015, 8, 24), P3M, null, RollConventions.NONE, null, null, ImmutableList.of(date(2014, 11, 24), date(2015, 2, 24), date(2015, 5, 24), date(2015, 8, 24)), ImmutableList.of(date(2014, 11, 24), date(2015, 2, 24), date(2015, 5, 25), date(2015, 8, 24))}, // stub LONG_INITIAL {JUN_04, SEP_17, P1M, LONG_INITIAL, null, null, null, ImmutableList.of(JUN_04, JUL_17, AUG_17, SEP_17), ImmutableList.of(JUN_04, JUL_17, AUG_18, SEP_17)}, {JUN_17, SEP_17, P1M, LONG_INITIAL, null, null, null, ImmutableList.of(JUN_17, JUL_17, AUG_17, SEP_17), ImmutableList.of(JUN_17, JUL_17, AUG_18, SEP_17)}, {JUN_17, JUL_04, P1M, LONG_INITIAL, null, null, null, ImmutableList.of(JUN_17, JUL_04), ImmutableList.of(JUN_17, JUL_04)}, {JUN_17, AUG_04, P1M, LONG_INITIAL, null, null, null, ImmutableList.of(JUN_17, AUG_04), ImmutableList.of(JUN_17, AUG_04)}, // stub SHORT_FINAL {JUN_04, SEP_17, P1M, SHORT_FINAL, null, null, null, ImmutableList.of(JUN_04, JUL_04, AUG_04, SEP_04, SEP_17), ImmutableList.of(JUN_04, JUL_04, AUG_04, SEP_04, SEP_17)}, {JUN_17, SEP_17, P1M, SHORT_FINAL, null, null, null, ImmutableList.of(JUN_17, JUL_17, AUG_17, SEP_17), ImmutableList.of(JUN_17, JUL_17, AUG_18, SEP_17)}, {JUN_17, JUL_04, P1M, SHORT_FINAL, null, null, null, ImmutableList.of(JUN_17, JUL_04), ImmutableList.of(JUN_17, JUL_04)}, {date(2011, 6, 28), date(2011, 6, 30), P1M, SHORT_FINAL, EOM, null, null, ImmutableList.of(date(2011, 6, 28), date(2011, 6, 30)), ImmutableList.of(date(2011, 6, 28), date(2011, 6, 30))}, {date(2014, 11, 29), date(2015, 9, 2), P3M, SHORT_FINAL, null, null, null, ImmutableList.of(date(2014, 11, 29), date(2015, 2, 28), date(2015, 5, 29), date(2015, 8, 29), date(2015, 9, 2)), ImmutableList.of(date(2014, 11, 28), date(2015, 2, 27), date(2015, 5, 29), date(2015, 8, 31), date(2015, 9, 2))}, {date(2014, 11, 29), date(2015, 9, 2), P3M, SHORT_FINAL, RollConventions.NONE, null, null, ImmutableList.of(date(2014, 11, 29), date(2015, 2, 28), date(2015, 5, 29), date(2015, 8, 29), date(2015, 9, 2)), ImmutableList.of(date(2014, 11, 28), date(2015, 2, 27), date(2015, 5, 29), date(2015, 8, 31), date(2015, 9, 2))}, // stub LONG_FINAL {JUN_04, SEP_17, P1M, LONG_FINAL, null, null, null, ImmutableList.of(JUN_04, JUL_04, AUG_04, SEP_17), ImmutableList.of(JUN_04, JUL_04, AUG_04, SEP_17)}, {JUN_17, SEP_17, P1M, LONG_FINAL, null, null, null, ImmutableList.of(JUN_17, JUL_17, AUG_17, SEP_17), ImmutableList.of(JUN_17, JUL_17, AUG_18, SEP_17)}, {JUN_17, JUL_04, P1M, LONG_FINAL, null, null, null, ImmutableList.of(JUN_17, JUL_04), ImmutableList.of(JUN_17, JUL_04)}, {JUN_17, AUG_04, P1M, LONG_FINAL, null, null, null, ImmutableList.of(JUN_17, AUG_04), ImmutableList.of(JUN_17, AUG_04)}, // explicit initial stub {JUN_04, SEP_17, P1M, null, null, JUN_17, null, ImmutableList.of(JUN_04, JUN_17, JUL_17, AUG_17, SEP_17), ImmutableList.of(JUN_04, JUN_17, JUL_17, AUG_18, SEP_17)}, {JUN_04, SEP_17, P1M, SHORT_INITIAL, null, JUN_17, null, ImmutableList.of(JUN_04, JUN_17, JUL_17, AUG_17, SEP_17), ImmutableList.of(JUN_04, JUN_17, JUL_17, AUG_18, SEP_17)}, {JUN_17, SEP_17, P1M, null, null, JUN_17, null, ImmutableList.of(JUN_17, JUL_17, AUG_17, SEP_17), ImmutableList.of(JUN_17, JUL_17, AUG_18, SEP_17)}, // explicit final stub {JUN_04, SEP_17, P1M, null, null, null, AUG_04, ImmutableList.of(JUN_04, JUL_04, AUG_04, SEP_17), ImmutableList.of(JUN_04, JUL_04, AUG_04, SEP_17)}, {JUN_04, SEP_17, P1M, SHORT_FINAL, null, null, AUG_04, ImmutableList.of(JUN_04, JUL_04, AUG_04, SEP_17), ImmutableList.of(JUN_04, JUL_04, AUG_04, SEP_17)}, {JUN_17, SEP_17, P1M, null, null, null, AUG_17, ImmutableList.of(JUN_17, JUL_17, AUG_17, SEP_17), ImmutableList.of(JUN_17, JUL_17, AUG_18, SEP_17)}, // explicit double stub {JUN_04, SEP_17, P1M, null, null, JUL_11, AUG_11, ImmutableList.of(JUN_04, JUL_11, AUG_11, SEP_17), ImmutableList.of(JUN_04, JUL_11, AUG_11, SEP_17)}, {JUN_04, SEP_17, P1M, STUB_BOTH, null, JUL_11, AUG_11, ImmutableList.of(JUN_04, JUL_11, AUG_11, SEP_17), ImmutableList.of(JUN_04, JUL_11, AUG_11, SEP_17)}, {JUN_17, SEP_17, P1M, null, null, JUN_17, SEP_17, ImmutableList.of(JUN_17, JUL_17, AUG_17, SEP_17), ImmutableList.of(JUN_17, JUL_17, AUG_18, SEP_17)}, // near end of month // EOM flag false, thus roll on 30th {NOV_30_2013, NOV_30, P3M, STUB_NONE, null, null, null, ImmutableList.of(NOV_30_2013, FEB_28, MAY_30, AUG_30, NOV_30), ImmutableList.of(date(2013, NOVEMBER, 29), FEB_28, MAY_30, date(2014, AUGUST, 29), date(2014, NOVEMBER, 28))}, // EOM flag true and is EOM, thus roll at EOM {NOV_30_2013, NOV_30, P3M, STUB_NONE, EOM, null, null, ImmutableList.of(NOV_30_2013, FEB_28, MAY_31, AUG_31, NOV_30), ImmutableList.of(date(2013, NOVEMBER, 29), FEB_28, MAY_30, date(2014, AUGUST, 29), date(2014, NOVEMBER, 28))}, // EOM flag true, but not EOM, thus roll on 30th {MAY_30, NOV_30, P3M, STUB_NONE, EOM, null, null, ImmutableList.of(MAY_30, AUG_30, NOV_30), ImmutableList.of(MAY_30, date(2014, AUGUST, 29), date(2014, NOVEMBER, 28))}, // EOM flag true and is EOM, double stub, thus roll at EOM {date(2014, 1, 3), SEP_17, P3M, STUB_BOTH, EOM, FEB_28, AUG_31, ImmutableList.of(date(2014, 1, 3), FEB_28, MAY_31, AUG_31, SEP_17), ImmutableList.of(date(2014, 1, 3), FEB_28, MAY_30, date(2014, AUGUST, 29), SEP_17)}, // TERM period {JUN_04, SEP_17, TERM, STUB_NONE, null, null, null, ImmutableList.of(JUN_04, SEP_17), ImmutableList.of(JUN_04, SEP_17)}, // IMM {date(2014, 9, 17), date(2014, 10, 15), P1M, STUB_NONE, IMM, null, null, ImmutableList.of(date(2014, 9, 17), date(2014, 10, 15)), ImmutableList.of(date(2014, 9, 17), date(2014, 10, 15))}, {date(2014, 9, 17), date(2014, 10, 15), TERM, STUB_NONE, IMM, null, null, ImmutableList.of(date(2014, 9, 17), date(2014, 10, 15)), ImmutableList.of(date(2014, 9, 17), date(2014, 10, 15))}, // IMM with stupid short period still works {date(2014, 9, 17), date(2014, 10, 15), Frequency.ofDays(2), STUB_NONE, IMM, null, null, ImmutableList.of(date(2014, 9, 17), date(2014, 10, 15)), ImmutableList.of(date(2014, 9, 17), date(2014, 10, 15))}, {date(2014, 9, 17), date(2014, 10, 1), Frequency.ofDays(2), STUB_NONE, IMM, null, null, ImmutableList.of(date(2014, 9, 17), date(2014, 10, 1)), ImmutableList.of(date(2014, 9, 17), date(2014, 10, 1))}, }; } @Test(dataProvider = "generation") public void test_monthly_schedule( LocalDate start, LocalDate end, Frequency freq, StubConvention stubConv, RollConvention rollConv, LocalDate firstReg, LocalDate lastReg, List<LocalDate> unadjusted, List<LocalDate> adjusted) { PeriodicSchedule defn = PeriodicSchedule.builder() .startDate(start) .endDate(end) .frequency(freq) .businessDayAdjustment(BDA) .stubConvention(stubConv) .rollConvention(rollConv) .firstRegularStartDate(firstReg) .lastRegularEndDate(lastReg) .build(); Schedule test = defn.createSchedule(); assertEquals(test.size(), unadjusted.size() - 1); for (int i = 0; i < test.size(); i++) { SchedulePeriod period = test.getPeriod(i); assertEquals(period.getUnadjustedStartDate(), unadjusted.get(i)); assertEquals(period.getUnadjustedEndDate(), unadjusted.get(i + 1)); assertEquals(period.getStartDate(), adjusted.get(i)); assertEquals(period.getEndDate(), adjusted.get(i + 1)); } assertEquals(test.getFrequency(), freq); assertEquals(test.getRollConvention(), defn.getEffectiveRollConvention()); } @Test(dataProvider = "generation") public void test_monthly_unadjusted( LocalDate start, LocalDate end, Frequency freq, StubConvention stubConv, RollConvention rollConv, LocalDate firstReg, LocalDate lastReg, List<LocalDate> unadjusted, List<LocalDate> adjusted) { PeriodicSchedule defn = PeriodicSchedule.builder() .startDate(start) .endDate(end) .frequency(freq) .businessDayAdjustment(BDA) .stubConvention(stubConv) .rollConvention(rollConv) .firstRegularStartDate(firstReg) .lastRegularEndDate(lastReg) .build(); ImmutableList<LocalDate> test = defn.createUnadjustedDates(); assertEquals(test, unadjusted); } @Test(dataProvider = "generation") public void test_monthly_adjusted( LocalDate start, LocalDate end, Frequency freq, StubConvention stubConv, RollConvention rollConv, LocalDate firstReg, LocalDate lastReg, List<LocalDate> unadjusted, List<LocalDate> adjusted) { PeriodicSchedule defn = PeriodicSchedule.builder() .startDate(start) .endDate(end) .frequency(freq) .businessDayAdjustment(BDA) .stubConvention(stubConv) .rollConvention(rollConv) .firstRegularStartDate(firstReg) .lastRegularEndDate(lastReg) .build(); ImmutableList<LocalDate> test = defn.createAdjustedDates(); assertEquals(test, adjusted); } //------------------------------------------------------------------------- public void test_startEndAdjust() { BusinessDayAdjustment bda1 = BusinessDayAdjustment.of(PRECEDING, HolidayCalendars.SAT_SUN); BusinessDayAdjustment bda2 = BusinessDayAdjustment.of(MODIFIED_PRECEDING, HolidayCalendars.SAT_SUN); PeriodicSchedule test = PeriodicSchedule.builder() .startDate(date(2014, 10, 4)) .endDate(date(2015, 4, 4)) .frequency(P3M) .businessDayAdjustment(BDA) .startDateBusinessDayAdjustment(bda1) .endDateBusinessDayAdjustment(bda2) .stubConvention(STUB_NONE) .build(); assertEquals(test.getEffectiveStartDateBusinessDayAdjustment(), bda1); assertEquals(test.getEffectiveEndDateBusinessDayAdjustment(), bda2); assertEquals(test.getAdjustedStartDate(), date(2014, 10, 3)); assertEquals(test.getAdjustedEndDate(), date(2015, 4, 3)); assertEquals(test.createUnadjustedDates(), ImmutableList.of(date(2014, 10, 4), date(2015, 1, 4), date(2015, 4, 4))); assertEquals(test.createAdjustedDates(), ImmutableList.of(date(2014, 10, 3), date(2015, 1, 5), date(2015, 4, 3))); } //------------------------------------------------------------------------- @Test(expectedExceptions = ScheduleException.class) public void test_none_badStub() { PeriodicSchedule defn = PeriodicSchedule.builder() .startDate(JUN_04) .endDate(SEP_17) .frequency(P1M) .businessDayAdjustment(BDA) .stubConvention(STUB_NONE) .rollConvention(DAY_4) .firstRegularStartDate(null) .lastRegularEndDate(null) .build(); defn.createUnadjustedDates(); } @Test(expectedExceptions = ScheduleException.class) public void test_both_badStub() { PeriodicSchedule defn = PeriodicSchedule.builder() .startDate(JUN_17) .endDate(SEP_17) .frequency(P1M) .businessDayAdjustment(BDA) .stubConvention(STUB_BOTH) .rollConvention(null) .firstRegularStartDate(JUN_17) .lastRegularEndDate(SEP_17) .build(); defn.createUnadjustedDates(); } @Test(expectedExceptions = ScheduleException.class) public void test_backwards_badStub() { PeriodicSchedule defn = PeriodicSchedule.builder() .startDate(JUN_17) .endDate(SEP_17) .frequency(P1M) .businessDayAdjustment(BDA) .stubConvention(SHORT_INITIAL) .rollConvention(DAY_11) .firstRegularStartDate(null) .lastRegularEndDate(null) .build(); defn.createUnadjustedDates(); } @Test(expectedExceptions = ScheduleException.class) public void test_forwards_badStub() { PeriodicSchedule defn = PeriodicSchedule.builder() .startDate(JUN_17) .endDate(SEP_17) .frequency(P1M) .businessDayAdjustment(BDA) .stubConvention(SHORT_FINAL) .rollConvention(DAY_11) .firstRegularStartDate(null) .lastRegularEndDate(null) .build(); defn.createUnadjustedDates(); } //------------------------------------------------------------------------- @Test(expectedExceptions = ScheduleException.class) public void test_termFrequency_badInitialStub() { PeriodicSchedule defn = PeriodicSchedule.builder() .startDate(JUN_04) .endDate(SEP_17) .frequency(TERM) .businessDayAdjustment(BDA) .stubConvention(STUB_NONE) .rollConvention(DAY_4) .firstRegularStartDate(JUN_17) .lastRegularEndDate(null) .build(); defn.createUnadjustedDates(); } @Test(expectedExceptions = ScheduleException.class) public void test_termFrequency_badFinalStub() { PeriodicSchedule defn = PeriodicSchedule.builder() .startDate(JUN_04) .endDate(SEP_17) .frequency(TERM) .businessDayAdjustment(BDA) .stubConvention(STUB_NONE) .rollConvention(DAY_4) .firstRegularStartDate(null) .lastRegularEndDate(SEP_04) .build(); defn.createUnadjustedDates(); } //------------------------------------------------------------------------- public void test_emptyWhenAdjusted_term_createUnadjustedDates() { PeriodicSchedule defn = PeriodicSchedule.builder() .startDate(date(2015, 5, 29)) .endDate(date(2015, 5, 31)) .frequency(TERM) .businessDayAdjustment(BDA) .stubConvention(null) .rollConvention(null) .firstRegularStartDate(null) .lastRegularEndDate(null) .build(); ImmutableList<LocalDate> test = defn.createUnadjustedDates(); assertEquals(test, ImmutableList.of(date(2015, 5, 29), date(2015, 5, 31))); } @Test(expectedExceptions = ScheduleException.class, expectedExceptionsMessageRegExp = ".*duplicate adjusted dates.*") public void test_emptyWhenAdjusted_term_createAdjustedDates() { PeriodicSchedule defn = PeriodicSchedule.builder() .startDate(date(2015, 5, 29)) .endDate(date(2015, 5, 31)) .frequency(TERM) .businessDayAdjustment(BDA) .stubConvention(null) .rollConvention(null) .firstRegularStartDate(null) .lastRegularEndDate(null) .build(); defn.createAdjustedDates(); } @Test(expectedExceptions = ScheduleException.class, expectedExceptionsMessageRegExp = ".*duplicate adjusted dates.*") public void test_emptyWhenAdjusted_term_createSchedule() { PeriodicSchedule defn = PeriodicSchedule.builder() .startDate(date(2015, 5, 29)) .endDate(date(2015, 5, 31)) .frequency(TERM) .businessDayAdjustment(BDA) .stubConvention(null) .rollConvention(null) .firstRegularStartDate(null) .lastRegularEndDate(null) .build(); defn.createSchedule(); } public void test_emptyWhenAdjusted_twoPeriods_createUnadjustedDates() { PeriodicSchedule defn = PeriodicSchedule.builder() .startDate(date(2015, 5, 27)) .endDate(date(2015, 5, 31)) .frequency(Frequency.ofDays(2)) .businessDayAdjustment(BDA) .stubConvention(STUB_NONE) .rollConvention(null) .firstRegularStartDate(null) .lastRegularEndDate(null) .build(); ImmutableList<LocalDate> test = defn.createUnadjustedDates(); assertEquals(test, ImmutableList.of(date(2015, 5, 27), date(2015, 5, 29), date(2015, 5, 31))); } @Test(expectedExceptions = ScheduleException.class, expectedExceptionsMessageRegExp = ".*duplicate adjusted dates.*") public void test_emptyWhenAdjusted_twoPeriods_createAdjustedDates() { PeriodicSchedule defn = PeriodicSchedule.builder() .startDate(date(2015, 5, 27)) .endDate(date(2015, 5, 31)) .frequency(Frequency.ofDays(2)) .businessDayAdjustment(BDA) .stubConvention(STUB_NONE) .rollConvention(null) .firstRegularStartDate(null) .lastRegularEndDate(null) .build(); defn.createAdjustedDates(); } @Test(expectedExceptions = ScheduleException.class, expectedExceptionsMessageRegExp = ".*duplicate adjusted dates.*") public void test_emptyWhenAdjusted_twoPeriods_createSchedule() { PeriodicSchedule defn = PeriodicSchedule.builder() .startDate(date(2015, 5, 27)) .endDate(date(2015, 5, 31)) .frequency(Frequency.ofDays(2)) .businessDayAdjustment(BDA) .stubConvention(STUB_NONE) .rollConvention(null) .firstRegularStartDate(null) .lastRegularEndDate(null) .build(); defn.createSchedule(); } @Test( expectedExceptions = ScheduleException.class, expectedExceptionsMessageRegExp = "Schedule calculation resulted in invalid period") public void test_brokenWhenAdjusted_twoPeriods_createSchedule() { // generate unadjusted dates that are sorted (Wed, then Fri, then Sun) // use weird BusinessDayConvention to move Sunday back to Thursday // result is adjusted dates that are not sorted (Wed, then Fri, then Thu) PeriodicSchedule defn = PeriodicSchedule.builder() .startDate(date(2015, 5, 27)) .endDate(date(2015, 5, 31)) .frequency(Frequency.ofDays(2)) .businessDayAdjustment(BusinessDayAdjustment.of(new BusinessDayConvention() { @Override public String getName() { return "TestBack3OnSun"; } @Override public LocalDate adjust(LocalDate date, HolidayCalendar calendar) { return (date.getDayOfWeek() == SUNDAY ? date.minusDays(3) : date); } }, NO_HOLIDAYS)) .stubConvention(STUB_NONE) .rollConvention(null) .firstRegularStartDate(null) .lastRegularEndDate(null) .build(); defn.createSchedule(); } @Test(expectedExceptions = ScheduleException.class, expectedExceptionsMessageRegExp = ".*duplicate unadjusted dates.*") public void test_emptyWhenAdjusted_badRoll_createUnadjustedDates() { RollConvention roll = new RollConvention() { private boolean seen; @Override public String getName() { return "Test"; } @Override public LocalDate adjust(LocalDate date) { return date; } @Override public LocalDate next(LocalDate date, Frequency frequency) { if (seen) { return date.plus(frequency); } else { seen = true; return date; } } }; PeriodicSchedule defn = PeriodicSchedule.builder() .startDate(date(2015, 5, 27)) .endDate(date(2015, 5, 31)) .frequency(Frequency.ofDays(2)) .businessDayAdjustment(BDA) .stubConvention(STUB_NONE) .rollConvention(roll) .firstRegularStartDate(null) .lastRegularEndDate(null) .build(); defn.createUnadjustedDates(); } //------------------------------------------------------------------------- @Test(dataProvider = "generation") public void coverage_equals( LocalDate start, LocalDate end, Frequency freq, StubConvention stubConv, RollConvention rollConv, LocalDate firstReg, LocalDate lastReg, List<LocalDate> unadjusted, List<LocalDate> adjusted) { PeriodicSchedule a1 = of(start, end, freq, BDA, stubConv, rollConv, firstReg, lastReg, null, null); PeriodicSchedule a2 = of(start, end, freq, BDA, stubConv, rollConv, firstReg, lastReg, null, null); PeriodicSchedule b = of(LocalDate.MIN, end, freq, BDA, stubConv, rollConv, firstReg, lastReg, null, null); PeriodicSchedule c = of(start, LocalDate.MAX, freq, BDA, stubConv, rollConv, firstReg, lastReg, null, null); PeriodicSchedule d = of( start, end, freq == P1M ? P3M : P1M, BDA, stubConv, rollConv, firstReg, lastReg, null, null); PeriodicSchedule e = of( start, end, freq, BusinessDayAdjustment.NONE, stubConv, rollConv, firstReg, lastReg, null, null); PeriodicSchedule f = of( start, end, freq, BDA, stubConv == STUB_NONE ? SHORT_FINAL : STUB_NONE, rollConv, firstReg, lastReg, null, null); PeriodicSchedule g = of(start, end, freq, BDA, stubConv, SFE, firstReg, lastReg, null, null); PeriodicSchedule h = of(start, end, freq, BDA, stubConv, rollConv, start.plusDays(1), lastReg, null, null); PeriodicSchedule i = of(start, end, freq, BDA, stubConv, rollConv, firstReg, end.minusDays(1), null, null); PeriodicSchedule j = of(start, end, freq, BDA, stubConv, rollConv, firstReg, lastReg, BDA, null); PeriodicSchedule k = of(start, end, freq, BDA, stubConv, rollConv, firstReg, lastReg, null, BDA); assertEquals(a1.equals(a1), true); assertEquals(a1.equals(a2), true); assertEquals(a1.equals(b), false); assertEquals(a1.equals(c), false); assertEquals(a1.equals(d), false); assertEquals(a1.equals(e), false); assertEquals(a1.equals(f), false); assertEquals(a1.equals(g), false); assertEquals(a1.equals(h), false); assertEquals(a1.equals(i), false); assertEquals(a1.equals(j), false); assertEquals(a1.equals(k), false); } private PeriodicSchedule of( LocalDate start, LocalDate end, Frequency freq, BusinessDayAdjustment bda, StubConvention stubConv, RollConvention rollConv, LocalDate firstReg, LocalDate lastReg, BusinessDayAdjustment startBda, BusinessDayAdjustment endBda) { return PeriodicSchedule.builder() .startDate(start) .endDate(end) .frequency(freq) .businessDayAdjustment(bda) .startDateBusinessDayAdjustment(startBda) .endDateBusinessDayAdjustment(endBda) .stubConvention(stubConv) .rollConvention(rollConv) .firstRegularStartDate(firstReg) .lastRegularEndDate(lastReg) .build(); } public void coverage_builder() { PeriodicSchedule.Builder builder = PeriodicSchedule.builder(); builder .startDate(JUL_17) .endDate(SEP_17) .frequency(P2M) .businessDayAdjustment(BusinessDayAdjustment.NONE) .startDateBusinessDayAdjustment(BusinessDayAdjustment.NONE) .endDateBusinessDayAdjustment(BusinessDayAdjustment.NONE) .stubConvention(STUB_NONE) .rollConvention(EOM) .firstRegularStartDate(JUL_17) .lastRegularEndDate(SEP_17) .build(); } //------------------------------------------------------------------------- public void coverage() { BusinessDayAdjustment bda = BusinessDayAdjustment.of(BusinessDayConventions.FOLLOWING, HolidayCalendars.SAT_SUN); PeriodicSchedule defn = PeriodicSchedule.of( date(2014, JUNE, 4), date(2014, SEPTEMBER, 17), P1M, bda, SHORT_INITIAL, false); coverImmutableBean(defn); } public void test_serialization() { BusinessDayAdjustment bda = BusinessDayAdjustment.of(BusinessDayConventions.FOLLOWING, HolidayCalendars.SAT_SUN); PeriodicSchedule defn = PeriodicSchedule.of( date(2014, JUNE, 4), date(2014, SEPTEMBER, 17), P1M, bda, SHORT_INITIAL, false); assertSerialization(defn); } }