From 288dee12dfe3ce16941e61c2cf0a87966043f0de Mon Sep 17 00:00:00 2001 From: Cindy Li Date: Thu, 18 Jun 2020 12:39:30 +0000 Subject: [PATCH] add test cases for optional guests cases, adjusted code to handle optional guests --- .../java/com/google/sps/FindMeetingQuery.java | 89 +++++++-- .../com/google/sps/FindMeetingQueryTest.java | 184 ++++++++++++++++++ 2 files changed, 252 insertions(+), 21 deletions(-) diff --git a/walkthroughs/week-5-tdd/project/src/main/java/com/google/sps/FindMeetingQuery.java b/walkthroughs/week-5-tdd/project/src/main/java/com/google/sps/FindMeetingQuery.java index 4efaf63..f387f5d 100644 --- a/walkthroughs/week-5-tdd/project/src/main/java/com/google/sps/FindMeetingQuery.java +++ b/walkthroughs/week-5-tdd/project/src/main/java/com/google/sps/FindMeetingQuery.java @@ -39,44 +39,91 @@ public int compare(Event a, Event b) { Collections.sort(eventsArray, compareByEventStart); + Collection requestedEventAttendees = request.getAttendees(); + // collection of available meeting times - Collection openTimes = new ArrayList<>(); + Collection openTimesRequiredAttendees = new ArrayList<>(); + Collection openTimesOptionalAttendees = new ArrayList<>(); + + // keep track of when the next block of free time starts for requried + // attendees and optional attendees + int requiredAttendeesStart = TimeRange.START_OF_DAY; + int optionalAttendeesStart = TimeRange.START_OF_DAY; - // initial available time: the entire day - int start = TimeRange.START_OF_DAY; int end = TimeRange.END_OF_DAY; for (Event event: eventsArray) { - TimeRange tryTime = TimeRange.fromStartEnd(start, end, true); + // try largest block of free time + TimeRange tryTime = TimeRange.fromStartEnd(requiredAttendeesStart, end, true); if (tryTime.overlaps(event.getWhen())) { - // get lists of event attendees - Collection requestedEventAttendees = request.getAttendees(); - Set scheduledEventAttendees = event.getAttendees(); - - for (String attendee: requestedEventAttendees) { - // check for overlapping attendees - if (scheduledEventAttendees.contains(attendee)) { - int newEnd = event.getWhen().start(); - - // see if meeting can be scheduled between start and conflicting event - if (newEnd - start >= request.getDuration()) { - openTimes.add(TimeRange.fromStartEnd(start, newEnd, false)); + // get lists of the current event attendees + Set eventAttendees = event.getAttendees(); + + + if (checkConflictingAttendees(requestedEventAttendees, eventAttendees)) { + int endOfFreeTime = event.getWhen().start(); + if (endOfFreeTime - requiredAttendeesStart >= request.getDuration()) { + openTimesRequiredAttendees.add(TimeRange.fromStartEnd(requiredAttendeesStart, endOfFreeTime, false)); + } + + if (endOfFreeTime - optionalAttendeesStart >= request.getDuration()) { + openTimesOptionalAttendees.add(TimeRange.fromStartEnd(optionalAttendeesStart, endOfFreeTime, false)); + } + + requiredAttendeesStart = event.getWhen().end(); + + if (optionalAttendeesStart < event.getWhen().end()) { + optionalAttendeesStart = event.getWhen().end(); + } + + } else { + // required attendees are all free, check if optional attendees are also free + Collection optionalEventAttendees = request.getOptionalAttendees(); + if (checkConflictingAttendees(optionalEventAttendees, eventAttendees)) { + int endOfFreeTime = event.getWhen().start(); + if (endOfFreeTime - optionalAttendeesStart >= request.getDuration()) { + openTimesOptionalAttendees.add(TimeRange.fromStartEnd(optionalAttendeesStart, endOfFreeTime, false)); } - start = event.getWhen().end(); - break; + optionalAttendeesStart = event.getWhen().end(); } + } + } } // see if meeting can be scheduled from start to end of day - if (end - start >= request.getDuration()) { - openTimes.add(TimeRange.fromStartEnd(start, end, true)); + if (end - requiredAttendeesStart >= request.getDuration()) { + openTimesRequiredAttendees.add(TimeRange.fromStartEnd(requiredAttendeesStart, end, true)); + } + + if (end - optionalAttendeesStart >= request.getDuration()) { + openTimesOptionalAttendees.add(TimeRange.fromStartEnd(optionalAttendeesStart, end, true)); + } + + if (openTimesOptionalAttendees.isEmpty()) { + if (requestedEventAttendees.isEmpty()) { + return new ArrayList<>(); + } + return openTimesRequiredAttendees; + } else { + return openTimesOptionalAttendees; } + } + + public boolean checkConflictingAttendees(Collection eventAttendees, + Set requestedAttendees) { - return openTimes; + for (String attendee: eventAttendees) { + if (requestedAttendees.contains(attendee)) { + return true; + } + } + return false; } } + + diff --git a/walkthroughs/week-5-tdd/project/src/test/java/com/google/sps/FindMeetingQueryTest.java b/walkthroughs/week-5-tdd/project/src/test/java/com/google/sps/FindMeetingQueryTest.java index 9235153..073448d 100644 --- a/walkthroughs/week-5-tdd/project/src/test/java/com/google/sps/FindMeetingQueryTest.java +++ b/walkthroughs/week-5-tdd/project/src/test/java/com/google/sps/FindMeetingQueryTest.java @@ -34,6 +34,7 @@ public final class FindMeetingQueryTest { // Some people that we can use in our tests. private static final String PERSON_A = "Person A"; private static final String PERSON_B = "Person B"; + private static final String PERSON_C = "Person C"; // All dates are the first day of the year 2020. private static final int TIME_0800AM = TimeRange.getTimeInMinutes(8, 0); @@ -270,5 +271,188 @@ public void notEnoughRoom() { Assert.assertEquals(expected, actual); } + + @Test + public void optionalPersonAllDayEvent() { + // Have each person have different events and one optional attendee who is + // busy the entire day. We should see three options because the optional + // attendee cannot attend any other event so only consider other people + // + // Optional: |--------------C--------------| + // Events : |--A--| |--B--| + // Day : |-----------------------------| + // Options : |--1--| |--2--| |--3--| + + Collection events = Arrays.asList( + new Event("Event 1", TimeRange.fromStartDuration(TIME_0800AM, DURATION_30_MINUTES), + Arrays.asList(PERSON_A)), + new Event("Event 2", TimeRange.fromStartDuration(TIME_0900AM, DURATION_30_MINUTES), + Arrays.asList(PERSON_B)), + new Event("Event 3", + TimeRange.fromStartDuration(TimeRange.START_OF_DAY, TimeRange.END_OF_DAY), + Arrays.asList(PERSON_C))); + + MeetingRequest request = + new MeetingRequest(Arrays.asList(PERSON_A, PERSON_B), DURATION_30_MINUTES); + + request.addOptionalAttendee(PERSON_C); + + Collection actual = query.query(events, request); + Collection expected = + Arrays.asList(TimeRange.fromStartEnd(TimeRange.START_OF_DAY, TIME_0800AM, false), + TimeRange.fromStartEnd(TIME_0830AM, TIME_0900AM, false), + TimeRange.fromStartEnd(TIME_0930AM, TimeRange.END_OF_DAY, true)); + + Assert.assertEquals(expected, actual); + } + + @Test + public void optionalPersonOneEvent() { + // Have each person have different events and one optional attendee + // overlapping with one of the free times. We should see two options because + // all three can attend at two times + // + // Optional : |-----C-----| + // Events : |--A--| |--B--| + // Day : |-----------------------------| + // Options : |--1--| |--2--| + + Collection events = Arrays.asList( + new Event("Event 1", TimeRange.fromStartDuration(TIME_0800AM, DURATION_30_MINUTES), + Arrays.asList(PERSON_A)), + new Event("Event 2", TimeRange.fromStartDuration(TIME_0900AM, DURATION_30_MINUTES), + Arrays.asList(PERSON_B)), + new Event("Event 3", + TimeRange.fromStartEnd(TIME_0800AM, TIME_0900AM, false), + Arrays.asList(PERSON_C))); + + MeetingRequest request = + new MeetingRequest(Arrays.asList(PERSON_A, PERSON_B), DURATION_30_MINUTES); + + request.addOptionalAttendee(PERSON_C); + + Collection actual = query.query(events, request); + Collection expected = + Arrays.asList(TimeRange.fromStartEnd(TimeRange.START_OF_DAY, TIME_0800AM, false), + TimeRange.fromStartEnd(TIME_0930AM, TimeRange.END_OF_DAY, true)); + + Assert.assertEquals(expected, actual); + } + + + @Test + public void justEnoughRoomWithoutOptional() { + // Have one person and one optional attendee, but make it so that there is + // just enough room at one point in the day to + // have the meeting if the optional attendee does not attend + // + // Optional: |-B-| + // Events : |--A--| |----A----| + // Day : |---------------------| + // Options : |-----| + + Collection events = Arrays.asList( + new Event("Event 1", TimeRange.fromStartEnd(TimeRange.START_OF_DAY, TIME_0830AM, false), + Arrays.asList(PERSON_A)), + new Event("Event 2", TimeRange.fromStartEnd(TIME_0900AM, TimeRange.END_OF_DAY, true), + Arrays.asList(PERSON_A)), + new Event("Event 3", TimeRange.fromStartDuration(TIME_0830AM, 15), + Arrays.asList(PERSON_B))); + + MeetingRequest request = new MeetingRequest(Arrays.asList(PERSON_A), DURATION_30_MINUTES); + + request.addOptionalAttendee(PERSON_B); + + Collection actual = query.query(events, request); + Collection expected = + Arrays.asList(TimeRange.fromStartDuration(TIME_0830AM, DURATION_30_MINUTES)); + + Assert.assertEquals(expected, actual); + } + + + @Test + public void onlyOptionalWithGaps() { + // Have only optional attendees with gaps in their schedules + // + // Optional: |--A--| |-A-||-B-| |-B-| + // Day : |------------------------------| + // Options : |--1--| |--2--| + + Collection events = Arrays.asList( + new Event("Event 1", TimeRange.fromStartEnd(TimeRange.START_OF_DAY, TIME_0830AM, false), + Arrays.asList(PERSON_A)), + new Event("Event 2", TimeRange.fromStartEnd(TIME_0900AM, TIME_1100AM, false), + Arrays.asList(PERSON_A)), + new Event("Event 3", TimeRange.fromStartDuration(TIME_1100AM, 30), + Arrays.asList(PERSON_B)), + new Event("Event 4", TimeRange.fromStartEnd(TimeRange.END_OF_DAY - 30, TimeRange.END_OF_DAY, true), + Arrays.asList(PERSON_B))); + + MeetingRequest request = new MeetingRequest(Arrays.asList(), DURATION_30_MINUTES); + + request.addOptionalAttendee(PERSON_A); + request.addOptionalAttendee(PERSON_B); + + Collection actual = query.query(events, request); + Collection expected = + Arrays.asList(TimeRange.fromStartDuration(TIME_0830AM, DURATION_30_MINUTES), + TimeRange.fromStartEnd(TIME_1100AM + 30, TimeRange.END_OF_DAY - 30, false)); + + Assert.assertEquals(expected, actual); + } + + @Test + public void onlyOptionalWithoutGaps() { + // Have only optional attendees with no gaps in their schedules + // + // Optional: |----A----||-------B-------| + // Day : |--------------------------| + // Options : + + Collection events = Arrays.asList( + new Event("Event 1", TimeRange.fromStartEnd(TimeRange.START_OF_DAY, TIME_1100AM, false), + Arrays.asList(PERSON_A)), + new Event("Event 2", TimeRange.fromStartEnd(TIME_1100AM, TimeRange.END_OF_DAY, true), + Arrays.asList(PERSON_B))); + + MeetingRequest request = new MeetingRequest(Arrays.asList(), DURATION_30_MINUTES); + + request.addOptionalAttendee(PERSON_A); + request.addOptionalAttendee(PERSON_B); + + Collection actual = query.query(events, request); + Collection expected = + Arrays.asList(); + + Assert.assertEquals(expected, actual); + } + + @Test + public void requiredFreeAllDayButNotOptional() { + // Have only optional attendees with no gaps in their schedules + // + // Optional: |---B---| + // Events : + // Day : |-------------------------| + // Options : + + Collection events = Arrays.asList( + new Event("Event 2", TimeRange.fromStartEnd(TIME_0900AM, TIME_1100AM, false), + Arrays.asList(PERSON_B))); + + MeetingRequest request = new MeetingRequest(Arrays.asList(PERSON_A), DURATION_30_MINUTES); + + request.addOptionalAttendee(PERSON_B); + + Collection actual = query.query(events, request); + Collection expected = + Arrays.asList(TimeRange.fromStartEnd(TimeRange.START_OF_DAY, TIME_0900AM, false), + TimeRange.fromStartEnd(TIME_1100AM, TimeRange.END_OF_DAY, true)); + + Assert.assertEquals(expected, actual); + } } + +