@@ -4,6 +4,7 @@ import app.cash.turbine.test
44import dev.mokkery.MockMode
55import dev.mokkery.answering.returns
66import dev.mokkery.everySuspend
7+ import dev.mokkery.matcher.eq
78import dev.mokkery.matcher.ofType
89import dev.mokkery.mock
910import dev.mokkery.verifySuspend
@@ -12,11 +13,15 @@ import kotlinx.coroutines.test.runTest
1213import kotlinx.datetime.Clock
1314import kotlinx.datetime.TimeZone
1415import kotlinx.datetime.toLocalDateTime
16+ import org.mobilenativefoundation.trails.xplat.lib.models.post.Creator
1517import org.mobilenativefoundation.trails.xplat.lib.models.post.Platform
1618import org.mobilenativefoundation.trails.xplat.lib.models.post.Post
1719import org.mobilenativefoundation.trails.xplat.lib.models.post.PostOutput
1820import org.mobilenativefoundation.trails.xplat.lib.operations.io.Operation
21+ import org.mobilenativefoundation.trails.xplat.lib.operations.io.Operation.Query.QueryMany
22+ import org.mobilenativefoundation.trails.xplat.lib.operations.io.Operation.Query.QueryOne
1923import org.mobilenativefoundation.trails.xplat.lib.operations.query.DataSources
24+ import org.mobilenativefoundation.trails.xplat.lib.operations.query.Query
2025import org.mobilenativefoundation.trails.xplat.lib.repositories.post.impl.extensions.PostExtensions.asPostEntity
2126import org.mobilenativefoundation.trails.xplat.lib.repositories.post.impl.store.database.PostDAO
2227import org.mobilenativefoundation.trails.xplat.lib.rest.api.post.PostOperations
@@ -29,6 +34,61 @@ class RealPostFetcherServicesTest {
2934 private val postDAO = mock<PostDAO >(MockMode .autoUnit)
3035 private val postFetcherServices = RealPostFetcherServices (client, postDAO)
3136
37+ @Test
38+ fun findAndEmitOne_givenNormalClientAndDb_whenSuccessfulNetworkRequest_thenShouldUpdateDbAndEmitOutput () = runTest {
39+ // Given
40+ val flow = MutableSharedFlow <PostOutput >(replay = 10 )
41+
42+ val operation = Operation .Query .FindOne (
43+ key = Post .Key (1 ),
44+ dataSources = DataSources .all
45+ )
46+
47+ val post1 = createPost(1 )
48+
49+ everySuspend { client.findOne(eq(operation.key)) }.returns(post1)
50+
51+ // When
52+ postFetcherServices.findAndEmitOne(operation) { flow.emit(it) }
53+
54+ // Then
55+ verifySuspend { postDAO.insertOne(post1.asPostEntity()) }
56+
57+ flow.test {
58+ val output = awaitItem()
59+ assertEquals(PostOutput .Single (post1), output)
60+ expectNoEvents()
61+ }
62+ }
63+
64+ @Test
65+ fun findAndEmitOneComposite_givenNormalClientAndDb_whenSuccessfulNetworkRequest_thenShouldUpdateDbAndEmitOutput () =
66+ runTest {
67+ // Given
68+ val flow = MutableSharedFlow <PostOutput >(replay = 10 )
69+
70+ val operation = Operation .Query .FindOneComposite (
71+ key = Post .Key (1 ),
72+ dataSources = DataSources .all
73+ )
74+
75+ val compositePost = createCompositePost(1 )
76+
77+ everySuspend { client.findOneComposite(eq(operation.key)) }.returns(compositePost)
78+
79+ // When
80+ postFetcherServices.findAndEmitOneComposite(operation) { flow.emit(it) }
81+
82+ // Then
83+ verifySuspend { postDAO.insertOneComposite(compositePost) }
84+
85+ flow.test {
86+ val output = awaitItem()
87+ assertEquals(PostOutput .Single (compositePost), output)
88+ expectNoEvents()
89+ }
90+ }
91+
3292 @Test
3393 fun findAndEmitMany_givenNormalClientAndDb_whenSuccessfulNetworkRequest_thenShouldUpdateDbAndEmitOutput () =
3494 runTest {
@@ -64,6 +124,153 @@ class RealPostFetcherServicesTest {
64124 }
65125 }
66126
127+ @Test
128+ fun findAndEmitAll_givenNormalClientAndDb_whenSuccessfulNetworkRequest_thenShouldUpdateDbAndEmitOutput () =
129+ runTest {
130+ // Given
131+ val flow = MutableSharedFlow <PostOutput >(replay = 10 )
132+
133+ val operation = Operation .Query .FindAll (
134+ dataSources = DataSources .all
135+ )
136+
137+ val post1 = createPost(1 )
138+ val post2 = createPost(2 )
139+
140+ val posts = listOf (
141+ post1,
142+ post2
143+ )
144+
145+ everySuspend { client.findAll() }.returns(posts)
146+
147+ // When
148+ postFetcherServices.findAndEmitAll(operation) { flow.emit(it) }
149+
150+ // Then
151+ verifySuspend { postDAO.insertOne(post1.asPostEntity()) }
152+ verifySuspend { postDAO.insertOne(post2.asPostEntity()) }
153+
154+ flow.test {
155+ val output = awaitItem()
156+ assertEquals(PostOutput .Collection (posts), output)
157+ expectNoEvents()
158+ }
159+ }
160+
161+ @Test
162+ fun queryAndEmitOne_givenNormalClientAndDb_whenSuccessfulNetworkRequest_thenShouldUpdateDbAndEmitOutput () =
163+ runTest {
164+ // Given
165+ val flow = MutableSharedFlow <PostOutput >(replay = 10 )
166+
167+ val operation = QueryOne (
168+ query = Query .One <Post .Node >(
169+ dataSources = DataSources .all,
170+ predicate = null ,
171+ order = null
172+ ),
173+ dataSources = DataSources .all
174+ )
175+
176+ val post1 = createPost(1 )
177+
178+ everySuspend { client.queryOne(ofType()) }.returns(post1)
179+
180+ // When
181+ postFetcherServices.queryAndEmitOne(operation) { flow.emit(it) }
182+
183+ // Then
184+ verifySuspend { postDAO.insertOne(post1.asPostEntity()) }
185+
186+ flow.test {
187+ val output = awaitItem()
188+ assertEquals(PostOutput .Single (post1), output)
189+ expectNoEvents()
190+ }
191+ }
192+
193+ @Test
194+ fun queryAndEmitMany_givenNormalClientAndDb_whenSuccessfulNetworkRequest_thenShouldUpdateDbAndEmitOutput () =
195+ runTest {
196+ // Given
197+ val flow = MutableSharedFlow <PostOutput >(replay = 10 )
198+
199+ val operation = QueryMany (
200+ query = Query .Many <Post .Node >(
201+ dataSources = DataSources .all,
202+ predicate = null ,
203+ order = null ,
204+ limit = null
205+ ),
206+ dataSources = DataSources .all
207+ )
208+
209+ val post1 = createPost(1 )
210+ val post2 = createPost(2 )
211+
212+ val posts = listOf (
213+ post1,
214+ post2
215+ )
216+
217+ everySuspend { client.queryMany(ofType()) }.returns(posts)
218+
219+ // When
220+ postFetcherServices.queryAndEmitMany(operation) { flow.emit(it) }
221+
222+ // Then
223+ verifySuspend { postDAO.insertOne(post1.asPostEntity()) }
224+ verifySuspend { postDAO.insertOne(post2.asPostEntity()) }
225+
226+ flow.test {
227+ val output = awaitItem()
228+ assertEquals(PostOutput .Collection (posts), output)
229+ expectNoEvents()
230+ }
231+ }
232+
233+
234+ @Test
235+ fun queryAndEmitManyComposite_givenNormalClientAndDb_whenSuccessfulNetworkRequest_thenShouldUpdateDbAndEmitOutput () =
236+ runTest {
237+ // Given
238+ val flow = MutableSharedFlow <PostOutput >(replay = 10 )
239+
240+ val operation = Operation .Query .QueryManyComposite (
241+ query = Query .Many <Post .Node >(
242+ dataSources = DataSources .all,
243+ predicate = null ,
244+ order = null ,
245+ limit = null
246+ ),
247+ dataSources = DataSources .all
248+ )
249+
250+ val post1 = createCompositePost(1 )
251+ val post2 = createCompositePost(2 )
252+
253+ val posts = listOf (
254+ post1,
255+ post2
256+ )
257+
258+ everySuspend { client.queryManyComposite(ofType()) }.returns(PostOutput .Collection (posts))
259+
260+ // When
261+ postFetcherServices.queryAndEmitManyComposite(operation) { flow.emit(it) }
262+
263+ // Then
264+ verifySuspend { postDAO.insertOneComposite(post1) }
265+ verifySuspend { postDAO.insertOneComposite(post2) }
266+
267+ flow.test {
268+ val output = awaitItem()
269+ assertEquals(PostOutput .Collection (posts), output)
270+ expectNoEvents()
271+ }
272+ }
273+
67274 private fun createPost (id : Int ) = Post .Node (
68275 key = Post .Key (id),
69276 properties = Post .Properties (
@@ -80,4 +287,26 @@ class RealPostFetcherServicesTest {
80287 locationName = null ,
81288 )
82289 )
290+
291+ private fun createCompositePost (id : Int ) = Post .Composite (
292+ node = createPost(id),
293+ edges = Post .Edges (
294+ creator = createCreator(id),
295+ hashtags = emptyList(),
296+ mentions = emptyList(),
297+ media = emptyList()
298+ )
299+ )
300+
301+ private fun createCreator (id : Int ) = Creator .Node (
302+ key = Creator .Key (id),
303+ properties = Creator .Properties (
304+ username = " " ,
305+ fullName = " " ,
306+ profilePicURL = " " ,
307+ isVerified = false ,
308+ bio = " " ,
309+ platform = Platform .Instagram
310+ )
311+ )
83312}
0 commit comments