Refactor LimitOffsetPagingSourceTest to use paging-testing artifact

Add paging-testing to COMPOSE build subset because room-paging belongs in COMPOSE subset and all its dependencies are required to be as well

Test: ./gradlew room:room-paging:cC
Bug: n/a
Change-Id: I4b2a0d4be59bdba619dfe08b941aa27e85214ca2
diff --git a/room/room-paging/build.gradle b/room/room-paging/build.gradle
index 5be305e..b6d0d5c 100644
--- a/room/room-paging/build.gradle
+++ b/room/room-paging/build.gradle
@@ -52,6 +52,7 @@
     androidTestImplementation(libs.truth)
     androidTestImplementation("androidx.arch.core:core-testing:2.0.1")
     androidTestImplementation(project(":internal-testutils-common"))
+    androidTestImplementation(projectOrArtifact(":paging:paging-testing"))
 }
 
 androidx {
diff --git a/room/room-paging/src/androidTest/kotlin/androidx/room/paging/LimitOffsetPagingSourceTest.kt b/room/room-paging/src/androidTest/kotlin/androidx/room/paging/LimitOffsetPagingSourceTest.kt
index 991314c..09a9564 100644
--- a/room/room-paging/src/androidTest/kotlin/androidx/room/paging/LimitOffsetPagingSourceTest.kt
+++ b/room/room-paging/src/androidTest/kotlin/androidx/room/paging/LimitOffsetPagingSourceTest.kt
@@ -18,11 +18,11 @@
 
 import android.database.Cursor
 import androidx.arch.core.executor.testing.CountingTaskExecutorRule
-import androidx.paging.LoadType
 import androidx.paging.PagingConfig
 import androidx.paging.PagingSource
+import androidx.paging.PagingSource.LoadParams
 import androidx.paging.PagingSource.LoadResult
-import androidx.paging.PagingState
+import androidx.paging.testing.TestPager
 import androidx.room.Room
 import androidx.room.RoomDatabase
 import androidx.room.RoomSQLiteQuery
@@ -39,7 +39,6 @@
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.test.advanceUntilIdle
-import kotlinx.coroutines.test.runTest
 import org.junit.After
 import org.junit.Before
 import org.junit.Rule
@@ -51,6 +50,7 @@
 import kotlin.test.assertFalse
 import kotlin.test.assertTrue
 import kotlinx.coroutines.Job
+import kotlinx.coroutines.test.runTest
 
 private const val tableName: String = "TestItem"
 
@@ -121,575 +121,477 @@
     }
 
     @Test
-    fun test_itemCount() {
+    fun test_itemCount() = runPagingSourceTest { pager, pagingSource ->
         dao.addAllItems(ITEMS_LIST)
-        val pagingSource = LimitOffsetPagingSourceImpl(database)
-        runBlocking {
-            // count query is executed on first load
-            pagingSource.refresh()
-
-            assertThat(pagingSource.itemCount.get()).isEqualTo(100)
-        }
+        // count query is executed on first load
+        pager.refresh()
+        assertThat(pagingSource.itemCount.get()).isEqualTo(100)
     }
 
     @Test
-    fun test_itemCountWithSuppliedLimitOffset() {
-        dao.addAllItems(ITEMS_LIST)
-        val pagingSource = LimitOffsetPagingSourceImpl(
+    fun test_itemCountWithSuppliedLimitOffset() = runPagingSourceTest(
+        LimitOffsetPagingSourceImpl(
             db = database,
             queryString = "SELECT * FROM $tableName ORDER BY id ASC LIMIT 60 OFFSET 30",
         )
-        runBlocking {
-            // count query is executed on first load
-            pagingSource.refresh()
-            // should be 60 instead of 100
-            assertThat(pagingSource.itemCount.get()).isEqualTo(60)
-        }
-    }
-
-    @Test
-    fun dbInsert_pagingSourceInvalidates() {
+    ) { pager, pagingSource ->
         dao.addAllItems(ITEMS_LIST)
-        val pagingSource = LimitOffsetPagingSourceImpl(database)
-        runBlocking {
-            // load once to register db observers
-            pagingSource.refresh()
-            assertThat(pagingSource.invalid).isFalse()
-            // paging source should be invalidated when insert into db
-            val result = dao.addTestItem(TestItem(101))
-            countingTaskExecutorRule.drainTasks(500, TimeUnit.MILLISECONDS)
-            assertThat(result).isEqualTo(101)
-            assertTrue(pagingSource.invalid)
-        }
+        // count query is executed on first load
+        pager.refresh()
+        // should be 60 instead of 100
+        assertThat(pagingSource.itemCount.get()).isEqualTo(60)
     }
 
     @Test
-    fun dbDelete_pagingSourceInvalidates() {
+    fun dbInsert_pagingSourceInvalidates() = runPagingSourceTest { pager, pagingSource ->
         dao.addAllItems(ITEMS_LIST)
-        val pagingSource = LimitOffsetPagingSourceImpl(database)
-        runBlocking {
-            // load once to register db observers
-            pagingSource.refresh()
-            assertThat(pagingSource.invalid).isFalse()
-            // paging source should be invalidated when delete from db
-            dao.deleteTestItem(TestItem(50))
-            countingTaskExecutorRule.drainTasks(5, TimeUnit.SECONDS)
-            assertTrue(pagingSource.invalid)
-        }
+        // load once to register db observers
+        pager.refresh()
+        assertThat(pagingSource.invalid).isFalse()
+        // paging source should be invalidated when insert into db
+        val result = dao.addTestItem(TestItem(101))
+        countingTaskExecutorRule.drainTasks(500, TimeUnit.MILLISECONDS)
+        assertThat(result).isEqualTo(101)
+        assertTrue(pagingSource.invalid)
     }
 
     @Test
-    fun invalidDbQuery_pagingSourceDoesNotInvalidate() {
+    fun dbDelete_pagingSourceInvalidates() = runPagingSourceTest { pager, pagingSource ->
         dao.addAllItems(ITEMS_LIST)
-        val pagingSource = LimitOffsetPagingSourceImpl(database)
-        runBlocking {
-            // load once to register db observers
-            pagingSource.refresh()
-            assertThat(pagingSource.invalid).isFalse()
-
-            val result = dao.deleteTestItem(TestItem(1000))
-
-            // invalid delete. Should have 0 items deleted and paging source remains valid
-            assertThat(result).isEqualTo(0)
-            assertFalse(pagingSource.invalid)
-        }
+        // load once to register db observers
+        pager.refresh()
+        assertThat(pagingSource.invalid).isFalse()
+        // paging source should be invalidated when delete from db
+        dao.deleteTestItem(TestItem(50))
+        countingTaskExecutorRule.drainTasks(5, TimeUnit.SECONDS)
+        assertTrue(pagingSource.invalid)
     }
 
     @Test
-    fun load_initialLoad() {
-        val pagingSource = LimitOffsetPagingSourceImpl(database)
+    fun invalidDbQuery_pagingSourceDoesNotInvalidate() = runPagingSourceTest {
+            pager, pagingSource ->
+
         dao.addAllItems(ITEMS_LIST)
-        runBlocking {
-            val result = pagingSource.refresh() as LoadResult.Page
+        // load once to register db observers
+        pager.refresh()
+        assertThat(pagingSource.invalid).isFalse()
 
-            assertThat(result.data).containsExactlyElementsIn(
-                ITEMS_LIST.subList(0, 15)
-            )
-        }
+        val result = dao.deleteTestItem(TestItem(1000))
+
+        // invalid delete. Should have 0 items deleted and paging source remains valid
+        assertThat(result).isEqualTo(0)
+        assertFalse(pagingSource.invalid)
     }
 
     @Test
-    fun load_initialEmptyLoad() {
-        val pagingSource = LimitOffsetPagingSourceImpl(database)
-        runBlocking {
-            val result = pagingSource.refresh() as LoadResult.Page
-
-            assertTrue(result.data.isEmpty())
-
-            // now add items
-            dao.addAllItems(ITEMS_LIST)
-
-            // invalidate pagingSource to imitate invalidation from running refreshVersionSync
-            pagingSource.invalidate()
-            assertTrue(pagingSource.invalid)
-
-            // this refresh should check pagingSource's invalid status, realize it is invalid, and
-            // return a LoadResult.Invalid
-            assertThat(pagingSource.refresh()).isInstanceOf(
-                LoadResult.Invalid::class.java
-            )
-        }
-    }
-
-    @Test
-    fun load_initialLoadWithInitialKey() {
+    fun load_initialLoad() = runPagingSourceTest { pager, _ ->
         dao.addAllItems(ITEMS_LIST)
-        val pagingSource = LimitOffsetPagingSourceImpl(database)
-        // refresh with initial key = 20
-        runBlocking {
-            val result = pagingSource.refresh(key = 20) as LoadResult.Page
-
-            // item in pos 21-35 (TestItemId 20-34) loaded
-            assertThat(result.data).containsExactlyElementsIn(
-                ITEMS_LIST.subList(20, 35)
-            )
-        }
+        val result = pager.refresh() as LoadResult.Page
+        assertThat(result.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(0, 15)
+        )
     }
 
     @Test
-    fun load_initialLoadWithSuppliedLimitOffset() {
+    fun load_initialEmptyLoad() = runPagingSourceTest { pager, _ ->
+        val result = pager.refresh(initialKey = 20) as LoadResult.Page
+
+        assertTrue(result.data.isEmpty())
+        // check that this returns a terminal load
+        assertThat(result.nextKey).isNull()
+        assertThat(result.prevKey).isNull()
+        assertThat(result.itemsBefore).isEqualTo(0)
+        assertThat(result.itemsAfter).isEqualTo(0)
+    }
+
+    @Test
+    fun load_initialLoadWithInitialKey() = runPagingSourceTest { pager, _ ->
         dao.addAllItems(ITEMS_LIST)
-        val pagingSource = LimitOffsetPagingSourceImpl(
+        val result = pager.refresh(initialKey = 20) as LoadResult.Page
+        assertThat(result.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(20, 35)
+        )
+    }
+
+    @Test
+    fun load_initialLoadWithSuppliedLimitOffset() = runPagingSourceTest(
+        LimitOffsetPagingSourceImpl(
             db = database,
             queryString = "SELECT * FROM $tableName ORDER BY id ASC LIMIT 10 OFFSET 30",
         )
-        runBlocking {
-            val result = pagingSource.refresh() as LoadResult.Page
-
-            // default initial loadSize = 15 starting from index 0.
-            // user supplied limit offset should cause initial loadSize = 10, starting from index 30
-            assertThat(result.data).containsExactlyElementsIn(
-                ITEMS_LIST.subList(30, 40)
-            )
-            // check that no append/prepend can be triggered after this terminal load
-            assertThat(result.nextKey).isNull()
-            assertThat(result.prevKey).isNull()
-            assertThat(result.itemsBefore).isEqualTo(0)
-            assertThat(result.itemsAfter).isEqualTo(0)
-        }
+    ) { pager, _ ->
+        dao.addAllItems(ITEMS_LIST)
+        val result = pager.refresh() as LoadResult.Page
+        // default initial loadSize = 15 starting from index 0.
+        // user supplied limit offset should cause initial loadSize = 10, starting from index 30
+        assertThat(result.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(30, 40)
+        )
+        // check that no append/prepend can be triggered after this terminal load
+        assertThat(result.nextKey).isNull()
+        assertThat(result.prevKey).isNull()
+        assertThat(result.itemsBefore).isEqualTo(0)
+        assertThat(result.itemsAfter).isEqualTo(0)
     }
 
     @Test
-    fun load_oneAdditionalQueryArguments() {
-        dao.addAllItems(ITEMS_LIST)
-        val pagingSource = LimitOffsetPagingSourceImpl(
+    fun load_oneAdditionalQueryArguments() = runPagingSourceTest(
+        LimitOffsetPagingSourceImpl(
             db = database,
             queryString = "SELECT * FROM $tableName WHERE id < 50 ORDER BY id ASC",
         )
-        // refresh with initial key = 40
-        runBlocking {
-            val result = pagingSource.refresh(key = 40) as LoadResult.Page
+    ) { pager, pagingSource ->
 
-            // initial loadSize = 15, but limited by id < 50, should only load items 40 - 50
-            assertThat(result.data).containsExactlyElementsIn(
-                ITEMS_LIST.subList(40, 50)
-            )
-            // should have 50 items fulfilling condition of id < 50 (TestItem id 0 - 49)
-            assertThat(pagingSource.itemCount.get()).isEqualTo(50)
-        }
+        dao.addAllItems(ITEMS_LIST)
+        val result = pager.refresh(initialKey = 40) as LoadResult.Page
+
+        // initial loadSize = 15, but limited by id < 50, should only load items 40 - 50
+        assertThat(result.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(40, 50)
+        )
+        // should have 50 items fulfilling condition of id < 50 (TestItem id 0 - 49)
+        assertThat(pagingSource.itemCount.get()).isEqualTo(50)
     }
 
     @Test
-    fun load_multipleQueryArguments() {
-        dao.addAllItems(ITEMS_LIST)
-        val pagingSource = LimitOffsetPagingSourceImpl(
+    fun load_multipleQueryArguments() = runPagingSourceTest(
+        LimitOffsetPagingSourceImpl(
             db = database,
             queryString = "SELECT * " +
                 "FROM $tableName " +
                 "WHERE id > 50 AND value LIKE 'item 90'" +
                 "ORDER BY id ASC",
         )
-        runBlocking {
-            val result = pagingSource.refresh() as LoadResult.Page
+    ) { pager, pagingSource ->
+        dao.addAllItems(ITEMS_LIST)
+        val result = pager.refresh() as LoadResult.Page
 
-            assertThat(result.data).containsExactly(ITEMS_LIST[90])
-            assertThat(pagingSource.itemCount.get()).isEqualTo(1)
-        }
+        assertThat(result.data).containsExactly(ITEMS_LIST[90])
+        assertThat(pagingSource.itemCount.get()).isEqualTo(1)
     }
 
     @Test
-    fun load_InvalidUserSuppliedOffset_returnEmpty() {
-        dao.addAllItems(ITEMS_LIST)
-        val pagingSource = LimitOffsetPagingSourceImpl(
+    fun load_InvalidUserSuppliedOffset_returnEmpty() = runPagingSourceTest(
+        LimitOffsetPagingSourceImpl(
             db = database,
             queryString = "SELECT * FROM $tableName ORDER BY id ASC LIMIT 10 OFFSET 500",
         )
-        runBlocking {
-            val result = pagingSource.refresh() as LoadResult.Page
+    ) { pager, pagingSource ->
+        dao.addAllItems(ITEMS_LIST)
 
-            // invalid OFFSET = 500 should return empty data
-            assertThat(result.data).isEmpty()
+        val result = pager.refresh() as LoadResult.Page
 
-            // check that no append/prepend can be triggered
-            assertThat(pagingSource.itemCount.get()).isEqualTo(0)
-            assertThat(result.nextKey).isNull()
-            assertThat(result.prevKey).isNull()
-            assertThat(result.itemsBefore).isEqualTo(0)
-            assertThat(result.itemsAfter).isEqualTo(0)
-        }
+        // invalid OFFSET = 500 should return empty data
+        assertThat(result.data).isEmpty()
+
+        // check that no append/prepend can be triggered
+        assertThat(pagingSource.itemCount.get()).isEqualTo(0)
+        assertThat(result.nextKey).isNull()
+        assertThat(result.prevKey).isNull()
+        assertThat(result.itemsBefore).isEqualTo(0)
+        assertThat(result.itemsAfter).isEqualTo(0)
     }
 
     @Test
-    fun load_UserSuppliedNegativeLimit() {
-        dao.addAllItems(ITEMS_LIST)
-        val pagingSource = LimitOffsetPagingSourceImpl(
+    fun load_UserSuppliedNegativeLimit() = runPagingSourceTest(
+        LimitOffsetPagingSourceImpl(
             db = database,
             queryString = "SELECT * FROM $tableName ORDER BY id ASC LIMIT -1",
         )
-        runBlocking {
-            val result = pagingSource.refresh() as LoadResult.Page
-
-            // ensure that it respects SQLite's default behavior for negative LIMIT
-            assertThat(result.data).containsExactlyElementsIn(
-                ITEMS_LIST.subList(0, 15)
-            )
-            // should behave as if no LIMIT were set
-            assertThat(pagingSource.itemCount.get()).isEqualTo(100)
-            assertThat(result.nextKey).isEqualTo(15)
-            assertThat(result.prevKey).isNull()
-            assertThat(result.itemsBefore).isEqualTo(0)
-            assertThat(result.itemsAfter).isEqualTo(85)
-        }
-    }
-
-    @Test
-    fun invalidInitialKey_dbEmpty_returnsEmpty() {
-        val pagingSource = LimitOffsetPagingSourceImpl(database)
-        runBlocking {
-            val result = pagingSource.refresh(key = 101) as LoadResult.Page
-
-            assertThat(result.data).isEmpty()
-        }
-    }
-
-    @Test
-    fun invalidInitialKey_keyTooLarge_returnsLastPage() {
-        val pagingSource = LimitOffsetPagingSourceImpl(database)
+    ) { pager, pagingSource ->
         dao.addAllItems(ITEMS_LIST)
-        runBlocking {
-            val result = pagingSource.refresh(key = 101) as LoadResult.Page
+        val result = pager.refresh() as LoadResult.Page
 
-            // should load the last page
-            assertThat(result.data).containsExactlyElementsIn(
-                ITEMS_LIST.subList(85, 100)
-            )
-        }
+        // ensure that it respects SQLite's default behavior for negative LIMIT
+        assertThat(result.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(0, 15)
+        )
+        // should behave as if no LIMIT were set
+        assertThat(pagingSource.itemCount.get()).isEqualTo(100)
+        assertThat(result.nextKey).isEqualTo(15)
+        assertThat(result.prevKey).isNull()
+        assertThat(result.itemsBefore).isEqualTo(0)
+        assertThat(result.itemsAfter).isEqualTo(85)
     }
 
     @Test
-    fun invalidInitialKey_negativeKey() {
-        val pagingSource = LimitOffsetPagingSourceImpl(database)
-        dao.addAllItems(ITEMS_LIST)
-        runBlocking {
-            // should throw error when initial key is negative
-            val expectedException = assertFailsWith<IllegalArgumentException> {
-                pagingSource.refresh(key = -1)
-            }
-            // default message from Paging 3 for negative initial key
-            assertThat(expectedException.message).isEqualTo(
-                "itemsBefore cannot be negative"
-            )
-        }
+    fun invalidInitialKey_dbEmpty_returnsEmpty() = runPagingSourceTest { pager, _ ->
+        assertThat(
+            (pager.refresh(initialKey = 101) as LoadResult.Page).data
+        ).isEmpty()
     }
 
     @Test
-    fun append_middleOfList() {
-        val pagingSource = LimitOffsetPagingSourceImpl(database)
-        dao.addAllItems(ITEMS_LIST)
-        // to bypass check for initial load and run as non-initial load
-        pagingSource.itemCount.set(100)
-        runBlocking {
-            val result = pagingSource.append(key = 20) as LoadResult.Page
+    fun invalidInitialKey_keyTooLarge_returnsLastPage() = runPagingSourceTest {
+            pager, _ ->
 
-            // item in pos 21-25 (TestItemId 20-24) loaded
-            assertThat(result.data).containsExactlyElementsIn(
-                ITEMS_LIST.subList(20, 25)
-            )
-            assertThat(result.nextKey).isEqualTo(25)
-            assertThat(result.prevKey).isEqualTo(20)
-        }
+        dao.addAllItems(ITEMS_LIST)
+        val result = pager.refresh(initialKey = 101) as LoadResult.Page
+
+        // should load the last page
+        assertThat(result.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(85, 100)
+        )
     }
 
     @Test
-    fun append_availableItemsLessThanLoadSize() {
-        val pagingSource = LimitOffsetPagingSourceImpl(database)
+    fun invalidInitialKey_negativeKey() = runPagingSourceTest { pager, _ ->
         dao.addAllItems(ITEMS_LIST)
-        // to bypass check for initial load and run as non-initial load
-        pagingSource.itemCount.set(100)
-        runBlocking {
-            val result = pagingSource.append(key = 97) as LoadResult.Page
-
-            // item in pos 98-100 (TestItemId 97-99) loaded
-            assertThat(result.data).containsExactlyElementsIn(
-                ITEMS_LIST.subList(97, 100)
-            )
-            assertThat(result.nextKey).isEqualTo(null)
-            assertThat(result.prevKey).isEqualTo(97)
+        // should throw error when initial key is negative
+        val expectedException = assertFailsWith<IllegalArgumentException> {
+            pager.refresh(initialKey = -1)
         }
+        // default message from Paging 3 for negative initial key
+        assertThat(expectedException.message).isEqualTo(
+            "itemsBefore cannot be negative"
+        )
     }
 
     @Test
-    fun load_consecutiveAppend() {
-        val pagingSource = LimitOffsetPagingSourceImpl(database)
+    fun append_middleOfList() = runPagingSourceTest { pager, _ ->
         dao.addAllItems(ITEMS_LIST)
-        // to bypass check for initial load and run as non-initial load
-        pagingSource.itemCount.set(100)
-        runBlocking {
+        val result = pager.run {
+            refresh(initialKey = 5)
+            append() as LoadResult.Page
+        }
+
+        // item in pos 21-25 (TestItemId 20-24) loaded
+        assertThat(result.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(20, 25)
+        )
+        assertThat(result.nextKey).isEqualTo(25)
+        assertThat(result.prevKey).isEqualTo(20)
+    }
+
+    @Test
+    fun append_availableItemsLessThanLoadSize() = runPagingSourceTest { pager, _ ->
+        dao.addAllItems(ITEMS_LIST)
+        val result = pager.run {
+            refresh(82)
+            append() as LoadResult.Page
+        }
+
+        // item in pos 98-100 (TestItemId 97-99) loaded
+        assertThat(result.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(97, 100)
+        )
+        assertThat(result.nextKey).isEqualTo(null)
+        assertThat(result.prevKey).isEqualTo(97)
+    }
+
+    @Test
+    fun load_consecutiveAppend() = runPagingSourceTest { pager, _ ->
+        dao.addAllItems(ITEMS_LIST)
+        val result1 = pager.run {
+            refresh(15)
             // first append
-            val result = pagingSource.append(key = 30) as LoadResult.Page
-
-            // TestItemId 30-34 loaded
-            assertThat(result.data).containsExactlyElementsIn(
-                ITEMS_LIST.subList(30, 35)
-            )
-            // second append using nextKey from previous load
-            val result2 = pagingSource.append(key = result.nextKey) as LoadResult.Page
-
-            // TestItemId 35 - 39 loaded
-            assertThat(result2.data).containsExactlyElementsIn(
-                ITEMS_LIST.subList(35, 40)
-            )
+            append() as LoadResult.Page
         }
+
+        // TestItemId 30-34 loaded from the append
+        assertThat(result1.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(30, 35)
+        )
+
+        // second append
+        val result2 = pager.append() as LoadResult.Page
+
+        // TestItemId 35 - 39 loaded
+        assertThat(result2.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(35, 40)
+        )
     }
 
     @Test
-    fun append_invalidResult() {
-        val pagingSource = LimitOffsetPagingSourceImpl(database)
+    fun append_invalidResult() = runPagingSourceTest { pager, pagingSource ->
         dao.addAllItems(ITEMS_LIST)
-        // to bypass check for initial load and run as non-initial load
-        pagingSource.itemCount.set(100)
-        runBlocking {
-            // first append
-            val result = pagingSource.append(key = 30) as LoadResult.Page
-
-            // TestItemId 30-34 loaded
-            assertThat(result.data).containsExactlyElementsIn(
-                ITEMS_LIST.subList(30, 35)
-            )
-
-            // invalidate pagingSource to imitate invalidation from running refreshVersionSync
-            pagingSource.invalidate()
-
-            // this append should check pagingSource's invalid status, realize it is invalid, and
-            // return a LoadResult.Invalid
-            val result2 = pagingSource.append(key = result.nextKey)
-
-            assertThat(result2).isInstanceOf(LoadResult.Invalid::class.java)
+        val result = pager.run {
+            refresh(initialKey = 15)
+            append() as LoadResult.Page
         }
+        // TestItemId 30-34 loaded
+        assertThat(result.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(30, 35)
+        )
+        // invalidate pagingSource to imitate invalidation from running refreshVersionSync
+        pagingSource.invalidate()
+
+        // this append should check pagingSource's invalid status, realize it is invalid, and
+        // return a LoadResult.Invalid
+        val result2 = pager.append()
+
+        assertThat(result2).isInstanceOf(LoadResult.Invalid::class.java)
     }
 
     @Test
-    fun prepend_middleOfList() {
-        val pagingSource = LimitOffsetPagingSourceImpl(database)
+    fun prepend_middleOfList() = runPagingSourceTest { pager, _ ->
         dao.addAllItems(ITEMS_LIST)
-        // to bypass check for initial load and run as non-initial load
-        pagingSource.itemCount.set(100)
-        runBlocking {
-            val result = pagingSource.prepend(key = 30) as LoadResult.Page
-
-            assertThat(result.data).containsExactlyElementsIn(
-                ITEMS_LIST.subList(25, 30)
-            )
-            assertThat(result.nextKey).isEqualTo(30)
-            assertThat(result.prevKey).isEqualTo(25)
+        val result = pager.run {
+            refresh(initialKey = 30)
+            prepend() as LoadResult.Page
         }
+
+        assertThat(result.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(25, 30)
+        )
+        assertThat(result.nextKey).isEqualTo(30)
+        assertThat(result.prevKey).isEqualTo(25)
     }
 
     @Test
-    fun prepend_availableItemsLessThanLoadSize() {
-        val pagingSource = LimitOffsetPagingSourceImpl(database)
+    fun prepend_availableItemsLessThanLoadSize() = runPagingSourceTest { pager, _ ->
         dao.addAllItems(ITEMS_LIST)
-        // to bypass check for initial load and run as non-initial load
-        pagingSource.itemCount.set(100)
-        runBlocking {
-            val result = pagingSource.prepend(key = 3) as LoadResult.Page
-
-            // items in pos 0 - 2 (TestItemId 0 - 2) loaded
-            assertThat(result.data).containsExactlyElementsIn(
-                ITEMS_LIST.subList(0, 3)
-            )
-            assertThat(result.nextKey).isEqualTo(3)
-            assertThat(result.prevKey).isEqualTo(null)
+        val result = pager.run {
+            refresh(initialKey = 3)
+            prepend() as LoadResult.Page
         }
+
+        // items in pos 0 - 2 (TestItemId 0 - 2) loaded
+        assertThat(result.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(0, 3)
+        )
+        assertThat(result.nextKey).isEqualTo(3)
+        assertThat(result.prevKey).isEqualTo(null)
     }
 
     @Test
-    fun load_consecutivePrepend() {
-        val pagingSource = LimitOffsetPagingSourceImpl(database)
+    fun load_consecutivePrepend() = runPagingSourceTest { pager, _ ->
         dao.addAllItems(ITEMS_LIST)
-        // to bypass check for initial load and run as non-initial load
-        pagingSource.itemCount.set(100)
-        runBlocking {
-            // first prepend
-            val result = pagingSource.prepend(key = 20) as LoadResult.Page
-
-            // items pos 16-20 (TestItemId 15-19) loaded
-            assertThat(result.data).containsExactlyElementsIn(
-                ITEMS_LIST.subList(15, 20)
-            )
-            // second prepend using prevKey from previous load
-            val result2 = pagingSource.prepend(key = result.prevKey) as LoadResult.Page
-
-            // items pos 11-15 (TestItemId 10 - 14) loaded
-            assertThat(result2.data).containsExactlyElementsIn(
-                ITEMS_LIST.subList(10, 15)
-            )
+        val result1 = pager.run {
+            refresh(initialKey = 20)
+            prepend() as LoadResult.Page // first prepend
         }
+        // items pos 16-20 (TestItemId 15-19) loaded
+        assertThat(result1.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(15, 20)
+        )
+
+        // second prepend
+        val result2 = pager.prepend() as LoadResult.Page
+
+        // items pos 11-15 (TestItemId 10 - 14) loaded
+        assertThat(result2.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(10, 15)
+        )
     }
 
     @Test
-    fun prepend_invalidResult() {
-        val pagingSource = LimitOffsetPagingSourceImpl(database)
+    fun prepend_invalidResult() = runPagingSourceTest { pager, pagingSource ->
         dao.addAllItems(ITEMS_LIST)
-        // to bypass check for initial load and run as non-initial load
-        pagingSource.itemCount.set(100)
-        runBlocking {
-            // first prepend
-            val result = pagingSource.prepend(key = 20) as LoadResult.Page
-
-            // items pos 16-20 (TestItemId 15-19) loaded
-            assertThat(result.data).containsExactlyElementsIn(
-                ITEMS_LIST.subList(15, 20)
-            )
-
-            // invalidate pagingSource to imitate invalidation from running refreshVersionSync
-            pagingSource.invalidate()
-
-            // this prepend should check pagingSource's invalid status, realize it is invalid, and
-            // return LoadResult.Invalid
-            val result2 = pagingSource.prepend(key = result.prevKey)
-
-            assertThat(result2).isInstanceOf(LoadResult.Invalid::class.java)
+        val result = pager.run {
+            refresh(initialKey = 20)
+            prepend() as LoadResult.Page
         }
+        // items pos 16-20 (TestItemId 15-19) loaded
+        assertThat(result.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(15, 20)
+        )
+
+        // invalidate pagingSource to imitate invalidation from running refreshVersionSync
+        pagingSource.invalidate()
+
+        // this prepend should check pagingSource's invalid status, realize it is invalid, and
+        // return LoadResult.Invalid
+        val result2 = pager.prepend()
+
+        assertThat(result2).isInstanceOf(LoadResult.Invalid::class.java)
     }
 
     @Test
-    fun test_itemsBefore() {
-        val pagingSource = LimitOffsetPagingSourceImpl(database)
+    fun test_itemsBefore() = runPagingSourceTest { pager, _ ->
         dao.addAllItems(ITEMS_LIST)
-        runBlocking {
-            // for initial load
-            val result = pagingSource.refresh(key = 50) as LoadResult.Page
+        // initial loads items in pos 51 - 65, should have 50 items before
+        assertThat(
+            (pager.refresh(50) as LoadResult.Page).itemsBefore
+        ).isEqualTo(50)
 
-            // initial loads items in pos 51 - 65, should have 50 items before
-            assertThat(result.itemsBefore).isEqualTo(50)
+        // prepend loads items in pos 46 - 50, should have 45 item before
+        assertThat(
+            (pager.prepend() as LoadResult.Page).itemsBefore
+        ).isEqualTo(45)
 
-            // prepend from initial load
-            val result2 = pagingSource.prepend(key = result.prevKey) as LoadResult.Page
-
-            // prepend loads items in pos 46 - 50, should have 45 item before
-            assertThat(result2.itemsBefore).isEqualTo(45)
-
-            // append from initial load
-            val result3 = pagingSource.append(key = result.nextKey) as LoadResult.Page
-
-            // append loads items in position 66 - 70 , should have 65 item before
-            assertThat(result3.itemsBefore).isEqualTo(65)
-        }
+        // append loads items in position 66 - 70 , should have 65 item before
+        assertThat(
+            (pager.append() as LoadResult.Page).itemsBefore
+        ).isEqualTo(65)
     }
 
     @Test
-    fun test_itemsAfter() {
-        val pagingSource = LimitOffsetPagingSourceImpl(database)
+    fun test_itemsAfter() = runPagingSourceTest { pager, _ ->
         dao.addAllItems(ITEMS_LIST)
-        runBlocking {
-            // for initial load
-            val result = pagingSource.refresh(key = 30) as LoadResult.Page
+        // initial loads items in position 31 - 45, should have 55 items after
+        assertThat(
+            (pager.refresh(30) as LoadResult.Page).itemsAfter
+        ).isEqualTo(55)
 
-            // initial loads items in position 31 - 45, should have 55 items after
-            assertThat(result.itemsAfter).isEqualTo(55)
+        // prepend loads items in position 26 - 30, should have 70 item after
+        assertThat(
+            (pager.prepend() as LoadResult.Page).itemsAfter
+        ).isEqualTo(70)
 
-            // prepend from initial load
-            val result2 = pagingSource.prepend(key = result.prevKey) as LoadResult.Page
-
-            // prepend loads items in position 26 - 30, should have 70 item after
-            assertThat(result2.itemsAfter).isEqualTo(70)
-
-            // append from initial load
-            val result3 = pagingSource.append(result.nextKey) as LoadResult.Page
-
-            // append loads items in position 46 - 50 , should have 50 item after
-            assertThat(result3.itemsAfter).isEqualTo(50)
-        }
+        // append loads items in position 46 - 50 , should have 50 item after
+        assertThat(
+            (pager.append() as LoadResult.Page).itemsAfter
+        ).isEqualTo(50)
     }
 
     @Test
-    fun test_getRefreshKey() {
-        val pagingSource = LimitOffsetPagingSourceImpl(database)
+    fun test_getRefreshKey() = runPagingSourceTest { pager, pagingSource ->
         dao.addAllItems(ITEMS_LIST)
-        runBlocking {
-            // initial load
-            val result = pagingSource.refresh() as LoadResult.Page
+        val pagingState1 = pager.run {
+            refresh()
             // 15 items loaded, assuming anchorPosition = 14 as the last item loaded
-            var refreshKey = pagingSource.getRefreshKey(
-                PagingState(
-                    pages = listOf(result),
-                    anchorPosition = 14,
-                    config = CONFIG,
-                    leadingPlaceholderCount = 0
-                )
-            )
-            // should load around anchor position
-            // Initial load size = 15, refresh key should be (15/2 = 7) items
-            // before anchorPosition (14 - 7 = 7)
-            assertThat(refreshKey).isEqualTo(7)
-
-            // append after refresh
-            val result2 = pagingSource.append(key = result.nextKey) as LoadResult.Page
-
-            assertThat(result2.data).isEqualTo(
-                ITEMS_LIST.subList(15, 20)
-            )
-            refreshKey = pagingSource.getRefreshKey(
-                PagingState(
-                    pages = listOf(result, result2),
-                    // 20 items loaded, assume anchorPosition = 19 as the last item loaded
-                    anchorPosition = 19,
-                    config = CONFIG,
-                    leadingPlaceholderCount = 0
-                )
-            )
-            // initial load size 15. Refresh key should be (15/2 = 7) items before anchorPosition
-            // (19 - 7 = 12)
-            assertThat(refreshKey).isEqualTo(12)
+            getPagingState(14)
         }
+        // should load around anchor position
+        // Initial load size = 15, refresh key should be (15/2 = 7) items
+        // before anchorPosition (14 - 7 = 7)
+        assertThat(pagingSource.getRefreshKey(pagingState1)).isEqualTo(7)
+
+        // append after refresh
+        val append = pager.append() as LoadResult.Page
+        assertThat(append.data).isEqualTo(
+            ITEMS_LIST.subList(15, 20)
+        )
+        // 20 items loaded, assume anchorPosition = 19 as the last item loaded
+        val pagingState2 = pager.getPagingState(19)
+        // initial load size 15. Refresh key should be (15/2 = 7) items before anchorPosition
+        // (19 - 7 = 12)
+        assertThat(pagingSource.getRefreshKey(pagingState2)).isEqualTo(12)
     }
 
     @Test
-    fun load_refreshKeyGreaterThanItemCount_lastPage() {
-        val pagingSource = LimitOffsetPagingSourceImpl(database)
+    fun load_refreshKeyGreaterThanItemCount_lastPage() = runPagingSourceTest {
+            pager, _ ->
+
         dao.addAllItems(ITEMS_LIST)
-        runBlocking {
+        pager.refresh(initialKey = 70)
+        dao.deleteTestItems(40, 100)
 
-            pagingSource.refresh(key = 70)
+        // assume user was viewing last item of the refresh load with anchorPosition = 85,
+        // initialLoadSize = 15. This mimics how getRefreshKey() calculates refresh key.
+        val refreshKey = 85 - (15 / 2)
 
-            dao.deleteTestItems(40, 100)
+        val pagingSource2 = LimitOffsetPagingSourceImpl(database)
+        val pager2 = TestPager(pagingSource2, CONFIG)
+        val result = pager2.refresh(initialKey = refreshKey) as LoadResult.Page
 
-            // assume user was viewing last item of the refresh load with anchorPosition = 85,
-            // initialLoadSize = 15. This mimics how getRefreshKey() calculates refresh key.
-            val refreshKey = 85 - (15 / 2)
-            assertThat(refreshKey).isEqualTo(78)
+        // database should only have 40 items left. Refresh key is invalid at this point
+        // (greater than item count after deletion)
+        assertThat(pagingSource2.itemCount.get()).isEqualTo(40)
+        // ensure that paging source can handle invalid refresh key properly
+        // should load last page with items 25 - 40
+        assertThat(result.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(25, 40)
+        )
 
-            val pagingSource2 = LimitOffsetPagingSourceImpl(database)
-            val result2 = pagingSource2.refresh(key = refreshKey) as LoadResult.Page
-
-            // database should only have 40 items left. Refresh key is invalid at this point
-            // (greater than item count after deletion)
-            assertThat(pagingSource2.itemCount.get()).isEqualTo(40)
-            // ensure that paging source can handle invalid refresh key properly
-            // should load last page with items 25 - 40
-            assertThat(result2.data).containsExactlyElementsIn(
-                ITEMS_LIST.subList(25, 40)
-            )
-
-            // should account for updated item count to return correct itemsBefore, itemsAfter,
-            // prevKey, nextKey
-            assertThat(result2.itemsBefore).isEqualTo(25)
-            assertThat(result2.itemsAfter).isEqualTo(0)
-            // no append can be triggered
-            assertThat(result2.prevKey).isEqualTo(25)
-            assertThat(result2.nextKey).isEqualTo(null)
-        }
+        // should account for updated item count to return correct itemsBefore, itemsAfter,
+        // prevKey, nextKey
+        assertThat(result.itemsBefore).isEqualTo(25)
+        assertThat(result.itemsAfter).isEqualTo(0)
+        // no append can be triggered
+        assertThat(result.prevKey).isEqualTo(25)
+        assertThat(result.nextKey).isEqualTo(null)
     }
 
     /**
@@ -704,73 +606,65 @@
      * Ideally, in the future Paging will be able to handle this case better.
      */
     @Test
-    fun load_refreshKeyGreaterThanItemCount_firstPage() {
-        val pagingSource = LimitOffsetPagingSourceImpl(database)
+    fun load_refreshKeyGreaterThanItemCount_firstPage() = runPagingSourceTest {
+            pager, pagingSource ->
+
         dao.addAllItems(ITEMS_LIST)
-        runBlocking {
-            pagingSource.refresh()
+        pager.refresh()
+        assertThat(pagingSource.itemCount.get()).isEqualTo(100)
+        // items id 0 - 29 deleted (30 items removed)
+        dao.deleteTestItems(0, 29)
 
-            assertThat(pagingSource.itemCount.get()).isEqualTo(100)
+        val pagingSource2 = LimitOffsetPagingSourceImpl(database)
+        val pager2 = TestPager(pagingSource2, CONFIG)
+        // assume user was viewing first few items with anchorPosition = 0 and refresh key
+        // clips to 0
+        val result = pager2.refresh(initialKey = 0) as LoadResult.Page
 
-            // items id 0 - 29 deleted (30 items removed)
-            dao.deleteTestItems(0, 29)
+        // database should only have 70 items left
+        assertThat(pagingSource2.itemCount.get()).isEqualTo(70)
+        // first 30 items deleted, refresh should load starting from pos 31 (item id 30 - 45)
+        assertThat(result.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(30, 45)
+        )
 
-            val pagingSource2 = LimitOffsetPagingSourceImpl(database)
-            // assume user was viewing first few items with anchorPosition = 0 and refresh key
-            // clips to 0
-            val refreshKey = 0
-
-            val result2 = pagingSource2.refresh(key = refreshKey) as LoadResult.Page
-
-            // database should only have 70 items left
-            assertThat(pagingSource2.itemCount.get()).isEqualTo(70)
-            // first 30 items deleted, refresh should load starting from pos 31 (item id 30 - 45)
-            assertThat(result2.data).containsExactlyElementsIn(
-                ITEMS_LIST.subList(30, 45)
-            )
-
-            // should account for updated item count to return correct itemsBefore, itemsAfter,
-            // prevKey, nextKey
-            assertThat(result2.itemsBefore).isEqualTo(0)
-            assertThat(result2.itemsAfter).isEqualTo(55)
-            // no prepend can be triggered
-            assertThat(result2.prevKey).isEqualTo(null)
-            assertThat(result2.nextKey).isEqualTo(15)
-        }
+        // should account for updated item count to return correct itemsBefore, itemsAfter,
+        // prevKey, nextKey
+        assertThat(result.itemsBefore).isEqualTo(0)
+        assertThat(result.itemsAfter).isEqualTo(55)
+        // no prepend can be triggered
+        assertThat(result.prevKey).isEqualTo(null)
+        assertThat(result.nextKey).isEqualTo(15)
     }
 
     @Test
-    fun load_loadSizeAndRefreshKeyGreaterThanItemCount() {
-        val pagingSource = LimitOffsetPagingSourceImpl(database)
+    fun load_loadSizeAndRefreshKeyGreaterThanItemCount() = runPagingSourceTest {
+            pager, pagingSource ->
+
         dao.addAllItems(ITEMS_LIST)
-        runBlocking {
+        pager.refresh(initialKey = 30)
+        assertThat(pagingSource.itemCount.get()).isEqualTo(100)
+        // items id 0 - 94 deleted (95 items removed)
+        dao.deleteTestItems(0, 94)
 
-            pagingSource.refresh(key = 30)
+        val pagingSource2 = LimitOffsetPagingSourceImpl(database)
+        val pager2 = TestPager(pagingSource2, CONFIG)
+        // assume user was viewing first few items with anchorPosition = 0 and refresh key
+        // clips to 0
+        val result = pager2.refresh(initialKey = 0) as LoadResult.Page
 
-            assertThat(pagingSource.itemCount.get()).isEqualTo(100)
-            // items id 0 - 94 deleted (95 items removed)
-            dao.deleteTestItems(0, 94)
+        // database should only have 5 items left
+        assertThat(pagingSource2.itemCount.get()).isEqualTo(5)
+        // only 5 items should be loaded with offset = 0
+        assertThat(result.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(95, 100)
+        )
 
-            val pagingSource2 = LimitOffsetPagingSourceImpl(database)
-            // assume user was viewing first few items with anchorPosition = 0 and refresh key
-            // clips to 0
-            val refreshKey = 0
-
-            val result2 = pagingSource2.refresh(key = refreshKey) as LoadResult.Page
-
-            // database should only have 5 items left
-            assertThat(pagingSource2.itemCount.get()).isEqualTo(5)
-            // only 5 items should be loaded with offset = 0
-            assertThat(result2.data).containsExactlyElementsIn(
-                ITEMS_LIST.subList(95, 100)
-            )
-
-            // should recognize that this is a terminal load
-            assertThat(result2.itemsBefore).isEqualTo(0)
-            assertThat(result2.itemsAfter).isEqualTo(0)
-            assertThat(result2.prevKey).isEqualTo(null)
-            assertThat(result2.nextKey).isEqualTo(null)
-        }
+        // should recognize that this is a terminal load
+        assertThat(result.itemsBefore).isEqualTo(0)
+        assertThat(result.itemsAfter).isEqualTo(0)
+        assertThat(result.prevKey).isEqualTo(null)
+        assertThat(result.nextKey).isEqualTo(null)
     }
 
     @Test
@@ -778,8 +672,22 @@
         val pagingSource = LimitOffsetPagingSourceImpl(database)
         assertTrue(pagingSource.jumpingSupported)
     }
+
+    private fun runPagingSourceTest(
+        pagingSource: LimitOffsetPagingSourceImpl = LimitOffsetPagingSourceImpl(database),
+        config: PagingConfig = CONFIG,
+        block: suspend (
+            pager: TestPager<Int, TestItem>,
+            pagingSource: LimitOffsetPagingSourceImpl
+        ) -> Unit
+    ) {
+        runBlocking {
+            block(TestPager(pagingSource, config), pagingSource)
+        }
+    }
 }
 
+@OptIn(ExperimentalCoroutinesApi::class)
 @RunWith(AndroidJUnit4::class)
 @SmallTest
 class LimitOffsetPagingSourceTestWithFilteringExecutor {
@@ -826,102 +734,69 @@
     }
 
     @Test
-    fun invalid_refresh() {
+    fun invalid_append() = runTest {
         val pagingSource = LimitOffsetPagingSourceImpl(db)
-        runBlocking {
-            val result = pagingSource.refresh() as LoadResult.Page
+        val pager = TestPager(pagingSource, CONFIG)
+        dao.addAllItems(ITEMS_LIST)
 
-            assertTrue(result.data.isEmpty())
+        val result = pager.refresh() as LoadResult.Page
+        // initial load
+        assertThat(result.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(0, 15)
+        )
 
-            // blocks invalidation notification from Room
-            queryExecutor.filterFunction = { runnable ->
-                runnable !== db.invalidationTracker.refreshRunnable
-            }
-
-            // now write to database
-            dao.addAllItems(ITEMS_LIST)
-
-            // make sure room requests a refresh
-            db.invalidationTracker.awaitPendingRefresh()
-            // and that this is blocked to simulate delayed notification from room
-            queryExecutor.awaitDeferredSizeAtLeast(1)
-
-            // the db write should cause pagingSource to realize it is invalid
-            assertThat(pagingSource.refresh()).isInstanceOf(
-                LoadResult.Invalid::class.java
-            )
-            assertTrue(pagingSource.invalid)
+        // blocks invalidation notification from Room
+        queryExecutor.filterFunction = { runnable ->
+            runnable !== db.invalidationTracker.refreshRunnable
         }
+
+        // now write to the database
+        dao.deleteTestItem(ITEMS_LIST[30])
+
+        // make sure room requests a refresh
+        db.invalidationTracker.awaitPendingRefresh()
+        // and that this is blocked to simulate delayed notification from room
+        queryExecutor.awaitDeferredSizeAtLeast(1)
+
+        // the db write should cause pagingSource to realize it is invalid when it tries to
+        // append
+        assertThat(pager.append()).isInstanceOf(
+            LoadResult.Invalid::class.java
+        )
+        assertThat(pagingSource.invalid).isTrue()
     }
 
     @Test
-    fun invalid_append() {
+    fun invalid_prepend() = runTest {
         val pagingSource = LimitOffsetPagingSourceImpl(db)
+        val pager = TestPager(pagingSource, CONFIG)
         dao.addAllItems(ITEMS_LIST)
 
-        runBlocking {
-            val result = pagingSource.refresh() as LoadResult.Page
+        val result = pager.refresh(initialKey = 20) as LoadResult.Page
+        // initial load
+        assertThat(result.data).containsExactlyElementsIn(
+            ITEMS_LIST.subList(20, 35)
+        )
 
-            // initial load
-            assertThat(result.data).containsExactlyElementsIn(
-                ITEMS_LIST.subList(0, 15)
-            )
-
-            // blocks invalidation notification from Room
-            queryExecutor.filterFunction = { runnable ->
-                runnable !== db.invalidationTracker.refreshRunnable
-            }
-
-            // now write to the database
-            dao.deleteTestItem(ITEMS_LIST[30])
-
-            // make sure room requests a refresh
-            db.invalidationTracker.awaitPendingRefresh()
-            // and that this is blocked to simulate delayed notification from room
-            queryExecutor.awaitDeferredSizeAtLeast(1)
-
-            // the db write should cause pagingSource to realize it is invalid when it tries to
-            // append
-            assertThat(pagingSource.append(15)).isInstanceOf(
-                LoadResult.Invalid::class.java
-            )
-            assertTrue(pagingSource.invalid)
+        // blocks invalidation notification from Room
+        queryExecutor.filterFunction = { runnable ->
+            runnable !== db.invalidationTracker.refreshRunnable
         }
-    }
 
-    @Test
-    fun invalid_prepend() {
-        val pagingSource = LimitOffsetPagingSourceImpl(db)
-        dao.addAllItems(ITEMS_LIST)
+        // now write to the database
+        dao.deleteTestItem(ITEMS_LIST[30])
 
-        runBlocking {
-            val result = pagingSource.refresh(key = 20) as LoadResult.Page
+        // make sure room requests a refresh
+        db.invalidationTracker.awaitPendingRefresh()
+        // and that this is blocked to simulate delayed notification from room
+        queryExecutor.awaitDeferredSizeAtLeast(1)
 
-            // initial load
-            assertThat(result.data).containsExactlyElementsIn(
-                ITEMS_LIST.subList(20, 35)
-            )
-
-            // blocks invalidation notification from Room
-            queryExecutor.filterFunction = { runnable ->
-                runnable !== db.invalidationTracker.refreshRunnable
-            }
-
-            // now write to the database
-            dao.deleteTestItem(ITEMS_LIST[30])
-
-            // make sure room requests a refresh
-            db.invalidationTracker.awaitPendingRefresh()
-            // and that this is blocked to simulate delayed notification from room
-            queryExecutor.awaitDeferredSizeAtLeast(1)
-
-            // the db write should cause pagingSource to realize it is invalid when it tries to
-            // append
-            assertThat(pagingSource.prepend(20)).isInstanceOf(
-                LoadResult.Invalid::class.java
-            )
-            assertTrue(pagingSource.invalid)
-        }
+        // the db write should cause pagingSource to realize it is invalid when it tries to
+        // prepend
+        assertThat(pager.prepend()).isInstanceOf(
+            LoadResult.Invalid::class.java
+        )
+        assertThat(pagingSource.invalid).isTrue()
     }
 }
 
@@ -956,75 +831,10 @@
 
 private val ITEMS_LIST = createItemsForDb(0, 100)
 
-private fun createLoadParam(
-    loadType: LoadType,
-    key: Int? = null,
-    initialLoadSize: Int = CONFIG.initialLoadSize,
-    pageSize: Int = CONFIG.pageSize,
-    placeholdersEnabled: Boolean = CONFIG.enablePlaceholders
-): PagingSource.LoadParams<Int> {
-    return when (loadType) {
-        LoadType.REFRESH -> {
-            PagingSource.LoadParams.Refresh(
-                key = key,
-                loadSize = initialLoadSize,
-                placeholdersEnabled = placeholdersEnabled
-            )
-        }
-        LoadType.APPEND -> {
-            PagingSource.LoadParams.Append(
-                key = key ?: -1,
-                loadSize = pageSize,
-                placeholdersEnabled = placeholdersEnabled
-            )
-        }
-        LoadType.PREPEND -> {
-            PagingSource.LoadParams.Prepend(
-                key = key ?: -1,
-                loadSize = pageSize,
-                placeholdersEnabled = placeholdersEnabled
-            )
-        }
-    }
-}
-
 private fun createItemsForDb(startId: Int, count: Int): List<TestItem> {
     return List(count) {
         TestItem(
             id = it + startId,
         )
     }
-}
-
-private suspend fun PagingSource<Int, TestItem>.refresh(
-    key: Int? = null,
-): LoadResult<Int, TestItem> {
-    return this.load(
-        createLoadParam(
-            loadType = LoadType.REFRESH,
-            key = key,
-        )
-    )
-}
-
-private suspend fun PagingSource<Int, TestItem>.append(
-    key: Int? = -1,
-): LoadResult<Int, TestItem> {
-    return this.load(
-        createLoadParam(
-            loadType = LoadType.APPEND,
-            key = key,
-        )
-    )
-}
-
-private suspend fun PagingSource<Int, TestItem>.prepend(
-    key: Int? = -1,
-): LoadResult<Int, TestItem> {
-    return this.load(
-        createLoadParam(
-            loadType = LoadType.PREPEND,
-            key = key,
-        )
-    )
-}
+}
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index 3e517c5..bf5bfdc 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -767,7 +767,7 @@
 includeProject(":paging:paging-rxjava2-ktx", [BuildType.MAIN])
 includeProject(":paging:paging-rxjava3", [BuildType.MAIN])
 includeProject(":paging:paging-samples", "paging/samples", [BuildType.MAIN, BuildType.COMPOSE])
-includeProject(":paging:paging-testing", [BuildType.MAIN])
+includeProject(":paging:paging-testing", [BuildType.MAIN, BuildType.COMPOSE])
 includeProject(":palette:palette", [BuildType.MAIN])
 includeProject(":palette:palette-ktx", [BuildType.MAIN])
 includeProject(":percentlayout:percentlayout", [BuildType.MAIN])