gradle-plugin: Improve test harness

This commit is contained in:
Ilya Matveev
2017-10-19 19:29:25 +03:00
committed by ilmat192
parent a04f9e423b
commit 2eac1d33ee
6 changed files with 88 additions and 86 deletions
@@ -11,7 +11,7 @@ class DefaultSpecification extends BaseKonanSpecification {
plugins { id 'konan' }
konanArtifacts {
interop('stdio')
program('main')
library('main')
}
""".stripIndent())
it.generateDefFile("stdio.def", "")
@@ -15,8 +15,8 @@ class IncrementalSpecification extends BaseKonanSpecification {
return new Tuple(project, firstResult, secondResult)
}
Tuple buildTwice(Closure change) {
return buildTwice(KonanProject.createWithInterop(projectDirectory), change)
Tuple buildTwice(ArtifactType mainArtifactType = ArtifactType.LIBRARY, Closure change) {
return buildTwice(KonanProject.createWithInterop(projectDirectory, mainArtifactType), change)
}
Boolean noRecompilationHappened(KonanProject project, BuildResult firstResult, BuildResult secondResult) {
@@ -74,14 +74,6 @@ class IncrementalSpecification extends BaseKonanSpecification {
recompilationAndInteropProcessingHappened(*results)
}
def 'Compilation is up-to-date if there is no changes in empty project'() {
when:
def results = buildTwice {}
then:
noRecompilationHappened(*results)
}
@Unroll("#parameter change for a compilation task should cause only recompilation")
def 'Parameter changes should cause only recompilaton'() {
when:
@@ -98,24 +90,22 @@ class IncrementalSpecification extends BaseKonanSpecification {
"baseDir" | "'build/new/outputDir'"
"enableOptimizations" | "true"
"linkerOpts" | "'--help'"
"languageVersion" | "'1.2'"
"apiVersion" | "'1.0'"
"enableAssertions" | "true"
"enableDebug" | "true"
"outputName" | "'foo'"
"artifactName" | "'foo'"
"extraOpts" | "'--time'"
"noDefaultLibs" | "true"
}
def 'inputFiles change for a compilation task should cause only recompilation'() {
def 'srcFiles change for a compilation task should cause only recompilation'() {
when:
def project = KonanProject.createWithInterop(projectDirectory) { KonanProject it ->
def project = KonanProject.createWithInterop(projectDirectory, ArtifactType.LIBRARY) { KonanProject it ->
it.generateSrcFile(["src", "foo", "kotlin"], 'bar.kt', """
fun main(args: Array<String>) { println("Hello!") }
""".stripIndent())
}
def results = buildTwice(project) { KonanProject it ->
it.addSetting("main", "inputFiles", "project.fileTree('src/foo/kotlin')")
it.addSetting("main", "srcFiles", "project.fileTree('src/foo/kotlin')")
}
then:
@@ -124,12 +114,12 @@ class IncrementalSpecification extends BaseKonanSpecification {
def 'Library change for a compilation task should cause only recompilation'() {
when:
def project = KonanProject.create(projectDirectory) { KonanProject it ->
def project = KonanProject.create(projectDirectory, ArtifactType.LIBRARY) { KonanProject it ->
it.generateSrcFile(["src", "lib", "kotlin"], "lib.kt", "fun bar() { println(\"Hello!\") }")
it.buildFile.append("""
konanArtifacts {
library('lib') {
inputFiles fileTree('src/lib/kotlin')
srcFiles fileTree('src/lib/kotlin')
}
}
""".stripIndent())
@@ -142,14 +132,14 @@ class IncrementalSpecification extends BaseKonanSpecification {
onlyRecompilationHappened(*results)
}
def 'Library changes should cause only recompilaton'() {
def 'Native library change for a compilation task should cause only recompilaton'() {
when:
def project = KonanProject.createWithInterop(projectDirectory) { KonanProject it ->
def project = KonanProject.createWithInterop(projectDirectory, ArtifactType.LIBRARY) { KonanProject it ->
it.generateSrcFile(["src", "lib", "kotlin"], "lib.kt", "fun bar() { println(\"Hello!\") }")
it.buildFile.append("""
konanArtifacts {
bitcode('lib') {
inputFiles fileTree('src/lib/kotlin')
srcFiles fileTree('src/lib/kotlin')
}
}
""".stripIndent())
@@ -176,7 +166,7 @@ class IncrementalSpecification extends BaseKonanSpecification {
where:
parameter | value
"pkg" | "'org.sample'"
"packageName" | "'org.sample'"
"compilerOpts" | "'-g'"
"linkerOpts" | "'--help'"
"includeDirs" | "'src'"
@@ -186,7 +176,7 @@ class IncrementalSpecification extends BaseKonanSpecification {
def 'defFile change for an interop task should cause recompilation and interop reprocessing'() {
when:
def project = KonanProject.createWithInterop(projectDirectory)
def project = KonanProject.createWithInterop(projectDirectory, ArtifactType.LIBRARY)
def defFile = project.generateDefFile("foo.def", "#some content")
def results = buildTwice(project) { KonanProject it ->
it.addSetting("stdio", "defFile", defFile)
@@ -198,7 +188,7 @@ class IncrementalSpecification extends BaseKonanSpecification {
def 'header change for an interop task should cause recompilation and interop reprocessing'() {
when:
def project = KonanProject.createWithInterop(projectDirectory)
def project = KonanProject.createWithInterop(projectDirectory, ArtifactType.LIBRARY)
def header = project.generateSrcFile('header.h', "#define CONST 1")
def results = buildTwice(project) { KonanProject it ->
it.addSetting("stdio", "headers", header)
@@ -210,12 +200,12 @@ class IncrementalSpecification extends BaseKonanSpecification {
def 'link change for an interop task should cause recompilation and interop reprocessing'() {
when:
def project = KonanProject.createWithInterop(projectDirectory) { KonanProject it ->
def project = KonanProject.createWithInterop(projectDirectory, ArtifactType.LIBRARY) { KonanProject it ->
it.generateSrcFile(["src", "lib", "kotlin"], 'lib.kt', 'fun foo() { println(42) }')
it.buildFile.append("""
konanArtifacts {
bitcode('lib') {
inputFiles fileTree('src/lib/kotlin')
srcFiles fileTree('src/lib/kotlin')
}
}
""".stripIndent())
@@ -231,7 +221,7 @@ class IncrementalSpecification extends BaseKonanSpecification {
def 'konan version change should cause recompilation and interop reprocessing'() {
when:
def project = KonanProject.createWithInterop(projectDirectory) { KonanProject it ->
def project = KonanProject.createWithInterop(projectDirectory, ArtifactType.LIBRARY) { KonanProject it ->
it.propertiesFile.append("konan.version=0.3\n")
}
def results = buildTwice(project) { KonanProject it ->
@@ -243,5 +233,7 @@ class IncrementalSpecification extends BaseKonanSpecification {
recompilationAndInteropProcessingHappened(*results)
}
// TODO: Add incremental tests for the 'libraries' block.
//endregion
}
@@ -8,6 +8,17 @@ import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
enum ArtifactType {
PROGRAM("program"),
LIBRARY("library"),
BITCODE("bitcode"),
INTEROP("interop")
String type
ArtifactType(String type) { this.type = type }
String toString() { return type }
}
class KonanProject {
static String DEFAULT_ARTIFACT_NAME = 'main'
@@ -37,12 +48,6 @@ class KonanProject {
List<String> getBuildingTasks() { return compilationTasks + interopTasks }
List<String> getKonanTasks() { return getBuildingTasks() + downloadTask }
// TODO: Must be an enum.
static String PROGRAM = "program"
static String LIBRARY = "library"
static String BITCODE = "bitcode"
static String INTEROP = "interop"
static String DEFAULT_SRC_CONTENT = """
fun main(args: Array<String>) {
println(42)
@@ -133,10 +138,10 @@ class KonanProject {
*/
File generateBuildFile() {
def result = generateBuildFile("""
plugins { id 'konan' }
konanTargets = [${targets.collect { "'$it'" }.join(", ")}]
""".stripIndent()
|plugins { id 'konan' }
|
|konan.targets = [${targets.collect { "'$it'" }.join(", ")}]
""".stripMargin()
)
compilationTasks = [":compileKonan", ":build"]
return result
@@ -233,68 +238,83 @@ class KonanProject {
}
/** Returns the path of compileKonan... task for the default artifact. */
String defaultCompilationTask(String target = HOST) {
static String defaultCompilationTask(String target = HOST) {
return compilationTask(DEFAULT_ARTIFACT_NAME, target)
}
String defaultInteropTask(String target = HOST) {
static String defaultInteropTask(String target = HOST) {
return compilationTask(DEFAULT_INTEROP_NAME, target)
}
/** Returns the path of compileKonan... task for the artifact specified. */
String compilationTask(String artifactName, String target = HOST) {
static String compilationTask(String artifactName, String target = HOST) {
return ":compileKonan${artifactName.capitalize()}${target.capitalize()}"
}
String defaultCompilationConfig() {
static String defaultCompilationConfig() {
return artifactConfig(DEFAULT_ARTIFACT_NAME)
}
String defaultInteropConfig() {
static String defaultInteropConfig() {
return artifactConfig(DEFAULT_INTEROP_NAME)
}
String artifactConfig(String artifactName) {
static String artifactConfig(String artifactName) {
return "konanArtifacts.$artifactName"
}
void addCompilerArtifact(String name, String content = "", String type = PROGRAM) {
static String outputAccessCode(String artifact, String target = HOST) {
return "${artifactConfig(artifact)}.${target}.artifact"
}
void addCompilerArtifact(String name, String content = "", ArtifactType type = ArtifactType.PROGRAM) {
def newTasks = targets.collect { compilationTask(name, it) } + ":compileKonan${name.capitalize()}".toString()
if (type == INTEROP) {
buildFile.append("konanArtifacts { $type('$name') }\n")
if (type == ArtifactType.INTEROP) {
defFiles += generateDefFile("${name}.def", content)
interopTasks += newTasks
} else {
srcFiles += generateSrcFile(projectPath.resolve("src/$name/kotlin"), "source.kt", content)
def src = generateSrcFile(projectPath.resolve("src/$name/kotlin"), "source.kt", content)
addSetting(name, "srcFiles", src)
srcFiles += src
compilationTasks += newTasks
}
buildFile.append("konanArtifacts { $type('$name') }\n")
}
/** Creates a project with default build and source files. */
static KonanProject create(File projectDir, List<String> targets = [HOST]) {
static KonanProject create(File projectDir,
ArtifactType artifactType = ArtifactType.PROGRAM,
List<String> targets = [HOST]) {
return createEmpty(projectDir, targets) { KonanProject p ->
p.addCompilerArtifact(DEFAULT_ARTIFACT_NAME, DEFAULT_SRC_CONTENT)
p.addCompilerArtifact(DEFAULT_ARTIFACT_NAME, DEFAULT_SRC_CONTENT, artifactType)
}
}
// TODO: Add 'type parameter'
/** Creates a project with default build and source files. */
static KonanProject create(File projectDir, List<String> targets = [HOST], Closure config) {
def result = create(projectDir, targets)
static KonanProject create(File projectDir,
ArtifactType artifactType = ArtifactType.PROGRAM,
List<String> targets = [HOST],
Closure config) {
def result = create(projectDir, artifactType, targets)
config(result)
return result
}
static KonanProject createWithInterop(File projectDir, List<String> targets = [HOST]) {
return create(projectDir, targets) { KonanProject p ->
p.addCompilerArtifact(DEFAULT_INTEROP_NAME, DEFAULT_DEF_CONTENT, INTEROP)
static KonanProject createWithInterop(File projectDir,
ArtifactType mainArtifactType = ArtifactType.PROGRAM,
List<String> targets = [HOST]) {
return create(projectDir, mainArtifactType, targets) { KonanProject p ->
p.addCompilerArtifact(DEFAULT_INTEROP_NAME, DEFAULT_DEF_CONTENT, ArtifactType.INTEROP)
p.addLibraryToArtifact()
}
}
static KonanProject createWithInterop(File projectDir, List<String> targets = [HOST], Closure config) {
def result = createWithInterop(projectDir, targets)
static KonanProject createWithInterop(File projectDir,
ArtifactType mainArtifactType = ArtifactType.PROGRAM,
List<String> targets = [HOST],
Closure config) {
def result = createWithInterop(projectDir, mainArtifactType, targets)
config(result)
return result
}
@@ -1,8 +1,6 @@
package org.jetbrains.kotlin.gradle.plugin.test
import org.gradle.testkit.runner.TaskOutcome
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.target.TargetManager
class PathSpecification extends BaseKonanSpecification {
@@ -13,10 +11,9 @@ class PathSpecification extends BaseKonanSpecification {
def 'Plugin should create all necessary directories'() {
when:
def project = KonanProject.createWithInterop(projectDirectory)
project.addCompilerArtifact("lib", "fun foo() {}", KonanProject.LIBRARY)
project.addCompilerArtifact("bit", "fun bar() {}", KonanProject.BITCODE)
println(project.buildFile.text)
def result = project.createRunner().withArguments('build').build()
project.addCompilerArtifact("lib", "fun foo() {}", ArtifactType.LIBRARY)
project.addCompilerArtifact("bit", "fun bar() {}", ArtifactType.BITCODE)
project.createRunner().withArguments('build').build()
then:
project.konanBuildDir.toPath().resolve("bin/$KonanProject.HOST").toFile().listFiles().findAll {
@@ -31,7 +28,7 @@ class PathSpecification extends BaseKonanSpecification {
def 'Plugin should stop building if the compiler classpath is empty'() {
when:
def project = KonanProject.create(projectDirectory)
project.propertiesFile.write("konan.home=${projectDirectory.canonicalPath}}")
project.propertiesFile.write("konan.home=fakepath")
def result = project.createRunner().withArguments('build').buildAndFail()
then:
@@ -41,7 +38,7 @@ class PathSpecification extends BaseKonanSpecification {
def 'Plugin should stop building if the stub generator classpath is empty'() {
when:
def project = KonanProject.createWithInterop(projectDirectory)
project.propertiesFile.write("konan.home=${projectDirectory.canonicalPath}}")
project.propertiesFile.write("konan.home=fakepath")
def result = project.createRunner().withArguments('build').buildAndFail()
then:
@@ -51,26 +48,24 @@ class PathSpecification extends BaseKonanSpecification {
def 'Plugin should remove custom output directories'() {
when:
def customOutputDir = projectDirectory.toPath().resolve("foo").toFile()
def project = KonanProject.create(projectDirectory) { KonanProject it ->
def project = KonanProject.create(projectDirectory, ArtifactType.LIBRARY) { KonanProject it ->
it.addSetting("baseDir", customOutputDir)
}
def res1 = project.createRunner().withArguments("build").build()
def artifactExistsAfterBuild = customOutputDir.toPath()
.resolve("${KonanProject.HOST}").toFile()
.listFiles()
.findAll { it.name.matches("^${KonanProject.DEFAULT_ARTIFACT_NAME}\\.[^.]+") }.size() > 0
.resolve("${KonanProject.HOST}/${KonanProject.DEFAULT_ARTIFACT_NAME}.klib").toFile()
.exists()
def res2 = project.createRunner().withArguments("clean").build()
def artifactDoesntNotExistAfterClean = customOutputDir.toPath()
.resolve("${KonanProject.HOST}").toFile()
.listFiles()
.findAll { it.name.matches("^${KonanProject.DEFAULT_ARTIFACT_NAME}\\.[^.]+") }.isEmpty()
def artifactExistsAfterClean = customOutputDir.toPath()
.resolve("${KonanProject.HOST}/${KonanProject.DEFAULT_ARTIFACT_NAME}.klib").toFile()
.exists()
then:
res1.taskPaths(TaskOutcome.SUCCESS).containsAll(project.buildingTasks)
res2.taskPaths(TaskOutcome.SUCCESS).contains(":clean")
artifactExistsAfterBuild
artifactDoesntNotExistAfterClean
!artifactExistsAfterClean
}
}
@@ -46,7 +46,7 @@ class RegressionSpecification extends BaseKonanSpecification {
fun main(args: Array<String>) {
foo()
}
""", KonanProject.PROGRAM)
""", ArtifactType.PROGRAM)
}
def result = project.createRunner().withArguments('build').buildAndFail()
@@ -3,13 +3,11 @@ package org.jetbrains.kotlin.gradle.plugin.test
import org.gradle.testkit.runner.BuildResult
import org.gradle.testkit.runner.TaskOutcome
import java.nio.file.Paths
class TaskSpecification extends BaseKonanSpecification {
def 'Configs should allow user to add dependencies to them'() {
when:
def project = KonanProject.createWithInterop(projectDirectory)
def project = KonanProject.createWithInterop(projectDirectory, ArtifactType.LIBRARY)
project.buildFile.append("""
task beforeInterop(type: DefaultTask) { doLast { println("Before Interop") } }
task beforeCompilation(type: DefaultTask) { doLast { println("Before compilation") } }
@@ -27,18 +25,16 @@ class TaskSpecification extends BaseKonanSpecification {
def 'Compiler should print time measurements if measureTime flag is set'() {
when:
def project = KonanProject.create(projectDirectory)
def project = KonanProject.create(projectDirectory, ArtifactType.LIBRARY)
project.addSetting("measureTime", "true")
def result = project.createRunner().withArguments('build').build()
then:
result.output.findAll(~/FRONTEND:\s+\d+\s+msec/).size() == 1
result.output.findAll(~/BACKEND:\s+\d+\s+msec/).size() == 1
result.output.findAll(~/LINK_STAGE:\s+\d+\s+msec/).size() == 1
}
BuildResult failOnPropertyAccess(String property) {
def project = KonanProject.createWithInterop(projectDirectory)
BuildResult failOnPropertyAccess(KonanProject project, String property) {
project.buildFile.append("""
task testTask(type: DefaultTask) {
doLast {
@@ -49,8 +45,7 @@ class TaskSpecification extends BaseKonanSpecification {
return project.createRunner().withArguments("testTask").buildAndFail()
}
BuildResult failOnTaskAccess(String task) {
def project = KonanProject.createWithInterop(projectDirectory)
BuildResult failOnTaskAccess(KonanProject project, String task) {
project.buildFile.append("""
task testTask(type: DefaultTask) {
dependsOn $task