From 610a7e9a214259b9fcc1dc34226e83f2a6c20033 Mon Sep 17 00:00:00 2001 From: Alexandru Caraus Date: Wed, 4 Sep 2024 11:07:39 +0200 Subject: [PATCH 1/2] Fix ktlint and unit tests --- features/news/build.gradle.kts | 3 -- .../news/data/{LocaleStore.kt => Locale.kt} | 7 ++--- .../eu/acaraus/news/data/SpeechRecognizer.kt | 8 ++--- .../eu/acaraus/news/data/remote/NewsApi.kt | 18 ++++------- .../news/data/remote/client/HttpClient.kt | 2 +- .../{LocaleStore.kt => LocaleRepository.kt} | 2 +- .../{NewsApi.kt => NewsRepository.kt} | 2 +- ...cognizer.kt => SpeechRecognizerService.kt} | 2 +- .../news/domain/usecases/GetArticles.kt | 12 ++++---- .../domain/usecases/GetArticlesSources.kt | 12 ++++---- .../presentation/list/ArticlesListScreen.kt | 4 +-- .../list/ArticlesListScreenPreview.kt | 2 +- .../components/AudioCommandButtonPreview.kt | 1 - .../list/holders/ArticlesListStateHolder.kt | 4 +-- .../holders/SpeechRecognizerStateHolder.kt | 18 +++++------ .../{NewsApiTest.kt => NewsRepositoryTest.kt} | 30 +++++++++---------- .../eu/acaraus/news/test/rules/UTest.kt | 2 +- .../list/ArticleListStateHolderTest.kt | 10 +++---- .../articles/list/ArticleListViewModelTest.kt | 14 ++++----- .../list/ArticlesFilterStateHolderTest.kt | 11 ++++--- .../screens/articles/list/KoinScopeTest.kt | 14 ++++----- .../news/test/snapshots/SnapshotTest.kt | 1 - shared_lib/build.gradle.kts | 7 ----- .../kotlin/eu/acaraus/shared/lib/Either.kt | 1 - .../shared/lib/coroutines/Coroutines.kt | 2 -- shared_test_lib/build.gradle.kts | 2 -- .../test/lib/ExampleInstrumentedTest.kt | 24 --------------- .../eu/acaraus/shared/test/lib/UnitTest.kt | 2 -- .../lib/coroutines/UnitTestDispatchers.kt | 1 - .../eu/acaraus/shared/test/lib/di/TestDi.kt | 1 - .../shared/test/lib/ExampleUnitTest.kt | 3 +- uicomponents/build.gradle.kts | 1 - .../components/ExampleInstrumentedTest.kt | 6 ++-- .../design/components/ExampleUnitTest.kt | 3 +- 34 files changed, 87 insertions(+), 145 deletions(-) rename features/news/src/main/kotlin/eu/acaraus/news/data/{LocaleStore.kt => Locale.kt} (80%) rename features/news/src/main/kotlin/eu/acaraus/news/domain/repositories/{LocaleStore.kt => LocaleRepository.kt} (86%) rename features/news/src/main/kotlin/eu/acaraus/news/domain/repositories/{NewsApi.kt => NewsRepository.kt} (95%) rename features/news/src/main/kotlin/eu/acaraus/news/domain/repositories/{SpeechRecognizer.kt => SpeechRecognizerService.kt} (94%) rename features/news/src/test/kotlin/eu/acaraus/news/test/data/news/{NewsApiTest.kt => NewsRepositoryTest.kt} (64%) delete mode 100644 shared_test_lib/src/androidTest/kotlin/eu/acaraus/shared/test/lib/ExampleInstrumentedTest.kt diff --git a/features/news/build.gradle.kts b/features/news/build.gradle.kts index da54a4e..f5e1a9e 100644 --- a/features/news/build.gradle.kts +++ b/features/news/build.gradle.kts @@ -76,7 +76,6 @@ dependencies { testFixturesImplementation(libs.androidx.compose.ui) } - android { namespace = "eu.acaraus.news" compileSdk = libs.versions.compileSdk.get().toInt() @@ -126,5 +125,3 @@ android { enable = true } } - - diff --git a/features/news/src/main/kotlin/eu/acaraus/news/data/LocaleStore.kt b/features/news/src/main/kotlin/eu/acaraus/news/data/Locale.kt similarity index 80% rename from features/news/src/main/kotlin/eu/acaraus/news/data/LocaleStore.kt rename to features/news/src/main/kotlin/eu/acaraus/news/data/Locale.kt index 5cd2dca..cd56fd8 100644 --- a/features/news/src/main/kotlin/eu/acaraus/news/data/LocaleStore.kt +++ b/features/news/src/main/kotlin/eu/acaraus/news/data/Locale.kt @@ -1,12 +1,11 @@ package eu.acaraus.news.data -import eu.acaraus.news.domain.repositories.LocaleStore +import eu.acaraus.news.domain.repositories.LocaleRepository import org.koin.core.annotation.Single import java.util.Locale - -@Single(binds = [LocaleStore::class]) -class LocaleStoreImpl : LocaleStore { +@Single(binds = [LocaleRepository::class]) +class Locale : LocaleRepository { private var languageCode = Locale.getDefault().language private var countryCode = Locale.getDefault().country diff --git a/features/news/src/main/kotlin/eu/acaraus/news/data/SpeechRecognizer.kt b/features/news/src/main/kotlin/eu/acaraus/news/data/SpeechRecognizer.kt index d14072d..0b52966 100644 --- a/features/news/src/main/kotlin/eu/acaraus/news/data/SpeechRecognizer.kt +++ b/features/news/src/main/kotlin/eu/acaraus/news/data/SpeechRecognizer.kt @@ -6,7 +6,7 @@ import android.os.Bundle import android.speech.RecognitionListener import android.speech.RecognizerIntent import eu.acaraus.news.domain.repositories.SpeechEvent -import eu.acaraus.news.domain.repositories.SpeechRecognizer +import eu.acaraus.news.domain.repositories.SpeechRecognizerService import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -14,10 +14,10 @@ import kotlinx.coroutines.flow.callbackFlow import org.koin.core.annotation.Factory import android.speech.SpeechRecognizer as AndroidSpeechRecognizer -@Factory(binds = [SpeechRecognizer::class]) -class SpeechRecognizerImpl( +@Factory(binds = [SpeechRecognizerService::class]) +class SpeechRecognizer( context: Context, -) : SpeechRecognizer { +) : SpeechRecognizerService { override val isAvailable = MutableStateFlow( AndroidSpeechRecognizer.isRecognitionAvailable(context), diff --git a/features/news/src/main/kotlin/eu/acaraus/news/data/remote/NewsApi.kt b/features/news/src/main/kotlin/eu/acaraus/news/data/remote/NewsApi.kt index dcbf684..1b888b3 100644 --- a/features/news/src/main/kotlin/eu/acaraus/news/data/remote/NewsApi.kt +++ b/features/news/src/main/kotlin/eu/acaraus/news/data/remote/NewsApi.kt @@ -6,7 +6,7 @@ import eu.acaraus.news.domain.entities.ArticlesFilter import eu.acaraus.news.domain.entities.ArticlesSources import eu.acaraus.news.domain.entities.NewsError import eu.acaraus.news.domain.entities.SortBy -import eu.acaraus.news.domain.repositories.NewsApi +import eu.acaraus.news.domain.repositories.NewsRepository import eu.acaraus.shared.lib.Either import eu.acaraus.shared.lib.Either.Success import eu.acaraus.shared.lib.coroutines.DispatcherProvider @@ -19,19 +19,18 @@ import kotlinx.coroutines.withContext import org.koin.core.annotation.Factory import java.time.format.DateTimeFormatter -@Factory(binds = [NewsApi::class]) -class NewsApiImpl( +@Factory(binds = [NewsRepository::class]) +class NewsApi( private val httpClient: HttpClient, private val httpClientConfig: HttpClientConfig, private val dispatchers: DispatcherProvider, -) : NewsApi { +) : NewsRepository { override suspend fun getHeadlines( language: String, category: String, ): Either, NewsError> = withContext(dispatchers.io) { kotlin.runCatching { - val response = httpClient.get(path("/v2/top-headlines")) { parameter(LANGUAGE, language) parameter(CATEGORY, category) @@ -43,7 +42,6 @@ class NewsApiImpl( else -> Either.Error(response.toError()) } - }.getOrElse { failure -> Either.error(failure.toError()) } } @@ -62,20 +60,18 @@ class NewsApiImpl( else -> Either.Error(response.toError()) } - }.getOrElse { failure -> Either.error(failure.toError()) } } override suspend fun getEverything(filter: ArticlesFilter): Either, NewsError> = withContext(dispatchers.io) { kotlin.runCatching { - val response: NewsApiResponse = httpClient.get((path("/v2/everything"))) { parameter(LANGUAGE, filter.language) parameter( filter.query.isNotBlank(), QUERY, - filter.query + filter.query, ) parameter( filter.sources.isNotEmpty(), @@ -93,9 +89,7 @@ class NewsApiImpl( else -> Either.Error(response.toError()) } - }.getOrElse { failure -> Either.error(failure.toError()) } - } private fun path(path: String) = httpClientConfig.baseUrl + path @@ -103,7 +97,7 @@ class NewsApiImpl( private fun HttpRequestBuilder.parameter( condition: Boolean, key: String, - value: Any? + value: Any?, ) { if (condition) parameter(key, value) } diff --git a/features/news/src/main/kotlin/eu/acaraus/news/data/remote/client/HttpClient.kt b/features/news/src/main/kotlin/eu/acaraus/news/data/remote/client/HttpClient.kt index d8892b0..0de34d6 100644 --- a/features/news/src/main/kotlin/eu/acaraus/news/data/remote/client/HttpClient.kt +++ b/features/news/src/main/kotlin/eu/acaraus/news/data/remote/client/HttpClient.kt @@ -19,7 +19,7 @@ import org.koin.core.annotation.Single @Single fun client( json: Json, - httpClientConfig: HttpClientConfig + httpClientConfig: HttpClientConfig, ): HttpClient = HttpClient(OkHttp) { install(DefaultRequest) { diff --git a/features/news/src/main/kotlin/eu/acaraus/news/domain/repositories/LocaleStore.kt b/features/news/src/main/kotlin/eu/acaraus/news/domain/repositories/LocaleRepository.kt similarity index 86% rename from features/news/src/main/kotlin/eu/acaraus/news/domain/repositories/LocaleStore.kt rename to features/news/src/main/kotlin/eu/acaraus/news/domain/repositories/LocaleRepository.kt index e46167a..f30979a 100644 --- a/features/news/src/main/kotlin/eu/acaraus/news/domain/repositories/LocaleStore.kt +++ b/features/news/src/main/kotlin/eu/acaraus/news/domain/repositories/LocaleRepository.kt @@ -1,6 +1,6 @@ package eu.acaraus.news.domain.repositories -interface LocaleStore { +interface LocaleRepository { fun setLanguageCode(code: String) fun getLanguageCode(): String fun setCountryCode(code: String) diff --git a/features/news/src/main/kotlin/eu/acaraus/news/domain/repositories/NewsApi.kt b/features/news/src/main/kotlin/eu/acaraus/news/domain/repositories/NewsRepository.kt similarity index 95% rename from features/news/src/main/kotlin/eu/acaraus/news/domain/repositories/NewsApi.kt rename to features/news/src/main/kotlin/eu/acaraus/news/domain/repositories/NewsRepository.kt index daec5b5..bae5b44 100644 --- a/features/news/src/main/kotlin/eu/acaraus/news/domain/repositories/NewsApi.kt +++ b/features/news/src/main/kotlin/eu/acaraus/news/domain/repositories/NewsRepository.kt @@ -6,7 +6,7 @@ import eu.acaraus.news.domain.entities.ArticlesSources import eu.acaraus.news.domain.entities.NewsError import eu.acaraus.shared.lib.Either -interface NewsApi { +interface NewsRepository { suspend fun getHeadlines( language: String = "de", diff --git a/features/news/src/main/kotlin/eu/acaraus/news/domain/repositories/SpeechRecognizer.kt b/features/news/src/main/kotlin/eu/acaraus/news/domain/repositories/SpeechRecognizerService.kt similarity index 94% rename from features/news/src/main/kotlin/eu/acaraus/news/domain/repositories/SpeechRecognizer.kt rename to features/news/src/main/kotlin/eu/acaraus/news/domain/repositories/SpeechRecognizerService.kt index 8f93425..4ec8831 100644 --- a/features/news/src/main/kotlin/eu/acaraus/news/domain/repositories/SpeechRecognizer.kt +++ b/features/news/src/main/kotlin/eu/acaraus/news/domain/repositories/SpeechRecognizerService.kt @@ -9,7 +9,7 @@ sealed class SpeechEvent { data class Result(val matches: List) : SpeechEvent() } -interface SpeechRecognizer { +interface SpeechRecognizerService { val isListening: MutableStateFlow val isAvailable: MutableStateFlow fun events(): Flow diff --git a/features/news/src/main/kotlin/eu/acaraus/news/domain/usecases/GetArticles.kt b/features/news/src/main/kotlin/eu/acaraus/news/domain/usecases/GetArticles.kt index 0f3d6ab..898a678 100644 --- a/features/news/src/main/kotlin/eu/acaraus/news/domain/usecases/GetArticles.kt +++ b/features/news/src/main/kotlin/eu/acaraus/news/domain/usecases/GetArticles.kt @@ -4,8 +4,8 @@ import eu.acaraus.news.domain.entities.Article import eu.acaraus.news.domain.entities.ArticlesFilter import eu.acaraus.news.domain.entities.NewsError import eu.acaraus.news.domain.entities.toNewsError -import eu.acaraus.news.domain.repositories.LocaleStore -import eu.acaraus.news.domain.repositories.NewsApi +import eu.acaraus.news.domain.repositories.LocaleRepository +import eu.acaraus.news.domain.repositories.NewsRepository import eu.acaraus.shared.lib.Either import eu.acaraus.shared.lib.map import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -20,8 +20,8 @@ import java.util.Locale @Factory class GetArticles( - private val newsApi: NewsApi, - private val localeStore: LocaleStore, + private val newsRepository: NewsRepository, + private val localeRepository: LocaleRepository, ) { operator fun invoke(filter: ArticlesFilter): Flow, NewsError>> = @@ -38,11 +38,11 @@ class GetArticles( private fun ArticlesFilter.isDefault() = this == ArticlesFilter() private fun fetchHeadlines(): Flow, NewsError>> = flow { - emit(newsApi.getHeadlines(language = localeStore.getLanguageCode())) + emit(newsRepository.getHeadlines(language = localeRepository.getLanguageCode())) } private fun fetchEverything(filter: ArticlesFilter): Flow, NewsError>> = flow { - emit(newsApi.getEverything(filter)) + emit(newsRepository.getEverything(filter)) } private fun Flow, NewsError>>.filterRemovedArticles() = map { result -> diff --git a/features/news/src/main/kotlin/eu/acaraus/news/domain/usecases/GetArticlesSources.kt b/features/news/src/main/kotlin/eu/acaraus/news/domain/usecases/GetArticlesSources.kt index 01fdce0..07d13c3 100644 --- a/features/news/src/main/kotlin/eu/acaraus/news/domain/usecases/GetArticlesSources.kt +++ b/features/news/src/main/kotlin/eu/acaraus/news/domain/usecases/GetArticlesSources.kt @@ -3,8 +3,8 @@ package eu.acaraus.news.domain.usecases import eu.acaraus.news.domain.entities.ArticlesSources import eu.acaraus.news.domain.entities.NewsError import eu.acaraus.news.domain.entities.toNewsError -import eu.acaraus.news.domain.repositories.LocaleStore -import eu.acaraus.news.domain.repositories.NewsApi +import eu.acaraus.news.domain.repositories.LocaleRepository +import eu.acaraus.news.domain.repositories.NewsRepository import eu.acaraus.shared.lib.Either import eu.acaraus.shared.lib.map import eu.acaraus.shared.lib.onEachSuccess @@ -17,21 +17,21 @@ import java.util.concurrent.atomic.AtomicReference @Factory class GetArticlesSources( - private val newsApi: NewsApi, - private val localeStore: LocaleStore, + private val newsRepository: NewsRepository, + private val localeRepository: LocaleRepository, ) { private val atomicArticleSources = AtomicReference>(emptyList()) operator fun invoke(): Flow, NewsError>> = flow { if (atomicArticleSources.get().isEmpty()) { - newsApi + newsRepository .getSources() .onEachSuccess { atomicArticleSources.set(it) } } emit(Either.success, NewsError>(atomicArticleSources.get())) }.map { sourcesResult -> - sourcesResult.map { sources -> sources.filter { it.language == localeStore.getLanguageCode() } } + sourcesResult.map { sources -> sources.filter { it.language == localeRepository.getLanguageCode() } } }.catch { cause -> emit(Either.error(cause.toNewsError())) } diff --git a/features/news/src/main/kotlin/eu/acaraus/news/presentation/list/ArticlesListScreen.kt b/features/news/src/main/kotlin/eu/acaraus/news/presentation/list/ArticlesListScreen.kt index 9ec926d..12712ce 100644 --- a/features/news/src/main/kotlin/eu/acaraus/news/presentation/list/ArticlesListScreen.kt +++ b/features/news/src/main/kotlin/eu/acaraus/news/presentation/list/ArticlesListScreen.kt @@ -8,6 +8,8 @@ import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import eu.acaraus.design.components.Toaster +import eu.acaraus.design.components.ToasterState import eu.acaraus.news.domain.entities.Article import eu.acaraus.news.presentation.list.components.ArticleFilter import eu.acaraus.news.presentation.list.components.ArticleFilterActionIcon @@ -16,8 +18,6 @@ import eu.acaraus.news.presentation.list.components.ArticleListState import eu.acaraus.news.presentation.list.components.ArticlesFilterEditorState import eu.acaraus.news.presentation.list.components.AudioCommandButton import eu.acaraus.news.presentation.list.components.AudioCommandButtonState -import eu.acaraus.design.components.Toaster -import eu.acaraus.design.components.ToasterState @OptIn(ExperimentalMaterial3Api::class) @Composable diff --git a/features/news/src/main/kotlin/eu/acaraus/news/presentation/list/ArticlesListScreenPreview.kt b/features/news/src/main/kotlin/eu/acaraus/news/presentation/list/ArticlesListScreenPreview.kt index 585b618..60df1e3 100644 --- a/features/news/src/main/kotlin/eu/acaraus/news/presentation/list/ArticlesListScreenPreview.kt +++ b/features/news/src/main/kotlin/eu/acaraus/news/presentation/list/ArticlesListScreenPreview.kt @@ -4,11 +4,11 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview +import eu.acaraus.design.components.ToasterState import eu.acaraus.news.domain.entities.Article import eu.acaraus.news.presentation.list.components.ArticleListState import eu.acaraus.news.presentation.list.components.ArticlesFilterEditorState import eu.acaraus.news.presentation.list.components.AudioCommandButtonState -import eu.acaraus.design.components.ToasterState @Composable @Preview(showBackground = true, showSystemUi = true) diff --git a/features/news/src/main/kotlin/eu/acaraus/news/presentation/list/components/AudioCommandButtonPreview.kt b/features/news/src/main/kotlin/eu/acaraus/news/presentation/list/components/AudioCommandButtonPreview.kt index 6aab834..bc76ab2 100644 --- a/features/news/src/main/kotlin/eu/acaraus/news/presentation/list/components/AudioCommandButtonPreview.kt +++ b/features/news/src/main/kotlin/eu/acaraus/news/presentation/list/components/AudioCommandButtonPreview.kt @@ -4,7 +4,6 @@ import androidx.compose.foundation.layout.Column import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.Preview - @Composable @Preview(showBackground = true) fun AudioCommandButtonPreview() = Column { diff --git a/features/news/src/main/kotlin/eu/acaraus/news/presentation/list/holders/ArticlesListStateHolder.kt b/features/news/src/main/kotlin/eu/acaraus/news/presentation/list/holders/ArticlesListStateHolder.kt index e4ee246..ea3a502 100644 --- a/features/news/src/main/kotlin/eu/acaraus/news/presentation/list/holders/ArticlesListStateHolder.kt +++ b/features/news/src/main/kotlin/eu/acaraus/news/presentation/list/holders/ArticlesListStateHolder.kt @@ -52,8 +52,8 @@ class ArticlesListStateHolder( updateError( NewsError( code = "unknown", - exception.message ?: "Failed to load articles" - ) + exception.message ?: "Failed to load articles", + ), ) } .launchIn(this) diff --git a/features/news/src/main/kotlin/eu/acaraus/news/presentation/list/holders/SpeechRecognizerStateHolder.kt b/features/news/src/main/kotlin/eu/acaraus/news/presentation/list/holders/SpeechRecognizerStateHolder.kt index 20676ef..7e77141 100644 --- a/features/news/src/main/kotlin/eu/acaraus/news/presentation/list/holders/SpeechRecognizerStateHolder.kt +++ b/features/news/src/main/kotlin/eu/acaraus/news/presentation/list/holders/SpeechRecognizerStateHolder.kt @@ -1,12 +1,12 @@ package eu.acaraus.news.presentation.list.holders +import eu.acaraus.design.components.PermissionState +import eu.acaraus.design.components.ToasterState import eu.acaraus.news.domain.repositories.SpeechEvent -import eu.acaraus.news.domain.repositories.SpeechRecognizer +import eu.acaraus.news.domain.repositories.SpeechRecognizerService import eu.acaraus.news.domain.usecases.MatchVoiceCommands import eu.acaraus.news.domain.usecases.VoiceCommand import eu.acaraus.news.presentation.list.components.AudioCommandButtonState -import eu.acaraus.design.components.PermissionState -import eu.acaraus.design.components.ToasterState import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -21,14 +21,14 @@ import org.koin.core.annotation.Scope @Factory @Scope(ArticlesListKoinScope::class) class SpeechRecognizerStateHolder( - private val speechRecognizer: SpeechRecognizer, + private val speechRecognizerService: SpeechRecognizerService, private val matchVoiceCommands: MatchVoiceCommands, scope: CoroutineScope, ) : CoroutineScope by scope { private val audioCommandButtonState = MutableStateFlow( AudioCommandButtonState( - isEnabled = speechRecognizer.isAvailable.value, + isEnabled = speechRecognizerService.isAvailable.value, toggleListening = ::toggleListening, changePermissionState = ::changePermissionsState, ), @@ -44,9 +44,9 @@ class SpeechRecognizerStateHolder( val reloadCommand = MutableSharedFlow() init { - speechRecognizer.isListening.onEach(::updateListeningState).launchIn(this) + speechRecognizerService.isListening.onEach(::updateListeningState).launchIn(this) - speechRecognizer.events().onEach { event -> + speechRecognizerService.events().onEach { event -> when (event) { is SpeechEvent.Result -> executeVoiceCommands(event.matches) is SpeechEvent.Error -> showToast(event.errorMessage) @@ -54,7 +54,7 @@ class SpeechRecognizerStateHolder( } }.launchIn(this) - coroutineContext.job.invokeOnCompletion { speechRecognizer.destroy() } + coroutineContext.job.invokeOnCompletion { speechRecognizerService.destroy() } } private suspend fun executeVoiceCommands(words: List) { @@ -70,7 +70,7 @@ class SpeechRecognizerStateHolder( private fun changePermissionsState(newPermissionState: PermissionState) { if (newPermissionState.isEqualTo(PermissionState.Granted)) { - speechRecognizer.toggleListening() + speechRecognizerService.toggleListening() updatePermissionStateTo(PermissionState.ConfirmationNeeded) } else { updatePermissionStateTo(newPermissionState) diff --git a/features/news/src/test/kotlin/eu/acaraus/news/test/data/news/NewsApiTest.kt b/features/news/src/test/kotlin/eu/acaraus/news/test/data/news/NewsRepositoryTest.kt similarity index 64% rename from features/news/src/test/kotlin/eu/acaraus/news/test/data/news/NewsApiTest.kt rename to features/news/src/test/kotlin/eu/acaraus/news/test/data/news/NewsRepositoryTest.kt index b9b86d4..cb16452 100644 --- a/features/news/src/test/kotlin/eu/acaraus/news/test/data/news/NewsApiTest.kt +++ b/features/news/src/test/kotlin/eu/acaraus/news/test/data/news/NewsRepositoryTest.kt @@ -4,7 +4,7 @@ import eu.acaraus.news.di.DataDi import eu.acaraus.news.domain.entities.Article import eu.acaraus.news.domain.entities.ArticlesFilter import eu.acaraus.news.domain.entities.NewsError -import eu.acaraus.news.domain.repositories.NewsApi +import eu.acaraus.news.domain.repositories.NewsRepository import eu.acaraus.shared.lib.Either import eu.acaraus.shared.lib.onEachError import eu.acaraus.shared.lib.onEachSuccess @@ -17,7 +17,7 @@ import org.koin.ksp.generated.module import org.koin.test.inject import java.time.LocalDate -class NewsApiTest : UnitTest { +class NewsRepositoryTest : UnitTest { @get:Rule override val koinUnitTestRule = KoinUnitTestRule( @@ -26,42 +26,42 @@ class NewsApiTest : UnitTest { @Test fun fetch_news_headlines_successfully() = runTest { - val newsApi: NewsApi by inject() - val headlinesResult: Either,NewsError> = newsApi.getHeadlines() + val newsRepository: NewsRepository by inject() + val headlinesResult: Either, NewsError> = newsRepository.getHeadlines() assert(headlinesResult.isSuccess) } @Test fun fetch_news_sources_successfully() = runTest { - val newsApi: NewsApi by inject() + val newsApi: NewsRepository by inject() val sourcesResult = newsApi.getSources() assert((sourcesResult as Either.Success).value.isNotEmpty()) } @Test fun fetch_everything_news_successfully() = runTest { - val newsApi: NewsApi by inject() + val newsRepository: NewsRepository by inject() val filter = ArticlesFilter( query = "android", language = "de", ) - val everythingResult = newsApi.getEverything(filter) + val everythingResult = newsRepository.getEverything(filter) assert((everythingResult as Either.Success).value.isNotEmpty()) } @Test fun fetch_everything_news_invalid_parameter() = runTest { - val newsApi: NewsApi by inject() + val newsRepository: NewsRepository by inject() val filter = ArticlesFilter( query = "android", language = "de", - fromDate = LocalDate.now().minusYears(29) + fromDate = LocalDate.now().minusYears(29), ) - newsApi.getEverything(filter) - .onEachError { - assert(it.code == "parameterInvalid") - }.onEachSuccess { - assert(false) { "Should not be invoked" } - } + newsRepository.getEverything(filter) + .onEachError { + assert(it.code == "parameterInvalid") + }.onEachSuccess { + assert(false) { "Should not be invoked" } + } } } diff --git a/features/news/src/test/kotlin/eu/acaraus/news/test/rules/UTest.kt b/features/news/src/test/kotlin/eu/acaraus/news/test/rules/UTest.kt index 4c1c043..105df33 100644 --- a/features/news/src/test/kotlin/eu/acaraus/news/test/rules/UTest.kt +++ b/features/news/src/test/kotlin/eu/acaraus/news/test/rules/UTest.kt @@ -14,6 +14,6 @@ interface UTest : SharedUnitTest { get() = arrayOf( DomainDi().module, PresentationDi().module, - module { single{ DispatcherProviderApp() } } + module { single { DispatcherProviderApp() } }, ) } diff --git a/features/news/src/test/kotlin/eu/acaraus/news/test/screens/articles/list/ArticleListStateHolderTest.kt b/features/news/src/test/kotlin/eu/acaraus/news/test/screens/articles/list/ArticleListStateHolderTest.kt index 4e0dce7..e178c00 100644 --- a/features/news/src/test/kotlin/eu/acaraus/news/test/screens/articles/list/ArticleListStateHolderTest.kt +++ b/features/news/src/test/kotlin/eu/acaraus/news/test/screens/articles/list/ArticleListStateHolderTest.kt @@ -2,14 +2,14 @@ package eu.acaraus.news.test.screens.articles.list import app.cash.turbine.test import app.cash.turbine.turbineScope -import eu.acaraus.news.data.LocaleStoreImpl +import eu.acaraus.news.data.Locale import eu.acaraus.news.domain.entities.Article import eu.acaraus.news.domain.entities.ArticlesFilter import eu.acaraus.news.domain.entities.ArticlesSources import eu.acaraus.news.domain.entities.NewsError import eu.acaraus.news.domain.entities.SortBy -import eu.acaraus.news.domain.repositories.LocaleStore -import eu.acaraus.news.domain.repositories.NewsApi +import eu.acaraus.news.domain.repositories.LocaleRepository +import eu.acaraus.news.domain.repositories.NewsRepository import eu.acaraus.news.presentation.list.holders.ArticlesListKoinScope import eu.acaraus.news.presentation.list.holders.ArticlesListStateHolder import eu.acaraus.news.test.rules.UTest @@ -119,7 +119,7 @@ private var simulateApiError = false class ArticleListTestModule { @Factory - fun newsApi(): NewsApi = object : NewsApi { + fun newsApi(): NewsRepository = object : NewsRepository { override suspend fun getHeadlines( language: String, @@ -144,7 +144,7 @@ class ArticleListTestModule { } @Single - fun localeStore(): LocaleStore = LocaleStoreImpl() + fun localeStore(): LocaleRepository = Locale() } private val dummyArticles = listOf( diff --git a/features/news/src/test/kotlin/eu/acaraus/news/test/screens/articles/list/ArticleListViewModelTest.kt b/features/news/src/test/kotlin/eu/acaraus/news/test/screens/articles/list/ArticleListViewModelTest.kt index 55b7d91..e3dd53e 100644 --- a/features/news/src/test/kotlin/eu/acaraus/news/test/screens/articles/list/ArticleListViewModelTest.kt +++ b/features/news/src/test/kotlin/eu/acaraus/news/test/screens/articles/list/ArticleListViewModelTest.kt @@ -2,15 +2,15 @@ package eu.acaraus.news.test.screens.articles.list import app.cash.turbine.test import app.cash.turbine.turbineScope -import eu.acaraus.news.data.LocaleStoreImpl +import eu.acaraus.news.data.Locale import eu.acaraus.news.domain.entities.Article import eu.acaraus.news.domain.entities.ArticlesFilter import eu.acaraus.news.domain.entities.ArticlesSources import eu.acaraus.news.domain.entities.NewsError -import eu.acaraus.news.domain.repositories.LocaleStore -import eu.acaraus.news.domain.repositories.NewsApi +import eu.acaraus.news.domain.repositories.LocaleRepository +import eu.acaraus.news.domain.repositories.NewsRepository import eu.acaraus.news.domain.repositories.SpeechEvent -import eu.acaraus.news.domain.repositories.SpeechRecognizer +import eu.acaraus.news.domain.repositories.SpeechRecognizerService import eu.acaraus.news.presentation.list.ArticlesListViewModel import eu.acaraus.news.presentation.list.holders.ArticlesListKoinScope import eu.acaraus.news.test.rules.UTest @@ -66,7 +66,7 @@ private val speechEvent = MutableSharedFlow() class ArticleListViewModelTestModule { @Factory - fun newsApi(): NewsApi = object : NewsApi { + fun newsApi(): NewsRepository = object : NewsRepository { override suspend fun getHeadlines( language: String, @@ -83,7 +83,7 @@ class ArticleListViewModelTestModule { } @Factory - fun speechRecognizer(): SpeechRecognizer = object : SpeechRecognizer { + fun speechRecognizer(): SpeechRecognizerService = object : SpeechRecognizerService { override val isListening: MutableStateFlow get() = MutableStateFlow(true) @@ -109,7 +109,7 @@ class ArticleListViewModelTestModule { } @Single - fun localeStore(): LocaleStore = LocaleStoreImpl() + fun localeStore(): LocaleRepository = Locale() } private val dummyArticles = listOf( diff --git a/features/news/src/test/kotlin/eu/acaraus/news/test/screens/articles/list/ArticlesFilterStateHolderTest.kt b/features/news/src/test/kotlin/eu/acaraus/news/test/screens/articles/list/ArticlesFilterStateHolderTest.kt index 0f55ddd..cca9c81 100644 --- a/features/news/src/test/kotlin/eu/acaraus/news/test/screens/articles/list/ArticlesFilterStateHolderTest.kt +++ b/features/news/src/test/kotlin/eu/acaraus/news/test/screens/articles/list/ArticlesFilterStateHolderTest.kt @@ -2,14 +2,14 @@ package eu.acaraus.news.test.screens.articles.list import app.cash.turbine.test import app.cash.turbine.turbineScope -import eu.acaraus.news.data.LocaleStoreImpl +import eu.acaraus.news.data.Locale import eu.acaraus.news.domain.entities.Article import eu.acaraus.news.domain.entities.ArticlesFilter import eu.acaraus.news.domain.entities.ArticlesSources import eu.acaraus.news.domain.entities.NewsError import eu.acaraus.news.domain.entities.SortBy -import eu.acaraus.news.domain.repositories.LocaleStore -import eu.acaraus.news.domain.repositories.NewsApi +import eu.acaraus.news.domain.repositories.LocaleRepository +import eu.acaraus.news.domain.repositories.NewsRepository import eu.acaraus.news.presentation.list.holders.ArticlesFilterStateHolder import eu.acaraus.news.presentation.list.holders.ArticlesListKoinScope import eu.acaraus.news.test.rules.UTest @@ -28,7 +28,6 @@ import kotlin.test.assertEquals class ArticlesFilterStateHolderTest : UTest { - override fun perTestModules() = arrayOf(ArticlesFilterStateHolderModule().module) private fun createSubject(coroutineScope: CoroutineScope): ArticlesFilterStateHolder = @@ -145,7 +144,7 @@ class ArticlesFilterStateHolderTest : UTest { class ArticlesFilterStateHolderModule { @Factory - fun newsApi(): NewsApi = object : NewsApi { + fun newsApi(): NewsRepository = object : NewsRepository { override suspend fun getHeadlines( language: String, category: String, @@ -163,7 +162,7 @@ class ArticlesFilterStateHolderModule { } @Single - fun localeStore(): LocaleStore = LocaleStoreImpl() + fun localeStore(): LocaleRepository = Locale() } val dummyArticlesSources = listOf( diff --git a/features/news/src/test/kotlin/eu/acaraus/news/test/screens/articles/list/KoinScopeTest.kt b/features/news/src/test/kotlin/eu/acaraus/news/test/screens/articles/list/KoinScopeTest.kt index 96107c9..65e79f4 100644 --- a/features/news/src/test/kotlin/eu/acaraus/news/test/screens/articles/list/KoinScopeTest.kt +++ b/features/news/src/test/kotlin/eu/acaraus/news/test/screens/articles/list/KoinScopeTest.kt @@ -1,15 +1,15 @@ package eu.acaraus.news.test.screens.articles.list import app.cash.turbine.turbineScope -import eu.acaraus.news.data.LocaleStoreImpl +import eu.acaraus.news.data.Locale import eu.acaraus.news.domain.entities.Article import eu.acaraus.news.domain.entities.ArticlesFilter import eu.acaraus.news.domain.entities.ArticlesSources import eu.acaraus.news.domain.entities.NewsError -import eu.acaraus.news.domain.repositories.LocaleStore -import eu.acaraus.news.domain.repositories.NewsApi +import eu.acaraus.news.domain.repositories.LocaleRepository +import eu.acaraus.news.domain.repositories.NewsRepository import eu.acaraus.news.domain.repositories.SpeechEvent -import eu.acaraus.news.domain.repositories.SpeechRecognizer +import eu.acaraus.news.domain.repositories.SpeechRecognizerService import eu.acaraus.news.presentation.list.ArticlesListViewModel import eu.acaraus.news.presentation.list.holders.ArticlesListKoinScope import eu.acaraus.news.test.rules.UTest @@ -58,7 +58,7 @@ private val speechEvent = MutableSharedFlow() class ArticleListViewModelTestModule1 { @Factory - fun newsApi(): NewsApi = object : NewsApi { + fun newsApi(): NewsRepository = object : NewsRepository { override suspend fun getHeadlines( language: String, @@ -75,7 +75,7 @@ class ArticleListViewModelTestModule1 { } @Factory - fun speechRecognizer(): SpeechRecognizer = object : SpeechRecognizer { + fun speechRecognizer(): SpeechRecognizerService = object : SpeechRecognizerService { override val isListening: MutableStateFlow get() = MutableStateFlow(true) @@ -101,7 +101,7 @@ class ArticleListViewModelTestModule1 { } @Single - fun localeStore(): LocaleStore = LocaleStoreImpl() + fun localeStore(): LocaleRepository = Locale() } private val dummyArticles = listOf( diff --git a/features/news/src/test/kotlin/eu/acaraus/news/test/snapshots/SnapshotTest.kt b/features/news/src/test/kotlin/eu/acaraus/news/test/snapshots/SnapshotTest.kt index 0a0a9ea..55f47e7 100644 --- a/features/news/src/test/kotlin/eu/acaraus/news/test/snapshots/SnapshotTest.kt +++ b/features/news/src/test/kotlin/eu/acaraus/news/test/snapshots/SnapshotTest.kt @@ -7,7 +7,6 @@ import eu.acaraus.news.test.rules.UTest import eu.acaraus.shared.lib.coroutines.DispatcherProvider import eu.acaraus.shared.lib.coroutines.DispatcherProviderApp import eu.acaraus.shared.test.lib.previews.getAListOfAllComposablePreviewMethods - import org.junit.Rule import org.junit.Test import org.koin.core.module.Module diff --git a/shared_lib/build.gradle.kts b/shared_lib/build.gradle.kts index 3ac714f..2119a9c 100644 --- a/shared_lib/build.gradle.kts +++ b/shared_lib/build.gradle.kts @@ -1,5 +1,3 @@ -@file:Suppress("UnstableApiUsage") - plugins { alias(libs.plugins.android.library) alias(libs.plugins.kotlin.android) @@ -43,7 +41,6 @@ dependencies { debugImplementation(libs.androidx.ui.test.manifest) } - android { namespace = "eu.acaraus.shared.lib" compileSdk = libs.versions.compileSdk.get().toInt() @@ -88,8 +85,4 @@ android { excludes += "/META-INF/{AL2.0,LGPL2.1,INDEX.LIST}" } } - - testFixtures { - enable = true - } } diff --git a/shared_lib/src/main/kotlin/eu/acaraus/shared/lib/Either.kt b/shared_lib/src/main/kotlin/eu/acaraus/shared/lib/Either.kt index 0b7815f..7cf992a 100644 --- a/shared_lib/src/main/kotlin/eu/acaraus/shared/lib/Either.kt +++ b/shared_lib/src/main/kotlin/eu/acaraus/shared/lib/Either.kt @@ -2,7 +2,6 @@ package eu.acaraus.shared.lib import eu.acaraus.shared.lib.Either.Companion.success - sealed class Either { val isSuccess get() = this is Success diff --git a/shared_lib/src/main/kotlin/eu/acaraus/shared/lib/coroutines/Coroutines.kt b/shared_lib/src/main/kotlin/eu/acaraus/shared/lib/coroutines/Coroutines.kt index 9b2848f..f84fd7f 100644 --- a/shared_lib/src/main/kotlin/eu/acaraus/shared/lib/coroutines/Coroutines.kt +++ b/shared_lib/src/main/kotlin/eu/acaraus/shared/lib/coroutines/Coroutines.kt @@ -16,5 +16,3 @@ class DispatcherProviderApp : DispatcherProvider { override val unconfined: CoroutineDispatcher get() = KotlinProvidedDispatchers.Unconfined override val ui: CoroutineDispatcher get() = KotlinProvidedDispatchers.Main.immediate } - - diff --git a/shared_test_lib/build.gradle.kts b/shared_test_lib/build.gradle.kts index 88688c5..39ca60b 100644 --- a/shared_test_lib/build.gradle.kts +++ b/shared_test_lib/build.gradle.kts @@ -47,10 +47,8 @@ dependencies { implementation(libs.koin.test) implementation(libs.turbine) implementation(libs.classgraph) - } - android { namespace = "eu.acaraus.shared.test.lib" compileSdk = libs.versions.compileSdk.get().toInt() diff --git a/shared_test_lib/src/androidTest/kotlin/eu/acaraus/shared/test/lib/ExampleInstrumentedTest.kt b/shared_test_lib/src/androidTest/kotlin/eu/acaraus/shared/test/lib/ExampleInstrumentedTest.kt deleted file mode 100644 index aab7940..0000000 --- a/shared_test_lib/src/androidTest/kotlin/eu/acaraus/shared/test/lib/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,24 +0,0 @@ -package eu.acaraus.shared.test.lib - -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.ext.junit.runners.AndroidJUnit4 - -import org.junit.Test -import org.junit.runner.RunWith - -import org.junit.Assert.* - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("eu.acaraus.shared.test.lib.test", appContext.packageName) - } -} diff --git a/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/UnitTest.kt b/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/UnitTest.kt index d463305..311a370 100644 --- a/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/UnitTest.kt +++ b/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/UnitTest.kt @@ -1,6 +1,5 @@ package eu.acaraus.shared.test.lib - import eu.acaraus.shared.test.lib.rules.CoroutinesTestRule import eu.acaraus.shared.test.lib.rules.KoinUnitTestRule import org.junit.Rule @@ -17,5 +16,4 @@ interface UnitTest : KoinTest { @get:Rule val coroutinesTestRule get() = CoroutinesTestRule() - } diff --git a/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/coroutines/UnitTestDispatchers.kt b/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/coroutines/UnitTestDispatchers.kt index 615fe8c..be91966 100644 --- a/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/coroutines/UnitTestDispatchers.kt +++ b/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/coroutines/UnitTestDispatchers.kt @@ -2,7 +2,6 @@ package eu.acaraus.shared.test.lib.coroutines - import eu.acaraus.shared.lib.coroutines.DispatcherProvider import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.ExperimentalCoroutinesApi diff --git a/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/di/TestDi.kt b/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/di/TestDi.kt index c7cd1f1..6b8f27c 100644 --- a/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/di/TestDi.kt +++ b/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/di/TestDi.kt @@ -1,6 +1,5 @@ package eu.acaraus.shared.test.lib.di - import eu.acaraus.shared.lib.coroutines.DispatcherProvider import eu.acaraus.shared.lib.coroutines.DispatcherProviderApp import org.koin.core.context.GlobalContext diff --git a/shared_test_lib/src/test/kotlin/eu/acaraus/shared/test/lib/ExampleUnitTest.kt b/shared_test_lib/src/test/kotlin/eu/acaraus/shared/test/lib/ExampleUnitTest.kt index daa4965..bff9caa 100644 --- a/shared_test_lib/src/test/kotlin/eu/acaraus/shared/test/lib/ExampleUnitTest.kt +++ b/shared_test_lib/src/test/kotlin/eu/acaraus/shared/test/lib/ExampleUnitTest.kt @@ -1,9 +1,8 @@ package eu.acaraus.shared.test.lib +import org.junit.Assert.assertEquals import org.junit.Test -import org.junit.Assert.* - /** * Example local unit test, which will execute on the development machine (host). * diff --git a/uicomponents/build.gradle.kts b/uicomponents/build.gradle.kts index 5a378df..f9e2bc0 100644 --- a/uicomponents/build.gradle.kts +++ b/uicomponents/build.gradle.kts @@ -31,7 +31,6 @@ dependencies { testImplementation(libs.junit) } - android { namespace = "eu.acaraus.design.components" compileSdk = libs.versions.compileSdk.get().toInt() diff --git a/uicomponents/src/androidTest/kotlin/eu/acaraus/design/components/ExampleInstrumentedTest.kt b/uicomponents/src/androidTest/kotlin/eu/acaraus/design/components/ExampleInstrumentedTest.kt index ffdfec9..7ec33f8 100644 --- a/uicomponents/src/androidTest/kotlin/eu/acaraus/design/components/ExampleInstrumentedTest.kt +++ b/uicomponents/src/androidTest/kotlin/eu/acaraus/design/components/ExampleInstrumentedTest.kt @@ -1,13 +1,11 @@ package eu.acaraus.design.components -import androidx.test.platform.app.InstrumentationRegistry import androidx.test.ext.junit.runners.AndroidJUnit4 - +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Assert.assertEquals import org.junit.Test import org.junit.runner.RunWith -import org.junit.Assert.* - /** * Instrumented test, which will execute on an Android device. * diff --git a/uicomponents/src/test/kotlin/eu/acaraus/design/components/ExampleUnitTest.kt b/uicomponents/src/test/kotlin/eu/acaraus/design/components/ExampleUnitTest.kt index f4cb97b..c3906d5 100644 --- a/uicomponents/src/test/kotlin/eu/acaraus/design/components/ExampleUnitTest.kt +++ b/uicomponents/src/test/kotlin/eu/acaraus/design/components/ExampleUnitTest.kt @@ -1,9 +1,8 @@ package eu.acaraus.design.components +import org.junit.Assert.assertEquals import org.junit.Test -import org.junit.Assert.* - /** * Example local unit test, which will execute on the development machine (host). * From 300029e170580b13abef53f5422b40c4d96cc6dd Mon Sep 17 00:00:00 2001 From: Alexandru Caraus Date: Wed, 4 Sep 2024 11:54:47 +0200 Subject: [PATCH 2/2] Provide correct dispatchers --- .../news/test/data/news/NewsRepositoryTest.kt | 4 +++ .../eu/acaraus/news/test/rules/UTest.kt | 4 --- .../news/test/snapshots/SnapshotTest.kt | 26 ++++++++++++++----- gradle/libs.versions.toml | 6 ++--- .../eu/acaraus/shared/test/lib/UnitTest.kt | 12 ++++++++- ...spatchers.kt => DispatcherProviderTest.kt} | 2 +- .../eu/acaraus/shared/test/lib/di/TestDi.kt | 7 +---- .../test/lib/rules/CoroutinesTestRule.kt | 3 +-- .../shared/test/lib/rules/KoinUnitTestRule.kt | 3 ++- 9 files changed, 43 insertions(+), 24 deletions(-) rename shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/coroutines/{UnitTestDispatchers.kt => DispatcherProviderTest.kt} (94%) diff --git a/features/news/src/test/kotlin/eu/acaraus/news/test/data/news/NewsRepositoryTest.kt b/features/news/src/test/kotlin/eu/acaraus/news/test/data/news/NewsRepositoryTest.kt index cb16452..45c61ff 100644 --- a/features/news/src/test/kotlin/eu/acaraus/news/test/data/news/NewsRepositoryTest.kt +++ b/features/news/src/test/kotlin/eu/acaraus/news/test/data/news/NewsRepositoryTest.kt @@ -6,6 +6,8 @@ import eu.acaraus.news.domain.entities.ArticlesFilter import eu.acaraus.news.domain.entities.NewsError import eu.acaraus.news.domain.repositories.NewsRepository import eu.acaraus.shared.lib.Either +import eu.acaraus.shared.lib.coroutines.DispatcherProvider +import eu.acaraus.shared.lib.coroutines.DispatcherProviderApp import eu.acaraus.shared.lib.onEachError import eu.acaraus.shared.lib.onEachSuccess import eu.acaraus.shared.test.lib.UnitTest @@ -13,6 +15,7 @@ import eu.acaraus.shared.test.lib.rules.KoinUnitTestRule import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test +import org.koin.dsl.module import org.koin.ksp.generated.module import org.koin.test.inject import java.time.LocalDate @@ -22,6 +25,7 @@ class NewsRepositoryTest : UnitTest { @get:Rule override val koinUnitTestRule = KoinUnitTestRule( DataDi().module, + module { single { DispatcherProviderApp() } }, ) @Test diff --git a/features/news/src/test/kotlin/eu/acaraus/news/test/rules/UTest.kt b/features/news/src/test/kotlin/eu/acaraus/news/test/rules/UTest.kt index 105df33..ddfdb73 100644 --- a/features/news/src/test/kotlin/eu/acaraus/news/test/rules/UTest.kt +++ b/features/news/src/test/kotlin/eu/acaraus/news/test/rules/UTest.kt @@ -2,10 +2,7 @@ package eu.acaraus.news.test.rules import eu.acaraus.news.di.DomainDi import eu.acaraus.news.di.PresentationDi -import eu.acaraus.shared.lib.coroutines.DispatcherProvider -import eu.acaraus.shared.lib.coroutines.DispatcherProviderApp import org.koin.core.module.Module -import org.koin.dsl.module import org.koin.ksp.generated.module import eu.acaraus.shared.test.lib.UnitTest as SharedUnitTest @@ -14,6 +11,5 @@ interface UTest : SharedUnitTest { get() = arrayOf( DomainDi().module, PresentationDi().module, - module { single { DispatcherProviderApp() } }, ) } diff --git a/features/news/src/test/kotlin/eu/acaraus/news/test/snapshots/SnapshotTest.kt b/features/news/src/test/kotlin/eu/acaraus/news/test/snapshots/SnapshotTest.kt index 55f47e7..7995d6c 100644 --- a/features/news/src/test/kotlin/eu/acaraus/news/test/snapshots/SnapshotTest.kt +++ b/features/news/src/test/kotlin/eu/acaraus/news/test/snapshots/SnapshotTest.kt @@ -5,24 +5,38 @@ import app.cash.paparazzi.DeviceConfig import app.cash.paparazzi.Paparazzi import eu.acaraus.news.test.rules.UTest import eu.acaraus.shared.lib.coroutines.DispatcherProvider -import eu.acaraus.shared.lib.coroutines.DispatcherProviderApp import eu.acaraus.shared.test.lib.previews.getAListOfAllComposablePreviewMethods +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.resetMain +import kotlinx.coroutines.test.setMain +import org.junit.After +import org.junit.Before import org.junit.Rule import org.junit.Test -import org.koin.core.module.Module -import org.koin.dsl.module +import org.koin.core.component.inject class SnapshotTest : UTest { - override fun perTestModules(): Array = - arrayOf(module { single { DispatcherProviderApp() } }) - @get:Rule val paparazzi = Paparazzi( theme = "android:Theme.Material.Light.NoActionBar", deviceConfig = DeviceConfig.PIXEL_6_PRO, ) + @OptIn(ExperimentalCoroutinesApi::class) + @Before + fun setup() { + val dispatcherProvider by inject() + Dispatchers.setMain(dispatcherProvider.ui) + } + + @OptIn(ExperimentalCoroutinesApi::class) + @After + fun teardown() { + Dispatchers.resetMain() + } + @Test fun generateSnapshot() { "eu.acaraus.news.presentation" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 125c601..9cd41be 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ [versions] ################################# - +# Kotlin kotlin = "2.0.0" kotlin-coroutines = "1.9.0-RC.2" kotlin-datetime = "0.6.0" @@ -15,7 +15,7 @@ minSdk = "26" targetSdk = "34" # Libs -kotlinStdlib = "2.0.0" +kotlinStdlib = "2.0.20" coreKtx = "1.13.1" lifecycleRuntimeKtx = "2.8.4" activityCompose = "1.9.1" @@ -23,7 +23,7 @@ composeBom = "2024.08.00" compose = "1.7.0-rc01" compose-nav = "2.8.0-rc01" -koin-bom = "4.0.0-RC1" +koin-bom = "4.0.0-RC2" koin-ksp = "1.4.0-RC3" coil = "2.7.0" diff --git a/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/UnitTest.kt b/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/UnitTest.kt index 311a370..a3185bf 100644 --- a/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/UnitTest.kt +++ b/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/UnitTest.kt @@ -1,18 +1,28 @@ package eu.acaraus.shared.test.lib +import eu.acaraus.shared.lib.coroutines.DispatcherProvider +import eu.acaraus.shared.test.lib.coroutines.DispatcherProviderTest import eu.acaraus.shared.test.lib.rules.CoroutinesTestRule import eu.acaraus.shared.test.lib.rules.KoinUnitTestRule import org.junit.Rule import org.koin.core.module.Module +import org.koin.dsl.module import org.koin.test.KoinTest interface UnitTest : KoinTest { + private fun commonModule() = module { single { DispatcherProviderTest() } } + val perFeatureModules: Array get() = emptyArray() fun perTestModules(): Array = emptyArray() @get:Rule - val koinUnitTestRule get() = KoinUnitTestRule(*perFeatureModules, *perTestModules()) + val koinUnitTestRule + get() = KoinUnitTestRule( + commonModule(), + *perFeatureModules, + *perTestModules(), + ) @get:Rule val coroutinesTestRule get() = CoroutinesTestRule() diff --git a/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/coroutines/UnitTestDispatchers.kt b/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/coroutines/DispatcherProviderTest.kt similarity index 94% rename from shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/coroutines/UnitTestDispatchers.kt rename to shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/coroutines/DispatcherProviderTest.kt index be91966..f15beb9 100644 --- a/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/coroutines/UnitTestDispatchers.kt +++ b/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/coroutines/DispatcherProviderTest.kt @@ -11,7 +11,7 @@ import kotlinx.coroutines.test.UnconfinedTestDispatcher import org.koin.core.annotation.Single @Single(binds = [DispatcherProvider::class]) -class UnitTestDispatchers : DispatcherProvider { +class DispatcherProviderTest : DispatcherProvider { @OptIn(ExperimentalCoroutinesApi::class) private val dispatcher: TestDispatcher = UnconfinedTestDispatcher(TestCoroutineScheduler()) diff --git a/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/di/TestDi.kt b/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/di/TestDi.kt index 6b8f27c..1d55791 100644 --- a/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/di/TestDi.kt +++ b/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/di/TestDi.kt @@ -1,14 +1,9 @@ package eu.acaraus.shared.test.lib.di -import eu.acaraus.shared.lib.coroutines.DispatcherProvider -import eu.acaraus.shared.lib.coroutines.DispatcherProviderApp import org.koin.core.context.GlobalContext -import org.koin.dsl.module fun setupUnitTestDi(mockModules: List = emptyList()) { - val allModules = - mockModules + module { single { DispatcherProviderApp() } } GlobalContext.startKoin { - modules(allModules) + modules(mockModules) } } diff --git a/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/rules/CoroutinesTestRule.kt b/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/rules/CoroutinesTestRule.kt index 9e89662..0704c57 100644 --- a/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/rules/CoroutinesTestRule.kt +++ b/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/rules/CoroutinesTestRule.kt @@ -12,10 +12,9 @@ import kotlinx.coroutines.Dispatchers as KotlinDispatchers class CoroutinesTestRule : TestWatcher(), KoinTest { - private val testDispatcher by inject() - @OptIn(ExperimentalCoroutinesApi::class) override fun starting(description: Description) { + val testDispatcher by inject() KotlinDispatchers.setMain(testDispatcher.ui) } diff --git a/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/rules/KoinUnitTestRule.kt b/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/rules/KoinUnitTestRule.kt index 219e19a..a5ecfe5 100644 --- a/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/rules/KoinUnitTestRule.kt +++ b/shared_test_lib/src/main/kotlin/eu/acaraus/shared/test/lib/rules/KoinUnitTestRule.kt @@ -13,7 +13,8 @@ class KoinUnitTestRule(private vararg val mockModules: Module) : TestWatcher() { override fun starting(description: Description) { try { setupUnitTestDi(mockModules.toList()) - } catch (ignore: Exception) { + } catch (koinSetupError: Exception) { + println(koinSetupError.message) } }