Schedule
is a simple class that could be used in program to manage when a task should be repeated (a todo list, for example). Its constructor requires a start date and an optional end date, then type of repetition (daily, weekly or monthly) has to be set. If weekly is chosen, then the days of weeks when repetition occurs has to be set too. This is a simple exercise I made to practice test driven development. All test passes, so I guess it works as expected. Any suggestion about how to improve tests will be very appreciated (but any other are welcome too).
This is the class:
public class Schedule {
public enum REPETITION {
NONE, DAILY, WEEKLY, MONTHLY
}
public enum DAY_OF_WEEK {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
Date dateStart;
Date dateStop;
REPETITION repetitionType = REPETITION.NONE;
EnumSet<DAY_OF_WEEK> daysOfWeek = EnumSet.noneOf(DAY_OF_WEEK.class);
public Schedule(Date dateStart, Date dateStop){
if (dateStop != null){
if (dateStart.after(dateStop))
throw new IllegalArgumentException("Date start after date stop.");
this.dateStop = new Date(dateStop.getTime());
}
this.dateStart = new Date(dateStart.getTime());
}
/**
*
* @param dateToCheck
* @return true if repetition is expected int the day to check
*/
public boolean checkDateValid(Date dateToCheck){
if (dateToCheck == null)
return false;
try {
checkDateBetweenLimits(dateToCheck);
if (repetitionType != null){
switch (repetitionType){
case WEEKLY: checkWeekRepetition(dateToCheck); break;
case MONTHLY: checkMonthRepetition(dateToCheck); break;
default:
}
}
}
catch (IllegalArgumentException ex){
return false;
}
return true;
}
public void checkDateBetweenLimits(Date dateToCheck) throws IllegalArgumentException{
if (dateToCheck.before(dateStart))
throw new IllegalArgumentException("Date before limit");
if (dateStop != null && dateToCheck.after(dateStop))
throw new IllegalArgumentException("Date after limit");
}
public void checkMonthRepetition(Date dateToCheck) throws IllegalArgumentException{
Calendar calendar = Calendar.getInstance();
calendar.setTime(dateToCheck);
int dayOfWeekToValidate = calendar.get(Calendar.DAY_OF_MONTH);
calendar = Calendar.getInstance();
calendar.setTime(dateStart);
int dayOfWeek = calendar.get(Calendar.DAY_OF_MONTH);
if (dayOfWeek != dayOfWeekToValidate){
throw new IllegalArgumentException("Not same day of month.");
}
}
private void checkWeekRepetition(Date dateToCheck) throws IllegalArgumentException{
DAY_OF_WEEK day = evaluateDayOfWeek(dateToCheck);
if (!daysOfWeek.contains(day))
throw new IllegalArgumentException("No repetition in this day of week.");
}
private DAY_OF_WEEK evaluateDayOfWeek(Date date){
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
switch (dayOfWeek){
case Calendar.MONDAY: return DAY_OF_WEEK.MONDAY;
case Calendar.TUESDAY: return DAY_OF_WEEK.TUESDAY;
case Calendar.WEDNESDAY: return DAY_OF_WEEK.WEDNESDAY;
case Calendar.THURSDAY: return DAY_OF_WEEK.THURSDAY;
case Calendar.FRIDAY: return DAY_OF_WEEK.FRIDAY;
case Calendar.SATURDAY: return DAY_OF_WEEK.SATURDAY;
case Calendar.SUNDAY: return DAY_OF_WEEK.SUNDAY;
default: throw new IllegalArgumentException("Unexpected value.");
}
}
public Date getDateStop() {
return dateStop;
}
public Date getDateStart() {
return dateStart;
}
public void setRepetitionType(REPETITION repetitionType) {
this.repetitionType = repetitionType;
}
public void addDayOfWeek(DAY_OF_WEEK day) {
daysOfWeek.add(day);
}
public void removeDayOfWeek(DAY_OF_WEEK day){
daysOfWeek.remove(day);
}
}
This is the test class (Junit4):
public class ScheduleTest {
Date mon = new Date(2014, 0, 5);
Date tue = new Date(2014, 0, 6);
Date wed = new Date(2014, 0, 7);
Date thu = new Date(2014, 0, 8);
Date fri = new Date(2014, 0, 9);
Date sat = new Date(2014, 0, 10);
Date sun = new Date(2014, 0, 11);
Date firstOf2014 = new Date(2014, 0, 1);
Date lastOf2014 = new Date(2014, 11, 31);
Date today = GregorianCalendar.getInstance().getTime();
Date tomorrow = new Date(today.getTime() + (1000L * 3600 * 24));
Date nextMonth = new Date(today.getTime() + (1000L * 3600 * 24 * 31));
Date prevMonth = new Date(today.getTime() - (1000L * 3600 * 24 * 31));
Schedule scheduleTodayTomorrow = new Schedule(today, tomorrow);
@Test
public void testDateStartBeforeDateStop(){
try{
scheduleTodayTomorrow = new Schedule(tomorrow, today);
Assert.fail("Should throw IllegalArgumentException when dateStart after dateStop.");
}
catch (IllegalArgumentException ex){
//OK
}
}
@Test
public void testDateStopCanBeNull(){
Schedule schedule = new Schedule(today, null);
}
@Test
public void testDefensiveCopy(){
long todayTime = today.getTime();
today.setTime(1000);
Assert.assertEquals(todayTime, scheduleTodayTomorrow.getDateStart().getTime());
long tomorrowTime = tomorrow.getTime();
tomorrow.setTime(1000);
Assert.assertEquals(tomorrowTime, scheduleTodayTomorrow.getDateStop().getTime());
}
@Test
public void testDateValidity(){
Assert.assertTrue(scheduleTodayTomorrow.checkDateValid(today));
Assert.assertTrue(scheduleTodayTomorrow.checkDateValid(tomorrow));
Assert.assertFalse(scheduleTodayTomorrow.checkDateValid(prevMonth));
Assert.assertFalse(scheduleTodayTomorrow.checkDateValid(nextMonth));
Date inDate = new Date(today.getTime() + 1000L);
Assert.assertTrue(scheduleTodayTomorrow.checkDateValid(inDate));
}
@Test
public void testDailyRepetition(){
Schedule schedule = new Schedule(today, nextMonth);
schedule.setRepetitionType(Schedule.REPETITION.DAILY);
Assert.assertTrue(schedule.checkDateValid(today));
Assert.assertTrue(schedule.checkDateValid(tomorrow));
Assert.assertTrue(schedule.checkDateValid(nextMonth));
}
@Test
public void testMonthRepetition(){
Schedule schedule = new Schedule(firstOf2014, lastOf2014);
schedule.setRepetitionType(Schedule.REPETITION.MONTHLY);
// As the scheduleTodayTomorrow starts on 1/1, then every first day of months should be valid
for (int i=1; i<=11; i++){
Date date = new Date(2014, i, 1);
Assert.assertTrue("Valid date with month " + i + " treated as invalid.", schedule.checkDateValid(date));
}
// Every other days of every month are invalid
for (int i=1; i<=11; i++){
Date date = new Date(2014, i, 2);
Assert.assertFalse("Invalid date with month " + i + " treated as valid.", schedule.checkDateValid(date));
}
}
@Test
public void testWeekRepetitionNoValidDateAsDefault(){
Schedule schedule = new Schedule(firstOf2014, lastOf2014);
schedule.setRepetitionType(Schedule.REPETITION.WEEKLY);
Assert.assertFalse(schedule.checkDateValid(mon));
Assert.assertFalse(schedule.checkDateValid(tue));
Assert.assertFalse(schedule.checkDateValid(wed));
Assert.assertFalse(schedule.checkDateValid(thu));
Assert.assertFalse(schedule.checkDateValid(fri));
Assert.assertFalse(schedule.checkDateValid(sat));
Assert.assertFalse(schedule.checkDateValid(sun));
}
@Test
public void testWeekRepetitionAddMonday(){
Schedule schedule = new Schedule(firstOf2014, lastOf2014);
schedule.setRepetitionType(Schedule.REPETITION.WEEKLY);
schedule.addDayOfWeek(Schedule.DAY_OF_WEEK.MONDAY);
Assert.assertTrue(schedule.checkDateValid(mon));
Assert.assertFalse(schedule.checkDateValid(tue));
Assert.assertFalse(schedule.checkDateValid(wed));
Assert.assertFalse(schedule.checkDateValid(thu));
Assert.assertFalse(schedule.checkDateValid(fri));
Assert.assertFalse(schedule.checkDateValid(sat));
Assert.assertFalse(schedule.checkDateValid(sun));
}
@Test
public void testWeekRepetitionAddTuesday(){
Schedule schedule = new Schedule(firstOf2014, lastOf2014);
schedule.setRepetitionType(Schedule.REPETITION.WEEKLY);
schedule.addDayOfWeek(Schedule.DAY_OF_WEEK.TUESDAY);
Assert.assertTrue(schedule.checkDateValid(tue));
Assert.assertFalse(schedule.checkDateValid(mon));
Assert.assertFalse(schedule.checkDateValid(wed));
Assert.assertFalse(schedule.checkDateValid(thu));
Assert.assertFalse(schedule.checkDateValid(fri));
Assert.assertFalse(schedule.checkDateValid(sat));
Assert.assertFalse(schedule.checkDateValid(sun));
}
@Test
public void testWeekRepetitionAddWednesday(){
Schedule schedule = new Schedule(firstOf2014, lastOf2014);
schedule.setRepetitionType(Schedule.REPETITION.WEEKLY);
schedule.addDayOfWeek(Schedule.DAY_OF_WEEK.WEDNESDAY);
Assert.assertTrue(schedule.checkDateValid(wed));
Assert.assertFalse(schedule.checkDateValid(mon));
Assert.assertFalse(schedule.checkDateValid(tue));
Assert.assertFalse(schedule.checkDateValid(thu));
Assert.assertFalse(schedule.checkDateValid(fri));
Assert.assertFalse(schedule.checkDateValid(sat));
Assert.assertFalse(schedule.checkDateValid(sun));
}
@Test
public void testWeekRepetitionAddThursday(){
Schedule schedule = new Schedule(firstOf2014, lastOf2014);
schedule.setRepetitionType(Schedule.REPETITION.WEEKLY);
schedule.addDayOfWeek(Schedule.DAY_OF_WEEK.THURSDAY);
Assert.assertTrue(schedule.checkDateValid(thu));
Assert.assertFalse(schedule.checkDateValid(mon));
Assert.assertFalse(schedule.checkDateValid(tue));
Assert.assertFalse(schedule.checkDateValid(wed));
Assert.assertFalse(schedule.checkDateValid(fri));
Assert.assertFalse(schedule.checkDateValid(sat));
Assert.assertFalse(schedule.checkDateValid(sun));
}
@Test
public void testWeekRepetitionAddFriday(){
Schedule schedule = new Schedule(firstOf2014, lastOf2014);
schedule.setRepetitionType(Schedule.REPETITION.WEEKLY);
schedule.addDayOfWeek(Schedule.DAY_OF_WEEK.FRIDAY);
Assert.assertTrue(schedule.checkDateValid(fri));
Assert.assertFalse(schedule.checkDateValid(mon));
Assert.assertFalse(schedule.checkDateValid(tue));
Assert.assertFalse(schedule.checkDateValid(wed));
Assert.assertFalse(schedule.checkDateValid(thu));
Assert.assertFalse(schedule.checkDateValid(sat));
Assert.assertFalse(schedule.checkDateValid(sun));
}
@Test
public void testWeekRepetitionAddSaturday(){
Schedule schedule = new Schedule(firstOf2014, lastOf2014);
schedule.setRepetitionType(Schedule.REPETITION.WEEKLY);
schedule.addDayOfWeek(Schedule.DAY_OF_WEEK.SATURDAY);
Assert.assertTrue(schedule.checkDateValid(sat));
Assert.assertFalse(schedule.checkDateValid(mon));
Assert.assertFalse(schedule.checkDateValid(tue));
Assert.assertFalse(schedule.checkDateValid(wed));
Assert.assertFalse(schedule.checkDateValid(thu));
Assert.assertFalse(schedule.checkDateValid(fri));
Assert.assertFalse(schedule.checkDateValid(sun));
}
@Test
public void testWeekRepetitionAddSunday(){
Schedule schedule = new Schedule(firstOf2014, lastOf2014);
schedule.setRepetitionType(Schedule.REPETITION.WEEKLY);
schedule.addDayOfWeek(Schedule.DAY_OF_WEEK.SUNDAY);
Assert.assertTrue(schedule.checkDateValid(sun));
Assert.assertFalse(schedule.checkDateValid(mon));
Assert.assertFalse(schedule.checkDateValid(tue));
Assert.assertFalse(schedule.checkDateValid(wed));
Assert.assertFalse(schedule.checkDateValid(thu));
Assert.assertFalse(schedule.checkDateValid(fri));
Assert.assertFalse(schedule.checkDateValid(sat));
}
@Test
public void testWeekRepetitionAddMultipleDays(){
Schedule schedule = new Schedule(firstOf2014, lastOf2014);
schedule.setRepetitionType(Schedule.REPETITION.WEEKLY);
schedule.addDayOfWeek(Schedule.DAY_OF_WEEK.MONDAY);
schedule.addDayOfWeek(Schedule.DAY_OF_WEEK.WEDNESDAY);
schedule.addDayOfWeek(Schedule.DAY_OF_WEEK.FRIDAY);
Assert.assertTrue(schedule.checkDateValid(mon));
Assert.assertTrue(schedule.checkDateValid(wed));
Assert.assertTrue(schedule.checkDateValid(fri));
Assert.assertFalse(schedule.checkDateValid(tue));
Assert.assertFalse(schedule.checkDateValid(thu));
Assert.assertFalse(schedule.checkDateValid(sat));
Assert.assertFalse(schedule.checkDateValid(sun));
}
@Test
public void testWeekRepetitionAddAndRemoveDays(){
Schedule schedule = new Schedule(firstOf2014, lastOf2014);
schedule.setRepetitionType(Schedule.REPETITION.WEEKLY);
schedule.addDayOfWeek(Schedule.DAY_OF_WEEK.MONDAY);
schedule.addDayOfWeek(Schedule.DAY_OF_WEEK.WEDNESDAY);
schedule.addDayOfWeek(Schedule.DAY_OF_WEEK.FRIDAY);
Assert.assertTrue(schedule.checkDateValid(mon));
Assert.assertTrue(schedule.checkDateValid(wed));
Assert.assertTrue(schedule.checkDateValid(fri));
schedule.removeDayOfWeek(Schedule.DAY_OF_WEEK.MONDAY);
Assert.assertFalse(schedule.checkDateValid(mon));
Assert.assertTrue(schedule.checkDateValid(wed));
Assert.assertTrue(schedule.checkDateValid(fri));
schedule.removeDayOfWeek(Schedule.DAY_OF_WEEK.WEDNESDAY);
Assert.assertFalse(schedule.checkDateValid(mon));
Assert.assertFalse(schedule.checkDateValid(wed));
Assert.assertTrue(schedule.checkDateValid(fri));
schedule.removeDayOfWeek(Schedule.DAY_OF_WEEK.FRIDAY);
Assert.assertFalse(schedule.checkDateValid(mon));
Assert.assertFalse(schedule.checkDateValid(wed));
Assert.assertFalse(schedule.checkDateValid(fri));
}
}