// todo Unify test tasks into one multithreaded execution unit with a custom fork frequency
// todo Add test progress listener with dot notation.

repositories {
    mavenCentral()
}

configurations {
    coverage
}

dependencies {
    testRuntime files('src/test', 'src/grails/grails-app/utils', projectDir, "src/war/WEB-INF", coreJar.archivePath)
    coverage "net.sourceforge.cobertura:cobertura:1.9.3"
}

// we disable the default test task of the java plugin as we use a bunch of custom ones.
// todo remove this line as soon as the java plugin is split up in two.
test.enabled = false

task instrumentForCoverage {
    instrumentedClassesDir = "${sourceSets.main.classesDir}-instrumented" as File

    inputs.dir sourceSets.test.classesDir
    outputs.files instrumentedClassesDir

    cobSerFile = "${project.buildDir}/cobertura.ser"
    doFirst {
        ant {
            // delete data file for cobertura, otherwise coverage would be added
            delete(file: cobSerFile, failonerror: false)
            // delete copy of original classes
            delete(dir: instrumentedClassesDir, failonerror: false)
            // import cobertura task, so it is available in the script
            taskdef(resource: 'tasks.properties', classpath: configurations.coverage.asPath)
        }
        copy {
            from sourceSets.main.classes
            into instrumentedClassesDir
        }
        ant {
            'cobertura-instrument'(datafile: cobSerFile) {
                fileset(dir: instrumentedClassesDir) { include(name: "**/*.class") }
            }
        }
    }
}

task coverageReport {
    destinationDir = "${project.buildDirName}/reports/coverage" as File
    inputs.files instrumentForCoverage.cobSerFile
    outputs.files destinationDir

    doFirst {
        project.ant.taskdef(resource: 'tasks.properties', classpath: configurations.coverage.asPath)
        ant.'cobertura-report'(destdir: destinationDir,
                format: 'xml', datafile: instrumentForCoverage.cobSerFile) {
            sourceSets.main.allJava.addToAntBuilder(ant, 'fileset')
        }
    }
}

test {
    options.systemProperties = ['grails.cli.testing': "true"]
    options.forkOptions.jvmArgs = ["-server", "-Xmx1G", "-Xms256m", "-XX:MaxPermSize=256m", "-Dgroovy.grails.joint=true"] // todo, "-Dgroovy.grails.joint=${groovy.grails.joint}"
}

createTestTask("contentFormat", ["org/codehaus/groovy/grails/web/mime/ContentFormatControllerTests.class"], [])
createTestTask("transactionalService", ["org/codehaus/groovy/grails/reload/TransactionalServiceReloadTests.class"], [])
createTestTask("packagePlugins", ["org/codehaus/groovy/grails/cli/PackagePluginTests.class"], [])
createTestTask("installTemplates", ["org/codehaus/groovy/grails/cli/InstallTemplatesTests.class"], [])
createTestTask("generateAll", ["org/codehaus/groovy/grails/cli/GenerateAllTests.class"], [])
createTestTask("cli", ["org/codehaus/groovy/grails/cli/**/*Tests.class"], ["org/codehaus/groovy/grails/cli/**/*Tests.class", "**/PackagePluginTests", "**/InstallTemplatesTests"])
createTestTask("hibernate", ["**/orm/hibernate/*Tests.class",
        "**/orm/hibernate/binding/*Tests.class",
        "**/orm/hibernate/cfg/*Tests.class",
        "**/orm/hibernate/validation/*Tests.class"], ["**/Abstract*", "**/UniqueConstraint*"])
createTestTask("uniqueConstraints", ["**/UniqueConstraintTests.class"], [])
createTestTask("webflow", ["**/webflow/**/*Tests.class"], ["**/Abstract*"])
createTestTask("taglib", ["**/web/taglib/**/*Tests.class"], ["**/Abstract*"])
createTestTask("other", ["**/*Tests.class"], ["**/Abstract*", "**/TransactionalServiceReloadTests*",
        "**/ContentFormatControllerTests*", "**/orm/hibernate/**", "**/webflow/**", "**/web/taglib/**", "**/cli/**Tests.class"])

def createTestTask(name, includes, excludes) {
    createTestTaskWithoutSuffix("${name}Test", includes, excludes)
}

def createTestTaskWithoutSuffix(String name, includes, excludes) {
    task = tasks.add(name: name, type: AntTest) {
        options.systemProperties = ['grails.cli.testing': "true"]
        options.forkOptions.jvmArgs = ["-server", "-Xmx1500m", "-Xms256m", "-XX:MaxPermSize=256m", "-Dgroovy.grails.joint=true"] // todo, "-Dgroovy.grails.joint=${groovy.grails.joint}"
        options.systemProperties['net.sourceforge.cobertura.datafile'] = instrumentForCoverage.cobSerFile
        include includes as String[]
        exclude excludes as String[]
        testReport = true
        ignoreFailures = false
        coverageHtmlReport = false
        classpath = classpath + project.rootProject.configurations.coverage
    }
    test.dependsOn task
    task.dependsOn coreJar
}

tasks.addRule("Pattern: <testTaskName>Coverage will execute the corresponding test task with coverage") {String taskName ->
    String coverageName = 'Coverage'
    if (taskName.endsWith(coverageName)) {
        def testTaskName = taskName.substring(0, taskName.length() - coverageName.length())
        def testTask = tasks.findByName(testTaskName)
        if (testTask) {
            def testTasks = testTask == tasks.test ? tasks.withType(AntTest) : testTask
            applyCoveragetToTestTasks(testTasks)
            tasks.add(name: taskName).dependsOn testTask, coverageReport
        }
    }
}

def applyCoveragetToTestTasks(def testTasks) {
    testTasks.each {testTask ->
        testTask.dependsOn instrumentForCoverage
        testTask.classpath = project.files(tasks.instrumentForCoverage.instrumentedClassesDir) + testTask.classpath + project.rootProject.configurations.coverage
        coverageReport.dependsOn testTask
    }
}

tasks.addRule("Pattern: testSingle<Name> will test **/<Name>Tests.class") {String taskName ->
    if (taskName.startsWith("testSingle") && !taskName.endsWith('Coverage')) {
        createTestTaskWithoutSuffix(taskName, ['**/' + taskName.substring(10) + 'Tests.class'], [])
    }
}


