Skip to content
Merged
Changes from 1 commit
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
bdbf213
[UI/#226] OrbitPicker 사이즈 축소
DongChyeon Jul 14, 2025
3705c85
[UI/#226] 미션 선택 섹션 추가
DongChyeon Jul 14, 2025
0d281bd
[REFACTOR/#226] Type 안정성과 재사용성을 위해 PickeState를 generic으로 처리
DongChyeon Jul 14, 2025
1b3a951
[FEAT/#226] 미션 종류에 없음 추가
DongChyeon Jul 15, 2025
e6b9872
[REMOVE/#226] JUnit4를 사용하므로 useJUnitPlatform 제거
DongChyeon Jul 15, 2025
7474871
[FEAT/#226] AlarmEntity isAm 컬럼 제거
DongChyeon Jul 15, 2025
153cca5
[FEAT/#226] OrbitPicker가 java.time.LocalTime을 사용하도록 수정
DongChyeon Jul 15, 2025
aa761ec
[FEAT/#226] 알람 시간 표현을 LocalTime으로 통일
DongChyeon Jul 15, 2025
1826d1e
[FEAT/#226] 미션 타입이 NONE일 때 처리 추가
DongChyeon Jul 15, 2025
5c58962
[REMOVE/#226] 사용하지 않는 DB 연산 제거
DongChyeon Jul 15, 2025
ec9ab8b
[FEAT/#226] AlarmDateTimeFormatter에 알람 시간 계산 로직 위임
DongChyeon Jul 16, 2025
790faf6
[TEST/#226] AlarmDateTimeFormatter 테스트 코드 추가
DongChyeon Jul 16, 2025
2fcbf39
[REFACTOR/#226] AlarmScheduler를 UseCase를 통해 사용하도록 변경
DongChyeon Jul 16, 2025
b258571
[REFACTOR/#226] 알람 시간 계산 로직을 AlarmTimeCalculator로 분리
DongChyeon Jul 16, 2025
a68c962
[FIX/#226] 알람 스케줄링 시 공휴일 건너뛰기 여부에 따라 건너뛰도록 수정
DongChyeon Jul 16, 2025
d28a2ef
[TEST/#226] AlarmTimeCalculator 테스트 코드 추가
DongChyeon Jul 16, 2025
5587818
[FEAT/#226] AlarmEntity 관련 매핑 함수에 missionType과 missionCount 필드 추가
DongChyeon Jul 16, 2025
e3eea36
[FEAT/#226] MIGRATION_1_2 로직에 isAm 컬럼에 따른 시간 변환 로직 추가
DongChyeon Jul 16, 2025
955f467
[REFACTOR/#226] AlarmDateTimeFormatter 상수 정의 및 로그 제거
DongChyeon Jul 16, 2025
28d7e10
[FEAT/#226] 데이터베이스 마이그레이션 로직에 롤백 보장을 위한 트랜잭션 적용
DongChyeon Jul 16, 2025
05f5150
[TEST/#226] 12시간제에서 24시간제로 시간 변환 검증 테스트 추가
DongChyeon Jul 16, 2025
152b993
[REFACTOR/#226] 반복 알람 요일이 비어있을 경우 예외 발생하도록 검증 로직 변경
DongChyeon Jul 16, 2025
f392798
[REFACTOR/#226] 반복 알람 로직에서 잘못된 fallback 제거 및 명시적 예외 처리
DongChyeon Jul 16, 2025
bb9f921
[TEST/#226] AlarmDateTimeFormatterTest에 Clock 주입 적용하여 CI 환경 시간 오류 방지
DongChyeon Jul 16, 2025
a72dfae
[FIX/#226] ClockModule 생성 및 의존성 주입
DongChyeon Jul 16, 2025
8bbaea0
[REFACTOR/#226] AlarmDateTimeFormatter :feature:home 모듈로 이전
DongChyeon Jul 17, 2025
b114a1d
[MOVE/#226] 홈 모듈 내 알람 관련 파일 com.yapp.alarm 패키지로 이동
DongChyeon Jul 17, 2025
ecb5d2a
[MOVE/#226] ClockModule을 common 모듈로 이동
DongChyeon Jul 17, 2025
acf0c82
[TEST/#226] AlarmDateTimeFormatter 테스트용 Locale 사용
DongChyeon Jul 17, 2025
fc1702b
[FEAT/#226] AlarmDateTimeFormatter 예외 발생 시 로그 추가
DongChyeon Jul 17, 2025
06107dd
[REFACTOR/#226] formatTimeDifference 중복 검사 로직 제거
DongChyeon Jul 17, 2025
36bcb48
[FEAT/#226] AlarmDateTimeFormatter 테스트 용이성을 위한 Locale 주입
DongChyeon Jul 17, 2025
57d2da9
[FEAT/#226] 의존성 그래프 모듈 유형별 색상 구분
DongChyeon Jul 17, 2025
c5f3202
[REFACTOR/#226] given/when/then 분리
DongChyeon Jul 17, 2025
8ce6247
[CHORE/#227] Jacoco 리포트를 Codecov에 업로드하도록 수정
MoonsuKang Jul 20, 2025
d9cb6aa
[ADD/#227] Jacoco XML 리포트 생성 활성화
MoonsuKang Jul 20, 2025
1b958ab
[MOD/#227] CI 워크플로우에 Codecov 토큰 추가
MoonsuKang Jul 20, 2025
6a56222
[ADD/#227] Codecov 설정 파일 추가
MoonsuKang Jul 20, 2025
1f10398
[MOD/#227] 커버리지 리포트 PR 자동 코멘트 기능 삭제
MoonsuKang Jul 20, 2025
f63bce9
[FEAT/#226] MigrationTest에서 db를 닫기 위해 close 호출
DongChyeon Jul 21, 2025
d38d230
[REFACTOR/#226] AlarmDateTimeFormatter 코드 가독성 개선
DongChyeon Jul 21, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

매우 깔끔스 ㄷㄷㄷㄷㄷㄷ
엣지 케이스로 나중에 자정 경계값 측정이나 반복 알람 추가하면 좋을듯!

Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package com.yapp.domain.formatter

import com.yapp.domain.model.Alarm
import com.yapp.domain.model.AlarmDay
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import java.time.LocalDateTime

class AlarmDateTimeFormatterTest {

private lateinit var formatter: AlarmDateTimeFormatter
private val fixedNow: LocalDateTime = LocalDateTime.of(2023, 10, 26, 10, 0, 0) // 목요일

@Before
fun `테스트_준비`() {
formatter = AlarmDateTimeFormatter()
}

private val deliveryFormats = AlarmDateTimeFormatter.DeliveryTimeFormats(
noAlarm = "받을 수 있는 운세가 없어요",
today = "%1\$s 도착",
tomorrow = "내일 %1\$s 도착",
thisYear = "%1\$s 도착",
otherYear = "%1\$s 도착",
todayTimePattern = "a h:mm", // 예시: "오후 2:30"
thisYearDatePattern = "M월 d일 a h:mm", // 예시: "11월 20일 오후 2:30"
otherYearDatePattern = "yy년 M월 d일 a h:mm" // 예시: "24년 1월 15일 오전 9:00"
)

@Test
fun `가장빠른_알람시간_포맷팅_활성알람_없으면_수정된_알람없음_반환`() {
val alarms = listOf(
Alarm(id = 1, hour = 14, minute = 0, repeatDays = 0, isAlarmActive = false)
)
val result = formatter.getFormattedEarliestUpcomingAlarmDeliveryTime(alarms, deliveryFormats, fixedNow)
assertEquals("받을 수 있는 운세가 없어요", result)
}

@Test
fun `가장빠른_알람시간_포맷팅_오늘_미래_활성알람_하나면_수정된_오늘형식_반환`() {
val alarms = listOf(
Alarm(id = 1, hour = 14, minute = 30, repeatDays = 0, isAlarmActive = true)
)
// deliveryFormats.today = "%1$s 도착"
// deliveryFormats.todayTimePattern = "a h:mm" -> "오후 2:30"
val result = formatter.getFormattedEarliestUpcomingAlarmDeliveryTime(alarms, deliveryFormats, fixedNow)
assertEquals("오후 2:30 도착", result)
}

@Test
fun `가장빠른_알람시간_포맷팅_내일_활성알람_하나면_수정된_내일형식_반환`() {
val alarms = listOf(
Alarm(id = 1, hour = 8, minute = 0, repeatDays = 0, isAlarmActive = true)
)
// deliveryFormats.tomorrow = "내일 %1$s 도착"
// deliveryFormats.todayTimePattern = "a h:mm" -> "오전 8:00"
val result = formatter.getFormattedEarliestUpcomingAlarmDeliveryTime(alarms, deliveryFormats, fixedNow)
assertEquals("내일 오전 8:00 도착", result)
}

@Test
fun `가장빠른_알람시간_포맷팅_올해_다른날짜면_수정된_올해형식_반환`() {
// fixedNow = 2023년 10월 26일 (목요일) 10:00
// 목표: 11월 5일 (일요일) 14:30 에 알람이 울리도록.
// 이 날짜는 fixedNow 기준 "오늘"도 "내일"도 아님.
val alarmsForThisYearTest = listOf(
Alarm(
id = 1,
hour = 14, // 알람 시간
minute = 30,
repeatDays = AlarmDay.SUN.bitValue, // 일요일 반복
isAlarmActive = true,
)
)

val result = formatter.getFormattedEarliestUpcomingAlarmDeliveryTime(alarmsForThisYearTest, deliveryFormats, fixedNow)
assertEquals("10월 29일 오후 2:30 도착", result) // 예상 결과 수정
}

@Test
fun `가장빠른_알람시간_포맷팅_다른해면_수정된_다른해형식_반환`() {
// 현재 시간을 2023년 12월 31일 10:00 으로 설정
val nowInLate2023 = LocalDateTime.of(2023, 12, 31, 10, 0, 0)

// 알람이 다음 해인 2024년 1월 1일 9:00 에 울리도록 설정 (단일 알람)
val alarmsForNewYear = listOf(
Alarm(
id = 1,
hour = 9,
minute = 0,
repeatDays = 0, // 단일 알람
isAlarmActive = true,
)
)

// formatter.getFormattedEarliestUpcomingAlarmDeliveryTime 내부에서
// calculateNextOccurrence(9, 0, 0, nowInLate2023)가 호출됨.
// nowInLate2023 (2023-12-31 10:00) 기준으로, 알람 시간 09:00은 과거이므로,
// 다음 날인 2024-01-01 09:00이 반환되어야 함.
val result = formatter.getFormattedEarliestUpcomingAlarmDeliveryTime(alarmsForNewYear, deliveryFormats, nowInLate2023)

// deliveryFormats.otherYear = "%1$s 도착"
// deliveryFormats.otherYearDatePattern = "yy년 M월 d일 a h:mm"
// nowInLate2023의 year (2023)와 결과 날짜의 year (2024)가 다르므로 "otherYear" 포맷 사용
assertEquals("24년 1월 1일 오전 9:00 도착", result)
}

@Test
fun `가장빠른_알람시간_포맷팅_여러_활성알람중_가장빠른것_정확히_포맷팅_수정된형식`() {
val alarms = listOf(
Alarm(id = 1, hour = 15, minute = 0, repeatDays = 0, isAlarmActive = true), // 오늘 15:00
Alarm(id = 2, hour = 12, minute = 0, repeatDays = 0, isAlarmActive = true), // 오늘 12:00 (이게 더 빠름)
Alarm(id = 3, hour = 9, minute = 0, repeatDays = 0, isAlarmActive = false),
Alarm(id = 4, hour = 8, minute = 0, repeatDays = AlarmDay.FRI.bitValue, isAlarmActive = true) // 내일 08:00
)
val result = formatter.getFormattedEarliestUpcomingAlarmDeliveryTime(alarms, deliveryFormats, fixedNow)
assertEquals("오후 12:00 도착", result)
}

@Test
fun `날짜시간문자열_포맷팅_잘못된_날짜형식이면_수정된_알람없음_반환`() {
val result = formatter.getFormattedEarliestUpcomingAlarmDeliveryTime(emptyList(), deliveryFormats, fixedNow)
assertEquals("받을 수 있는 운세가 없어요", result)
}


private val timeFormats = AlarmDateTimeFormatter.TimeDifferenceFormats(
daysHoursMinutesFormat = "%1\$d일 %2\$d시간 %3\$d분 후에 울려요",
hoursMinutesFormat = "%1\$d시간 %2\$d분 후에 울려요",
minutesFormat = "%1\$d분 후에 울려요",
soonFormat = "곧 울려요"
)
Comment on lines +128 to +
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P4
요거랑 deliveryFormats companion object로 분리하는거 어떻게 생가하심까??
불변이라라 테스트 간 공유 문제 없고, 내부 객체가 JVM에 한 번만 올라가서 메모리 측면에서도 효율적이라고 생각해서염

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어어어어.... 이거 못보고 병합했네요
다음 PR 때 수정해서 같이 올릴게요


@Test
fun `시간차이_포맷팅_차이없거나_과거면_곧울려요_반환`() {
assertEquals(timeFormats.soonFormat, formatter.formatTimeDifference(fixedNow, fixedNow, timeFormats))
assertEquals(timeFormats.soonFormat, formatter.formatTimeDifference(fixedNow, fixedNow.minusMinutes(1), timeFormats))
}

@Test
fun `시간차이_포맷팅_1분미만_차이면_곧울려요_반환`() {
val future = fixedNow.plusSeconds(30)
assertEquals(timeFormats.soonFormat, formatter.formatTimeDifference(fixedNow, future, timeFormats))
}

@Test
fun `시간차이_포맷팅_25분_차이면_정확한_문자열_반환`() {
val futureTime = fixedNow.plusMinutes(25)
val result = formatter.formatTimeDifference(fixedNow, futureTime, timeFormats)
assertEquals("25분 후에 울려요", result)
}

@Test
fun `시간차이_포맷팅_70분_차이면_정확한_문자열_반환`() {
val futureTime = fixedNow.plusMinutes(70) // 1시간 10분
val result = formatter.formatTimeDifference(fixedNow, futureTime, timeFormats)
assertEquals("1시간 10분 후에 울려요", result)
}

@Test
fun `시간차이_포맷팅_1일_1시간_5분_차이면_정확한_문자열_반환`() {
val futureTime = fixedNow.plusDays(1).plusHours(1).plusMinutes(5)
val result = formatter.formatTimeDifference(fixedNow, futureTime, timeFormats)
assertEquals("1일 1시간 5분 후에 울려요", result)
}
}