Skip to content

Commit d7ba290

Browse files
authored
Minor tidy ups (#935)
* Add suspend to upsertAll * withContext only wraps mapping functions * Remove main coroutine rule from TaskDaoTest * Rename tasksRepository to taskRepository * Replace MainCoroutineRule with testScope and testDispatcher * Fix spotless * All tests run with testScope.runTest * Add mutex to TaskNetworkDataSource * Fix spotless * Recreate database before each test
1 parent 4aff247 commit d7ba290

File tree

6 files changed

+87
-107
lines changed

6 files changed

+87
-107
lines changed

app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/data/source/local/TaskDaoTest.kt

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,11 @@ import androidx.room.Room
2020
import androidx.test.core.app.ApplicationProvider.getApplicationContext
2121
import androidx.test.ext.junit.runners.AndroidJUnit4
2222
import androidx.test.filters.SmallTest
23-
import com.example.android.architecture.blueprints.todoapp.MainCoroutineRule
2423
import junit.framework.TestCase.assertEquals
2524
import junit.framework.TestCase.assertNotNull
2625
import kotlinx.coroutines.ExperimentalCoroutinesApi
2726
import kotlinx.coroutines.test.runTest
2827
import org.junit.Before
29-
import org.junit.Rule
3028
import org.junit.Test
3129
import org.junit.runner.RunWith
3230

@@ -37,19 +35,16 @@ class TaskDaoTest {
3735

3836
// using an in-memory database because the information stored here disappears when the
3937
// process is killed
40-
private val database = Room.inMemoryDatabaseBuilder(
41-
getApplicationContext(),
42-
ToDoDatabase::class.java
43-
).allowMainThreadQueries().build()
38+
private lateinit var database: ToDoDatabase
4439

45-
// Set the main coroutines dispatcher for unit testing.
46-
@get:Rule
47-
val mainCoroutineRule = MainCoroutineRule()
48-
49-
// Ensure that we use an empty database for each test.
40+
// Ensure that we use a new database for each test.
5041
@Before
51-
fun initDb() = database.clearAllTables()
52-
42+
fun initDb() {
43+
database = Room.inMemoryDatabaseBuilder(
44+
getApplicationContext(),
45+
ToDoDatabase::class.java
46+
).allowMainThreadQueries().build()
47+
}
5348
@Test
5449
fun insertTaskAndGetById() = runTest {
5550
// GIVEN - insert a task

app/src/main/java/com/example/android/architecture/blueprints/todoapp/data/DefaultTaskRepository.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,10 @@ class DefaultTaskRepository @Inject constructor(
174174
scope.launch {
175175
try {
176176
val localTasks = localDataSource.getAll()
177-
networkDataSource.saveTasks(localTasks.toNetwork())
177+
val networkTasks = withContext(dispatcher) {
178+
localTasks.toNetwork()
179+
}
180+
networkDataSource.saveTasks(networkTasks)
178181
} catch (e: Exception) {
179182
// In a real app you'd handle the exception e.g. by exposing a `networkStatus` flow
180183
// to an app level UI state holder which could then display a Toast message.

app/src/main/java/com/example/android/architecture/blueprints/todoapp/data/source/local/TaskDao.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ interface TaskDao {
7575
* @param tasks the tasks to be inserted or updated.
7676
*/
7777
@Upsert
78-
fun upsertAll(tasks: List<LocalTask>)
78+
suspend fun upsertAll(tasks: List<LocalTask>)
7979

8080
/**
8181
* Update the complete status of a task

app/src/main/java/com/example/android/architecture/blueprints/todoapp/data/source/network/TaskNetworkDataSource.kt

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,46 +18,35 @@ package com.example.android.architecture.blueprints.todoapp.data.source.network
1818

1919
import javax.inject.Inject
2020
import kotlinx.coroutines.delay
21+
import kotlinx.coroutines.sync.Mutex
22+
import kotlinx.coroutines.sync.withLock
2123

22-
/**
23-
* Implementation of the data source that adds a latency simulating network.
24-
*
25-
*/
2624
class TaskNetworkDataSource @Inject constructor() : NetworkDataSource {
2725

28-
private val SERVICE_LATENCY_IN_MILLIS = 2000L
29-
30-
private var TASK_SERVICE_DATA = LinkedHashMap<String, NetworkTask>(2)
31-
32-
init {
33-
addTask(
26+
// A mutex is used to ensure that reads and writes are thread-safe.
27+
private val accessMutex = Mutex()
28+
private var tasks = listOf(
29+
NetworkTask(
3430
id = "PISA",
3531
title = "Build tower in Pisa",
3632
shortDescription = "Ground looks good, no foundation work required."
37-
)
38-
addTask(
33+
),
34+
NetworkTask(
3935
id = "TACOMA",
4036
title = "Finish bridge in Tacoma",
4137
shortDescription = "Found awesome girders at half the cost!"
4238
)
43-
}
39+
)
4440

45-
override suspend fun loadTasks(): List<NetworkTask> {
46-
// Simulate network by delaying the execution.
47-
val tasks = TASK_SERVICE_DATA.values.toList()
41+
override suspend fun loadTasks(): List<NetworkTask> = accessMutex.withLock {
4842
delay(SERVICE_LATENCY_IN_MILLIS)
4943
return tasks
5044
}
5145

52-
override suspend fun saveTasks(tasks: List<NetworkTask>) {
53-
// Simulate network by delaying the execution.
46+
override suspend fun saveTasks(newTasks: List<NetworkTask>) = accessMutex.withLock {
5447
delay(SERVICE_LATENCY_IN_MILLIS)
55-
TASK_SERVICE_DATA.clear()
56-
TASK_SERVICE_DATA.putAll(tasks.associateBy(NetworkTask::id))
57-
}
58-
59-
private fun addTask(id: String, title: String, shortDescription: String) {
60-
val newTask = NetworkTask(id = id, title = title, shortDescription = shortDescription)
61-
TASK_SERVICE_DATA[newTask.id] = newTask
48+
tasks = newTasks
6249
}
6350
}
51+
52+
private const val SERVICE_LATENCY_IN_MILLIS = 2000L

0 commit comments

Comments
 (0)