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

com.vandalsoftware.tools.gradle.RobolectricPlugin.groovy Maven / Gradle / Ivy

The newest version!
package com.vandalsoftware.tools.gradle

import com.android.build.gradle.AppPlugin
import com.android.build.gradle.LibraryPlugin
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.file.FileTree
import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.api.tasks.testing.Test
import org.gradle.testing.jacoco.plugins.JacocoPlugin
import org.gradle.testing.jacoco.tasks.JacocoReport

class RobolectricPlugin implements Plugin {
    public static final String COMPILE_TASK_NAME = 'compile'
    public static final String TEST_TASK_NAME = 'robolectricTest'
    public static final String TASK_NAME_PREFIX = 'robolectric'

    public static final String TEST_COMPILE_CONFIGURATION_NAME = 'testCompile'

    public static final String JUNIT_JAR_VERSION = '4.11'
    public static final String ROBOLECTRIC_JAR_VERSION = "2.3"

    public static final String VERIFICATION_GROUP_NAME = 'Verification'
    public static final String CHECK_TASK_NAME = 'check'

    @Override
    void apply(Project project) {
        def variants
        def plugin
        if (project.plugins.hasPlugin(AppPlugin)) {
            variants = project.android.applicationVariants
            plugin = project.plugins.getPlugin(AppPlugin)
        } else if (project.plugins.hasPlugin(LibraryPlugin)) {
            variants = project.android.libraryVariants
            plugin = project.plugins.getPlugin(LibraryPlugin)
        } else {
            throw new UnsupportedOperationException("This project must apply" +
                    " com.android.application or com.android.library")
        }

        def extension = project.extensions.create('robolectric', RobolectricExtension)

        def compileConfig = project.configurations.getByName(COMPILE_TASK_NAME)
        Configuration testConfig = project.configurations.create(TEST_COMPILE_CONFIGURATION_NAME) {
            extendsFrom compileConfig
        }

        project.afterEvaluate {
            def deps = [] as HashSet
            testConfig.dependencies.each { dep ->
                deps.add("$dep.group:$dep.name".toString())
            }
            if (!deps.contains('junit:junit')) {
                project.dependencies.add(testConfig.name, "junit:junit:$JUNIT_JAR_VERSION") {
                    exclude module: 'hamcrest-core'
                }
            }
            if (!deps.contains('org.robolectric:robolectric')) {
                project.dependencies.add(testConfig.name, "org.robolectric:robolectric:$ROBOLECTRIC_JAR_VERSION") {
                    exclude module: 'commons-logging'
                    exclude module: 'httpclient'
                }
            }
        }

        project.android.productFlavors.all {
            project.configurations.create("test${it.name.capitalize()}Compile", {
                extendsFrom testConfig
            })
        }

        def testAll = project.tasks.create(name: TEST_TASK_NAME, group: VERIFICATION_GROUP_NAME,
                description: 'Runs all Robolectric tests')

        variants.all { variant ->
            if ('release'.equals(variant.buildType.name)) {
                return
            }
            def flavors = variant.productFlavors.collect { flavor ->
                flavor.name.capitalize()
            }
            def testVariant
            if (flavors.isEmpty()) {
                testVariant = variant.buildType.name.capitalize()
            } else {
                testVariant = flavors.join('') + variant.buildType.name.capitalize()
            }
            def variantJavaCompile = variant.javaCompile
            def testClasspath = testConfig.plus(project.files(variantJavaCompile.destinationDir,
                    variantJavaCompile.classpath))
            flavors.each { flavor ->
                def config = project.configurations.findByName("test${flavor}Compile")
                if (config) {
                    testClasspath.add(config)
                }
            }
            FileTree tree = project.fileTree('src') {
                include 'test/java/**/*.java'
                flavors.each { flavor ->
                    include "test${flavor}/java/**/*.java"
                }
            }
            def testVariantOutputDirName = testVariant.toLowerCase()
            def testDestinationDir =
                    project.file("${project.buildDir}/test-classes/$testVariantOutputDirName")
            def compileTask = project.tasks.create("${TASK_NAME_PREFIX}Compile${testVariant}TestJava",
                    JavaCompile)
            compileTask.dependsOn variantJavaCompile
            compileTask.classpath = testClasspath
            compileTask.source = tree
            compileTask.destinationDir = testDestinationDir
            compileTask.doFirst {
                compileTask.options.bootClasspath = plugin.bootClasspath.join(File.pathSeparator)
            }

            def procResTask = project.tasks.create("${TASK_NAME_PREFIX}Process${testVariant}TestResources",
                    Copy)
            procResTask.from('src/test/resources') {
                include '**/*'
            }
            flavors.each { flavor ->
                procResTask.from("test${flavor}/resources") {
                    include '**/*'
                }
            }
            procResTask.destinationDir =
                    project.file("${project.buildDir}/test-resources/$testVariantOutputDirName")

            def classesTask = project.tasks.create("${TASK_NAME_PREFIX}${testVariant}TestClasses")
            classesTask.dependsOn procResTask, compileTask

            def testTask = project.tasks.create("${TASK_NAME_PREFIX}Test${testVariant}", Test)
            testTask.dependsOn classesTask

            def testResultsOutput =
                    project.file("${project.testResultsDir}/$testVariantOutputDirName/binary/${testTask.name}")
            testTask.reports.html.destination = project.reporting.file(testVariantOutputDirName)
            testTask.reports.junitXml.destination = testResultsOutput
            testTask.binResultsDir = testResultsOutput

            testTask.testClassesDir = testDestinationDir
            testTask.inputs.sourceFiles.from.clear()
            testTask.classpath = testClasspath.plus(project.files(testDestinationDir, procResTask.destinationDir))
            testTask.doFirst {
                testTask.classpath = testClasspath.plus(project.files(testDestinationDir,
                        procResTask.destinationDir,
                        plugin.bootClasspath.join(File.pathSeparator)))
            }
            // Set the applicationId as the packageName to avoid unknown resource errors when
            // applicationIdSuffix is used.
            def applicationId = project.android.defaultConfig.applicationId
            if (applicationId != null) {
                testTask.systemProperties.put('android.package', applicationId)
            }

            // Add the path to the correct manifest, resources, assets as a system property.
            def processedManifestPath = variant.outputs[0].processManifest.manifestOutputFile
            def processedResourcesPath = variant.mergeResources.outputDir
            def processedAssetsPath = variant.mergeAssets.outputDir

            testTask.systemProperties.put('android.manifest', processedManifestPath)
            testTask.systemProperties.put('android.resources', processedResourcesPath)
            testTask.systemProperties.put('android.assets', processedAssetsPath)

            // Work around http://issues.gradle.org/browse/GRADLE-1682
            testTask.scanForTestClasses = false

            if (extension.testCoverageEnabled) {
                if (!project.plugins.hasPlugin(JacocoPlugin)) {
                    project.apply plugin: JacocoPlugin
                }
                testTask.jacoco {
                    destinationFile =
                            project.file("${project.buildDir}/jacoco/${testVariantOutputDirName}/coverage.exec")
                }
                def jacocoTask = project.tasks.create("$TASK_NAME_PREFIX${testVariant}JacocoTestReport", JacocoReport)
                jacocoTask.classDirectories = project.fileTree(
                        dir: variantJavaCompile.destinationDir,
                        excludes: ['**/R.class',
                                   '**/R$*.class',
                                   '**/BuildConfig.*',
                                   '**/Manifest*.*']
                )

                def sourceDirs = [project.android.sourceSets.main.java.srcDirs]
                variant.productFlavors.each { flavor ->
                    sourceDirs.add(project.android.sourceSets[flavor.name].java.srcDirs)
                }
                jacocoTask.sourceDirectories = project.files(sourceDirs)
                jacocoTask.executionData =
                        project.files("${project.buildDir}/jacoco/${testVariantOutputDirName}/coverage.exec")
                jacocoTask.reports {
                    xml.enabled true
                    html {
                        enabled true
                        destination "${project.buildDir}/jacoco/${testVariantOutputDirName}/html"
                    }
                    csv.enabled false
                }
                jacocoTask.dependsOn testTask
                testAll.dependsOn jacocoTask
            } else {
                testAll.dependsOn testTask
            }
        }
        def checkTask = project.tasks.findByName(CHECK_TASK_NAME)
        if (checkTask) {
            checkTask.dependsOn testAll
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy