Skip to content

Commit 0eaf6ff

Browse files
committed
test: add initial tests to HikeRoutesRepositoryOverpass
1 parent c7457d6 commit 0eaf6ff

File tree

1 file changed

+264
-0
lines changed

1 file changed

+264
-0
lines changed
Lines changed: 264 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,264 @@
1+
package ch.hikemate.app.model.route
2+
3+
import java.io.IOException
4+
import java.util.concurrent.atomic.AtomicInteger
5+
import okhttp3.Call
6+
import okhttp3.OkHttpClient
7+
import okhttp3.Protocol
8+
import okhttp3.Response
9+
import okhttp3.ResponseBody.Companion.toResponseBody
10+
import org.junit.Assert.assertEquals
11+
import org.junit.Assert.assertNotEquals
12+
import org.junit.Assert.fail
13+
import org.junit.Before
14+
import org.junit.Test
15+
import org.junit.runner.RunWith
16+
import org.mockito.Mock
17+
import org.mockito.Mockito.mock
18+
import org.mockito.Mockito.`when`
19+
import org.mockito.MockitoAnnotations
20+
import org.mockito.kotlin.any
21+
import org.mockito.kotlin.argumentCaptor
22+
import org.mockito.kotlin.verify
23+
import org.robolectric.RobolectricTestRunner
24+
25+
@RunWith(RobolectricTestRunner::class)
26+
class HikeRoutesRepositoryOverpassTest {
27+
@Mock private lateinit var mockClient: OkHttpClient
28+
private lateinit var hikingRouteProviderRepositoryOverpass: HikeRoutesRepositoryOverpass
29+
private val bounds = Bounds(46.52291, 6.55989, 46.51402, 6.58243)
30+
31+
private val emptyResponse =
32+
Response.Builder()
33+
.code(200)
34+
.message("OK")
35+
.body(
36+
"""
37+
{
38+
"version": 0.6,
39+
"generator": "Overpass API 0.7.62.1 084b4234",
40+
"osm3s": {
41+
"timestamp_osm_base": "2024-10-10T19:14:42Z",
42+
"copyright": "The data included in this document is from www.openstreetmap.org. The data is made available under ODbL."
43+
},
44+
"elements": []
45+
}
46+
"""
47+
.trimIndent()
48+
.replace("\n", "")
49+
.toResponseBody())
50+
.header("Content-Type", "application/json")
51+
.protocol(Protocol.HTTP_1_1)
52+
.request(mock())
53+
.build()
54+
55+
private val simpleResponse =
56+
Response.Builder()
57+
.code(200)
58+
.message("OK")
59+
.body(
60+
"""
61+
{
62+
"version": 0.6,
63+
"generator": "Overpass API 0.7.62.1 084b4234",
64+
"osm3s": {
65+
"timestamp_osm_base": "2024-10-10T19:14:42Z",
66+
"copyright": "The data included in this document is from www.openstreetmap.org. The data is made available under ODbL."
67+
},
68+
"elements": [
69+
{
70+
"type": "relation",
71+
"id": 124582,
72+
"bounds": {
73+
"minlat": 45.8689061,
74+
"minlon": 6.4395807,
75+
"maxlat": 46.8283926,
76+
"maxlon": 7.2109599
77+
},
78+
"members": [
79+
{
80+
"type": "way",
81+
"ref": 936770892,
82+
"role": "",
83+
"geometry": [
84+
{
85+
"lat": 46.8240018,
86+
"lon": 6.4395807
87+
},
88+
{
89+
"lat": 46.823965,
90+
"lon": 6.4396698
91+
}
92+
]
93+
},
94+
{
95+
"type": "way",
96+
"ref": 24956166,
97+
"role": "",
98+
"geometry": [
99+
{
100+
"lat": 46.8236197,
101+
"lon": 6.4400574
102+
},
103+
{
104+
"lat": 46.8235322,
105+
"lon": 6.4401168
106+
},
107+
{
108+
"lat": 46.8234367,
109+
"lon": 6.4401715
110+
}
111+
]
112+
},
113+
{
114+
"type": "node",
115+
"ref": 1107816214,
116+
"role": "",
117+
"lat": 46.8232651,
118+
"lon": 6.4402355
119+
}
120+
],
121+
"tags": {
122+
"distance": "31",
123+
"from": "Lausanne",
124+
"int_name": "Camino de Santiago",
125+
"name": "ViaJacobi",
126+
"network": "nwn",
127+
"operator": "Wanderland Schweiz",
128+
"osmc:symbol": "green:green::4:white",
129+
"pilgrimage": "Camino de Santiago",
130+
"ref": "4",
131+
"religion": "christian",
132+
"route": "hiking",
133+
"stage": "17",
134+
"symbol": "weisse 4 auf grünem Rechteck und in südwestlicher Richtung Jakobsmuschel",
135+
"to": "Roll",
136+
"type": "route",
137+
"url": "https://www.schweizmobil.ch/fr/wanderland/etappe4.17"
138+
}
139+
}
140+
]
141+
}
142+
"""
143+
.trimIndent()
144+
.replace("\n", "")
145+
.toResponseBody())
146+
.protocol(Protocol.HTTP_1_1)
147+
.header("Content-Type", "application/json")
148+
.request(mock())
149+
.build()
150+
151+
private val failedResponse =
152+
Response.Builder()
153+
.code(419)
154+
.message("Too Many Requests")
155+
.body("Too Many Requests".toResponseBody())
156+
.protocol(Protocol.HTTP_1_1)
157+
.request(mock())
158+
.build()
159+
160+
private val simpleRoutes: List<HikeRoute> =
161+
listOf(
162+
HikeRoute(
163+
"124582",
164+
Bounds(45.8689061, 6.4395807, 46.8283926, 7.2109599),
165+
listOf(
166+
LatLong(46.8240018, 6.4395807),
167+
LatLong(46.8239650, 6.4396698),
168+
LatLong(46.8236197, 6.4400574),
169+
LatLong(46.8235322, 6.4401168),
170+
LatLong(46.8234367, 6.4401715),
171+
LatLong(46.8232651, 6.4402355))))
172+
173+
@Before
174+
fun setUp() {
175+
MockitoAnnotations.openMocks(this)
176+
177+
hikingRouteProviderRepositoryOverpass = HikeRoutesRepositoryOverpass(mockClient)
178+
}
179+
180+
@Test
181+
fun getRoutes_callsClient() {
182+
`when`(mockClient.newCall(any())).thenReturn(mock())
183+
hikingRouteProviderRepositoryOverpass.getRoutes(
184+
bounds,
185+
{ routes ->
186+
assertNotEquals(routes.size, 0)
187+
print(routes)
188+
}) {
189+
fail("Failed to fetch routes from Overpass API")
190+
}
191+
verify(mockClient).newCall(any())
192+
}
193+
194+
@Test
195+
fun getRoutes_worksOnEmptyAnswer() {
196+
val mockCall = mock(Call::class.java)
197+
`when`(mockClient.newCall(any())).thenReturn(mockCall)
198+
199+
val callbackCapture = argumentCaptor<okhttp3.Callback>()
200+
201+
`when`(mockCall.enqueue(callbackCapture.capture())).then {
202+
callbackCapture.firstValue.onResponse(mockCall, emptyResponse)
203+
}
204+
205+
hikingRouteProviderRepositoryOverpass.getRoutes(
206+
bounds, { routes -> assertEquals(0, routes.size) }) {
207+
fail("Failed to fetch routes from Overpass API")
208+
}
209+
}
210+
211+
@Test
212+
fun getRoutes_worksOnSimpleAnswer() {
213+
val mockCall = mock(Call::class.java)
214+
`when`(mockClient.newCall(any())).thenReturn(mockCall)
215+
216+
val callbackCapture = argumentCaptor<okhttp3.Callback>()
217+
218+
`when`(mockCall.enqueue(callbackCapture.capture())).then {
219+
callbackCapture.firstValue.onResponse(mockCall, simpleResponse)
220+
}
221+
222+
hikingRouteProviderRepositoryOverpass.getRoutes(
223+
bounds, { routes -> assertEquals(simpleRoutes, routes) }) {
224+
fail("Failed to fetch routes from Overpass API")
225+
}
226+
}
227+
228+
@Test
229+
fun getRoutes_failsCorrectlyWithServerResponse() {
230+
val failureCounter = AtomicInteger(0)
231+
val mockCall = mock(Call::class.java)
232+
`when`(mockClient.newCall(any())).thenReturn(mockCall)
233+
234+
val callbackCapture = argumentCaptor<okhttp3.Callback>()
235+
236+
`when`(mockCall.enqueue(callbackCapture.capture())).then {
237+
callbackCapture.firstValue.onResponse(mockCall, failedResponse)
238+
}
239+
240+
hikingRouteProviderRepositoryOverpass.getRoutes(bounds, { fail("Overpass hasn't failed") }) {
241+
failureCounter.incrementAndGet()
242+
}
243+
assertEquals(1, failureCounter.get())
244+
}
245+
246+
@Test
247+
fun getRoutes_failsCorrectlyWithNoServerResponse() {
248+
val failureCounter = AtomicInteger(0)
249+
val mockCall = mock(Call::class.java)
250+
`when`(mockClient.newCall(any())).thenReturn(mockCall)
251+
252+
val callbackCapture = argumentCaptor<okhttp3.Callback>()
253+
254+
`when`(mockCall.enqueue(callbackCapture.capture())).then {
255+
callbackCapture.firstValue.onFailure(
256+
mockCall, IOException("Failed to fetch routes from Overpass API"))
257+
}
258+
259+
hikingRouteProviderRepositoryOverpass.getRoutes(bounds, { fail("Overpass hasn't failed") }) {
260+
failureCounter.incrementAndGet()
261+
}
262+
assertEquals(1, failureCounter.get())
263+
}
264+
}

0 commit comments

Comments
 (0)