Browse files

Finished Scenario Table tutorial.

  • Loading branch information...
1 parent 805de84 commit b30d94935c3cab606f879116d31e53d3f404f552 Brett L. Schuchert committed Apr 12, 2009
View
74 DVR/src/com/om/example/dvr/domain/Program.java
@@ -6,39 +6,43 @@
public class Program {
- public final String programName;
- public final String episodeName;
- public final TimeSlot timeSlot;
-
- public Program(String programName, String episodeName, TimeSlot timeSlot) {
- this.programName = programName;
- this.episodeName = episodeName;
- this.timeSlot = timeSlot;
- }
-
- public String getId() {
- return String.format("(%s:%d)", programName, timeSlot.channel);
- }
-
- public String getProgramName() {
- return programName;
- }
-
- public String getEpisodeName() {
- return episodeName;
- }
-
- public TimeSlot getTimeSlot() {
- return timeSlot;
- }
-
- public boolean sameEpisodeAs(Program program) {
- return timeSlot.channel == program.timeSlot.channel
- && programName.equals(program.programName)
- && episodeName.equals(program.episodeName);
- }
-
- public boolean isOn(Date date) {
- return DateUtil.instance().isSameDate(timeSlot.startDateTime, date);
- }
+ public final String programName;
+ public final String episodeName;
+ public final TimeSlot timeSlot;
+
+ public Program(String programName, String episodeName, TimeSlot timeSlot) {
+ this.programName = programName;
+ this.episodeName = episodeName;
+ this.timeSlot = timeSlot;
+ }
+
+ public String getId() {
+ return String.format("(%s:%d)", programName, timeSlot.channel);
+ }
+
+ public String getProgramName() {
+ return programName;
+ }
+
+ public String getEpisodeName() {
+ return episodeName;
+ }
+
+ public TimeSlot getTimeSlot() {
+ return timeSlot;
+ }
+
+ public boolean sameEpisodeAs(Program program) {
+ return timeSlot.channel == program.timeSlot.channel
+ && programName.equals(program.programName)
+ && episodeName.equals(program.episodeName);
+ }
+
+ public boolean isOn(Date date) {
+ return DateUtil.instance().isSameDate(timeSlot.startDateTime, date);
+ }
+
+ public boolean hasTimeConflictWith(Program other) {
+ return timeSlot.conflictsInTimeWith(other.timeSlot);
+ }
}
View
104 DVR/src/com/om/example/dvr/domain/SeasonPassManager.java
@@ -5,58 +5,82 @@
import java.util.List;
public class SeasonPassManager {
- private final Schedule schedule;
- private List<Program> toDoList = new LinkedList<Program>();
+ private final Schedule schedule;
+ private List<Program> toDoList = new LinkedList<Program>();
+ private int numberOfRecorders = 1;
- public SeasonPassManager(Schedule schedule) {
- this.schedule = schedule;
- }
+ public SeasonPassManager(Schedule schedule) {
+ this.schedule = schedule;
+ }
- public int sizeOfToDoList() {
- return toDoList.size();
- }
+ public void setNumberOfRecorders(int number) {
+ this.numberOfRecorders = number;
+ }
- public Program createNewSeasonPass(String programName, int channel) {
- List<Program> programsFound = schedule.findProgramsNamedOn(programName, channel);
+ public int sizeOfToDoList() {
+ return toDoList.size();
+ }
- for (Program current : programsFound)
- if (!alreadyInToDoList(current))
- toDoList.add(current);
+ public Program createNewSeasonPass(String programName, int channel) {
+ List<Program> programsFound = schedule.findProgramsNamedOn(programName,
+ channel);
- if (programsFound.size() > 0)
- return programsFound.get(0);
- return null;
- }
+ for (Program current : programsFound)
+ if (!alreadyInToDoList(current)
+ && !conflictsWithExistingSchedule(current))
+ toDoList.add(current);
- private boolean alreadyInToDoList(Program candidate) {
- for (Program current : toDoList)
- if (current.sameEpisodeAs(candidate))
- return true;
+ if (programsFound.size() > 0)
+ return programsFound.get(0);
+ return null;
+ }
- return false;
- }
+ private boolean conflictsWithExistingSchedule(Program program) {
+ int remainingConflicts = numberOfRecorders - 1;
- public Iterable<?> toDoListIterator() {
- return toDoList;
- }
+ for (Program current : toDoList)
+ if (current.hasTimeConflictWith(program)) {
+ --remainingConflicts;
+ if (remainingConflicts < 0)
+ return true;
+ }
- public List<Program> toDoListContentsFor(String programId) {
- List<Program> result = new LinkedList<Program>();
+ return remainingConflicts < 0;
+ }
- for (Program current : toDoList)
- if (current.getId().equals(programId))
- result.add(current);
+ private boolean alreadyInToDoList(Program candidate) {
+ for (Program current : toDoList)
+ if (current.sameEpisodeAs(candidate))
+ return true;
- return result;
- }
+ return false;
+ }
- public List<Program> toDoListContentsOn(Date date) {
- List<Program> result = new LinkedList<Program>();
+ public Iterable<?> toDoListIterator() {
+ return toDoList;
+ }
- for (Program current : toDoList)
- if (current.isOn(date))
- result.add(current);
+ public List<Program> toDoListContentsFor(String programId) {
+ List<Program> result = new LinkedList<Program>();
- return result;
- }
+ for (Program current : toDoList)
+ if (programId.length() == 0 || current.getId().equals(programId))
+ result.add(current);
+
+ return result;
+ }
+
+ public List<Program> toDoListContentsOn(Date date) {
+ List<Program> result = new LinkedList<Program>();
+
+ for (Program current : toDoList)
+ if (current.isOn(date))
+ result.add(current);
+
+ return result;
+ }
+
+ public void clearToDoList() {
+ toDoList.clear();
+ }
}
View
35 DVR/src/com/om/example/dvr/domain/TimeSlot.java
@@ -2,21 +2,30 @@
import java.util.Date;
+import com.om.example.util.DateUtil;
+
public class TimeSlot {
- public final int channel;
- public final Date startDateTime;
- public final int durationInMinutes;
+ public final int channel;
+ public final Date startDateTime;
+ public final int durationInMinutes;
+
+ public TimeSlot(int channel, Date startDateTime, int durationInMinutes) {
+ this.channel = channel;
+ this.startDateTime = startDateTime;
+ this.durationInMinutes = durationInMinutes;
+ }
- public TimeSlot(int channel, Date startDateTime, int durationInMinutes) {
- this.channel = channel;
- this.startDateTime = startDateTime;
- this.durationInMinutes = durationInMinutes;
- }
+ public boolean conflictsWith(TimeSlot other) {
+ if (channel == other.channel
+ && startDateTime.equals(other.startDateTime))
+ return true;
+ return false;
+ }
- public boolean conflictsWith(TimeSlot other) {
- if (channel == other.channel && startDateTime.equals(other.startDateTime))
- return true;
- return false;
- }
+ public boolean conflictsInTimeWith(TimeSlot other) {
+ return DateUtil.instance()
+ .segmentsConflict(startDateTime, durationInMinutes,
+ other.startDateTime, other.durationInMinutes);
+ }
}
View
102 DVR/src/com/om/example/dvr/fixtures/AddProgramsToSchedule.java
@@ -9,63 +9,67 @@
import com.om.example.util.DateUtil;
public class AddProgramsToSchedule {
- static SimpleDateFormat dateFormat = new SimpleDateFormat("M/d/yyyy|h:mm");
- private static Schedule schedule = new Schedule();
- private int channel;
- private String date;
- private String startTime;
- private int minutes;
- private String programName;
- private String episodeName;
- private String lastId;
- private boolean lastCreationSuccessful;
+ static SimpleDateFormat dateFormat = new SimpleDateFormat("M/d/yyyy|h:mm");
+ private static Schedule schedule = new Schedule();
+ private int channel;
+ private String date;
+ private String startTime;
+ private int minutes;
+ private String programName;
+ private String episodeName;
+ private String lastId;
+ private boolean lastCreationSuccessful;
- public static Schedule getSchedule() {
- return schedule;
- }
+ public static void resetSchedule() {
+ schedule = new Schedule();
+ }
- public void setName(String name) {
- this.programName = name;
- }
+ public static Schedule getSchedule() {
+ return schedule;
+ }
- public void setEpisode(String name) {
- this.episodeName = name;
- }
+ public void setName(String name) {
+ this.programName = name;
+ }
- public void setChannel(int channel) {
- this.channel = channel;
- }
+ public void setEpisode(String name) {
+ this.episodeName = name;
+ }
- public void setDate(String date) {
- this.date = date;
- }
+ public void setChannel(int channel) {
+ this.channel = channel;
+ }
- public void setStartTime(String startTime) {
- this.startTime = startTime;
- }
+ public void setDate(String date) {
+ this.date = date;
+ }
- public void setMinutes(int minutes) {
- this.minutes = minutes;
- }
+ public void setStartTime(String startTime) {
+ this.startTime = startTime;
+ }
- public void execute() throws ParseException {
- try {
- Program p = schedule.addProgram(programName, episodeName, channel, DateUtil
- .instance().buildDate(date, startTime), minutes);
- lastId = p.getId();
- lastCreationSuccessful = true;
- } catch (ConflictingProgramException e) {
- lastCreationSuccessful = false;
- }
- }
+ public void setMinutes(int minutes) {
+ this.minutes = minutes;
+ }
- public boolean created() {
- return lastCreationSuccessful;
- }
+ public void execute() throws ParseException {
+ try {
+ Program p = schedule.addProgram(programName, episodeName, channel,
+ DateUtil.instance().buildDate(date, startTime), minutes);
+ lastId = p.getId();
+ lastCreationSuccessful = true;
+ } catch (ConflictingProgramException e) {
+ lastCreationSuccessful = false;
+ }
+ }
- public String lastId() {
- if (lastCreationSuccessful)
- return lastId;
- return "n/a";
- }
+ public boolean created() {
+ return lastCreationSuccessful;
+ }
+
+ public String lastId() {
+ if (lastCreationSuccessful)
+ return lastId;
+ return "n/a";
+ }
}
View
8 DVR/src/com/om/example/dvr/fixtures/ClearProgramSchedule.java
@@ -1,7 +1,7 @@
package com.om.example.dvr.fixtures;
public class ClearProgramSchedule {
- public ClearProgramSchedule() {
- AddProgramsToSchedule.getSchedule().clear();
- }
-}
+ public ClearProgramSchedule() {
+ AddProgramsToSchedule.resetSchedule();
+ }
+}
View
7 DVR/src/com/om/example/dvr/fixtures/ClearToDoList.java
@@ -0,0 +1,7 @@
+package com.om.example.dvr.fixtures;
+
+public class ClearToDoList {
+ public ClearToDoList() {
+ CreateSeasonPassFor.resetSeasonPassManager();
+ }
+}
View
34 DVR/src/com/om/example/dvr/fixtures/CreateSeasonPassFor.java
@@ -4,21 +4,27 @@
import com.om.example.dvr.domain.SeasonPassManager;
public class CreateSeasonPassFor {
- private static SeasonPassManager seasonPassManager = new SeasonPassManager(
- AddProgramsToSchedule.getSchedule());
- private Program lastProgramFound;
+ private static SeasonPassManager seasonPassManager = new SeasonPassManager(
+ AddProgramsToSchedule.getSchedule());
+ private Program lastProgramFound;
- public static SeasonPassManager getSeasonPassManager() {
- return seasonPassManager;
- }
+ public static SeasonPassManager getSeasonPassManager() {
+ return seasonPassManager;
+ }
- public CreateSeasonPassFor(String programName, int channel) {
- lastProgramFound = seasonPassManager.createNewSeasonPass(programName, channel);
- }
+ public static void resetSeasonPassManager() {
+ seasonPassManager = new SeasonPassManager(AddProgramsToSchedule
+ .getSchedule());
+ }
- public String idOfProgramScheduled() {
- if (lastProgramFound != null)
- return lastProgramFound.getId();
- return "n/a";
- }
+ public CreateSeasonPassFor(String programName, int channel) {
+ lastProgramFound = seasonPassManager.createNewSeasonPass(programName,
+ channel);
+ }
+
+ public String idOfProgramScheduled() {
+ if (lastProgramFound != null)
+ return lastProgramFound.getId();
+ return "n/a";
+ }
}
View
106 DVR/src/com/om/example/dvr/fixtures/DvrRecording.java
@@ -0,0 +1,106 @@
+package com.om.example.dvr.fixtures;
+
+import java.util.Iterator;
+import java.util.List;
+
+import com.om.example.dvr.domain.Program;
+
+public class DvrRecording {
+ public void givenDvrCanRecord(int number) {
+ CreateSeasonPassFor.getSeasonPassManager().setNumberOfRecorders(number);
+ }
+
+ public void whenICreateSeasonPasses(String listOfSeasonPasses) {
+ String[] individualSeasonPasses = listOfSeasonPasses.split(",");
+
+ for (String programNameChannel : individualSeasonPasses)
+ addOneSeasonPass(programNameChannel);
+ }
+
+ private void addOneSeasonPass(String programNameChannel) {
+ String[] parts = programNameChannel.split(":");
+
+ String programName = parts[0];
+ int channel = Integer.parseInt(parts[1]);
+
+ new CreateSeasonPassFor(programName, channel);
+ }
+
+ public boolean thenTheToDoListShouldContain(String listOfEpisodes) {
+ List<Program> toDoList = CreateSeasonPassFor.getSeasonPassManager()
+ .toDoListContentsFor("");
+
+ String[] episodesSets = listOfEpisodes.split(",");
+
+ for (String episodeSet : episodesSets)
+ if (!removeAllFrom(episodeSet, toDoList))
+ return false;
+
+ return toDoList.size() == 0;
+ }
+
+ private boolean removeAllFrom(String episodeSet, List<Program> toDoList) {
+ String programName = extractProgramNameFrom(episodeSet);
+ String baseEpisodeName = extractBaseNameFrom(episodeSet);
+ int lowerRange = extractLowerRangeFrom(episodeSet);
+ int upperRange = extractUpperRangeFrom(episodeSet);
+
+ for (int episodeNumber = lowerRange; episodeNumber <= upperRange; ++episodeNumber)
+ if (!remove(programName, baseEpisodeName, episodeNumber, toDoList))
+ return false;
+
+ return true;
+ }
+
+ private String extractProgramNameFrom(String episodeSet) {
+ return episodeSet.split(":")[0];
+ }
+
+ private String extractBaseNameFrom(String episodeSet) {
+ String[] values = episodeSet.split(":");
+
+ String result = "";
+ if (values.length > 1)
+ result = values[1];
+
+ return result;
+ }
+
+ private int extractLowerRangeFrom(String episodeSet) {
+ String[] values = episodeSet.split(":");
+ if (values.length > 2) {
+ String lowRange = episodeSet.split(":")[2].split("-")[0];
+ return Integer.parseInt(lowRange);
+ }
+ return 0;
+ }
+
+ private int extractUpperRangeFrom(String episodeSet) {
+ String[] values = episodeSet.split(":");
+ if (values.length > 2) {
+ String highRange = episodeSet.split(":")[2].split("-")[1];
+ return Integer.parseInt(highRange);
+ }
+ return -1;
+ }
+
+ private boolean remove(String programName, String baseEpisodeName,
+ int episodeNumber, List<Program> toDoList) {
+ String episodeName = String.format("%s%d", baseEpisodeName,
+ episodeNumber);
+
+ for (Iterator<Program> iter = toDoList.iterator(); iter.hasNext();) {
+ if (matches(iter.next(), programName, episodeName)) {
+ iter.remove();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean matches(Program current, String programName,
+ String episodeName) {
+ return programName.equals(current.programName)
+ && episodeName.equals(current.episodeName);
+ }
+}
View
28 DVR/src/com/om/example/dvr/fixtures/EpisodesInToDoList.java
@@ -7,18 +7,22 @@
import com.om.query.domain.QueryResult;
public class EpisodesInToDoList {
- private final String programId;
+ private final String programId;
- public EpisodesInToDoList(String programId) {
- this.programId = programId;
- }
+ public EpisodesInToDoList() {
+ programId = "";
+ }
- public List<Object> query() {
- List<Program> programs = CreateSeasonPassFor.getSeasonPassManager()
- .toDoListContentsFor(programId);
- QueryResultBuilder builder = new QueryResultBuilder(Program.class);
- builder.register("timeSlot", new TimeSlotPropertyHandler());
- QueryResult result = builder.build(programs);
- return result.render();
- }
+ public EpisodesInToDoList(String programId) {
+ this.programId = programId;
+ }
+
+ public List<Object> query() {
+ List<Program> programs = CreateSeasonPassFor.getSeasonPassManager()
+ .toDoListContentsFor(programId);
+ QueryResultBuilder builder = new QueryResultBuilder(Program.class);
+ builder.register("timeSlot", new TimeSlotPropertyHandler());
+ QueryResult result = builder.build(programs);
+ return result.render();
+ }
}
View
2 DVR/src/com/om/example/dvr/fixtures/GenerateProgramsTest.java
@@ -37,7 +37,7 @@ public void ReviewToDoListByDay() throws Exception {
List<Program> results = CreateSeasonPassFor.getSeasonPassManager()
.toDoListContentsOn(DateUtil.instance().formatDate("3/4/2008"));
- assertEquals(4, results.size());
+ assertEquals(3, results.size());
}
@Test(expected = ConflictingProgramException.class)
View
97 DVR/src/com/om/example/util/DateUtil.java
@@ -6,49 +6,78 @@
import java.util.Date;
public class DateUtil {
- private static DateUtil INSTANCE = new DateUtil();
+ private static DateUtil INSTANCE = new DateUtil();
- private DateUtil() {
- }
+ private DateUtil() {
+ }
- public static DateUtil instance() {
- return INSTANCE;
- }
+ public static DateUtil instance() {
+ return INSTANCE;
+ }
- public static final SimpleDateFormat dateFormat = new SimpleDateFormat("M/d/yyyy");
+ public static final SimpleDateFormat dateFormat = new SimpleDateFormat(
+ "M/d/yyyy");
- public Date formatDate(String date) throws ParseException {
- return dateFormat.parse(date);
- }
+ public Date formatDate(String date) throws ParseException {
+ return dateFormat.parse(date);
+ }
- public String formatDate(Date startDateTime) {
- return dateFormat.format(startDateTime);
- }
+ public String formatDate(Date startDateTime) {
+ return dateFormat.format(startDateTime);
+ }
- static SimpleDateFormat timeFormat = new SimpleDateFormat("h:mm");
+ static SimpleDateFormat timeFormat = new SimpleDateFormat("H:mm");
- public String formatTime(Date startDateTime) {
- return timeFormat.format(startDateTime);
- }
+ public String formatTime(Date startDateTime) {
+ return timeFormat.format(startDateTime);
+ }
- public String addDaysTo(int days, String nextStartDate) throws ParseException {
- Calendar calendar = Calendar.getInstance();
- calendar.clear();
- Date startingDate = dateFormat.parse(nextStartDate);
- calendar.setTime(startingDate);
- calendar.add(Calendar.DATE, days);
- return dateFormat.format(calendar.getTime());
- }
+ public String addDaysTo(int days, String nextStartDate)
+ throws ParseException {
+ Calendar calendar = Calendar.getInstance();
+ calendar.clear();
+ Date startingDate = dateFormat.parse(nextStartDate);
+ calendar.setTime(startingDate);
+ calendar.add(Calendar.DATE, days);
+ return dateFormat.format(calendar.getTime());
+ }
- public static final SimpleDateFormat dateTimeMergedFormat = new SimpleDateFormat(
- "M/d/yyyy|h:mm");
+ public static final SimpleDateFormat dateTimeMergedFormat = new SimpleDateFormat(
+ "M/d/yyyy|h:mm");
- public Date buildDate(String date, String startTime) throws ParseException {
- String dateTime = String.format("%s|%s", date, startTime);
- return dateTimeMergedFormat.parse(dateTime);
- }
+ public Date buildDate(String date, String startTime) throws ParseException {
+ String dateTime = String.format("%s|%s", date, startTime);
+ return dateTimeMergedFormat.parse(dateTime);
+ }
- public boolean isSameDate(Date startDateTime, Date date) {
- return formatDate(startDateTime).equals(formatDate(date));
- }
+ public boolean isSameDate(Date startDateTime, Date date) {
+ return formatDate(startDateTime).equals(formatDate(date));
+ }
+
+ public Date createEndDate(Date startDateTime, int durationInMinutes) {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(startDateTime);
+ calendar.add(Calendar.MINUTE, durationInMinutes);
+ return calendar.getTime();
+ }
+
+ public boolean segmentsConflict(Date lhs, int lhsDurationMins, Date rhs,
+ int rhsDurationMins) {
+ Date lhsEnd = createEndDate(lhs, lhsDurationMins);
+ Date rhsEnd = createEndDate(rhs, rhsDurationMins);
+
+ return isOnToJustBefore(lhs, rhs, rhsEnd)
+ || isStrictlyWithin(lhsEnd, rhs, rhsEnd)
+ || isOnToJustBefore(rhs, lhs, lhsEnd)
+ || isStrictlyWithin(rhsEnd, lhs, lhsEnd);
+ }
+
+ private boolean isOnToJustBefore(Date date, Date rangeBegin, Date rangeEnd) {
+ return date.equals(rangeBegin)
+ || (date.after(rangeBegin) && date.before(rangeEnd));
+ }
+
+ private boolean isStrictlyWithin(Date date, Date rangeBegin, Date rangeEnd) {
+ return date.after(rangeBegin) && date.before(rangeEnd);
+ }
}
View
65 DVR/src/com/om/example/util/DateUtilConflictsInTimeWithTest.java
@@ -0,0 +1,65 @@
+package com.om.example.util;
+
+import static org.junit.Assert.assertEquals;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class DateUtilConflictsInTimeWithTest {
+ private final String message;
+ private Date lhsDate;
+ private int lhsDuration;
+ private Date rhsDate;
+ private int rhsDuration;
+ private final boolean expected;
+
+ @Parameters
+ public static Collection<?> parameters() {
+ ArrayList<Object[]> v = new ArrayList<Object[]>();
+ v.add(new Object[] { "rhs inside lhs", "1/2/2008", "20:00", 60,
+ "1/2/2008", "20:30", 1, true });
+ v.add(new Object[] { "unrelated times", "1/2/2008", "20:00", 60,
+ "1/2/2008", "10:00", 60, false });
+ v.add(new Object[] { "same times", "1/2/2008", "20:00", 60, "1/2/2008",
+ "20:00", 60, true });
+ v.add(new Object[] { "lhs offset by 30 mins on rhs", "1/2/2008",
+ "20:00", 60, "1/2/2008", "20:30", 60, true });
+ v.add(new Object[] { "different dates", "1/4/2008", "20:00", 60,
+ "1/2/2008", "20:30", 60, false });
+ v.add(new Object[] { "lhs just ends before rhs", "1/2/2008", "20:00",
+ 60, "1/2/2008", "21:00", 60, false });
+ return v;
+ }
+
+ public DateUtilConflictsInTimeWithTest(String message, String lhsDate,
+ String lhsTime, int lhsDuration, String rhsDate, String rhsTime,
+ int rhsDuration, boolean expected) throws ParseException {
+ this.message = message;
+ this.lhsDuration = lhsDuration;
+ this.rhsDuration = rhsDuration;
+ this.expected = expected;
+
+ this.lhsDate = DateUtil.instance().buildDate(lhsDate, lhsTime);
+ this.rhsDate = DateUtil.instance().buildDate(rhsDate, rhsTime);
+ }
+
+ @Test
+ public void lhsComparedToRhs() {
+ assertEquals(message, expected, DateUtil.instance().segmentsConflict(
+ lhsDate, lhsDuration, rhsDate, rhsDuration));
+ }
+
+ @Test
+ public void rhsComparedToLhs() {
+ assertEquals(message, expected, DateUtil.instance().segmentsConflict(
+ rhsDate, rhsDuration, lhsDate, lhsDuration));
+ }
+}

0 comments on commit b30d949

Please sign in to comment.