From 9339bd38a7b334bb7b8a796dced0c75e9b428460 Mon Sep 17 00:00:00 2001 From: baejeonghwan777 Date: Fri, 11 Sep 2026 21:28:08 +0900 Subject: [PATCH 1/4] =?UTF-8?q?=EC=A2=85=EC=9D=BC=20=ED=95=99=EC=82=AC?= =?UTF-8?q?=EC=9D=BC=EC=A0=95=EC=9D=B4=202=EC=9D=BC=EC=97=90=20=EA=B1=B8?= =?UTF-8?q?=EC=B3=90=20=ED=91=9C=EC=8B=9C=EB=90=98=EB=8A=94=20=ED=98=84?= =?UTF-8?q?=EC=83=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../calendar/AcademicEventConverter.java | 70 +++++++- .../domain/AcademicEventConverterTest.java | 159 ++++++++++++++++++ 2 files changed, 220 insertions(+), 9 deletions(-) create mode 100644 src/test/java/com/kustacks/kuring/calendar/domain/AcademicEventConverterTest.java diff --git a/src/main/java/com/kustacks/kuring/worker/update/calendar/AcademicEventConverter.java b/src/main/java/com/kustacks/kuring/worker/update/calendar/AcademicEventConverter.java index 7677ac4a0..5e1607862 100644 --- a/src/main/java/com/kustacks/kuring/worker/update/calendar/AcademicEventConverter.java +++ b/src/main/java/com/kustacks/kuring/worker/update/calendar/AcademicEventConverter.java @@ -43,19 +43,57 @@ public static Optional convertToAcademicEvent(IcsEvent icsEvent) // 2. summary 전처리 (괄호 안 날짜/시간 제거 등) String summary = AcademicEventSummaryNormalizer.normalize(rawSummary); - LocalDateTime startTime = StringToDateTimeConverter.convert(icsEvent.dtstart()); - LocalDateTime endTime = StringToDateTimeConverter.convert(icsEvent.dtend()); - - AcademicEventCategory category = AcademicEventCategorizer.categorize(summary); - Transparent transparent = convertToTransparent(icsEvent.transp()); - Integer sequence = convertToSequence(icsEvent.sequence()); - - boolean notifyEnabled = AcademicEventNotificationClassifier.proceed(transparent, summary); + // 3. 종일 일정이 이틀에 걸쳐서 표시되지 않도록 수정 try { + if (icsEvent.dtstart() == null || icsEvent.dtstart().isBlank()) { + log.warn("DTSTART가 존재하지 않습니다. (uid={}, summary={})", uid, summary); + return Optional.empty(); + } + + boolean isAllDayEvent = isAllDayEvent(icsEvent.dtstart()); // 종일 일정을 판단하기 위한 boolean 변수 + + if (icsEvent.dtend() != null + && !icsEvent.dtend().isBlank() + && isAllDayEvent != isAllDayEvent(icsEvent.dtend())) { + + log.warn( + "DTSTART와 DTEND의 형식이 다릅니다. (uid={}, dtstart={}, dtend={})", + uid, + icsEvent.dtstart(), + icsEvent.dtend() + ); + return Optional.empty(); + } + + LocalDateTime startTime = StringToDateTimeConverter.convert(icsEvent.dtstart()); + LocalDateTime endTime; + + if (icsEvent.dtend() == null || icsEvent.dtend().isBlank()) { // DTEND가 존재하지 않을 경우 + if (isAllDayEvent) { + endTime = startTime.plusDays(1).minusSeconds(1); + } else { + endTime = startTime; + } + } else { // DTEND가 정상적으로 존재할 경우 + endTime = StringToDateTimeConverter.convert(icsEvent.dtend()); + + if (isAllDayEvent) { + endTime = adjustAllDayEndTime(endTime); + } + } + + AcademicEventCategory category = AcademicEventCategorizer.categorize(summary); + Transparent transparent = convertToTransparent(icsEvent.transp()); + Integer sequence = convertToSequence(icsEvent.sequence()); + + boolean notifyEnabled = + AcademicEventNotificationClassifier.proceed(transparent, summary); + return Optional.of( AcademicEvent.from(uid, summary, description, category, - transparent, sequence, notifyEnabled, startTime, endTime) + transparent, sequence, notifyEnabled, startTime, endTime + ) ); } catch (Exception e) { log.warn("ICS event 변환에 실패했습니다.(uid={}, summary={}): {}", uid, summary, e.toString()); @@ -106,4 +144,18 @@ private static boolean isHolidayEvent(String summary) { return HOLIDAY_PATTERN.matcher(summary).matches(); } + /** + * 종일 일정인지 판별하는 메서드 + */ + private static boolean isAllDayEvent(String dateTime) { + return dateTime != null && dateTime.matches("^\\d{8}$"); + } + + /** + * 종일 일정일 때 endTime의 날짜를 1초 당기는 메서드 + */ + private static LocalDateTime adjustAllDayEndTime(LocalDateTime endTime) { + return endTime.minusSeconds(1); + } + } \ No newline at end of file diff --git a/src/test/java/com/kustacks/kuring/calendar/domain/AcademicEventConverterTest.java b/src/test/java/com/kustacks/kuring/calendar/domain/AcademicEventConverterTest.java new file mode 100644 index 000000000..4c013874c --- /dev/null +++ b/src/test/java/com/kustacks/kuring/calendar/domain/AcademicEventConverterTest.java @@ -0,0 +1,159 @@ +package com.kustacks.kuring.calendar.domain; + +import com.kustacks.kuring.worker.parser.calendar.dto.IcsEvent; +import com.kustacks.kuring.worker.update.calendar.AcademicEventConverter; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.LocalDateTime; +import java.util.Optional; + +public class AcademicEventConverterTest { + + @Test + @DisplayName("DTEND가 없는 종일 일정은 해당 날짜의 23시 59분 59초로 종료 시간을 설정한다") + void convert_all_day_event_without_dtend() { + // given + IcsEvent icsEvent = IcsEvent.builder() + .uid("test-uid") + .summary("개강") + .dtstart("20260831") + .dtend(null) + .build(); + + // when + Optional result = + AcademicEventConverter.convertToAcademicEvent(icsEvent); + + // then + assertThat(result).isPresent(); + + AcademicEvent event = result.get(); + + assertThat(event.getStartTime()) + .isEqualTo(LocalDateTime.of(2026, 8, 31, 0, 0, 0)); + + assertThat(event.getEndTime()) + .isEqualTo(LocalDateTime.of(2026, 8, 31, 23, 59, 59)); + } + + @Test + @DisplayName("DTEND가 없는 일반 일정은 시작 시간과 종료 시간을 동일하게 설정한다") + void convert_non_all_day_event_without_dtend() { + // given + IcsEvent icsEvent = IcsEvent.builder() + .uid("test-uid") + .summary("수강신청") + .dtstart("20260818T093000") + .dtend(null) + .build(); + + // when + Optional result = + AcademicEventConverter.convertToAcademicEvent(icsEvent); + + // then + assertThat(result).isPresent(); + + AcademicEvent event = result.get(); + + assertThat(event.getStartTime()) + .isEqualTo(LocalDateTime.of(2026, 8, 18, 9, 30)); + + assertThat(event.getEndTime()) + .isEqualTo(LocalDateTime.of(2026, 8, 18, 9, 30)); + } + + @Test + @DisplayName("DTSTART가 없으면 변환하지 않는다") + void convert_without_dtstart() { + // given + IcsEvent icsEvent = IcsEvent.builder() + .uid("test-uid") + .summary("개강") + .dtstart(null) + .dtend("20260818") + .build(); + + // when + Optional result = + AcademicEventConverter.convertToAcademicEvent(icsEvent); + + // then + assertThat(result).isEmpty(); + } + + @Test + @DisplayName("DTSTART와 DTEND의 형식이 다르면 변환하지 않는다") + void convert_different_dtstart_dtend_format() { + // given + IcsEvent icsEvent = IcsEvent.builder() + .uid("test-uid") + .summary("개강") + .dtstart("20260831") + .dtend("20260901T090000") + .build(); + + // when + Optional result = + AcademicEventConverter.convertToAcademicEvent(icsEvent); + + // then + assertThat(result).isEmpty(); + } + + @Test + @DisplayName("종일 일정은 종료 시간을 1초 앞당겨 변환한다") + void convert_all_day_event() { + // given + IcsEvent icsEvent = IcsEvent.builder() + .uid("test-uid") + .summary("개강") + .dtstart("20260817") + .dtend("20260818") + .build(); + + // when + Optional result = + AcademicEventConverter.convertToAcademicEvent(icsEvent); + + // then + assertThat(result).isPresent(); + + AcademicEvent event = result.get(); + + assertThat(event.getStartTime()) + .isEqualTo(LocalDateTime.of(2026, 8, 17, 0, 0, 0)); + + assertThat(event.getEndTime()) + .isEqualTo(LocalDateTime.of(2026, 8, 17, 23, 59, 59)); + } + + @Test + @DisplayName("종일 일정이 아닌 경우 시작 시간과 종료 시간을 그대로 유지한다") + void convert_non_all_day_event() { + // given + IcsEvent icsEvent = IcsEvent.builder() + .uid("test-uid") + .summary("수강신청") + .dtstart("20260818T093000") + .dtend("20260818T170000") + .build(); + + // when + Optional result = + AcademicEventConverter.convertToAcademicEvent(icsEvent); + + // then + assertThat(result).isPresent(); + + AcademicEvent event = result.get(); + + assertThat(event.getStartTime()) + .isEqualTo(LocalDateTime.of(2026, 8, 18, 9, 30)); + + assertThat(event.getEndTime()) + .isEqualTo(LocalDateTime.of(2026, 8, 18, 17, 0)); + } +} From d3f88537c4d74b1f836dd8c6666eb91ac7bd2671 Mon Sep 17 00:00:00 2001 From: baejeonghwan777 Date: Sat, 12 Sep 2026 13:41:58 +0900 Subject: [PATCH 2/4] =?UTF-8?q?=EC=A2=85=EB=A3=8C=20=EC=8B=9C=EA=B0=84?= =?UTF-8?q?=EC=9D=B4=20=EC=8B=9C=EC=9E=91=20=EC=8B=9C=EA=B0=84=EA=B3=BC=20?= =?UTF-8?q?=EA=B0=99=EC=9D=84=20=EB=95=8C=20=EC=A2=85=EB=A3=8C=20=EC=8B=9C?= =?UTF-8?q?=EA=B0=84=EC=9D=84=201=EC=B4=88=20=EC=95=9E=EB=8B=B9=EA=B2=A8?= =?UTF-8?q?=20=ED=91=9C=ED=98=84=ED=95=98=EB=8D=98=20=EB=AC=B8=EC=A0=9C=20?= =?UTF-8?q?=EC=88=98=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../calendar/AcademicEventConverter.java | 6 + .../domain/AcademicEventConverterTest.java | 159 ---------------- .../calendar/AcademicEventConverterTest.java | 180 +++++++++++++++++- .../calendar/AcademicEventUpdaterTest.java | 8 +- 4 files changed, 187 insertions(+), 166 deletions(-) delete mode 100644 src/test/java/com/kustacks/kuring/calendar/domain/AcademicEventConverterTest.java diff --git a/src/main/java/com/kustacks/kuring/worker/update/calendar/AcademicEventConverter.java b/src/main/java/com/kustacks/kuring/worker/update/calendar/AcademicEventConverter.java index 5e1607862..591e1ca03 100644 --- a/src/main/java/com/kustacks/kuring/worker/update/calendar/AcademicEventConverter.java +++ b/src/main/java/com/kustacks/kuring/worker/update/calendar/AcademicEventConverter.java @@ -83,6 +83,12 @@ public static Optional convertToAcademicEvent(IcsEvent icsEvent) } } + if (endTime.isBefore(startTime)) { + log.warn("DTEND가 DTSTART보다 이전입니다. (uid={}, dtstart={}, dtend={})", + uid, icsEvent.dtstart(), icsEvent.dtend()); + return Optional.empty(); + } + AcademicEventCategory category = AcademicEventCategorizer.categorize(summary); Transparent transparent = convertToTransparent(icsEvent.transp()); Integer sequence = convertToSequence(icsEvent.sequence()); diff --git a/src/test/java/com/kustacks/kuring/calendar/domain/AcademicEventConverterTest.java b/src/test/java/com/kustacks/kuring/calendar/domain/AcademicEventConverterTest.java deleted file mode 100644 index 4c013874c..000000000 --- a/src/test/java/com/kustacks/kuring/calendar/domain/AcademicEventConverterTest.java +++ /dev/null @@ -1,159 +0,0 @@ -package com.kustacks.kuring.calendar.domain; - -import com.kustacks.kuring.worker.parser.calendar.dto.IcsEvent; -import com.kustacks.kuring.worker.update.calendar.AcademicEventConverter; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThat; - -import java.time.LocalDateTime; -import java.util.Optional; - -public class AcademicEventConverterTest { - - @Test - @DisplayName("DTEND가 없는 종일 일정은 해당 날짜의 23시 59분 59초로 종료 시간을 설정한다") - void convert_all_day_event_without_dtend() { - // given - IcsEvent icsEvent = IcsEvent.builder() - .uid("test-uid") - .summary("개강") - .dtstart("20260831") - .dtend(null) - .build(); - - // when - Optional result = - AcademicEventConverter.convertToAcademicEvent(icsEvent); - - // then - assertThat(result).isPresent(); - - AcademicEvent event = result.get(); - - assertThat(event.getStartTime()) - .isEqualTo(LocalDateTime.of(2026, 8, 31, 0, 0, 0)); - - assertThat(event.getEndTime()) - .isEqualTo(LocalDateTime.of(2026, 8, 31, 23, 59, 59)); - } - - @Test - @DisplayName("DTEND가 없는 일반 일정은 시작 시간과 종료 시간을 동일하게 설정한다") - void convert_non_all_day_event_without_dtend() { - // given - IcsEvent icsEvent = IcsEvent.builder() - .uid("test-uid") - .summary("수강신청") - .dtstart("20260818T093000") - .dtend(null) - .build(); - - // when - Optional result = - AcademicEventConverter.convertToAcademicEvent(icsEvent); - - // then - assertThat(result).isPresent(); - - AcademicEvent event = result.get(); - - assertThat(event.getStartTime()) - .isEqualTo(LocalDateTime.of(2026, 8, 18, 9, 30)); - - assertThat(event.getEndTime()) - .isEqualTo(LocalDateTime.of(2026, 8, 18, 9, 30)); - } - - @Test - @DisplayName("DTSTART가 없으면 변환하지 않는다") - void convert_without_dtstart() { - // given - IcsEvent icsEvent = IcsEvent.builder() - .uid("test-uid") - .summary("개강") - .dtstart(null) - .dtend("20260818") - .build(); - - // when - Optional result = - AcademicEventConverter.convertToAcademicEvent(icsEvent); - - // then - assertThat(result).isEmpty(); - } - - @Test - @DisplayName("DTSTART와 DTEND의 형식이 다르면 변환하지 않는다") - void convert_different_dtstart_dtend_format() { - // given - IcsEvent icsEvent = IcsEvent.builder() - .uid("test-uid") - .summary("개강") - .dtstart("20260831") - .dtend("20260901T090000") - .build(); - - // when - Optional result = - AcademicEventConverter.convertToAcademicEvent(icsEvent); - - // then - assertThat(result).isEmpty(); - } - - @Test - @DisplayName("종일 일정은 종료 시간을 1초 앞당겨 변환한다") - void convert_all_day_event() { - // given - IcsEvent icsEvent = IcsEvent.builder() - .uid("test-uid") - .summary("개강") - .dtstart("20260817") - .dtend("20260818") - .build(); - - // when - Optional result = - AcademicEventConverter.convertToAcademicEvent(icsEvent); - - // then - assertThat(result).isPresent(); - - AcademicEvent event = result.get(); - - assertThat(event.getStartTime()) - .isEqualTo(LocalDateTime.of(2026, 8, 17, 0, 0, 0)); - - assertThat(event.getEndTime()) - .isEqualTo(LocalDateTime.of(2026, 8, 17, 23, 59, 59)); - } - - @Test - @DisplayName("종일 일정이 아닌 경우 시작 시간과 종료 시간을 그대로 유지한다") - void convert_non_all_day_event() { - // given - IcsEvent icsEvent = IcsEvent.builder() - .uid("test-uid") - .summary("수강신청") - .dtstart("20260818T093000") - .dtend("20260818T170000") - .build(); - - // when - Optional result = - AcademicEventConverter.convertToAcademicEvent(icsEvent); - - // then - assertThat(result).isPresent(); - - AcademicEvent event = result.get(); - - assertThat(event.getStartTime()) - .isEqualTo(LocalDateTime.of(2026, 8, 18, 9, 30)); - - assertThat(event.getEndTime()) - .isEqualTo(LocalDateTime.of(2026, 8, 18, 17, 0)); - } -} diff --git a/src/test/java/com/kustacks/kuring/worker/update/calendar/AcademicEventConverterTest.java b/src/test/java/com/kustacks/kuring/worker/update/calendar/AcademicEventConverterTest.java index a4c935815..1edacb4f1 100644 --- a/src/test/java/com/kustacks/kuring/worker/update/calendar/AcademicEventConverterTest.java +++ b/src/test/java/com/kustacks/kuring/worker/update/calendar/AcademicEventConverterTest.java @@ -10,6 +10,7 @@ import java.time.LocalDateTime; import java.util.List; +import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; @@ -60,7 +61,7 @@ void convert_ics_event_to_academic_event() { //then assertEventFields(academicEvent, "하계방학", 0, Transparent.TRANSPARENT, false, LocalDateTime.of(2024, 6, 22, 0, 0), - LocalDateTime.of(2024, 9, 2, 0, 0)); + LocalDateTime.of(2024, 9, 1, 23, 59, 59)); } @DisplayName("다건 학사 이벤트 변환을 수행할 수 있다.") @@ -72,11 +73,11 @@ void convert_multi_ics_event_to_academic_event() { //then assertEventFields(academicEvents.get(0), "하계방학", 0, Transparent.TRANSPARENT, false, LocalDateTime.of(2024, 6, 22, 0, 0), - LocalDateTime.of(2024, 9, 2, 0, 0)); + LocalDateTime.of(2024, 9, 1, 23, 59, 59)); assertEventFields(academicEvents.get(1), "폐강교과목 공지(1차)", 0, Transparent.TRANSPARENT, false, LocalDateTime.of(2024, 9, 2, 0, 0), - LocalDateTime.of(2024, 9, 3, 0, 0)); + LocalDateTime.of(2024, 9, 2, 23, 59, 59)); } @DisplayName("공휴일 이벤트는 변환에서 제외") @@ -214,4 +215,177 @@ private void assertEventFields(AcademicEvent academicEvent, String summary, Inte () -> assertThat(academicEvent.getEndTime()).isEqualTo(endDate) ); } + + @Test + @DisplayName("DTEND가 없는 종일 일정은 해당 날짜의 23시 59분 59초로 종료 시간을 설정한다") + void convert_all_day_event_without_dtend() { + // given + IcsEvent icsEvent = IcsEvent.builder() + .uid("test-uid") + .summary("개강") + .dtstart("20260831") + .dtend(null) + .build(); + + // when + Optional result = + AcademicEventConverter.convertToAcademicEvent(icsEvent); + + // then + assertThat(result).isPresent(); + + AcademicEvent event = result.get(); + + assertThat(event.getStartTime()) + .isEqualTo(LocalDateTime.of(2026, 8, 31, 0, 0, 0)); + + assertThat(event.getEndTime()) + .isEqualTo(LocalDateTime.of(2026, 8, 31, 23, 59, 59)); + } + + @Test + @DisplayName("DTEND가 없는 일반 일정은 시작 시간과 종료 시간을 동일하게 설정한다") + void convert_non_all_day_event_without_dtend() { + // given + IcsEvent icsEvent = IcsEvent.builder() + .uid("test-uid") + .summary("수강신청") + .dtstart("20260818T093000") + .dtend(null) + .build(); + + // when + Optional result = + AcademicEventConverter.convertToAcademicEvent(icsEvent); + + // then + assertThat(result).isPresent(); + + AcademicEvent event = result.get(); + + assertThat(event.getStartTime()) + .isEqualTo(LocalDateTime.of(2026, 8, 18, 9, 30)); + + assertThat(event.getEndTime()) + .isEqualTo(LocalDateTime.of(2026, 8, 18, 9, 30)); + } + + @Test + @DisplayName("DTSTART가 없으면 변환하지 않는다") + void convert_without_dtstart() { + // given + IcsEvent icsEvent = IcsEvent.builder() + .uid("test-uid") + .summary("개강") + .dtstart(null) + .dtend("20260818") + .build(); + + // when + Optional result = + AcademicEventConverter.convertToAcademicEvent(icsEvent); + + // then + assertThat(result).isEmpty(); + } + + @Test + @DisplayName("DTSTART와 DTEND의 형식이 다르면 변환하지 않는다") + void convert_different_dtstart_dtend_format() { + // given + IcsEvent icsEvent = IcsEvent.builder() + .uid("test-uid") + .summary("개강") + .dtstart("20260831") + .dtend("20260901T090000") + .build(); + + // when + Optional result = + AcademicEventConverter.convertToAcademicEvent(icsEvent); + + // then + assertThat(result).isEmpty(); + } + + @Test + @DisplayName("종일 일정은 종료 시간을 1초 앞당겨 변환한다") + void convert_all_day_event() { + // given + IcsEvent icsEvent = IcsEvent.builder() + .uid("test-uid") + .summary("개강") + .dtstart("20260817") + .dtend("20260818") + .build(); + + // when + Optional result = + AcademicEventConverter.convertToAcademicEvent(icsEvent); + + // then + assertThat(result).isPresent(); + + AcademicEvent event = result.get(); + + assertThat(event.getStartTime()) + .isEqualTo(LocalDateTime.of(2026, 8, 17, 0, 0, 0)); + + assertThat(event.getEndTime()) + .isEqualTo(LocalDateTime.of(2026, 8, 17, 23, 59, 59)); + } + + @Test + @DisplayName("종일 일정이 아닌 경우 시작 시간과 종료 시간을 그대로 유지한다") + void convert_non_all_day_event() { + // given + IcsEvent icsEvent = IcsEvent.builder() + .uid("test-uid") + .summary("수강신청") + .dtstart("20260818T093000") + .dtend("20260818T170000") + .build(); + + // when + Optional result = + AcademicEventConverter.convertToAcademicEvent(icsEvent); + + // then + assertThat(result).isPresent(); + + AcademicEvent event = result.get(); + + assertThat(event.getStartTime()) + .isEqualTo(LocalDateTime.of(2026, 8, 18, 9, 30)); + + assertThat(event.getEndTime()) + .isEqualTo(LocalDateTime.of(2026, 8, 18, 17, 0)); + } + + @DisplayName("종일 이벤트의 종료 시간이 시작 시간보다 이전이면 변환에서 제외") + @Test + void convert_exclude_all_day_event_when_end_time_is_before_start_time() { + // given + IcsEvent icsEvent = new IcsEvent( + "test-uid", + "테스트 일정", + "설명", + "20260817", + "20260817", + "PUBLIC", + "0", + "20260817T000000Z", + "TRANSPARENT", + "CONFIRMED", + "0", + "" + ); + + // when + AcademicEvent academicEvent = + AcademicEventConverter.convertToAcademicEvent(icsEvent).orElse(null); + + // then + assertThat(academicEvent).isNull(); + } } \ No newline at end of file diff --git a/src/test/java/com/kustacks/kuring/worker/update/calendar/AcademicEventUpdaterTest.java b/src/test/java/com/kustacks/kuring/worker/update/calendar/AcademicEventUpdaterTest.java index 93d7b8e17..7d5fd97c3 100644 --- a/src/test/java/com/kustacks/kuring/worker/update/calendar/AcademicEventUpdaterTest.java +++ b/src/test/java/com/kustacks/kuring/worker/update/calendar/AcademicEventUpdaterTest.java @@ -83,12 +83,12 @@ void should_save_initial_calendar_data_to_db() throws IOException, ParserExcepti // 하계방학 이벤트 검증 assertEventFields(event1, "하계방학", 0, Transparent.TRANSPARENT, false, LocalDateTime.of(2024, 6, 22, 0, 0), - LocalDateTime.of(2024, 9, 2, 0, 0)); + LocalDateTime.of(2024, 9, 1, 23, 59, 59)); // 폐강교과목 공지 이벤트 검증 assertEventFields(event2, "폐강교과목 공지(1차)", 0, Transparent.TRANSPARENT, false, LocalDateTime.of(2024, 9, 2, 0, 0), - LocalDateTime.of(2024, 9, 3, 0, 0)); + LocalDateTime.of(2024, 9, 2, 23, 59, 59)); } @Test @@ -125,12 +125,12 @@ void should_update_existing_and_add_new_events() throws IOException, ParserExcep // 하계방학 이벤트 검증 assertEventFields(event1, "하계방학", 0, Transparent.TRANSPARENT, false, LocalDateTime.of(2024, 6, 22, 0, 0), - LocalDateTime.of(2024, 9, 2, 0, 0)); + LocalDateTime.of(2024, 9, 1, 23, 59, 59)); // 폐강교과목 공지 이벤트 검증 assertEventFields(event2, "폐강교과목 공지(1차)", 1, Transparent.OPAQUE, true, LocalDateTime.of(2024, 9, 3, 0, 0), - LocalDateTime.of(2024, 9, 4, 0, 0)); + LocalDateTime.of(2024, 9, 3, 23, 59, 59)); // 신규 공지 이벤트 검증 assertEventFields(event3, "김한주가넣은가짜학사일정", 0, Transparent.OPAQUE, true, From eeb8d5a436fbb1e23ccf5825bdbae7d506ed627f Mon Sep 17 00:00:00 2001 From: baejeonghwan777 Date: Sat, 12 Sep 2026 14:02:24 +0900 Subject: [PATCH 3/4] =?UTF-8?q?=EB=8F=99=EC=9D=BC=ED=95=9C=20=EB=82=A0?= =?UTF-8?q?=EC=A7=9C=20=EB=B0=8F=20=EC=8B=9C=EA=B0=84=EC=9D=84=20=EA=B0=80?= =?UTF-8?q?=EC=A1=8C=EC=9D=84=20=EB=95=8C=EC=9D=98=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EA=B2=80=EC=A6=9D=20=EC=B6=94=EA=B0=80=20=EB=B0=8F?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=ED=95=9C=20=EC=A2=85=EC=9D=BC=20=EC=9D=BC?= =?UTF-8?q?=EC=A0=95=EC=97=90=20=EB=A7=9E=EA=B2=8C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../calendar/AcademicEventConverterTest.java | 31 +++++++++++++++++++ .../calendar/AcademicEventUpdaterTest.java | 2 +- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/kustacks/kuring/worker/update/calendar/AcademicEventConverterTest.java b/src/test/java/com/kustacks/kuring/worker/update/calendar/AcademicEventConverterTest.java index 1edacb4f1..ba7f071df 100644 --- a/src/test/java/com/kustacks/kuring/worker/update/calendar/AcademicEventConverterTest.java +++ b/src/test/java/com/kustacks/kuring/worker/update/calendar/AcademicEventConverterTest.java @@ -388,4 +388,35 @@ void convert_exclude_all_day_event_when_end_time_is_before_start_time() { // then assertThat(academicEvent).isNull(); } + + @DisplayName("일반 이벤트의 시작 시간과 종료 시간이 같으면 변환에서 제외") + @Test + void convert_non_all_day_event_with_same_start_and_end_time() { + // given + IcsEvent icsEvent = new IcsEvent( + "test-uid", + "테스트 일정", + "설명", + "20260818T093000", + "20260818T093000", + "PUBLIC", + "0", + "20260818T093000Z", + "TRANSPARENT", + "CONFIRMED", + "0", + "" + ); + + // when + AcademicEvent academicEvent = + AcademicEventConverter.convertToAcademicEvent(icsEvent).orElse(null); + + // then + assertThat(academicEvent).isNotNull(); + assertThat(academicEvent.getStartTime()) + .isEqualTo(LocalDateTime.of(2026, 8, 18, 9, 30)); + assertThat(academicEvent.getEndTime()) + .isEqualTo(LocalDateTime.of(2026, 8, 18, 9, 30)); + } } \ No newline at end of file diff --git a/src/test/java/com/kustacks/kuring/worker/update/calendar/AcademicEventUpdaterTest.java b/src/test/java/com/kustacks/kuring/worker/update/calendar/AcademicEventUpdaterTest.java index 7d5fd97c3..052bc110d 100644 --- a/src/test/java/com/kustacks/kuring/worker/update/calendar/AcademicEventUpdaterTest.java +++ b/src/test/java/com/kustacks/kuring/worker/update/calendar/AcademicEventUpdaterTest.java @@ -135,7 +135,7 @@ void should_update_existing_and_add_new_events() throws IOException, ParserExcep // 신규 공지 이벤트 검증 assertEventFields(event3, "김한주가넣은가짜학사일정", 0, Transparent.OPAQUE, true, LocalDateTime.of(2028, 2, 29, 0, 0), - LocalDateTime.of(2028, 2, 29, 0, 0)); + LocalDateTime.of(2028, 2, 29, 23, 59, 59)); } @Test From 47a5586f77ced0198fc60c9ca7bce32ad3783ec0 Mon Sep 17 00:00:00 2001 From: baejeonghwan777 Date: Sat, 12 Sep 2026 14:11:52 +0900 Subject: [PATCH 4/4] =?UTF-8?q?ics=20=ED=8C=8C=EC=9D=BC=EC=97=90=20?= =?UTF-8?q?=EA=B0=80=EC=A7=9C=20=ED=95=99=EC=82=AC=EC=9D=BC=EC=A0=95=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=EC=82=AC=ED=95=AD=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/resources/calendar/academic-calendar-updated.ics | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/resources/calendar/academic-calendar-updated.ics b/src/test/resources/calendar/academic-calendar-updated.ics index 763ed6f0c..719762d38 100644 --- a/src/test/resources/calendar/academic-calendar-updated.ics +++ b/src/test/resources/calendar/academic-calendar-updated.ics @@ -4980,7 +4980,7 @@ UID:140000008200E00074C5B7101A82E00800000000C1545CD275FFDB01000000000000000 010000000A6974AF4EE07FD42979F2F3DA1D208DC SUMMARY:김한주가넣은가짜학사일정 DTSTART;VALUE=DATE:20280229 -DTEND;VALUE=DATE:20280229 +DTEND;VALUE=DATE:20280301 CLASS:PUBLIC PRIORITY:9 DTSTAMP:20250826T143707Z