@@ -21,12 +21,17 @@ import com.tidal.sdk.player.events.reflectionComponentFactoryF
2121import com.tidal.sdk.player.playbackengine.model.Event
2222import com.tidal.sdk.player.setBodyFromFile
2323import kotlin.math.absoluteValue
24+ import kotlin.time.Duration.Companion.milliseconds
2425import kotlin.time.Duration.Companion.minutes
26+ import kotlin.time.Duration.Companion.seconds
2527import kotlinx.coroutines.Dispatchers
28+ import kotlinx.coroutines.delay
2629import kotlinx.coroutines.flow.Flow
30+ import kotlinx.coroutines.flow.collect
2731import kotlinx.coroutines.flow.emptyFlow
2832import kotlinx.coroutines.flow.filter
2933import kotlinx.coroutines.flow.first
34+ import kotlinx.coroutines.flow.take
3035import kotlinx.coroutines.launch
3136import kotlinx.coroutines.runBlocking
3237import kotlinx.coroutines.test.StandardTestDispatcher
@@ -48,6 +53,7 @@ import org.junit.Test
4853import org.junit.runners.Parameterized
4954import org.mockito.Mockito.atMost
5055import org.mockito.Mockito.mock
56+ import org.mockito.Mockito.times
5157import org.mockito.Mockito.verifyNoMoreInteractions
5258import org.mockito.kotlin.anyOrNull
5359import org.mockito.kotlin.argThat
@@ -235,6 +241,65 @@ internal class TwoMediaProductsPlayLogTest {
235241 )
236242 }
237243
244+ @Test
245+ fun repeatOneWithNext () = runTest {
246+ val gson = Gson ()
247+
248+ player.playbackEngine.load(mediaProduct1)
249+ player.playbackEngine.setNext(mediaProduct2)
250+ player.playbackEngine.setRepeatOne(true )
251+ player.playbackEngine.play()
252+ withContext(Dispatchers .Default .limitedParallelism(1 )) {
253+ withTimeout(8 .seconds) {
254+ player.playbackEngine.events.filter { it is Event .MediaProductTransition }
255+ .take(2 )
256+ .collect()
257+ }
258+ player.playbackEngine.setRepeatOne(false )
259+ withTimeout(8 .seconds) {
260+ player.playbackEngine.events.filter { it is Event .MediaProductTransition }.first()
261+ }
262+ delay(1 .seconds)
263+ while (player.playbackEngine.assetPosition < 1 ) {
264+ delay(10 .milliseconds)
265+ }
266+ player.playbackEngine.reset()
267+ }
268+
269+ eventReporterCoroutineScope.advanceUntilIdle()
270+ verify(eventSender, times(2 )).sendEvent(
271+ eq(" playback_session" ),
272+ eq(ConsentCategory .NECESSARY ),
273+ argThat {
274+ with (gson.fromJson(this , JsonObject ::class .java)[" payload" ].asJsonObject) {
275+ get(" startAssetPosition" ).asDouble.isAssetPositionEqualTo(0.0 ) &&
276+ get(" endAssetPosition" ).asDouble
277+ .isAssetPositionEqualTo(MEDIA_PRODUCT_1_DURATION_SECONDS ) &&
278+ get(" actualProductId" )?.asString.contentEquals(mediaProduct1.productId) &&
279+ get(" sourceType" )?.asString.contentEquals(mediaProduct1.sourceType) &&
280+ get(" sourceId" )?.asString.contentEquals(mediaProduct1.sourceId) &&
281+ get(" actions" ).asJsonArray.isEmpty
282+ }
283+ },
284+ eq(emptyMap()),
285+ )
286+ verify(eventSender).sendEvent(
287+ eq(" playback_session" ),
288+ eq(ConsentCategory .NECESSARY ),
289+ argThat {
290+ with (gson.fromJson(this , JsonObject ::class .java)[" payload" ].asJsonObject) {
291+ get(" startAssetPosition" ).asDouble.isAssetPositionEqualTo(0.0 ) &&
292+ get(" endAssetPosition" ).asDouble.isAssetPositionEqualTo(1.0 ) &&
293+ get(" actualProductId" )?.asString.contentEquals(mediaProduct2.productId) &&
294+ get(" sourceType" )?.asString.contentEquals(mediaProduct2.sourceType) &&
295+ get(" sourceId" )?.asString.contentEquals(mediaProduct2.sourceId) &&
296+ get(" actions" ).asJsonArray.isEmpty
297+ }
298+ },
299+ eq(emptyMap()),
300+ )
301+ }
302+
238303 private fun Double.isAssetPositionEqualTo (targetPosition : Double ) =
239304 (this - targetPosition).absoluteValue < 0.5
240305}
0 commit comments