Skip to content

Commit

Permalink
Merge pull request #294 from ASAP-as-soon-as-possible/feat/#293
Browse files Browse the repository at this point in the history
#293 [feat] BestMeetingTimeStrategy 구현체 로직 개발
  • Loading branch information
KWY0218 authored Aug 4, 2024
2 parents 87b804d + 12a6995 commit eecb6af
Show file tree
Hide file tree
Showing 4 changed files with 344 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public List<BestMeetingTimeVo> getBestMeetingTime(

List<BestMeetingTimeVo> candidateMeetingTimes = new ArrayList<>(
continuousMeetingTimeStrategy.find(timeBlocksFilteredUserCount, timeCase.duration()));
candidateMeetingTimes = bestMeetingTimeStrategy.find(candidateMeetingTimes);
candidateMeetingTimes = bestMeetingTimeStrategy.find(candidateMeetingTimes, timeCase.duration());
bestMeetingTimes.addAll(candidateMeetingTimes);

if (bestMeetingTimes.size() < BEST_MEETING_TIME_SIZE) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package com.asap.server.service.meeting.recommend.strategy;

import com.asap.server.persistence.domain.enums.Duration;
import com.asap.server.service.vo.BestMeetingTimeVo;
import java.util.List;

public interface BestMeetingTimeStrategy {
List<BestMeetingTimeVo> find(List<BestMeetingTimeVo> candidateMeetingTimes);
List<BestMeetingTimeVo> find(List<BestMeetingTimeVo> candidateMeetingTimes, Duration duration);
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,42 @@
package com.asap.server.service.meeting.recommend.strategy.impl;

import com.asap.server.persistence.domain.enums.Duration;
import com.asap.server.persistence.domain.enums.TimeSlot;
import com.asap.server.service.meeting.recommend.strategy.BestMeetingTimeStrategy;
import com.asap.server.service.vo.BestMeetingTimeVo;
import java.util.ArrayList;
import java.util.List;
import org.springframework.stereotype.Component;

@Component
public class BestMeetingTimeStrategyImpl implements BestMeetingTimeStrategy {
private static final int EXTRA_BLOCKS = 4;

@Override
public List<BestMeetingTimeVo> find(List<BestMeetingTimeVo> candidateMeetingTimes) {
return null;
public List<BestMeetingTimeVo> find(List<BestMeetingTimeVo> candidateMeetingTimes, Duration duration) {
List<BestMeetingTimeVo> bestMeetingTimes = new ArrayList<>();
for (BestMeetingTimeVo candidate : candidateMeetingTimes) {
bestMeetingTimes.add(createFirstMeetingTime(candidate, duration));

if (isTimeBlockSufficientlyLong(candidate, duration)) {
bestMeetingTimes.add(createSecondMeetingTime(candidate, duration));
}
}
return bestMeetingTimes;
}

private BestMeetingTimeVo createFirstMeetingTime(BestMeetingTimeVo candidate, Duration duration) {
TimeSlot endTimeSlot = TimeSlot.getTimeSlot(candidate.startTime().getIndex() + duration.getNeedBlock());
return new BestMeetingTimeVo(candidate.date(), candidate.startTime(), endTimeSlot, candidate.weight());
}

private BestMeetingTimeVo createSecondMeetingTime(BestMeetingTimeVo candidate, Duration duration) {
TimeSlot startTimeSlot = TimeSlot.getTimeSlot(candidate.endTime().getIndex() - duration.getNeedBlock());
return new BestMeetingTimeVo(candidate.date(), startTimeSlot, candidate.endTime(), candidate.weight());
}

private boolean isTimeBlockSufficientlyLong(BestMeetingTimeVo candidate, Duration duration) {
int timeBlockLength = candidate.endTime().getIndex() - candidate.startTime().getIndex();
return timeBlockLength >= duration.getNeedBlock() * 2 + EXTRA_BLOCKS;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,311 @@
package com.asap.server.service.meeting.recommend.strategy.impl;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;

import com.asap.server.persistence.domain.enums.Duration;
import com.asap.server.persistence.domain.enums.TimeSlot;
import com.asap.server.service.meeting.recommend.strategy.BestMeetingTimeStrategy;
import com.asap.server.service.vo.BestMeetingTimeVo;
import java.time.LocalDate;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

class BestMeetingTimeStrategyImplTest {
private final BestMeetingTimeStrategy continuousMeetingTimeStrategy = new BestMeetingTimeStrategyImpl();

@DisplayName("회의 진행 시간이 30분인 경우, 3시간 이상인 블록은 긴 블록으로 처리한다.")
@Nested
class DurationHalfTest {
Duration duration = Duration.HALF;

@DisplayName("14:00 - 16:00 returns 14:00 - 14:30")
@Test
void test() {
// given
LocalDate availableDate = LocalDate.of(2023, 7, 10);
BestMeetingTimeVo bestMeetingTimeVo =
new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_14_00, TimeSlot.SLOT_16_00, 0);
List<BestMeetingTimeVo> candidateMeetingTimes = List.of(bestMeetingTimeVo);

BestMeetingTimeVo e1 = new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_14_00, TimeSlot.SLOT_14_30, 0);
List<BestMeetingTimeVo> expected = List.of(e1);

// when
List<BestMeetingTimeVo> response = continuousMeetingTimeStrategy.find(candidateMeetingTimes, duration);

// then
assertThat(response).isEqualTo(expected);
}

@DisplayName("14:00 - 17:00 returns 14:00 - 14:30, 16:30 - 17:00")
@Test
void test2() {
// given
LocalDate availableDate = LocalDate.of(2023, 7, 10);
BestMeetingTimeVo bestMeetingTimeVo =
new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_14_00, TimeSlot.SLOT_17_00, 0);
List<BestMeetingTimeVo> candidateMeetingTimes = List.of(bestMeetingTimeVo);

BestMeetingTimeVo e1 = new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_14_00, TimeSlot.SLOT_14_30, 0);
BestMeetingTimeVo e2 = new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_16_30, TimeSlot.SLOT_17_00, 0);
List<BestMeetingTimeVo> expected = List.of(e1, e2);

// when
List<BestMeetingTimeVo> response = continuousMeetingTimeStrategy.find(candidateMeetingTimes, duration);

// then
assertThat(response).isEqualTo(expected);
}

@DisplayName("6:00 - 6:30, 21:00 - 24:00 returns 6:00 - 6:30, 21:00 - 21:30, 23:30 - 24:00")
@Test
void test3() {
// given
LocalDate availableDate = LocalDate.of(2023, 7, 10);
BestMeetingTimeVo bestMeetingTimeVo =
new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_6_00, TimeSlot.SLOT_6_30, 0);
BestMeetingTimeVo bestMeetingTimeVo2 =
new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_21_00, TimeSlot.SLOT_24_00, 0);
List<BestMeetingTimeVo> candidateMeetingTimes = List.of(bestMeetingTimeVo, bestMeetingTimeVo2);

BestMeetingTimeVo e1 = new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_6_00, TimeSlot.SLOT_6_30, 0);
BestMeetingTimeVo e2 = new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_21_00, TimeSlot.SLOT_21_30, 0);
BestMeetingTimeVo e3 = new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_23_30, TimeSlot.SLOT_24_00, 0);
List<BestMeetingTimeVo> expected = List.of(e1, e2, e3);

// when
List<BestMeetingTimeVo> response = continuousMeetingTimeStrategy.find(candidateMeetingTimes, duration);

// then
assertThat(response).isEqualTo(expected);
}
}

@DisplayName("회의 진행 시간이 1시간인 경우, 4시간 이상인 블록은 긴 블록으로 처리한다.")
@Nested
class DurationHourTest {
Duration duration = Duration.HOUR;

@DisplayName("14:00 - 16:00 returns 14:00 - 15:00")
@Test
void test() {
// given
LocalDate availableDate = LocalDate.of(2023, 7, 10);
BestMeetingTimeVo bestMeetingTimeVo =
new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_14_00, TimeSlot.SLOT_16_00, 0);
List<BestMeetingTimeVo> candidateMeetingTimes = List.of(bestMeetingTimeVo);

BestMeetingTimeVo e1 = new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_14_00, TimeSlot.SLOT_15_00, 0);
List<BestMeetingTimeVo> expected = List.of(e1);

// when
List<BestMeetingTimeVo> response = continuousMeetingTimeStrategy.find(candidateMeetingTimes, duration);

// then
assertThat(response).isEqualTo(expected);
}

@DisplayName("14:00 - 18:00 returns 14:00 - 15:00, 17:00 - 18:00")
@Test
void test2() {
// given
LocalDate availableDate = LocalDate.of(2023, 7, 10);
BestMeetingTimeVo bestMeetingTimeVo =
new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_14_00, TimeSlot.SLOT_18_00, 0);
List<BestMeetingTimeVo> candidateMeetingTimes = List.of(bestMeetingTimeVo);

BestMeetingTimeVo e1 = new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_14_00, TimeSlot.SLOT_15_00, 0);
BestMeetingTimeVo e2 = new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_17_00, TimeSlot.SLOT_18_00, 0);
List<BestMeetingTimeVo> expected = List.of(e1, e2);

// when
List<BestMeetingTimeVo> response = continuousMeetingTimeStrategy.find(candidateMeetingTimes, duration);

// then
assertThat(response).isEqualTo(expected);
}
}

@DisplayName("회의 진행 시간이 1시간 30분인 경우, 5시간 이상인 블록은 긴 블록으로 처리한다.")
@Nested
class DurationHourHalfTest {
Duration duration = Duration.HOUR_HALF;

@DisplayName("14:00 - 16:00 returns 14:00 - 15:30")
@Test
void test() {
// given
LocalDate availableDate = LocalDate.of(2023, 7, 10);
BestMeetingTimeVo bestMeetingTimeVo =
new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_14_00, TimeSlot.SLOT_16_30, 0);
List<BestMeetingTimeVo> candidateMeetingTimes = List.of(bestMeetingTimeVo);

BestMeetingTimeVo e1 = new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_14_00, TimeSlot.SLOT_15_30, 0);
List<BestMeetingTimeVo> expected = List.of(e1);

// when
List<BestMeetingTimeVo> response = continuousMeetingTimeStrategy.find(candidateMeetingTimes, duration);

// then
assertThat(response).isEqualTo(expected);
}

@DisplayName("14:00 - 19:00 returns 14:00 - 15:30, 17:30 - 19:00")
@Test
void test2() {
// given
LocalDate availableDate = LocalDate.of(2023, 7, 10);
BestMeetingTimeVo bestMeetingTimeVo =
new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_14_00, TimeSlot.SLOT_19_00, 0);
List<BestMeetingTimeVo> candidateMeetingTimes = List.of(bestMeetingTimeVo);

BestMeetingTimeVo e1 = new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_14_00, TimeSlot.SLOT_15_30, 0);
BestMeetingTimeVo e2 = new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_17_30, TimeSlot.SLOT_19_00, 0);
List<BestMeetingTimeVo> expected = List.of(e1, e2);

// when
List<BestMeetingTimeVo> response = continuousMeetingTimeStrategy.find(candidateMeetingTimes, duration);

// then
assertThat(response).isEqualTo(expected);
}
}

@DisplayName("회의 진행 시간이 2시간인 경우, 6시간 이상인 블록은 긴 블록으로 처리한다.")
@Nested
class DurationTwoHourTest {
Duration duration = Duration.TWO_HOUR;

@DisplayName("14:00 - 16:00 returns 14:00 - 16:00")
@Test
void test() {
// given
LocalDate availableDate = LocalDate.of(2023, 7, 10);
BestMeetingTimeVo bestMeetingTimeVo =
new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_14_00, TimeSlot.SLOT_16_00, 0);
List<BestMeetingTimeVo> candidateMeetingTimes = List.of(bestMeetingTimeVo);

BestMeetingTimeVo e1 = new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_14_00, TimeSlot.SLOT_16_00, 0);
List<BestMeetingTimeVo> expected = List.of(e1);

// when
List<BestMeetingTimeVo> response = continuousMeetingTimeStrategy.find(candidateMeetingTimes, duration);

// then
assertThat(response).isEqualTo(expected);
}


@DisplayName("14:00 - 20:00 returns 14:00 - 16:00, 18:00 - 20:00")
@Test
void test2() {
// given
LocalDate availableDate = LocalDate.of(2023, 7, 10);
BestMeetingTimeVo bestMeetingTimeVo =
new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_14_00, TimeSlot.SLOT_20_00, 0);
List<BestMeetingTimeVo> candidateMeetingTimes = List.of(bestMeetingTimeVo);

BestMeetingTimeVo e1 = new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_14_00, TimeSlot.SLOT_16_00, 0);
BestMeetingTimeVo e2 = new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_18_00, TimeSlot.SLOT_20_00, 0);
List<BestMeetingTimeVo> expected = List.of(e1, e2);

// when
List<BestMeetingTimeVo> response = continuousMeetingTimeStrategy.find(candidateMeetingTimes, duration);

// then
assertThat(response).isEqualTo(expected);
}
}

@DisplayName("회의 진행 시간이 2시간 30분인 경우, 7시간 이상인 블록은 긴 블록으로 처리한다.")
@Nested
class DurationTwoHourHalfTest {
Duration duration = Duration.TWO_HOUR_HALF;

@DisplayName("14:00 - 17:00 returns 14:00 - 16:30")
@Test
void test() {
// given
LocalDate availableDate = LocalDate.of(2023, 7, 10);
BestMeetingTimeVo bestMeetingTimeVo =
new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_14_00, TimeSlot.SLOT_17_00, 0);
List<BestMeetingTimeVo> candidateMeetingTimes = List.of(bestMeetingTimeVo);

BestMeetingTimeVo e1 = new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_14_00, TimeSlot.SLOT_16_30, 0);
List<BestMeetingTimeVo> expected = List.of(e1);

// when
List<BestMeetingTimeVo> response = continuousMeetingTimeStrategy.find(candidateMeetingTimes, duration);

// then
assertThat(response).isEqualTo(expected);
}

@DisplayName("14:00 - 21:00 returns 14:00 - 16:30, 19:30 - 21:00")
@Test
void test2() {
// given
LocalDate availableDate = LocalDate.of(2023, 7, 10);
BestMeetingTimeVo bestMeetingTimeVo =
new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_14_00, TimeSlot.SLOT_21_00, 0);
List<BestMeetingTimeVo> candidateMeetingTimes = List.of(bestMeetingTimeVo);

BestMeetingTimeVo e1 = new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_14_00, TimeSlot.SLOT_16_30, 0);
BestMeetingTimeVo e2 = new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_18_30, TimeSlot.SLOT_21_00, 0);
List<BestMeetingTimeVo> expected = List.of(e1, e2);

// when
List<BestMeetingTimeVo> response = continuousMeetingTimeStrategy.find(candidateMeetingTimes, duration);

// then
assertThat(response).isEqualTo(expected);
}
}

@DisplayName("회의 진행 시간이 3시간인 경우, 8시간 이상인 블록은 긴 블록으로 처리한다.")
@Nested
class DurationThreeHourTest {
Duration duration = Duration.THREE_HOUR;

@DisplayName("14:00 - 17:00 returns 14:00 - 17:00")
@Test
void test() {
// given
LocalDate availableDate = LocalDate.of(2023, 7, 10);
BestMeetingTimeVo bestMeetingTimeVo =
new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_14_00, TimeSlot.SLOT_17_00, 0);
List<BestMeetingTimeVo> candidateMeetingTimes = List.of(bestMeetingTimeVo);

BestMeetingTimeVo e1 = new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_14_00, TimeSlot.SLOT_17_00, 0);
List<BestMeetingTimeVo> expected = List.of(e1);

// when
List<BestMeetingTimeVo> response = continuousMeetingTimeStrategy.find(candidateMeetingTimes, duration);

// then
assertThat(response).isEqualTo(expected);
}

@DisplayName("14:00 - 22:00 returns 14:00 - 17:00, 19:00 - 22:00")
@Test
void test2() {
// given
LocalDate availableDate = LocalDate.of(2023, 7, 10);
BestMeetingTimeVo bestMeetingTimeVo =
new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_14_00, TimeSlot.SLOT_22_00, 0);
List<BestMeetingTimeVo> candidateMeetingTimes = List.of(bestMeetingTimeVo);

BestMeetingTimeVo e1 = new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_14_00, TimeSlot.SLOT_17_00, 0);
BestMeetingTimeVo e2 = new BestMeetingTimeVo(availableDate, TimeSlot.SLOT_19_00, TimeSlot.SLOT_22_00, 0);
List<BestMeetingTimeVo> expected = List.of(e1, e2);

// when
List<BestMeetingTimeVo> response = continuousMeetingTimeStrategy.find(candidateMeetingTimes, duration);

// then
assertThat(response).isEqualTo(expected);
}
}
}

0 comments on commit eecb6af

Please sign in to comment.