1+ package com.example.util.simpletimetracker.core.mapper
2+
3+ import com.example.util.simpletimetracker.core.extension.shift
4+ import com.example.util.simpletimetracker.domain.extension.orZero
5+ import org.junit.Assert.assertEquals
6+ import org.junit.Rule
7+ import org.junit.Test
8+ import org.junit.rules.TestWatcher
9+ import org.junit.runner.Description
10+ import org.junit.runner.RunWith
11+ import org.junit.runners.Parameterized
12+ import java.util.Calendar
13+ import java.util.TimeZone
14+ import java.util.concurrent.TimeUnit
15+
16+ @RunWith(Parameterized ::class )
17+ class CalendarShiftTest (
18+ private val input : Pair <Calendar , String >,
19+ private val output : String ,
20+ ) {
21+
22+ @Rule
23+ @JvmField
24+ var timeZoneRule = TimeZoneRule ()
25+
26+ @Test
27+ fun map () {
28+ val expected = output
29+ val shift = input.second.split(" :" ).let {
30+ val negative = it.first().startsWith(" -" )
31+ val sign = if (negative) - 1 else 1
32+ it.first().toIntOrNull().orZero() * hourInMs +
33+ sign * it.last().toIntOrNull().orZero() * minInMs
34+ }
35+ val actual = input.first.shift(shift).let {
36+ " ${it.get(Calendar .HOUR_OF_DAY )} :${it.get(Calendar .MINUTE )} "
37+ }
38+
39+ assertEquals(
40+ " Test failed for params $input " ,
41+ expected,
42+ actual,
43+ )
44+ }
45+
46+ companion object {
47+ private val minInMs = TimeUnit .MINUTES .toMillis(1 )
48+ private val hourInMs = TimeUnit .HOURS .toMillis(1 )
49+
50+ // Day of dst forward change in Germany.
51+ private fun getDstForward (time : String ): Calendar {
52+ val hour = time.split(" :" ).first().toIntOrNull().orZero()
53+ val min = time.split(" :" ).last().toIntOrNull().orZero()
54+ return Calendar .getInstance(TimeZone .getTimeZone(" Europe/Berlin" )).apply {
55+ timeInMillis = 0
56+ set(Calendar .YEAR , 2025 )
57+ set(Calendar .MONTH , 2 )
58+ set(Calendar .HOUR_OF_DAY , hour)
59+ set(Calendar .MINUTE , min)
60+ set(Calendar .DAY_OF_MONTH , 30 )
61+ }
62+ }
63+
64+ // Day of dst forward change in Germany.
65+ private fun getDstBackward (time : String ): Calendar {
66+ val hour = time.split(" :" ).first().toIntOrNull().orZero()
67+ val min = time.split(" :" ).last().toIntOrNull().orZero()
68+ return Calendar .getInstance(TimeZone .getTimeZone(" Europe/Berlin" )).apply {
69+ timeInMillis = 0
70+ set(Calendar .YEAR , 2025 )
71+ set(Calendar .MONTH , 9 )
72+ set(Calendar .HOUR_OF_DAY , hour)
73+ set(Calendar .MINUTE , min)
74+ set(Calendar .DAY_OF_MONTH , 26 )
75+ }
76+ }
77+
78+ @JvmStatic
79+ @Parameterized.Parameters
80+ fun data () = listOf (
81+ // Forward dst change.
82+ arrayOf(getDstForward(" 0:0" ) to " 0:0" , " 0:0" ),
83+ arrayOf(getDstForward(" 0:0" ) to " 1:0" , " 1:0" ),
84+ arrayOf(getDstForward(" 0:0" ) to " 1:59" , " 1:59" ),
85+ arrayOf(getDstForward(" 0:0" ) to " 2:0" , " 3:0" ),
86+ arrayOf(getDstForward(" 0:0" ) to " 2:1" , " 3:1" ),
87+ arrayOf(getDstForward(" 0:0" ) to " 2:30" , " 3:30" ),
88+ arrayOf(getDstForward(" 0:0" ) to " 2:59" , " 3:59" ),
89+ arrayOf(getDstForward(" 0:0" ) to " 3:0" , " 3:0" ),
90+ arrayOf(getDstForward(" 0:0" ) to " 3:1" , " 3:1" ),
91+ arrayOf(getDstForward(" 0:0" ) to " 4:0" , " 4:0" ),
92+ arrayOf(getDstForward(" 0:0" ) to " 5:0" , " 5:0" ),
93+
94+ arrayOf(getDstForward(" 5:0" ) to " 0:0" , " 5:0" ),
95+ arrayOf(getDstForward(" 5:0" ) to " -1:0" , " 4:0" ),
96+ arrayOf(getDstForward(" 5:0" ) to " -1:59" , " 3:1" ),
97+ arrayOf(getDstForward(" 5:0" ) to " -2:0" , " 3:0" ),
98+ arrayOf(getDstForward(" 5:0" ) to " -2:1" , " 1:59" ),
99+ arrayOf(getDstForward(" 5:0" ) to " -2:30" , " 1:30" ),
100+ arrayOf(getDstForward(" 5:0" ) to " -2:59" , " 1:1" ),
101+ arrayOf(getDstForward(" 5:0" ) to " -3:0" , " 1:0" ),
102+ arrayOf(getDstForward(" 5:0" ) to " -3:1" , " 1:59" ),
103+ arrayOf(getDstForward(" 5:0" ) to " -4:0" , " 1:0" ),
104+ arrayOf(getDstForward(" 5:0" ) to " -5:0" , " 0:0" ),
105+
106+ arrayOf(getDstForward(" 0:0" ) to " 2:0" , " 3:0" ),
107+ arrayOf(getDstForward(" 0:0" ) to " 3:0" , " 3:0" ),
108+ arrayOf(getDstForward(" 1:0" ) to " 1:0" , " 3:0" ),
109+ arrayOf(getDstForward(" 1:0" ) to " 2:0" , " 3:0" ),
110+ arrayOf(getDstForward(" 2:0" ) to " 1:0" , " 4:0" ),
111+ arrayOf(getDstForward(" 2:0" ) to " 2:0" , " 5:0" ),
112+ arrayOf(getDstForward(" 3:0" ) to " 1:0" , " 4:0" ),
113+ arrayOf(getDstForward(" 3:0" ) to " 2:0" , " 5:0" ),
114+ arrayOf(getDstForward(" 3:0" ) to " -1:0" , " 1:0" ),
115+ arrayOf(getDstForward(" 3:0" ) to " -2:0" , " 1:0" ),
116+ arrayOf(getDstForward(" 3:0" ) to " -3:0" , " 0:0" ),
117+ arrayOf(getDstForward(" 2:0" ) to " -1:0" , " 1:0" ),
118+ arrayOf(getDstForward(" 2:0" ) to " -2:0" , " 1:0" ),
119+ arrayOf(getDstForward(" 1:0" ) to " -1:0" , " 0:0" ),
120+
121+ // Backward dst change.
122+ arrayOf(getDstBackward(" 0:0" ) to " 0:0" , " 0:0" ),
123+ arrayOf(getDstBackward(" 0:0" ) to " 1:0" , " 1:0" ),
124+ arrayOf(getDstBackward(" 0:0" ) to " 2:0" , " 2:0" ),
125+ arrayOf(getDstBackward(" 0:0" ) to " 3:0" , " 3:0" ),
126+ arrayOf(getDstBackward(" 0:0" ) to " 4:0" , " 4:0" ),
127+ arrayOf(getDstBackward(" 0:0" ) to " 5:0" , " 5:0" ),
128+
129+ arrayOf(getDstBackward(" 5:0" ) to " 0:0" , " 5:0" ),
130+ arrayOf(getDstBackward(" 5:0" ) to " -1:0" , " 4:0" ),
131+ arrayOf(getDstBackward(" 5:0" ) to " -2:0" , " 3:0" ),
132+ arrayOf(getDstBackward(" 5:0" ) to " -3:0" , " 2:0" ),
133+ arrayOf(getDstBackward(" 5:0" ) to " -4:0" , " 1:0" ),
134+ arrayOf(getDstBackward(" 5:0" ) to " -5:0" , " 0:0" ),
135+
136+ arrayOf(getDstBackward(" 0:0" ) to " 2:0" , " 2:0" ),
137+ arrayOf(getDstBackward(" 0:0" ) to " 3:0" , " 3:0" ),
138+ arrayOf(getDstBackward(" 1:0" ) to " 1:0" , " 2:0" ),
139+ arrayOf(getDstBackward(" 1:0" ) to " 2:0" , " 3:0" ),
140+ arrayOf(getDstBackward(" 2:0" ) to " 1:0" , " 3:0" ),
141+ arrayOf(getDstBackward(" 2:0" ) to " 2:0" , " 4:0" ),
142+ arrayOf(getDstBackward(" 3:0" ) to " 1:0" , " 4:0" ),
143+ arrayOf(getDstBackward(" 3:0" ) to " 2:0" , " 5:0" ),
144+ arrayOf(getDstBackward(" 3:0" ) to " -1:0" , " 2:0" ),
145+ arrayOf(getDstBackward(" 3:0" ) to " -2:0" , " 1:0" ),
146+ arrayOf(getDstBackward(" 3:0" ) to " -3:0" , " 0:0" ),
147+ arrayOf(getDstBackward(" 2:0" ) to " -1:0" , " 1:0" ),
148+ arrayOf(getDstBackward(" 2:0" ) to " -2:0" , " 0:0" ),
149+ arrayOf(getDstBackward(" 1:0" ) to " -1:0" , " 0:0" ),
150+ )
151+ }
152+
153+ class TimeZoneRule : TestWatcher () {
154+ private val origDefault: TimeZone = TimeZone .getDefault()
155+
156+ override fun starting (description : Description ? ) {
157+ TimeZone .setDefault(TimeZone .getTimeZone(" Europe/Berlin" ))
158+ }
159+
160+ override fun finished (description : Description ? ) {
161+ TimeZone .setDefault(origDefault)
162+ }
163+ }
164+ }
0 commit comments