/*
 * (C) Copyright IBM Deutschland GmbH 2021
 * (C) Copyright IBM Corp. 2021
 */

class Config {
    boolean enableTestCoverage = true
    boolean trackUI = true
    List<String> extraExcludes = []
}

ext.trackCoverage = { args = [:] ->
    apply plugin: 'jacoco'

    Config config = new Config(args)

    tasks.withType(Test) {
        jacoco.includeNoLocationClasses = true
        jacoco.excludes = ['jdk.internal.*']
    }

    jacoco {
        toolVersion = "0.8.7"
    }

    def isAndroidProject = project.file('src/main/AndroidManifest.xml').exists()
    def hasInstrumentationTests = isAndroidProject && project.file('src/androidTest').exists()

    if (isAndroidProject) {
        android {
            buildTypes {
                debug {
                    testCoverageEnabled = hasInstrumentationTests && config.enableTestCoverage
                }
            }

            testOptions {
                execution 'ANDROIDX_TEST_ORCHESTRATOR'
                animationsDisabled true
            }
        }
    }

    def androidTaskDeps = ['testDebugUnitTest']
    if (hasInstrumentationTests && config.enableTestCoverage) {
        androidTaskDeps.add('createDebugCoverageReport')
    }
    def taskDeps = isAndroidProject ? androidTaskDeps : ['test']
    task jacocoTestReportDefault(type: JacocoReport, dependsOn: taskDeps, group: 'verification') {
        reports {
            xml.required = true
            html.required = true
        }

        def fileFilter = [
            '**/R.class',
            '**/R$*.class',
            '**/BuildConfig.*',
            '**/Manifest*.*',
            '**/*Test*.*',
            'android/**/*.*',
            '**/databinding/*.*',
            // Ignore generated Hilt classes
            'hilt_aggregated_deps/*.*',
            '**/*_GeneratedInjector.*',
            '**/Hilt_*.*',
            '**/*_HiltComponents_*.*',
            '**/*_HiltModules_*.*',
            '**/*Module_*Factory*.*',
            // ignore room database
            '**/*Database.*',
            '**/*Dao.*',
            '**/*Dao_Impl.*',
            '**/*Database_Impl.*',
            // ignore sdkDependencies
            '**/SdkDependencies.*'
        ]
        if (!config.trackUI) {
            fileFilter.addAll([
                '**/*Binding*.*',
                '**/*BottomSheet*.*',
                '**/*Fragment*.*',
                '**/*FragmentNav.*',
                '**/*Activity*.*',
                '**/*ActivityNav.*',
                '**/*Adapter*.*',
                '**/*AdapterMapper.*',
                '**/*SectionMapper.*',
                '**/*ViewHolder*.*',
                '**/*Layout*.*',
                '**/*ViewFrame*.*',
                '**/*Popup*.*',
                '**/*PopUp*.*',
                '**/*Animation*.*',
                '**/*Divider*.*',
                '**/*Decoration.*',
                '**/*Drawable.*',
                '**/*Events.*',
                '**/*DiffUtilCallback.*',
                // Ignore compose screens/uis
                '**/*ScreenKt.*',
                '**/*UiKt.*',
            ])
        }
        fileFilter.addAll(config.extraExcludes)

        sourceDirectories.setFrom(files(["$project.projectDir/src/main/java", "$project.projectDir/src/main/kotlin"]))
        classDirectories.setFrom(files([
            isAndroidProject ?
                fileTree(dir: "$project.buildDir/intermediates/javac/debug", excludes: fileFilter)
                    + fileTree(dir: "$project.buildDir/intermediates/classes/debug", excludes: fileFilter)
                    + fileTree(dir: "$project.buildDir/tmp/kotlin-classes/debug", excludes: fileFilter)
                : fileTree(dir: "$project.buildDir/classes/kotlin")
        ]))
        executionData.setFrom(fileTree(dir: project.buildDir,
            includes: isAndroidProject ?
                ['jacoco/test*DebugUnitTest.exec', 'outputs/code_coverage/debugAndroidTest/connected/**/*.ec']
                : ['jacoco/test.exec'],
        ))
    }
}

ext.verifyCoverage = { minCoverage ->
    task jacocoTestCoverageVerificationDefault(type: JacocoCoverageVerification, group: 'verification') {
        executionData { project.fileTree(dir: project.buildDir, include: 'jacoco/**/*.exec') }

        violationRules {
            rule {
                limit {
                    minimum = minCoverage
                }
            }
        }
    }
}
