diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6edc876..e94f3e7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,3 +1,5 @@ +import ytemplate.android.jacoco.addExclusion + @Suppress("DSL_SCOPE_VIOLATION") // scope violation issue: work around suggested from: https://github.com/gradle/gradle/issues/22797 plugins { id("ytemplate.android.application") @@ -5,7 +7,11 @@ plugins { id("ytemplate.android.application.compose") id("ytemplate.android.hilt") } - +private val excludedFiles = mutableSetOf( + "**/ytemplate/android/MainActivity.*", + "**/ytemplate/android/YTemplate.*" +) +addExclusion(excludedFiles) android { namespace = "ytemplate.android" defaultConfig { diff --git a/build-logic/src/main/java/conventions/HiltConventionPlugin.kt b/build-logic/src/main/java/conventions/HiltConventionPlugin.kt index 77f55cc..0e0c996 100644 --- a/build-logic/src/main/java/conventions/HiltConventionPlugin.kt +++ b/build-logic/src/main/java/conventions/HiltConventionPlugin.kt @@ -33,4 +33,4 @@ class HiltConventionPlugin : Plugin { } } -} \ No newline at end of file +} diff --git a/build-logic/src/main/java/conventions/LibraryConventionPlugin.kt b/build-logic/src/main/java/conventions/LibraryConventionPlugin.kt index f2bed8b..33eadc0 100644 --- a/build-logic/src/main/java/conventions/LibraryConventionPlugin.kt +++ b/build-logic/src/main/java/conventions/LibraryConventionPlugin.kt @@ -24,7 +24,7 @@ class LibraryConventionPlugin : Plugin { apply(libs.findPlugin("android.library").get().get().pluginId) apply(libs.findPlugin("kotlin.android").get().get().pluginId) apply(libs.findPlugin("kotlin.serialization").get().get().pluginId) - + apply(libs.findPlugin("ksp").get().get().pluginId) } extensions.configure { diff --git a/build-logic/src/main/java/conventions/ProjectJacocoConventionPlugin.kt b/build-logic/src/main/java/conventions/ProjectJacocoConventionPlugin.kt index cb759ad..42d1bb6 100644 --- a/build-logic/src/main/java/conventions/ProjectJacocoConventionPlugin.kt +++ b/build-logic/src/main/java/conventions/ProjectJacocoConventionPlugin.kt @@ -15,6 +15,7 @@ import ytemplate.android.jacoco.jacoco * * @constructor Create empty Library jacoco convention plugin */ +@Suppress("UNCHECKED_CAST") class ProjectJacocoConventionPlugin : Plugin { private val project_level_limits = mutableMapOf( "instruction" to 0.0, @@ -36,7 +37,6 @@ class ProjectJacocoConventionPlugin : Plugin { override fun apply(target: Project) { with(target) { - val libs = extensions.getByType().named("versionCatalogLibs") with(pluginManager) { apply("jacoco") } diff --git a/build-logic/src/main/java/ytemplate/android/jacoco/Jacoco.kt b/build-logic/src/main/java/ytemplate/android/jacoco/Jacoco.kt index f05dc6a..db84b1c 100644 --- a/build-logic/src/main/java/ytemplate/android/jacoco/Jacoco.kt +++ b/build-logic/src/main/java/ytemplate/android/jacoco/Jacoco.kt @@ -208,7 +208,7 @@ private fun Project.addTestCoverageTask( } } } - +@Suppress("UNCHECKED_CAST") fun Project.jacocoTestReport(taskName: String) { val reportDir = jacoco.reportsDirectory.asFile.get() val report = file("$reportDir/$taskName/${taskName}.xml") @@ -235,7 +235,7 @@ private fun Project.addTestCoverageTask( } } - +@Suppress("UNCHECKED_CAST") fun File.extractTestCoverage(): Map { val xmlReader = XmlSlurper().apply { setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false) diff --git a/build.gradle.kts b/build.gradle.kts index c93e8b9..ecb854b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + buildscript { repositories { mavenCentral() @@ -14,6 +16,7 @@ buildscript { plugins { alias(versionCatalogLibs.plugins.kotlin.serialization) apply false alias(versionCatalogLibs.plugins.hilt) apply false + alias(versionCatalogLibs.plugins.ksp) apply false alias(versionCatalogLibs.plugins.sonar) alias(versionCatalogLibs.plugins.dokka) alias(versionCatalogLibs.plugins.ktlint) diff --git a/core/common/build.gradle.kts b/core/common/build.gradle.kts index 6b4a129..109ba6b 100644 --- a/core/common/build.gradle.kts +++ b/core/common/build.gradle.kts @@ -3,8 +3,8 @@ import ytemplate.android.jacoco.setModuleTestCoverageLimits plugins { id("ytemplate.android.library") - id("ytemplate.android.library.jacoco") id("ytemplate.android.hilt") + id("ytemplate.android.library.jacoco") } private val excludedFiles = mutableSetOf( diff --git a/core/database/build.gradle.kts b/core/database/build.gradle.kts index 3bf4ed4..150e024 100644 --- a/core/database/build.gradle.kts +++ b/core/database/build.gradle.kts @@ -29,13 +29,20 @@ setModuleTestCoverageLimits(limits) android { namespace = "ytemplate.android.database" + defaultConfig { + javaCompileOptions { + annotationProcessorOptions { + arguments["room.schemaLocation"] = "$projectDir/schemas" + } + } + } } dependencies { implementation(project(mapOf("path" to ":core:common"))) // Room implementation(versionCatalogLibs.bundles.room) - kapt(versionCatalogLibs.room.compiler) + ksp(versionCatalogLibs.room.compiler) implementation(versionCatalogLibs.androidx.test.monitor) androidTestImplementation(versionCatalogLibs.bundles.test) androidTestImplementation(versionCatalogLibs.coroutine.test) diff --git a/core/database/schemas/ytemplate.android.core.database.room.AppDataBase/5.json b/core/database/schemas/ytemplate.android.core.database.room.AppDataBase/5.json new file mode 100644 index 0000000..07c146e --- /dev/null +++ b/core/database/schemas/ytemplate.android.core.database.room.AppDataBase/5.json @@ -0,0 +1,52 @@ +{ + "formatVersion": 1, + "database": { + "version": 5, + "identityHash": "7c4a48bedc91be7b793fa52a2e0676ef", + "entities": [ + { + "tableName": "PostTable", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userId` INTEGER NOT NULL, `title` TEXT NOT NULL, `body` TEXT NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "body", + "columnName": "body", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '7c4a48bedc91be7b793fa52a2e0676ef')" + ] + } +} \ No newline at end of file diff --git a/core/database/src/main/java/ytemplate/android/core/database/room/AppDataBase.kt b/core/database/src/main/java/ytemplate/android/core/database/room/AppDataBase.kt index f468312..617e3bb 100644 --- a/core/database/src/main/java/ytemplate/android/core/database/room/AppDataBase.kt +++ b/core/database/src/main/java/ytemplate/android/core/database/room/AppDataBase.kt @@ -11,7 +11,7 @@ import ytemplate.android.core.database.model.PostEntity * * @constructor Create empty App data base */ -@Database(entities = [PostEntity::class], version = DATABASE_VERSION) +@Database(entities = [PostEntity::class], version = DATABASE_VERSION, exportSchema = false) abstract class AppDataBase : RoomDatabase() { /** * My model dao diff --git a/core/test/src/main/java/ytemplate/android/core/test/FakePostRepository.kt b/core/test/src/main/java/ytemplate/android/core/test/FakePostRepository.kt index bcfa322..77f6182 100644 --- a/core/test/src/main/java/ytemplate/android/core/test/FakePostRepository.kt +++ b/core/test/src/main/java/ytemplate/android/core/test/FakePostRepository.kt @@ -20,8 +20,8 @@ class FakePostRepository(val fakePostDao: FakePostDao = FakePostDao(), val fakeP private val _feed = MutableSharedFlow>() override val feed: SharedFlow> = _feed.asSharedFlow() - override suspend fun add(post: Post) { - fakePostDao.insert(post.map()) + override suspend fun add(postItem: Post) { + fakePostDao.insert(postItem.map()) emitData() } @@ -40,7 +40,7 @@ class FakePostRepository(val fakePostDao: FakePostDao = FakePostDao(), val fakeP AppResult.Success(remoteData.toPostList()) } else { emitData() - AppResult.Error((remoteData as AppResult.Error).exception) + AppResult.Error() } } catch (ex: Exception) { emitData() diff --git a/feature/post/src/main/java/ytemplate/android/feature/post/ui/PostListScreen.kt b/feature/post/src/main/java/ytemplate/android/feature/post/ui/PostListScreen.kt index 740c582..d7ac107 100644 --- a/feature/post/src/main/java/ytemplate/android/feature/post/ui/PostListScreen.kt +++ b/feature/post/src/main/java/ytemplate/android/feature/post/ui/PostListScreen.kt @@ -74,7 +74,11 @@ fun PostListScreen(viewModel: MyPostViewModel = hiltViewModel()) { AppLoadingIndicator() } is MyPostModelUiState.Error -> { - StickyErrorMessageCard((dataState as MyPostModelUiState.Error).throwable.localizedMessage) + (dataState as MyPostModelUiState.Error).throwable.localizedMessage?.let { + StickyErrorMessageCard( + it + ) + } } } } @@ -144,7 +148,7 @@ fun PreviewPostListScreen() { modifier = Modifier .fillMaxWidth() .padding(dimensions.paddingLarge) - ) { newPost -> + ) { _ -> } SimplePostList( listOf( diff --git a/feature/post/src/test/java/ytemplate/android/feature/post/MyPostViewModelTest.kt b/feature/post/src/test/java/ytemplate/android/feature/post/MyPostViewModelTest.kt index 3e46c25..0fdf474 100644 --- a/feature/post/src/test/java/ytemplate/android/feature/post/MyPostViewModelTest.kt +++ b/feature/post/src/test/java/ytemplate/android/feature/post/MyPostViewModelTest.kt @@ -23,8 +23,6 @@ import kotlin.time.Duration.Companion.milliseconds */ @OptIn(ExperimentalCoroutinesApi::class) class MyPostViewModelTest { - private lateinit var repository: FakePostRepository - /** * Set up * @@ -32,7 +30,6 @@ class MyPostViewModelTest { @Before fun setUp() { Dispatchers.setMain(UnconfinedTestDispatcher()) - repository = FakePostRepository() } /** @@ -41,6 +38,7 @@ class MyPostViewModelTest { */ @Test fun `test initial data is empty state`() = runTest { + var repository = FakePostRepository() val viewModel = MyPostViewModel(repository) viewModel.uiState.test { val firstDataState = awaitItem() @@ -56,6 +54,7 @@ class MyPostViewModelTest { */ @Test fun `test get data success state`() = runTest { + var repository = FakePostRepository() repository.fakePostApi.remotePostDataMock.setExpectSuccess() repository.fakePostApi.remotePostDataMock.setExpectedResponse(PlaceHolderData.DUMMY_DATA_GET_ALL_POST) val viewModel = MyPostViewModel(repository) @@ -76,6 +75,7 @@ class MyPostViewModelTest { */ @Test fun `test delete single data state`() = runTest { + var repository = FakePostRepository() repository.fakePostApi.remotePostDataMock.setExpectSuccess() repository.fakePostApi.remotePostDataMock.setExpectedResponse(PlaceHolderData.DUMMY_DATA_GET_ALL_POST) val viewModel = MyPostViewModel(repository) @@ -100,6 +100,7 @@ class MyPostViewModelTest { */ @Test fun `test add single data state`() = runTest { + var repository = FakePostRepository() repository.fakePostApi.remotePostDataMock.setExpectSuccess() repository.fakePostApi.remotePostDataMock.setExpectedResponse(PlaceHolderData.DUMMY_DATA_GET_ALL_POST) val viewModel = MyPostViewModel(repository) @@ -122,6 +123,7 @@ class MyPostViewModelTest { */ @Test fun `test errorState`() = runTest { + var repository = FakePostRepository() repository.fakePostApi.remotePostDataMock.setExpectFailure() repository.fakePostApi.remotePostDataMock.setExpectedResponse(null) val viewModel = MyPostViewModel(repository) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 259578e..c40e5aa 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ kotlinxCoroutines = "1.6.4" kotlinxSerializationJson = "1.4.1" #gradle -androidGradlePlugin = "7.4.1" +androidGradlePlugin = "7.4.2" #androidx androidxComposeBom = "2022.12.00" @@ -41,7 +41,7 @@ compose_ui_testing = "1.4.0-beta01" core_ktx = "1.9.0" #ksp -ksp = "1.7.21-1.0.8" +ksp = "1.8.10-1.0.9" #coroutine coroutine = "1.6.4" diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..86706a8 --- /dev/null +++ b/renovate.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:base" + ], + "baseBranches": ["multi_module"] +}