@Test
  public void shouldReturnLastAddedPeriodForASchedule() throws Exception {
    DateTime date1 = new DateTime();
    DateTime date2 = date1.plusMonths(3);

    ProcessingPeriod period1 =
        make(
            a(
                defaultProcessingPeriod,
                with(ProcessingPeriodBuilder.startDate, date1.toDate()),
                with(scheduleId, schedule.getId())));
    ProcessingPeriod period2 =
        make(
            a(
                defaultProcessingPeriod,
                with(ProcessingPeriodBuilder.startDate, date2.toDate()),
                with(scheduleId, schedule.getId()),
                with(name, "Month2")));

    mapper.insert(period1);
    mapper.insert(period2);

    ProcessingPeriod fetchedPeriod = mapper.getLastAddedProcessingPeriod(schedule.getId());
    assertThat(fetchedPeriod.getId(), is(period2.getId()));
  }
  @Test
  public void shouldReturnAllPeriodsForASchedule() throws Exception {
    DateTime date1 = new DateTime();
    DateTime date2 = date1.plusMonths(3);

    ProcessingPeriod period1 =
        make(
            a(
                defaultProcessingPeriod,
                with(ProcessingPeriodBuilder.startDate, date1.toDate()),
                with(scheduleId, schedule.getId())));
    ProcessingPeriod period2 =
        make(
            a(
                defaultProcessingPeriod,
                with(ProcessingPeriodBuilder.startDate, date2.toDate()),
                with(scheduleId, schedule.getId()),
                with(name, "Month2")));

    mapper.insert(period1);
    mapper.insert(period2);

    List<ProcessingPeriod> fetchedPeriods = mapper.getAll(schedule.getId());
    assertThat(fetchedPeriods.size(), is(2));
    assertThat(fetchedPeriods.get(0).getId(), is(period2.getId()));
  }
  @Test
  public void shouldGetAllPeriodsForPeriodDateRange() throws Exception {
    DateTime currentDate = DateTime.parse("2013-01-01");
    ProcessingPeriod period1 =
        make(
            a(
                defaultProcessingPeriod,
                with(ProcessingPeriodBuilder.startDate, currentDate.toDate()),
                with(ProcessingPeriodBuilder.endDate, currentDate.plusMonths(1).toDate()),
                with(scheduleId, schedule.getId()),
                with(name, "Month1")));
    ProcessingPeriod period2 =
        make(
            a(
                defaultProcessingPeriod,
                with(ProcessingPeriodBuilder.startDate, currentDate.plusMonths(1).toDate()),
                with(ProcessingPeriodBuilder.endDate, currentDate.plusMonths(2).toDate()),
                with(scheduleId, schedule.getId()),
                with(name, "Month2")));
    ProcessingPeriod period3 =
        make(
            a(
                defaultProcessingPeriod,
                with(ProcessingPeriodBuilder.startDate, currentDate.plusMonths(2).toDate()),
                with(ProcessingPeriodBuilder.endDate, currentDate.plusMonths(3).toDate()),
                with(scheduleId, schedule.getId()),
                with(name, "Month3")));
    ProcessingPeriod period4 =
        make(
            a(
                defaultProcessingPeriod,
                with(ProcessingPeriodBuilder.startDate, currentDate.plusDays(2).toDate()),
                with(ProcessingPeriodBuilder.endDate, currentDate.plusMonths(1).toDate()),
                with(scheduleId, schedule.getId()),
                with(name, "Month4")));
    ProcessingPeriod period5 =
        make(
            a(
                defaultProcessingPeriod,
                with(ProcessingPeriodBuilder.startDate, currentDate.minusDays(2).toDate()),
                with(ProcessingPeriodBuilder.endDate, currentDate.plusMonths(3).toDate()),
                with(scheduleId, schedule.getId()),
                with(name, "Month5")));

    mapper.insert(period1);
    mapper.insert(period2);
    mapper.insert(period3);
    mapper.insert(period4);
    mapper.insert(period5);
    DateTime searchStartDate = currentDate;
    DateTime searchEndDate = searchStartDate.plusDays(45);
    List<ProcessingPeriod> searchResults =
        mapper.getAllPeriodsForDateRange(
            schedule.getId(), searchStartDate.toDate(), searchEndDate.toDate());
    for (ProcessingPeriod period : searchResults) {
      period.setModifiedDate(null);
    }
    assertThat(searchResults, is(hasItems(period1, period2, period4, period5)));
    assertThat(searchResults, is(not(hasItems(period3))));
  }
  @Test
  public void shouldInsertPeriodWithAllData() throws Exception {
    Date date1 = new Date();
    Date date2 = new Date(date1.getTime() + 90 * 24 * 60 * 60 * 1000);

    ProcessingPeriod period1 =
        make(
            a(
                defaultProcessingPeriod,
                with(scheduleId, schedule.getId()),
                with(ProcessingPeriodBuilder.startDate, date1),
                with(endDate, date2),
                with(numberOfMonths, 3)));

    Integer insertCount = mapper.insert(period1);

    assertThat(insertCount, is(1));
    ProcessingPeriod insertedPeriod = mapper.getAll(schedule.getId()).get(0);
    assertThat(insertedPeriod.getName(), is("Month1"));
    assertThat(insertedPeriod.getDescription(), is("first month"));
    assertThat(insertedPeriod.getStartDate(), is(date1));
    assertThat(insertedPeriod.getEndDate(), is(date2));
    assertThat(insertedPeriod.getNumberOfMonths(), is(3));
    assertThat(insertedPeriod.getModifiedBy(), is(1L));
    assertThat(insertedPeriod.getModifiedDate(), is(notNullValue()));
  }
  @Test
  public void shouldReturnEmptyListIfNoPeriodFoundForGivenSchedule() throws Exception {
    ProcessingPeriod period1 = make(a(defaultProcessingPeriod, with(scheduleId, schedule.getId())));
    mapper.insert(period1);

    List<ProcessingPeriod> fetchedPeriods = mapper.getAll(1233L);
    assertTrue(fetchedPeriods.isEmpty());
  }
  @Test
  public void shouldGetPeriodById() {
    ProcessingPeriod processingPeriod =
        make(a(defaultProcessingPeriod, with(scheduleId, schedule.getId())));
    mapper.insert(processingPeriod);

    ProcessingPeriod period = mapper.getById(processingPeriod.getId());
    assertThat(period.getName(), is(processingPeriod.getName()));
  }
  @Test
  public void shouldDeleteAPeriod() {
    ProcessingPeriod processingPeriod =
        make(a(defaultProcessingPeriod, with(scheduleId, schedule.getId())));
    mapper.insert(processingPeriod);

    mapper.delete(processingPeriod.getId());
    assertThat(mapper.getAll(schedule.getId()).size(), is(0));
  }
  @Test
  public void shouldGetPeriodContainingADateForASchedule() throws Exception {
    Date currentDate = new Date();
    ProcessingPeriod period =
        make(
            a(
                defaultProcessingPeriod,
                with(startDate, addDays(currentDate, -1)),
                with(endDate, addDays(currentDate, 5)),
                with(scheduleId, schedule.getId()),
                with(name, "Month1")));
    mapper.insert(period);

    ProcessingPeriod periodForDate = mapper.getPeriodForDate(period.getScheduleId(), currentDate);

    assertThat(periodForDate, is(period));
  }
  @Test
  public void shouldGetAllPeriodsBeforeCurrentDate() throws Exception {
    DateTime currentDate = DateTime.parse("2013-01-01");
    ProcessingPeriod period1 =
        make(
            a(
                defaultProcessingPeriod,
                with(ProcessingPeriodBuilder.startDate, currentDate.toDate()),
                with(ProcessingPeriodBuilder.endDate, currentDate.plusMonths(1).toDate()),
                with(scheduleId, schedule.getId()),
                with(name, "Month1")));
    ProcessingPeriod period2 =
        make(
            a(
                defaultProcessingPeriod,
                with(ProcessingPeriodBuilder.startDate, currentDate.minusMonths(2).toDate()),
                with(ProcessingPeriodBuilder.endDate, currentDate.minusMonths(1).toDate()),
                with(scheduleId, schedule.getId()),
                with(name, "Month2")));
    ProcessingPeriod period3 =
        make(
            a(
                defaultProcessingPeriod,
                with(ProcessingPeriodBuilder.startDate, currentDate.minusMonths(1).toDate()),
                with(ProcessingPeriodBuilder.endDate, currentDate.plusMonths(1).toDate()),
                with(scheduleId, schedule.getId()),
                with(name, "Month3")));
    ProcessingPeriod period4 =
        make(
            a(
                defaultProcessingPeriod,
                with(ProcessingPeriodBuilder.startDate, currentDate.plusMonths(1).toDate()),
                with(ProcessingPeriodBuilder.endDate, currentDate.plusMonths(2).toDate()),
                with(scheduleId, schedule.getId()),
                with(name, "Month5")));

    mapper.insert(period1);
    mapper.insert(period2);
    mapper.insert(period3);
    mapper.insert(period4);
    List<ProcessingPeriod> searchResults = mapper.getAllPeriodsBefore(schedule.getId(), null);
    for (ProcessingPeriod period : searchResults) {
      period.setModifiedDate(null);
    }
    assertThat(searchResults, is(asList(period4, period1, period3, period2)));
  }
  @Test
  public void shouldNotInsertDuplicatePeriodName() throws Exception {
    ProcessingSchedule schedule2 = make(a(defaultProcessingSchedule, with(code, "XXX")));
    scheduleMapper.insert(schedule2);

    ProcessingPeriod period1 =
        make(a(defaultProcessingPeriod, with(scheduleId, schedule.getId()), with(name, "Month1")));
    ProcessingPeriod period2 =
        make(a(defaultProcessingPeriod, with(scheduleId, schedule2.getId()), with(name, "Month1")));
    ProcessingPeriod period3 =
        make(a(defaultProcessingPeriod, with(scheduleId, schedule2.getId()), with(name, "Month1")));
    expectedException.expect(DuplicateKeyException.class);
    expectedException.expectMessage("duplicate key value violates unique constraint");
    mapper.insert(period1);
    mapper.insert(period2);
    mapper.insert(period3);
  }
  @Test
  public void shouldReturnNullIfCurrentPeriodDoesNotExist() {
    Date currentDate = new Date();
    ProcessingPeriod period1 =
        make(
            a(
                defaultProcessingPeriod,
                with(startDate, addDays(currentDate, 2)),
                with(endDate, addDays(currentDate, 5)),
                with(scheduleId, schedule.getId()),
                with(name, "Month1")));

    mapper.insert(period1);

    ProcessingPeriod actualPeriod =
        mapper.getCurrentPeriod(schedule.getId(), period1.getStartDate());

    assertNull(actualPeriod);
  }
  @Test
  public void shouldNotGetCurrentPeriodIfProgramStartDateIsAfterCurrentPeriodEndDate() {
    Date currentDate = new Date();
    ProcessingPeriod period1 =
        make(
            a(
                defaultProcessingPeriod,
                with(startDate, addDays(currentDate, -1)),
                with(endDate, addDays(currentDate, 5)),
                with(scheduleId, schedule.getId()),
                with(name, "Month1")));

    mapper.insert(period1);

    Date programStartDate = addDays(period1.getStartDate(), 7);
    ProcessingPeriod actualPeriod = mapper.getCurrentPeriod(schedule.getId(), programStartDate);

    Assert.assertNull(actualPeriod);
  }
  @Test
  public void shouldGetCurrentPeriodByFacilityAndProgram() {
    Date currentDate = new Date();
    ProcessingPeriod period1 =
        make(
            a(
                defaultProcessingPeriod,
                with(startDate, addDays(currentDate, -1)),
                with(endDate, addDays(currentDate, 5)),
                with(scheduleId, schedule.getId()),
                with(name, "Month1")));

    mapper.insert(period1);

    ProcessingPeriod actualPeriod =
        mapper.getCurrentPeriod(schedule.getId(), period1.getStartDate());

    assertThat(actualPeriod, is(period1));
  }
  private ProcessingPeriod insertProcessingPeriod(
      String name, DateTime startDate, DateTime endDate) {
    ProcessingPeriod period =
        make(
            a(
                defaultProcessingPeriod,
                with(ProcessingPeriodBuilder.name, name),
                with(scheduleId, schedule.getId()),
                with(ProcessingPeriodBuilder.startDate, startDate.toDate()),
                with(ProcessingPeriodBuilder.endDate, endDate.toDate())));

    mapper.insert(period);
    return period;
  }
  @Test
  public void shouldGetNPreviousPeriodsGivenSpecificPeriod() throws Exception {
    DateTime now = DateTime.now();
    insertProcessingPeriod("Period1", now.minusDays(14), now.minusDays(13));
    ProcessingPeriod period2 =
        insertProcessingPeriod("Period2", now.minusDays(12), now.minusDays(11));
    ProcessingPeriod period3 =
        insertProcessingPeriod("Period3", now.minusDays(10), now.minusDays(9));
    ProcessingPeriod period4 =
        insertProcessingPeriod("Period4", now.minusDays(8), now.minusDays(7));
    ProcessingPeriod period5 =
        insertProcessingPeriod("Period5", now.minusDays(6), now.minusDays(5));
    ProcessingPeriod period6 =
        insertProcessingPeriod("Period6", now.minusDays(4), now.minusDays(3));
    ProcessingPeriod currentPeriod = insertProcessingPeriod("Period", now.minusDays(2), now);

    List<ProcessingPeriod> nPreviousPeriods = mapper.getNPreviousPeriods(currentPeriod, 5);

    assertThat(nPreviousPeriods, is(asList(period6, period5, period4, period3, period2)));
    assertThat(nPreviousPeriods.size(), is(5));
  }
  @Test
  public void shouldGetAllPeriodsAfterAGivenDate() throws Exception {
    DateTime date1 = new DateTime();
    DateTime date2 = date1.minusMonths(1);
    DateTime date3 = date1.minusMonths(2);
    DateTime date4 = date1.minusMonths(3);
    DateTime date5 = date1.minusMonths(4);
    DateTime futureDate = date1.plusMonths(1);

    insertProcessingPeriod("Period 1", date5, date4);
    ProcessingPeriod period2 = insertProcessingPeriod("Period 2", date4.plusDays(1), date3);
    ProcessingPeriod period3 = insertProcessingPeriod("Period 3", date3.plusDays(1), date2);
    ProcessingPeriod period4 = insertProcessingPeriod("Period 4", date2.plusDays(1), date1);
    insertProcessingPeriod("Period 5", date1.plusDays(1), futureDate);

    List<ProcessingPeriod> relevantPeriods =
        mapper.getAllPeriodsAfterDate(schedule.getId(), date3.toDate(), date1.toDate());

    assertThat(relevantPeriods.size(), is(3));
    assertThat(relevantPeriods.get(0).getId(), is(period2.getId()));
    assertThat(relevantPeriods.get(1).getId(), is(period3.getId()));
    assertThat(relevantPeriods.get(2).getId(), is(period4.getId()));
  }