Kapt4IT
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt
index cdeadde..a9be770 100644
--- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3IT.kt
@@ -28,7 +28,9 @@
 import org.junit.jupiter.api.Disabled
 import org.junit.jupiter.api.DisplayName
 import org.junit.jupiter.api.condition.OS
+import java.io.File
 import java.nio.file.Files
+import java.nio.file.Path
 import java.util.zip.ZipFile
 import java.util.zip.ZipOutputStream
 import kotlin.io.path.appendText
@@ -36,7 +38,7 @@
 import kotlin.io.path.outputStream
 import kotlin.test.assertEquals
 
-abstract class Kapt3BaseIT(val languageVersion: String = "1.9") : KGPBaseTest() {
+abstract class Kapt3BaseIT(val languageVersion: String = "1.9", val freeArgs: List<String> = emptyList()) : KGPBaseTest() {
     companion object {
         private const val KAPT_SUCCESSFUL_MESSAGE = "Annotation processing complete, errors: 0"
     }
@@ -45,6 +47,7 @@
         .copy(
             kaptOptions = this.kaptOptions(),
             languageVersion = languageVersion,
+            freeArgs = freeArgs
         )
 
     protected open fun kaptOptions(): BuildOptions.KaptOptions = BuildOptions.KaptOptions(
@@ -63,6 +66,41 @@
     }
 
     protected val String.withPrefix get() = "kapt2/$this"
+
+    @OptIn(EnvironmentalVariablesOverride::class)
+    fun project(
+        projectName: String,
+        gradleVersion: GradleVersion,
+        buildOptions: BuildOptions = defaultBuildOptions,
+        forceOutput: Boolean = false,
+        enableBuildScan: Boolean = false,
+        addHeapDumpOptions: Boolean = true,
+        enableGradleDebug: Boolean = false,
+        projectPathAdditionalSuffix: String = "",
+        buildJdk: File? = null,
+        localRepoDir: Path? = null,
+        environmentVariables: EnvironmentalVariables = EnvironmentalVariables(),
+        test: TestProject.() -> Unit = {},
+    ) {
+        (this as KGPBaseTest).project(
+            projectName = projectName,
+            gradleVersion = gradleVersion,
+            buildOptions = buildOptions,
+            forceOutput = forceOutput,
+            enableBuildScan = enableBuildScan,
+            addHeapDumpOptions = addHeapDumpOptions,
+            enableGradleDebug = enableGradleDebug,
+            projectPathAdditionalSuffix = projectPathAdditionalSuffix,
+            buildJdk = buildJdk,
+            localRepoDir = localRepoDir,
+            environmentVariables = environmentVariables,
+        ) {
+            customizeProject()
+            test()
+        }
+    }
+
+    protected open fun TestProject.customizeProject() {}
 }
 
 /**
@@ -140,7 +178,7 @@
 
 @DisplayName("Kapt base checks")
 @OtherGradlePluginTests
-open class Kapt3IT : Kapt3BaseIT() {
+open class Kapt3IT(languageVersion: String = "1.9", freeArgs: List<String> = emptyList()) : Kapt3BaseIT(languageVersion, freeArgs) {
     @DisplayName("Kapt is skipped when no annotation processors are added")
     @GradleTest
     fun testKaptSkipped(gradleVersion: GradleVersion) {
diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt4IT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt4IT.kt
new file mode 100644
index 0000000..5b07097
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt4IT.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.gradle
+
+import org.jetbrains.kotlin.gradle.testbase.TestProject
+import kotlin.io.path.appendText
+import kotlin.io.path.name
+import kotlin.io.path.walk
+
+class Kapt4IT : Kapt3IT(languageVersion = "2.0") {
+    override fun TestProject.customizeProject() {
+        forceKapt4()
+    }
+}
+
+fun TestProject.forceKapt4() {
+    projectPath.walk().forEach {
+        if (it.fileName.name == "build.gradle") {
+            it.appendText("""
+                
+            try {
+                compileKotlin.configure {
+                    kotlinOptions.freeCompilerArgs += "-Xuse-kapt4"
+                    kotlinOptions.freeCompilerArgs += "-Xsuppress-version-warnings"
+                }
+            } catch(Exception e) {}
+            try {
+                kaptGenerateStubsKotlin {
+                    kotlinOptions.freeCompilerArgs += "-Xuse-kapt4"
+                    kotlinOptions.freeCompilerArgs += "-Xsuppress-version-warnings"
+                } 
+            } catch(Exception e) {}           
+            """.trimIndent())
+        }
+    }
+}
\ No newline at end of file