Repository: analysis-dev/diktat (kotlin)

Issue:
Diktat-gradle-plugin 0.1.6 doesn't detect inputs on Linux
## Describe the bug
0 files are checked, while everything works fine on windows
It's time for integration tests: #576

Pull request:
### What's done:
* Introduced functional tests for diktat-gradle-plugin
* Calculate code coverage for functional tests for diktat-gradle-plugin
* Skip gradle tests when maven is run with `-DskipTests=true`
* Updated gradle to 6.7.1

This pull request closes #627

Patch:
diff --git a/diktat-gradle-plugin/build.gradle.kts b/diktat-gradle-plugin/build.gradle.kts
index 6d75f03456..4c855f2e9a 100644
--- a/diktat-gradle-plugin/build.gradle.kts
+++ b/diktat-gradle-plugin/build.gradle.kts
@@ -1,9 +1,11 @@
 import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.getCurrentOperatingSystem
 
 plugins {
     `java-gradle-plugin`
     kotlin("jvm") version "1.4.20"
     jacoco
+    id("pl.droidsonroids.jacoco.testkit") version "1.0.7"
 }
 
 repositories {
@@ -39,7 +41,8 @@ val generateVersionsFile by tasks.registering {
 
     doFirst {
         versionsFile.parentFile.mkdirs()
-        versionsFile.writeText("""
+        versionsFile.writeText(
+            """
             package generated
 
             internal const val DIKTAT_VERSION = "$diktatVersion"
@@ -75,19 +78,45 @@ java {
     withSourcesJar()
 }
 
-// === testing & code coverage, consistent with maven
+// === testing & code coverage, jacoco is run independent from maven
+val functionalTestTask by tasks.register<Test>("functionalTest")
+val jacocoMergeTask by tasks.register<JacocoMerge>("jacocoMerge")
 tasks.withType<Test> {
     useJUnitPlatform()
-    extensions.configure(JacocoTaskExtension::class) {
-        setDestinationFile(file("target/jacoco.exec"))
-    }
 }
 
+// === integration testing
+// fixme: should probably use KotlinSourceSet instead
+val functionalTest = sourceSets.create("functionalTest") {
+        compileClasspath += sourceSets.main.get().output + configurations.testRuntimeClasspath
+        runtimeClasspath += output + compileClasspath
+}
+tasks.getByName<Test>("functionalTest") {
+    dependsOn("test")
+    testClassesDirs = functionalTest.output.classesDirs
+    classpath = functionalTest.runtimeClasspath
+    doLast {
+        if (getCurrentOperatingSystem().isWindows) {
+            // workaround for https://github.com/koral--/jacoco-gradle-testkit-plugin/issues/9
+            logger.lifecycle("Sleeping for 5 sec after functionalTest to avoid error with file locking")
+            Thread.sleep(5_000)
+        }
+    }
+    finalizedBy(jacocoMergeTask)
+}
+tasks.check { dependsOn(tasks.jacocoTestReport) }
+jacocoTestKit {
+    applyTo("functionalTestRuntimeOnly", tasks.named("functionalTest"))
+}
+tasks.getByName("jacocoMerge", JacocoMerge::class) {
+    dependsOn(functionalTestTask)
+    executionData(tasks.test, functionalTestTask)
+}
 tasks.jacocoTestReport {
-    dependsOn(tasks.test)
+    dependsOn(jacocoMergeTask)
+    executionData("$buildDir/jacoco/jacocoMerge.exec")
     reports {
         // xml report is used by codecov
         xml.isEnabled = true
-        xml.destination = file("target/site/jacoco/jacoco.xml")
     }
-}
+}
\ No newline at end of file
diff --git a/diktat-gradle-plugin/gradle/wrapper/gradle-wrapper.properties b/diktat-gradle-plugin/gradle/wrapper/gradle-wrapper.properties
index be52383ef4..4d9ca16491 100644
--- a/diktat-gradle-plugin/gradle/wrapper/gradle-wrapper.properties
+++ b/diktat-gradle-plugin/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/diktat-gradle-plugin/pom.xml b/diktat-gradle-plugin/pom.xml
index bc804153c6..781a7a1312 100644
--- a/diktat-gradle-plugin/pom.xml
+++ b/diktat-gradle-plugin/pom.xml
@@ -18,6 +18,9 @@
         <gradle.task>build</gradle.task>
         <gradle.builddir>build</gradle.builddir>
         <skip.gradle.build>false</skip.gradle.build>
+        <skip.gradle.test>false</skip.gradle.test>
+        <!-- This property is set to excluded task in the specific build profile -->
+        <gradle.exclude.check></gradle.exclude.check>
     </properties>
 
     <dependencies>
@@ -69,7 +72,7 @@
                             <executable>${gradle.executable}</executable>
                             <arguments>
                                 <argument>clean</argument>
-                                <argument>jacocoTestReport</argument>
+                                <argument>test</argument>
                                 <argument>-Pgroup=${project.groupId}</argument>
                                 <argument>-Pversion=${project.version}</argument>
                                 <argument>-Pdescription=${project.description}</argument>
@@ -77,7 +80,7 @@
                                 <argument>-PjunitVersion=${junit.version}</argument>
                                 <argument>-S</argument>
                             </arguments>
-                            <skip>${skip.gradle.build}</skip>
+                            <skip>${skip.gradle.test}</skip>
                         </configuration>
                         <goals>
                             <goal>exec</goal>
@@ -96,6 +99,7 @@
                                 <argument>-PktlintVersion=${ktlint.version}</argument>
                                 <argument>-PjunitVersion=${junit.version}</argument>
                                 <argument>-S</argument>
+                                <argument>${gradle.exclude.check}</argument>
                             </arguments>
                             <skip>${skip.gradle.build}</skip>
                         </configuration>
@@ -185,5 +189,18 @@
                 <gradle.executable>${project.basedir}/gradlew.bat</gradle.executable>
             </properties>
         </profile>
+        <profile>
+            <id>skip-gradle-tests</id>
+            <activation>
+                <property>
+                    <name>skipTests</name>
+                    <value>true</value>
+                </property>
+            </activation>
+            <properties>
+                <gradle.exclude.check>-xcheck</gradle.exclude.check>
+                <skip.gradle.test>true</skip.gradle.test>
+            </properties>
+        </profile>
     </profiles>
 </project>
\ No newline at end of file
diff --git a/diktat-gradle-plugin/src/main/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskBase.kt b/diktat-gradle-plugin/src/main/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskBase.kt
index 9eb2cc3afa..b957052117 100644
--- a/diktat-gradle-plugin/src/main/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskBase.kt
+++ b/diktat-gradle-plugin/src/main/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskBase.kt
@@ -68,10 +68,10 @@ open class DiktatJavaExecTaskBase @Inject constructor(
                 }
                 .files
                 .forEach {
-                    add("\"${it.path}\"")
+                    add(it.path)
                 }
             diktatExtension.excludes?.files?.forEach {
-                add("\"!${it.path}\"")
+                add(it.path)
             }
         }
         logger.debug("Setting JavaExec args to $args")


Test patch:
diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml
index 9dafb60c08..ad8a117897 100644
--- a/.github/workflows/build_and_test.yml
+++ b/.github/workflows/build_and_test.yml
@@ -3,9 +3,6 @@ name: Build and test
 on:
   pull_request
 
-env:
-  GRADLE_OPTS: -Dorg.gradle.daemon=false
-
 jobs:
   test:
     name: Unit Test
diff --git a/diktat-gradle-plugin/src/functionalTest/kotlin/org/cqfn/diktat/plugin/gradle/DiktatGradlePluginFunctionalTest.kt b/diktat-gradle-plugin/src/functionalTest/kotlin/org/cqfn/diktat/plugin/gradle/DiktatGradlePluginFunctionalTest.kt
new file mode 100644
index 0000000000..595bd9720d
--- /dev/null
+++ b/diktat-gradle-plugin/src/functionalTest/kotlin/org/cqfn/diktat/plugin/gradle/DiktatGradlePluginFunctionalTest.kt
@@ -0,0 +1,101 @@
+package org.cqfn.diktat.plugin.gradle
+
+import org.cqfn.diktat.plugin.gradle.DiktatGradlePlugin.Companion.DIKTAT_CHECK_TASK
+import org.gradle.internal.impldep.org.junit.rules.TemporaryFolder
+import org.gradle.testkit.runner.GradleRunner
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.Assertions
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import java.io.File
+
+class DiktatGradlePluginFunctionalTest {
+    private val testProjectDir = TemporaryFolder()
+    private lateinit var buildFile: File
+
+    @BeforeEach
+    fun setUp() {
+        testProjectDir.create()
+        File("../examples/gradle-kotlin-dsl").copyRecursively(testProjectDir.root)
+        File(testProjectDir.root, "build.gradle.kts").delete()
+        buildFile = testProjectDir.newFile("build.gradle.kts").apply {
+            writeText(
+                """
+                plugins {
+                    id("org.cqfn.diktat.diktat-gradle-plugin")
+                }
+                
+                repositories {
+                    mavenLocal()
+                    mavenCentral()
+                }
+            """.trimIndent()
+            )
+        }
+    }
+
+    @AfterEach
+    fun tearDown() {
+        testProjectDir.delete()
+    }
+
+    @Test
+    fun `should execute diktatCheck on default values`() {
+        val result = runDiktat()
+
+        val diktatCheckBuildResult = result.task(":$DIKTAT_CHECK_TASK")
+        requireNotNull(diktatCheckBuildResult)
+        Assertions.assertEquals(TaskOutcome.FAILED, diktatCheckBuildResult.outcome)
+        Assertions.assertTrue(
+            result.output.contains("[HEADER_MISSING_OR_WRONG_COPYRIGHT]")
+        )
+    }
+
+    @Test
+    fun `should execute diktatCheck with explicit inputs`() {
+        buildFile.appendText(
+            """${System.lineSeparator()}
+                diktat {
+                    inputs = files("src/**/*.kt")
+                }
+            """.trimIndent()
+        )
+        val result = runDiktat()
+
+        val diktatCheckBuildResult = result.task(":$DIKTAT_CHECK_TASK")
+        requireNotNull(diktatCheckBuildResult)
+        Assertions.assertEquals(TaskOutcome.FAILED, diktatCheckBuildResult.outcome)
+        Assertions.assertTrue(
+            result.output.contains("[HEADER_MISSING_OR_WRONG_COPYRIGHT]")
+        )
+    }
+
+    private fun runDiktat() = GradleRunner.create()
+        .withProjectDir(testProjectDir.root)
+        .withArguments(DIKTAT_CHECK_TASK)
+        .withPluginClasspath()
+        .withJaCoCo()
+        .forwardOutput()
+        .runCatching {
+            buildAndFail()
+        }
+        .also {
+            require(it.isSuccess) { "Running gradle returned exception ${it.exceptionOrNull()}" }
+        }
+        .getOrNull()!!
+
+    /**
+     * This is support for jacoco reports in tests run with gradle TestKit
+     */
+    private fun GradleRunner.withJaCoCo() = apply {
+        javaClass.classLoader
+            .getResourceAsStream("testkit-gradle.properties")
+            .also { it ?: println("properties file for testkit is not available, check build configuration") }
+            ?.use { propertiesFileStream ->
+                File(projectDir, "gradle.properties").outputStream().use {
+                    propertiesFileStream.copyTo(it)
+                }
+            }
+    }
+}
diff --git a/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskTest.kt b/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskTest.kt
index 6c976f80b2..2debadc173 100644
--- a/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskTest.kt
+++ b/diktat-gradle-plugin/src/test/kotlin/org/cqfn/diktat/plugin/gradle/DiktatJavaExecTaskTest.kt
@@ -19,7 +19,7 @@ class DiktatJavaExecTaskTest {
     @Test
     fun `check command line for various inputs`() {
         assertCommandLineEquals(
-            listOf(null, "\"${combinePathParts("src", "**", "*.kt")}\""),
+            listOf(null, combinePathParts("src", "**", "*.kt")),
             DiktatExtension().apply {
                 inputs = project.files("src/**/*.kt")
             }
@@ -29,7 +29,7 @@ class DiktatJavaExecTaskTest {
     @Test
     fun `check command line in debug mode`() {
         assertCommandLineEquals(
-            listOf(null, "--debug", "\"${combinePathParts("src", "**", "*.kt")}\""),
+            listOf(null, "--debug", combinePathParts("src", "**", "*.kt")),
             DiktatExtension().apply {
                 inputs = project.files("src/**/*.kt")
                 debug = true
@@ -40,8 +40,8 @@ class DiktatJavaExecTaskTest {
     @Test
     fun `check command line with excludes`() {
         assertCommandLineEquals(
-            listOf(null, "\"${combinePathParts("src", "**", "*.kt")}\"",
-                "\"!${combinePathParts("src", "main", "kotlin", "generated")}\""
+            listOf(null, combinePathParts("src", "**", "*.kt"),
+                combinePathParts("src", "main", "kotlin", "generated")
             ),
             DiktatExtension().apply {
                 inputs = project.files("src/**/*.kt")
@@ -70,6 +70,6 @@ class DiktatJavaExecTaskTest {
         Assertions.assertIterableEquals(expected, task.commandLine)
     }
 
-    private fun combinePathParts(vararg parts: String) = project.projectDir.absolutePath +
+    private fun combinePathParts(vararg parts: String) = project.rootDir.absolutePath +
             parts.joinToString(File.separator, prefix = File.separator)
 }