diff --git a/AndroidApp/.idea/inspectionProfiles/Project_Default.xml b/AndroidApp/.idea/inspectionProfiles/Project_Default.xml
index 7061a0d6..343687f4 100644
--- a/AndroidApp/.idea/inspectionProfiles/Project_Default.xml
+++ b/AndroidApp/.idea/inspectionProfiles/Project_Default.xml
@@ -17,6 +17,7 @@
+
diff --git a/AndroidApp/data/repository/src/main/kotlin/me/nya_n/notificationnotifier/data/repository/impl/AppRepositoryImpl.kt b/AndroidApp/data/repository/src/main/kotlin/me/nya_n/notificationnotifier/data/repository/impl/AppRepositoryImpl.kt
index 427cd3ec..8bd590af 100644
--- a/AndroidApp/data/repository/src/main/kotlin/me/nya_n/notificationnotifier/data/repository/impl/AppRepositoryImpl.kt
+++ b/AndroidApp/data/repository/src/main/kotlin/me/nya_n/notificationnotifier/data/repository/impl/AppRepositoryImpl.kt
@@ -1,6 +1,7 @@
package me.nya_n.notificationnotifier.data.repository.impl
import android.content.pm.PackageManager
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import me.nya_n.notificationnotifier.data.repository.AppRepository
@@ -12,16 +13,17 @@ import me.nya_n.notificationnotifier.model.InstalledApp
class AppRepositoryImpl(
private val filterConditionDao: FilterConditionDao,
private val targetAppDao: TargetAppDao,
+ private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO
) : AppRepository {
override suspend fun clearAll() {
- withContext(Dispatchers.IO) {
+ withContext(coroutineDispatcher) {
filterConditionDao.clear()
targetAppDao.clear()
}
}
override suspend fun getFilterCondition(targetPackageName: String): FilterCondition? {
- return withContext(Dispatchers.IO) {
+ return withContext(coroutineDispatcher) {
filterConditionDao.get(targetPackageName)
}
}
@@ -31,31 +33,31 @@ class AppRepositoryImpl(
}
override suspend fun getFilterConditionList(): List {
- return withContext(Dispatchers.IO) {
+ return withContext(coroutineDispatcher) {
filterConditionDao.getAll()
}
}
override suspend fun saveFilterCondition(condition: FilterCondition) {
- withContext(Dispatchers.IO) {
+ withContext(coroutineDispatcher) {
filterConditionDao.insert(condition)
}
}
override suspend fun getTargetAppList(): List {
- return withContext(Dispatchers.IO) {
+ return withContext(coroutineDispatcher) {
targetAppDao.getAll()
}
}
override suspend fun addTargetApp(target: InstalledApp) {
- withContext(Dispatchers.IO) {
+ withContext(coroutineDispatcher) {
targetAppDao.insert(target)
}
}
override suspend fun deleteTargetApp(target: InstalledApp) {
- withContext(Dispatchers.IO) {
+ withContext(coroutineDispatcher) {
targetAppDao.delete(target)
}
}
diff --git a/AndroidApp/domain/build.gradle.kts b/AndroidApp/domain/build.gradle.kts
index e8cde834..29f7b8d2 100644
--- a/AndroidApp/domain/build.gradle.kts
+++ b/AndroidApp/domain/build.gradle.kts
@@ -21,10 +21,11 @@ dependencies {
api(libs.androidx.compose.runtime)
// test
- implementation(libs.junit)
- implementation(libs.com.google.truth)
- implementation(libs.androidx.test.ext.junit)
- implementation(libs.androidx.test.espresso.core)
+ androidTestImplementation(libs.junit)
+ androidTestImplementation(libs.com.google.truth)
+ androidTestImplementation(libs.androidx.test.ext.junit)
+ androidTestImplementation(libs.androidx.test.espresso.core)
+ androidTestImplementation(libs.kotlinx.coroutines.test)
// その他
implementation(libs.com.google.code.gson)
diff --git a/AndroidApp/domain/src/androidTest/java/me/nya_n/notificationnotifier/Annotations.kt b/AndroidApp/domain/src/androidTest/java/me/nya_n/notificationnotifier/Annotations.kt
new file mode 100644
index 00000000..1f222b1b
--- /dev/null
+++ b/AndroidApp/domain/src/androidTest/java/me/nya_n/notificationnotifier/Annotations.kt
@@ -0,0 +1,5 @@
+package me.nya_n.notificationnotifier
+
+@Target(AnnotationTarget.FUNCTION)
+@Retention(AnnotationRetention.RUNTIME)
+annotation class LocalOnly
\ No newline at end of file
diff --git a/AndroidApp/domain/src/androidTest/java/me/nya_n/notificationnotifier/UseCaseTest.kt b/AndroidApp/domain/src/androidTest/java/me/nya_n/notificationnotifier/UseCaseTest.kt
index 8d15e97a..26815640 100644
--- a/AndroidApp/domain/src/androidTest/java/me/nya_n/notificationnotifier/UseCaseTest.kt
+++ b/AndroidApp/domain/src/androidTest/java/me/nya_n/notificationnotifier/UseCaseTest.kt
@@ -7,14 +7,23 @@ import androidx.core.content.edit
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.runBlocking
-import me.nya_n.notificationnotifier.data.repository.AppRepository
-import me.nya_n.notificationnotifier.data.repository.UserSettingsRepository
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
import me.nya_n.notificationnotifier.data.repository.impl.AppRepositoryImpl
import me.nya_n.notificationnotifier.data.repository.impl.UserSettingsRepositoryImpl
import me.nya_n.notificationnotifier.data.repository.source.DB
import me.nya_n.notificationnotifier.data.repository.source.UserSettingsDataStore
import me.nya_n.notificationnotifier.data.repository.util.SharedPreferenceProvider
+import me.nya_n.notificationnotifier.domain.usecase.AddTargetAppUseCase
+import me.nya_n.notificationnotifier.domain.usecase.DeleteTargetAppUseCase
+import me.nya_n.notificationnotifier.domain.usecase.ExportDataUseCase
+import me.nya_n.notificationnotifier.domain.usecase.ImportDataUseCase
+import me.nya_n.notificationnotifier.domain.usecase.LoadAddressUseCase
+import me.nya_n.notificationnotifier.domain.usecase.LoadFilterConditionUseCase
+import me.nya_n.notificationnotifier.domain.usecase.NotifyUseCase
+import me.nya_n.notificationnotifier.domain.usecase.PackageVisibilityGrantedUseCase
+import me.nya_n.notificationnotifier.domain.usecase.SaveAddressUseCase
import me.nya_n.notificationnotifier.domain.usecase.SaveFilterConditionUseCase
import me.nya_n.notificationnotifier.domain.usecase.ToggleIgnoreSummaryUseCase
import me.nya_n.notificationnotifier.domain.usecase.impl.AddTargetAppUseCaseImpl
@@ -29,10 +38,11 @@ import me.nya_n.notificationnotifier.domain.usecase.impl.PackageVisibilityGrante
import me.nya_n.notificationnotifier.domain.usecase.impl.SaveAddressUseCaseImpl
import me.nya_n.notificationnotifier.domain.usecase.impl.SaveFilterConditionUseCaseImpl
import me.nya_n.notificationnotifier.domain.usecase.impl.ToggleIgnoreSummaryUseCaseImpl
+import me.nya_n.notificationnotifier.model.AppException.PermissionDeniedException
import me.nya_n.notificationnotifier.model.FilterCondition
import me.nya_n.notificationnotifier.model.InstalledApp
+import org.junit.Assume.assumeTrue
import org.junit.Before
-import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import java.io.File
@@ -40,24 +50,40 @@ import java.io.File
@Suppress("NonAsciiCharacters", "RemoveRedundantBackticks")
@RunWith(AndroidJUnit4::class)
class UseCaseTest {
+ companion object {
+ private const val ExportFileName: String = "export.json"
+ }
+
+ @OptIn(ExperimentalCoroutinesApi::class)
+ private val testDispatcher = UnconfinedTestDispatcher()
private lateinit var appContext: Context
- private lateinit var userSettingsRepository: UserSettingsRepository
- private lateinit var appRepository: AppRepository
private lateinit var pm: PackageManager
private lateinit var exportFile: File
- private val exportFileName: String = "export.json"
+
+ private lateinit var addTargetAppUseCase: AddTargetAppUseCase
+ private lateinit var loadAppUseCase: LoadAppUseCaseImpl
+ private lateinit var deleteTargetAppUseCase: DeleteTargetAppUseCase
+ private lateinit var packageVisibilityGrantedUseCase: PackageVisibilityGrantedUseCase
+ private lateinit var saveFilterConditionUseCase: SaveFilterConditionUseCase
+ private lateinit var toggleIgnoreSummaryUseCase: ToggleIgnoreSummaryUseCase
+ private lateinit var loadFilterConditionUseCase: LoadFilterConditionUseCase
+ private lateinit var saveAddressUseCase: SaveAddressUseCase
+ private lateinit var loadAddressUseCase: LoadAddressUseCase
+ private lateinit var notifyUseCase: NotifyUseCase
+ private lateinit var exportDataUseCase: ExportDataUseCase
+ private lateinit var importDataUseCase: ImportDataUseCase
@Before
fun setUp() {
appContext = InstrumentationRegistry.getInstrumentation().targetContext
exportFile = appContext.filesDir
- File(exportFile, exportFileName).apply {
+ File(exportFile, ExportFileName).apply {
if (exists()) {
delete()
}
}
pm = appContext.packageManager
- userSettingsRepository = UserSettingsRepositoryImpl(
+ val userSettingsRepository = UserSettingsRepositoryImpl(
UserSettingsDataStore(
SharedPreferenceProvider.create(
appContext,
@@ -69,36 +95,51 @@ class UseCaseTest {
}
)
)
- val db = DB.get(appContext, true).apply {
+ val db = DB.get(appContext, isInMemory = true).apply {
clearAllTables()
}
- appRepository = AppRepositoryImpl(
+ val appRepository = AppRepositoryImpl(
db.filterConditionDao(),
- db.targetAppDao()
+ db.targetAppDao(),
+ testDispatcher
)
+ addTargetAppUseCase = AddTargetAppUseCaseImpl(appRepository)
+ loadAppUseCase = LoadAppUseCaseImpl(userSettingsRepository, appRepository, testDispatcher)
+ deleteTargetAppUseCase = DeleteTargetAppUseCaseImpl(appRepository)
+ packageVisibilityGrantedUseCase =
+ PackageVisibilityGrantedUseCaseImpl(userSettingsRepository)
+ saveFilterConditionUseCase = SaveFilterConditionUseCaseImpl(appRepository)
+ toggleIgnoreSummaryUseCase = ToggleIgnoreSummaryUseCaseImpl(appRepository)
+ loadFilterConditionUseCase = LoadFilterConditionUseCaseImpl(appRepository)
+ saveAddressUseCase = SaveAddressUseCaseImpl(userSettingsRepository)
+ loadAddressUseCase = LoadAddressUseCaseImpl(userSettingsRepository)
+ notifyUseCase = NotifyUseCaseImpl(userSettingsRepository, testDispatcher)
+ exportDataUseCase =
+ ExportDataUseCaseImpl(userSettingsRepository, appRepository, testDispatcher)
+ importDataUseCase =
+ ImportDataUseCaseImpl(userSettingsRepository, appRepository, testDispatcher)
}
@Test
fun `通知対象アプリの追加、取得、削除`() {
- runBlocking {
+ runTest(testDispatcher) {
val app = InstalledApp("sample", "com.sample.www")
- AddTargetAppUseCaseImpl(appRepository)(app)
+ addTargetAppUseCase(app)
- val loader = LoadAppUseCaseImpl(userSettingsRepository, appRepository)
- val added = loader.loadTargetList()
+ val added = loadAppUseCase.loadTargetList()
assertThat(added).hasSize(1)
assertThat(added.first()).isEqualTo(app)
- DeleteTargetAppUseCaseImpl(appRepository)(app)
- val deleted = loader.loadTargetList()
+ deleteTargetAppUseCase(app)
+ val deleted = loadAppUseCase.loadTargetList()
assertThat(deleted).isEmpty()
}
}
@Test
fun `インストール済みアプリの取得_成功(ついでにアプリ一覧取得権限許可処理も)`() {
- PackageVisibilityGrantedUseCaseImpl(userSettingsRepository)()
- val ret = LoadAppUseCaseImpl(userSettingsRepository, appRepository).loadInstalledAppList(pm)
+ packageVisibilityGrantedUseCase()
+ val ret = loadAppUseCase.loadInstalledAppList(pm)
assertThat(ret.getOrNull()).apply {
isNotNull()
isNotEmpty()
@@ -107,166 +148,167 @@ class UseCaseTest {
@Test
fun `インストール済みアプリの取得_失敗`() {
- val ret = LoadAppUseCaseImpl(userSettingsRepository, appRepository).loadInstalledAppList(pm)
+ val ret = loadAppUseCase.loadInstalledAppList(pm)
assertThat(ret.exceptionOrNull()).apply {
isNotNull()
- isInstanceOf(me.nya_n.notificationnotifier.model.AppException.PermissionDeniedException::class.java)
+ isInstanceOf(PermissionDeniedException::class.java)
}
}
@Test
fun `通知条件の追加、取得、更新`() {
- runBlocking {
+ runTest(testDispatcher) {
val cond = "test"
val updatedCond = "updated"
val packageName = "com.sample.www"
val app = InstalledApp("sample", packageName)
- val saver = SaveFilterConditionUseCaseImpl(appRepository)
- val toggler = ToggleIgnoreSummaryUseCaseImpl(appRepository)
- val loader = LoadFilterConditionUseCaseImpl(appRepository)
-
// 追加
- saver(SaveFilterConditionUseCase.Args(app, cond))
- assertThat(loader(app)).isEqualTo(FilterCondition(packageName, false, cond))
+ saveFilterConditionUseCase(SaveFilterConditionUseCase.Args(app, cond))
+ assertThat(loadFilterConditionUseCase(app)).isEqualTo(
+ FilterCondition(
+ packageName,
+ false,
+ cond
+ )
+ )
// メッセージ条件の更新
- saver(SaveFilterConditionUseCase.Args(app, updatedCond))
- assertThat(loader(app)).isEqualTo(FilterCondition(packageName, false, updatedCond))
+ saveFilterConditionUseCase(SaveFilterConditionUseCase.Args(app, updatedCond))
+ assertThat(loadFilterConditionUseCase(app)).isEqualTo(
+ FilterCondition(
+ packageName,
+ false,
+ updatedCond
+ )
+ )
// サマリー条件の更新
- toggler.invoke(ToggleIgnoreSummaryUseCase.Args(app))
- assertThat(loader(app)).isEqualTo(FilterCondition(packageName, true, updatedCond))
+ toggleIgnoreSummaryUseCase.invoke(ToggleIgnoreSummaryUseCase.Args(app))
+ assertThat(loadFilterConditionUseCase(app)).isEqualTo(
+ FilterCondition(
+ packageName,
+ true,
+ updatedCond
+ )
+ )
}
}
@Test
fun `IPアドレスの追加、更新_成功、成功`() {
- val saver = SaveAddressUseCaseImpl(userSettingsRepository)
- val loader = LoadAddressUseCaseImpl(userSettingsRepository)
-
val host = "192.168.11.4"
val port = 5555
val addr = "$host:$port"
- assertThat(saver(addr).getOrNull()).isNotNull()
- assertThat(loader()).isEqualTo(addr)
+ assertThat(saveAddressUseCase(addr).getOrNull()).isNotNull()
+ assertThat(loadAddressUseCase()).isEqualTo(addr)
val updatedHost = "192.168.11.2"
val updatedPort = 3456
val updatedAddr = "$updatedHost:$updatedPort"
- assertThat(saver(updatedAddr).getOrNull()).isNotNull()
- assertThat(loader()).isEqualTo(updatedAddr)
+ assertThat(saveAddressUseCase(updatedAddr).getOrNull()).isNotNull()
+ assertThat(loadAddressUseCase()).isEqualTo(updatedAddr)
}
@Test
fun `IPアドレスの追加、更新_成功、失敗`() {
- val saver = SaveAddressUseCaseImpl(userSettingsRepository)
- val loader = LoadAddressUseCaseImpl(userSettingsRepository)
-
val host = "192.168.11.4"
val port = 5555
val addr = "$host:$port"
- assertThat(saver(addr).getOrNull()).isNotNull()
- assertThat(loader()).isEqualTo(addr)
+ assertThat(saveAddressUseCase(addr).getOrNull()).isNotNull()
+ assertThat(loadAddressUseCase()).isEqualTo(addr)
val updatedHost = "192.168.11.2"
val updatedAddr = "$updatedHost:"
- assertThat(saver(updatedAddr).exceptionOrNull()).isNotNull()
- assertThat(loader()).isEqualTo(addr)
+ assertThat(saveAddressUseCase(updatedAddr).exceptionOrNull()).isNotNull()
+ assertThat(loadAddressUseCase()).isEqualTo(addr)
}
@Test
fun `IPアドレスの追加_失敗_hostなし`() {
val port = 5555
val addr = ":$port"
- assertThat(SaveAddressUseCaseImpl(userSettingsRepository)(addr).exceptionOrNull()).isNotNull()
+ assertThat(saveAddressUseCase(addr).exceptionOrNull()).isNotNull()
}
@Test
fun `IPアドレスの追加_失敗_portなし`() {
val host = "192.168.11.4"
val addr = "$host:"
- assertThat(SaveAddressUseCaseImpl(userSettingsRepository)(addr).exceptionOrNull()).isNotNull()
+ assertThat(saveAddressUseCase(addr).exceptionOrNull()).isNotNull()
}
@Test
fun `IPアドレスの追加_失敗_portが数値じゃない`() {
val host = "192.168.11.4"
val addr = "$host:test"
- assertThat(SaveAddressUseCaseImpl(userSettingsRepository)(addr).exceptionOrNull()).isNotNull()
+ assertThat(saveAddressUseCase(addr).exceptionOrNull()).isNotNull()
}
@Test
fun `通知送信_失敗`() {
- runBlocking {
- assertThat(
- NotifyUseCaseImpl(userSettingsRepository)("通知テスト").exceptionOrNull()
- ).isNotNull()
+ runTest(testDispatcher) {
+ assertThat(notifyUseCase("通知テスト").exceptionOrNull()).isNotNull()
}
}
@Test
- @Ignore("FIXME: socket failed: EPERM (Operation not permitted)")
+ @LocalOnly
fun `通知送信_成功`() {
- runBlocking {
- val host = "192.168.11.4"
- val port = 5555
+ // CI環境で実行しないようにする
+ assumeTrue("Local only", System.getenv("CI") == null)
+
+ runTest(testDispatcher) {
+ val host = "192.168.10.18" // テスト環境のIPアドレスに変更する
+ val port = 8484
val addr = "$host:$port"
- SaveAddressUseCaseImpl(userSettingsRepository)(addr)
- assertThat(
- NotifyUseCaseImpl(userSettingsRepository)("通知テスト").getOrNull()
- ).isNotNull()
+ saveAddressUseCase(addr)
+ assertThat(notifyUseCase("通知テスト").getOrNull()).isNotNull()
}
}
@Test
fun `バックアップ、復元`() {
- val uri = Uri.fromFile(File.createTempFile(exportFileName, null, exportFile))
- runBlocking {
- val targetSaver = AddTargetAppUseCaseImpl(appRepository)
- val condSaver = SaveFilterConditionUseCaseImpl(appRepository)
- val addrSaver = SaveAddressUseCaseImpl(userSettingsRepository)
- val toggler = ToggleIgnoreSummaryUseCaseImpl(appRepository)
-
+ val uri = Uri.fromFile(File.createTempFile(ExportFileName, null, exportFile))
+ runTest(testDispatcher) {
// 初期値の保存
// ターゲット
val packageName = "test.export"
val app = InstalledApp("export", packageName)
- targetSaver(app)
+ addTargetAppUseCase(app)
// 条件
val cond = ".*"
- condSaver(SaveFilterConditionUseCase.Args(app, cond))
- toggler.invoke(ToggleIgnoreSummaryUseCase.Args(app))
+ saveFilterConditionUseCase(SaveFilterConditionUseCase.Args(app, cond))
+ toggleIgnoreSummaryUseCase.invoke(ToggleIgnoreSummaryUseCase.Args(app))
// アドレス
val addr = "192.168.1.4:5050"
- addrSaver(addr)
+ saveAddressUseCase(addr)
// バックアップ
- ExportDataUseCaseImpl(userSettingsRepository, appRepository)(appContext, uri)
+ exportDataUseCase(appContext, uri)
// バックアップ時とは異なるように適当に変更
// ターゲット
- targetSaver(InstalledApp("new", "new"))
+ addTargetAppUseCase(InstalledApp("new", "new"))
// 条件
- condSaver(SaveFilterConditionUseCase.Args(app, "new"))
- toggler.invoke(ToggleIgnoreSummaryUseCase.Args(app))
+ saveFilterConditionUseCase(SaveFilterConditionUseCase.Args(app, "new"))
+ toggleIgnoreSummaryUseCase.invoke(ToggleIgnoreSummaryUseCase.Args(app))
// 復元
- ImportDataUseCaseImpl(userSettingsRepository, appRepository)(appContext, uri)
+ importDataUseCase(appContext, uri)
// 正常に復元できているか確認
// ターゲット一覧
- val restoreTargets =
- LoadAppUseCaseImpl(userSettingsRepository, appRepository).loadTargetList()
+ val restoreTargets = loadAppUseCase.loadTargetList()
assertThat(restoreTargets).apply {
hasSize(1)
contains(app)
}
// 条件
- val restoreCond = LoadFilterConditionUseCaseImpl(appRepository)(app)
+ val restoreCond = loadFilterConditionUseCase(app)
assertThat(restoreCond).isEqualTo(FilterCondition(packageName, true, cond))
// アドレス
- val restoreAddr = LoadAddressUseCaseImpl(userSettingsRepository)()
+ val restoreAddr = loadAddressUseCase()
assertThat(restoreAddr).isEqualTo(addr)
}
}
diff --git a/AndroidApp/domain/src/main/AndroidManifest.xml b/AndroidApp/domain/src/main/AndroidManifest.xml
index 568741e5..40f057de 100644
--- a/AndroidApp/domain/src/main/AndroidManifest.xml
+++ b/AndroidApp/domain/src/main/AndroidManifest.xml
@@ -1,2 +1,5 @@
-
\ No newline at end of file
+
+
+
+
\ No newline at end of file
diff --git a/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/ExportDataUseCaseImpl.kt b/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/ExportDataUseCaseImpl.kt
index 69ac19c4..6d80df50 100644
--- a/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/ExportDataUseCaseImpl.kt
+++ b/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/ExportDataUseCaseImpl.kt
@@ -3,6 +3,7 @@ package me.nya_n.notificationnotifier.domain.usecase.impl
import android.content.Context
import android.net.Uri
import com.google.gson.Gson
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import me.nya_n.notificationnotifier.data.repository.AppRepository
@@ -14,6 +15,7 @@ import me.nya_n.notificationnotifier.model.Backup
class ExportDataUseCaseImpl(
private val userSettingsRepository: UserSettingsRepository,
private val appRepository: AppRepository,
+ private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO
) : ExportDataUseCase {
override suspend operator fun invoke(context: Context, uri: Uri): Result {
return runCatching {
@@ -24,7 +26,7 @@ class ExportDataUseCaseImpl(
appRepository.getFilterConditionList()
)
val json = Gson().toJson(data)
- withContext(Dispatchers.IO) {
+ withContext(coroutineDispatcher) {
context.contentResolver.openOutputStream(uri).use {
it?.write(json.toByteArray())
}
diff --git a/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/ImportDataUseCaseImpl.kt b/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/ImportDataUseCaseImpl.kt
index 4c422837..d3d3bba2 100644
--- a/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/ImportDataUseCaseImpl.kt
+++ b/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/ImportDataUseCaseImpl.kt
@@ -3,6 +3,7 @@ package me.nya_n.notificationnotifier.domain.usecase.impl
import android.content.Context
import android.net.Uri
import com.google.gson.Gson
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import me.nya_n.notificationnotifier.data.repository.AppRepository
@@ -16,11 +17,12 @@ import java.io.InputStreamReader
class ImportDataUseCaseImpl(
private val userSettingsRepository: UserSettingsRepository,
private val appRepository: AppRepository,
+ private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO
) : ImportDataUseCase {
override suspend operator fun invoke(context: Context, uri: Uri): Result {
return runCatching {
val sb = StringBuilder()
- withContext(Dispatchers.IO) {
+ withContext(coroutineDispatcher) {
context.contentResolver.openInputStream(uri).use { input ->
BufferedReader(InputStreamReader(input)).use { reader ->
sb.append(reader.readLine())
diff --git a/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/LoadAppUseCaseImpl.kt b/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/LoadAppUseCaseImpl.kt
index 2c3af9bc..9d3a11ce 100644
--- a/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/LoadAppUseCaseImpl.kt
+++ b/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/LoadAppUseCaseImpl.kt
@@ -2,6 +2,7 @@ package me.nya_n.notificationnotifier.domain.usecase.impl
import android.content.pm.PackageManager
import androidx.annotation.VisibleForTesting
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import me.nya_n.notificationnotifier.data.repository.AppRepository
@@ -13,11 +14,12 @@ import me.nya_n.notificationnotifier.model.InstalledApp
class LoadAppUseCaseImpl(
private val userSettingsRepository: UserSettingsRepository,
- private val appRepository: AppRepository
+ private val appRepository: AppRepository,
+ private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO
) : LoadAppUseCase {
override suspend operator fun invoke(pm: PackageManager): Result =
- withContext(Dispatchers.IO) {
+ withContext(coroutineDispatcher) {
val apps = loadInstalledAppList(pm).getOrElse {
return@withContext Result.failure(it)
}
diff --git a/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/NotifyTargetAppNotificationUseCaseImpl.kt b/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/NotifyTargetAppNotificationUseCaseImpl.kt
index 226f93a6..0230e740 100644
--- a/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/NotifyTargetAppNotificationUseCaseImpl.kt
+++ b/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/NotifyTargetAppNotificationUseCaseImpl.kt
@@ -1,15 +1,13 @@
package me.nya_n.notificationnotifier.domain.usecase.impl
import android.app.Notification
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
import me.nya_n.notificationnotifier.data.repository.AppRepository
import me.nya_n.notificationnotifier.domain.usecase.NotifyTargetAppNotificationUseCase
import me.nya_n.notificationnotifier.domain.usecase.NotifyUseCase
class NotifyTargetAppNotificationUseCaseImpl(
private val appRepository: AppRepository,
- private val notifyUseCase: NotifyUseCase
+ private val notifyUseCase: NotifyUseCase,
) : NotifyTargetAppNotificationUseCase {
override suspend operator fun invoke(
packageName: String,
@@ -36,10 +34,7 @@ class NotifyTargetAppNotificationUseCaseImpl(
return Result.success(Unit)
}
}
-
- withContext(Dispatchers.IO) {
- notifyUseCase("${title}\n${message}")
- }
+ notifyUseCase("${title}\n${message}")
}
}
}
\ No newline at end of file
diff --git a/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/NotifyUseCaseImpl.kt b/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/NotifyUseCaseImpl.kt
index 982731d5..1dfffee7 100644
--- a/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/NotifyUseCaseImpl.kt
+++ b/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/NotifyUseCaseImpl.kt
@@ -1,5 +1,6 @@
package me.nya_n.notificationnotifier.domain.usecase.impl
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import me.nya_n.notificationnotifier.data.repository.UserSettingsRepository
@@ -9,7 +10,8 @@ import java.net.InetSocketAddress
import java.net.Socket
class NotifyUseCaseImpl(
- private val userSettingsRepository: UserSettingsRepository
+ private val userSettingsRepository: UserSettingsRepository,
+ private val coroutineDispatcher: CoroutineDispatcher = Dispatchers.IO
) : NotifyUseCase {
companion object {
private const val CONNECTION_TIMEOUT = 1_000
@@ -17,7 +19,7 @@ class NotifyUseCaseImpl(
override suspend operator fun invoke(message: String): Result {
return runCatching {
- withContext(Dispatchers.IO) {
+ withContext(coroutineDispatcher) {
val settings = userSettingsRepository.getUserSettings()
val addr = InetSocketAddress(
InetAddress.getByName(settings.host),
diff --git a/AndroidApp/gradle/libs.versions.toml b/AndroidApp/gradle/libs.versions.toml
index 05e732c6..b62c350a 100644
--- a/AndroidApp/gradle/libs.versions.toml
+++ b/AndroidApp/gradle/libs.versions.toml
@@ -12,6 +12,7 @@ versionName = "1.1"
# Library
agp = "8.9.3"
kotlin = "2.2.21"
+kotlinx-coroutines = "1.10.2"
com-google-devtools-ksp = "2.3.3" # Kotlinのバージョンに合わせる必要がある
com-jaredsburrows-license = "0.9.8"
androidx-core = "1.17.0"
@@ -63,6 +64,7 @@ androidx-compose-navigation = { module = "androidx.navigation:navigation-compose
# test
junit = { module = "junit:junit", version.ref = "junit" }
+kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" }
com-google-truth = { module = "com.google.truth:truth", version.ref = "com-google-truth" }
androidx-test-ext-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-test-ext" }
androidx-test-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "androidx-test-espresso" }