All Downloads are FREE. Search and download functionalities are using the official Maven repository.

name.remal.gradle_plugins.dsl.extensions.org.gradle.testing.jacoco.tasks.JacocoReportBase.kt Maven / Gradle / Ivy

package name.remal.gradle_plugins.dsl.extensions

import name.remal.ASM_API
import name.remal.gradle_plugins.api.ExcludeFromCodeCoverage
import name.remal.gradle_plugins.dsl.internal.RelocatedClass
import name.remal.newTempFile
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.FileCollection
import org.gradle.testing.jacoco.tasks.JacocoReportBase
import org.objectweb.asm.AnnotationVisitor
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassReader.*
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.Type.getDescriptor
import java.io.File
import java.lang.reflect.Method

private val jacocoReportBaseGetExecutionDataMethod: Method by lazy {
    JacocoReportBase::class.java
        .getCompatibleMethod(FileCollection::class.java, "getExecutionData")
        .apply { isAccessible = true }
}
private val jacocoReportBaseSetExecutionDataMethod: Method by lazy {
    JacocoReportBase::class.java
        .getCompatibleMethod("setExecutionData", FileCollection::class.java)
        .apply { isAccessible = true }
}
var JacocoReportBase.executionDataCompatible: FileCollection
    get() = (jacocoReportBaseGetExecutionDataMethod.invoke(this) as? FileCollection) ?: project.files()
    set(value) {
        val executionData: FileCollection? = jacocoReportBaseGetExecutionDataMethod.invoke(this) as? FileCollection
        if (executionData == value) return
        if (executionData is ConfigurableFileCollection) {
            executionData.setFrom(value as Any)
        } else {
            jacocoReportBaseSetExecutionDataMethod.invoke(this, value)
        }
    }


private val jacocoReportBaseGetSourceDirectoriesMethod: Method by lazy {
    JacocoReportBase::class.java
        .getCompatibleMethod(FileCollection::class.java, "getSourceDirectories")
        .apply { isAccessible = true }
}
private val jacocoReportBaseSetSourceDirectoriesMethod: Method by lazy {
    JacocoReportBase::class.java
        .getCompatibleMethod("setSourceDirectories", FileCollection::class.java)
        .apply { isAccessible = true }
}
var JacocoReportBase.sourceDirectoriesCompatible: FileCollection
    get() = (jacocoReportBaseGetSourceDirectoriesMethod.invoke(this) as? FileCollection) ?: project.files()
    set(value) {
        val sourceDirectories: FileCollection? = jacocoReportBaseGetSourceDirectoriesMethod.invoke(this) as? FileCollection
        if (sourceDirectories == value) return
        if (sourceDirectories is ConfigurableFileCollection) {
            sourceDirectories.setFrom(value as Any)
        } else {
            jacocoReportBaseSetSourceDirectoriesMethod.invoke(this, value)
        }
    }


private val jacocoReportBaseGetClassDirectoriesMethod: Method by lazy {
    JacocoReportBase::class.java
        .getCompatibleMethod(FileCollection::class.java, "getClassDirectories")
        .apply { isAccessible = true }
}
private val jacocoReportBaseSetClassDirectoriesMethod: Method by lazy {
    JacocoReportBase::class.java
        .getCompatibleMethod("setClassDirectories", FileCollection::class.java)
        .apply { isAccessible = true }
}
var JacocoReportBase.classDirectoriesCompatible: FileCollection
    get() = (jacocoReportBaseGetClassDirectoriesMethod.invoke(this) as? FileCollection) ?: project.files()
    set(value) {
        val classDirectories: FileCollection? = jacocoReportBaseGetClassDirectoriesMethod.invoke(this) as? FileCollection
        if (classDirectories == value) return
        if (classDirectories is ConfigurableFileCollection) {
            classDirectories.setFrom(value as Any)
        } else {
            jacocoReportBaseSetClassDirectoriesMethod.invoke(this, value)
        }
    }


private val jacocoReportBaseGetAdditionalClassDirsMethod: Method by lazy {
    JacocoReportBase::class.java
        .getCompatibleMethod(FileCollection::class.java, "getAdditionalClassDirs")
        .apply { isAccessible = true }
}
private val jacocoReportBaseSetAdditionalClassDirsMethod: Method by lazy {
    JacocoReportBase::class.java
        .getCompatibleMethod("setAdditionalClassDirs", FileCollection::class.java)
        .apply { isAccessible = true }
}
var JacocoReportBase.additionalClassDirsCompatible: FileCollection
    get() = (jacocoReportBaseGetAdditionalClassDirsMethod.invoke(this) as? FileCollection) ?: project.files()
    set(value) {
        val additionalClassDirs: FileCollection? = jacocoReportBaseGetAdditionalClassDirsMethod.invoke(this) as? FileCollection
        if (additionalClassDirs == value) return
        if (additionalClassDirs is ConfigurableFileCollection) {
            additionalClassDirs.setFrom(value as Any)
        } else {
            jacocoReportBaseSetAdditionalClassDirsMethod.invoke(this, value)
        }
    }


private val jacocoReportBaseGetAdditionalSourceDirsMethod: Method by lazy {
    JacocoReportBase::class.java
        .getCompatibleMethod(FileCollection::class.java, "getAdditionalSourceDirs")
        .apply { isAccessible = true }
}
private val jacocoReportBaseSetAdditionalSourceDirsMethod: Method by lazy {
    JacocoReportBase::class.java
        .getCompatibleMethod("setAdditionalSourceDirs", FileCollection::class.java)
        .apply { isAccessible = true }
}
var JacocoReportBase.additionalSourceDirsCompatible: FileCollection
    get() = (jacocoReportBaseGetAdditionalSourceDirsMethod.invoke(this) as? FileCollection) ?: project.files()
    set(value) {
        val additionalSourceDirs: FileCollection? = jacocoReportBaseGetAdditionalSourceDirsMethod.invoke(this) as? FileCollection
        if (additionalSourceDirs == value) return
        if (additionalSourceDirs is ConfigurableFileCollection) {
            additionalSourceDirs.setFrom(value as Any)
        } else {
            jacocoReportBaseSetAdditionalSourceDirsMethod.invoke(this, value)
        }
    }


fun JacocoReportBase.prepareExecutionData() {
    var result = executionDataCompatible
    result = project.files(*result.files.filter(File::exists).toTypedArray())
    if (result.isEmpty) result = project.files(newTempFile("jacoco-", ".exec"))
    executionDataCompatible = result
}


private val excludeFromCodeCoverageDescs = setOf(
    getDescriptor(ExcludeFromCodeCoverage::class.java),
    getDescriptor(RelocatedClass::class.java)
)

fun JacocoReportBase.applyExcludeFromCodeCoverage() {
    fun FileCollection.applyExcludeFromCodeCoverage(): FileCollection {
        return project.files(this.files).asFileTree.filter { file ->
            if (!file.isFile) return@filter false
            if ("class" == file.extension) {
                var isExcluded = false
                ClassReader(file.readBytes()).accept(
                    object : ClassVisitor(ASM_API) {
                        override fun visitAnnotation(desc: String?, visible: Boolean): AnnotationVisitor? {
                            if (desc in excludeFromCodeCoverageDescs) isExcluded = true
                            return null
                        }
                    },
                    SKIP_DEBUG or SKIP_FRAMES or SKIP_CODE
                )

                return@filter !isExcluded

            } else {
                return@filter true
            }
        }
    }

    classDirectoriesCompatible = classDirectoriesCompatible.applyExcludeFromCodeCoverage()
    additionalClassDirsCompatible = additionalClassDirsCompatible.applyExcludeFromCodeCoverage()
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy