diff --git a/.github/workflows/ci_test_coverage.yml b/.github/workflows/ci_test_coverage.yml new file mode 100644 index 000000000..aefaa886a --- /dev/null +++ b/.github/workflows/ci_test_coverage.yml @@ -0,0 +1,34 @@ +name: CI - Test Coverage Check + +on: + pull_request: + branches: [main, development] + +jobs: + test-coverage: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up JDK + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + cache: 'gradle' + + - name: Grant permission for Gradle + run: chmod +x ./gradlew + + - name: Run Unit Tests with Kover Coverage + run: ./gradlew test koverVerify koverXmlReport koverHtmlReport + + - name: Upload Coverage to Codecov + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: build/reports/kover/merged/report.xml + flags: unittests + name: novix-coverage-report \ No newline at end of file diff --git a/app/src/main/java/com/sanaa/novix/MainActivity.kt b/app/src/main/java/com/sanaa/novix/MainActivity.kt index 632765359..b5c0a3b0a 100644 --- a/app/src/main/java/com/sanaa/novix/MainActivity.kt +++ b/app/src/main/java/com/sanaa/novix/MainActivity.kt @@ -18,30 +18,9 @@ class MainActivity : ComponentActivity() { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { - NovixTheme { - Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> - Greeting( - name = "Android", - modifier = Modifier.padding(innerPadding) - ) - } + } - } - } -} -@Composable -fun Greeting(name: String, modifier: Modifier = Modifier) { - Text( - text = "Hello $name!", - modifier = modifier - ) + } } -@Preview(showBackground = true) -@Composable -fun GreetingPreview() { - NovixTheme { - Greeting("Android") - } -} \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 9f70b3d03..4f52b6bc0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,4 +6,85 @@ plugins { alias(libs.plugins.google.services) apply false alias(libs.plugins.android.library) apply false alias(libs.plugins.jetbrains.kotlin.jvm) apply false + alias(libs.plugins.kover) +} +val excludedPackages = listOf( + "*.R", + "*.R_*", + "*.BuildConfig*", + "*.Manifest*", + "com.sanaa.novix.ui.theme.*", + "*.ComposableSingletons*", + "*.MainActivity*" +) +allprojects { + apply(plugin = "org.jetbrains.kotlinx.kover") + kover { + reports { + filters { + excludes { + classes( + excludedPackages + ) + } + } + total { + verify { + rule { + bound { + minValue = 80 + } + } + } + } + } + } +} + +dependencies { + kover(projects.app) + kover(projects.domain.authentication.repository) + kover(projects.domain.movies.repository) + kover(projects.domain.actors.repository) + kover(projects.domain.series) + kover(projects.domain.savedContent.repository) + kover(projects.domain.search.repository) + kover(projects.domain.userProfile.repository) + kover(projects.data.remoteDataSource.actors) + kover(projects.data.remoteDataSource.authentication) + kover(projects.data.remoteDataSource.movies) + kover(projects.data.remoteDataSource.savedContent) + kover(projects.data.remoteDataSource.search) + kover(projects.data.remoteDataSource.series) + kover(projects.data.remoteDataSource.userProfile) + kover(projects.data.localDataSource.actors) + kover(projects.data.localDataSource.authentication) + kover(projects.data.localDataSource.movies) + kover(projects.data.localDataSource.savedContent) + kover(projects.data.localDataSource.search) + kover(projects.data.localDataSource.series) + kover(projects.data.localDataSource.userProfile) + kover(projects.data.repositories.actors) + kover(projects.data.repositories.authentication) + kover(projects.data.repositories.movies) + kover(projects.data.repositories.savedContent) + kover(projects.data.repositories.search) + kover(projects.data.repositories.series) + kover(projects.data.repositories.userProfile) + kover(projects.feature.authentication.api) + kover(projects.feature.authentication.presentation) + kover(projects.feature.home.api) + kover(projects.feature.home.presentation) + kover(projects.feature.userProfile.api) + kover(projects.feature.userProfile.presentation) + kover(projects.feature.savedContent.api) + kover(projects.feature.savedContent.presentation) + kover(projects.feature.playlists.api) + kover(projects.feature.playlists.presentation) + kover(projects.feature.search.api) + kover(projects.feature.search.presentation) + kover(projects.feature.mediaDetails.api) + kover(projects.feature.mediaDetails.presentation) + kover(projects.feature.onboarding.api) + kover(projects.feature.onboarding.presentation) } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 794dae2a8..42da1f272 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,6 +11,8 @@ espressoCore = "3.6.1" lifecycleRuntimeKtx = "2.9.1" activityCompose = "1.10.1" composeBom = "2025.06.01" +kover = "0.9.1" + appcompat = "1.7.1" material = "1.12.0" jetbrainsKotlinJvm = "2.0.21" @@ -61,6 +63,8 @@ kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } firebase-appdistribution = { id = "com.google.firebase.appdistribution", version = "5.1.1" } google-services = { id = "com.google.gms.google-services", version = "4.4.3" } +kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" } + android-library = { id = "com.android.library", version.ref = "agp" } jetbrains-kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "jetbrainsKotlinJvm" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } diff --git a/settings.gradle.kts b/settings.gradle.kts index 2d6c069fb..4108789e3 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -18,7 +18,7 @@ dependencyResolutionManagement { mavenCentral() } } - +enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") rootProject.name = "Novix" include(":app") include(":feature:authentication:presentation")