diff --git a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanCompileTask.kt b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanCompileTask.kt index 52aea7c229d..6f075020779 100644 --- a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanCompileTask.kt +++ b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanCompileTask.kt @@ -62,7 +62,6 @@ import java.io.File * } * * } - */ diff --git a/tools/kotlin-native-gradle-plugin/src/test/groovy/org/jetbrains/kotlin/gradle/plugin/test/BaseKonanSpecification.groovy b/tools/kotlin-native-gradle-plugin/src/test/groovy/org/jetbrains/kotlin/gradle/plugin/test/BaseKonanSpecification.groovy new file mode 100644 index 00000000000..31b6ddd7458 --- /dev/null +++ b/tools/kotlin-native-gradle-plugin/src/test/groovy/org/jetbrains/kotlin/gradle/plugin/test/BaseKonanSpecification.groovy @@ -0,0 +1,14 @@ +package org.jetbrains.kotlin.gradle.plugin.test + +import org.junit.Rule +import org.junit.rules.TemporaryFolder +import spock.lang.Specification + + +class BaseKonanSpecification extends Specification { + + @Rule + TemporaryFolder tmpFolder = new TemporaryFolder() + File getProjectDirectory() { return tmpFolder.root } + +} diff --git a/tools/kotlin-native-gradle-plugin/src/test/groovy/org/jetbrains/kotlin/gradle/plugin/test/DefaultSpecification.groovy b/tools/kotlin-native-gradle-plugin/src/test/groovy/org/jetbrains/kotlin/gradle/plugin/test/DefaultSpecification.groovy index 951175c57cd..2a15704f576 100644 --- a/tools/kotlin-native-gradle-plugin/src/test/groovy/org/jetbrains/kotlin/gradle/plugin/test/DefaultSpecification.groovy +++ b/tools/kotlin-native-gradle-plugin/src/test/groovy/org/jetbrains/kotlin/gradle/plugin/test/DefaultSpecification.groovy @@ -6,14 +6,11 @@ import org.junit.rules.TemporaryFolder import spock.lang.Specification -class DefaultSpecification extends Specification { - - @Rule - TemporaryFolder tmpFolder = new TemporaryFolder() +class DefaultSpecification extends BaseKonanSpecification { def 'Plugin should build a project without additional settings'() { when: - def project = KonanInteropProject.create(tmpFolder) { KonanInteropProject it -> + def project = KonanInteropProject.create(projectDirectory) { KonanInteropProject it -> it.buildFile.write(""" plugins { id 'konan' } konanInterop { stdio {} } diff --git a/tools/kotlin-native-gradle-plugin/src/test/groovy/org/jetbrains/kotlin/gradle/plugin/test/IncrementalSpecification.groovy b/tools/kotlin-native-gradle-plugin/src/test/groovy/org/jetbrains/kotlin/gradle/plugin/test/IncrementalSpecification.groovy index 41d19f4d77a..9106080b8f5 100644 --- a/tools/kotlin-native-gradle-plugin/src/test/groovy/org/jetbrains/kotlin/gradle/plugin/test/IncrementalSpecification.groovy +++ b/tools/kotlin-native-gradle-plugin/src/test/groovy/org/jetbrains/kotlin/gradle/plugin/test/IncrementalSpecification.groovy @@ -8,10 +8,7 @@ import spock.lang.IgnoreIf import spock.lang.Specification import spock.lang.Unroll -class IncrementalSpecification extends Specification { - - @Rule - TemporaryFolder tmpFolder = new TemporaryFolder() +class IncrementalSpecification extends BaseKonanSpecification { Tuple buildTwice(KonanInteropProject project, Closure change) { def runner = project.createRunner().withArguments('build') @@ -22,11 +19,11 @@ class IncrementalSpecification extends Specification { } Tuple buildTwice(Closure change) { - return buildTwice(KonanInteropProject.create(tmpFolder), change) + return buildTwice(KonanInteropProject.create(projectDirectory), change) } Tuple buildTwiceEmpty(Closure change) { - def project = KonanInteropProject.createEmpty(tmpFolder) + def project = KonanInteropProject.createEmpty(projectDirectory) project.generateSrcFile("main.kt") return buildTwice(project, change) } @@ -120,10 +117,10 @@ class IncrementalSpecification extends Specification { def 'inputFiles change for a compilation task should cause only recompilation'() { when: - def project = KonanInteropProject.createEmpty(tmpFolder) { KonanInteropProject it -> + def project = KonanInteropProject.createEmpty(projectDirectory) { KonanInteropProject it -> it.generateSrcFile('main.kt') - it.newFolder('src', 'foo', 'kotlin') - it.generateSrcFile('src/foo/kotlin/', 'bar.kt', """ + it.createSubDir('src', 'foo', 'kotlin') + it.generateSrcFile(["src", "foo", "kotlin"], 'bar.kt', """ fun main(args: Array) { println("Hello!") } """.stripIndent()) } @@ -138,10 +135,10 @@ class IncrementalSpecification extends Specification { @Unroll("#parameter change for a compilation task should cause only recompilation") def 'Library changes should cause only recompilaton'() { when: - def project = KonanInteropProject.createEmpty(tmpFolder) { KonanInteropProject it -> + def project = KonanInteropProject.createEmpty(projectDirectory) { KonanInteropProject it -> it.generateSrcFile('main.kt') - it.newFolder('src', 'lib', 'kotlin') - it.generateSrcFile("src/lib/kotlin", "lib.kt", "fun bar() { println(\"Hello!\") }") + it.createSubDir('src', 'lib', 'kotlin') + it.generateSrcFile(["src", "lib", "kotlin"], "lib.kt", "fun bar() { println(\"Hello!\") }") it.buildFile.append(""" konanArtifacts { lib { @@ -166,7 +163,7 @@ class IncrementalSpecification extends Specification { def 'useInterop change for a compilation task should cause only recompilation'() { when: - def project = KonanInteropProject.createEmpty(tmpFolder) { KonanInteropProject it -> + def project = KonanInteropProject.createEmpty(projectDirectory) { KonanInteropProject it -> it.generateSrcFile('main.kt') it.buildFile.append("konanInterop { foo {} }\n") } @@ -180,7 +177,7 @@ class IncrementalSpecification extends Specification { def 'manifest parameter change for a compilation task should cause only recompilation'() { when: - def project = KonanInteropProject.createEmpty(tmpFolder) { KonanInteropProject it -> + def project = KonanInteropProject.createEmpty(projectDirectory) { KonanInteropProject it -> it.generateSrcFile('main.kt') } def results = buildTwice(project) { KonanInteropProject it -> @@ -195,7 +192,7 @@ class IncrementalSpecification extends Specification { def 'manifest file change should cause only recompilation'() { when: def manifest - def project = KonanInteropProject.createEmpty(tmpFolder) { KonanInteropProject it -> + def project = KonanInteropProject.createEmpty(projectDirectory) { KonanInteropProject it -> it.generateSrcFile('main.kt') manifest = it.generateSrcFile('manifest', "#some manifest file\n") it.addCompilationSetting("main", "manifest", manifest) @@ -228,7 +225,7 @@ class IncrementalSpecification extends Specification { def 'defFile change for an interop task should cause recompilation and interop reprocessing'() { when: - def project = KonanInteropProject.createEmpty(tmpFolder) + def project = KonanInteropProject.createEmpty(projectDirectory) project.generateSrcFile('main.kt') def defFile = project.generateDefFile("foo.def", "#some content") def results = buildTwice(project) { KonanInteropProject it -> @@ -241,7 +238,7 @@ class IncrementalSpecification extends Specification { def 'header change for an interop task should cause recompilation and interop reprocessing'() { when: - def project = KonanInteropProject.createEmpty(tmpFolder) + def project = KonanInteropProject.createEmpty(projectDirectory) project.generateSrcFile('main.kt') def header = project.generateSrcFile('header.h', "#define CONST 1") def results = buildTwice(project) { KonanInteropProject it -> @@ -254,10 +251,10 @@ class IncrementalSpecification extends Specification { def 'link change for an interop task should cause recompilation and interop reprocessing'() { when: - def project = KonanInteropProject.createEmpty(tmpFolder) { KonanInteropProject it -> + def project = KonanInteropProject.createEmpty(projectDirectory) { KonanInteropProject it -> it.generateSrcFile('main.kt') - it.newFolder('src', 'lib', 'kotlin') - it.generateSrcFile('src/lib/kotlin', 'lib.kt', 'fun foo() { println(42) }') + it.createSubDir('src', 'lib', 'kotlin') + it.generateSrcFile(["src", "lib", "kotlin"], 'lib.kt', 'fun foo() { println(42) }') it.buildFile.append(""" konanArtifacts { lib { @@ -279,7 +276,7 @@ class IncrementalSpecification extends Specification { def 'konan version change should cause recompilation and interop reprocessing'() { when: - def project = KonanInteropProject.createEmpty(tmpFolder) { KonanInteropProject it -> + def project = KonanInteropProject.createEmpty(projectDirectory) { KonanInteropProject it -> it.generateSrcFile('main.kt') it.propertiesFile.append("konan.version=0.3\n") } @@ -303,7 +300,7 @@ class IncrementalSpecification extends Specification { } else { throw new IllegalStateException("Unknown host platform") } - def project = KonanInteropProject.createEmpty(tmpFolder) { KonanInteropProject it -> + def project = KonanInteropProject.createEmpty(projectDirectory) { KonanInteropProject it -> it.generateSrcFile('main.kt') it.propertiesFile.append("konan.build.targets=all\n") } diff --git a/tools/kotlin-native-gradle-plugin/src/test/groovy/org/jetbrains/kotlin/gradle/plugin/test/KonanProject.groovy b/tools/kotlin-native-gradle-plugin/src/test/groovy/org/jetbrains/kotlin/gradle/plugin/test/KonanProject.groovy index e50ebe75a72..cf272c8a723 100644 --- a/tools/kotlin-native-gradle-plugin/src/test/groovy/org/jetbrains/kotlin/gradle/plugin/test/KonanProject.groovy +++ b/tools/kotlin-native-gradle-plugin/src/test/groovy/org/jetbrains/kotlin/gradle/plugin/test/KonanProject.groovy @@ -1,22 +1,24 @@ package org.jetbrains.kotlin.gradle.plugin.test import org.gradle.testkit.runner.GradleRunner -import org.junit.rules.TemporaryFolder + +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.Paths class KonanProject { static String DEFAULT_ARTIFACT_NAME = 'main' - TemporaryFolder projectDir - - File getProjectDirRoot() { return projectDir.root } + File projectDir + Path projectPath String konanHome File buildFile File propertiesFile - Set srcFiles = [] + Set srcFiles = [] List compilationTasks = [] String downloadTask = ":downloadKonanCompiler" @@ -24,12 +26,9 @@ class KonanProject { List getBuildingTasks() { return compilationTasks } List getKonanTasks() { return getBuildingTasks() + downloadTask } - GradleRunner createRunner(boolean withDebug = true) { - return GradleRunner.create().withProjectDir(projectDirRoot).withPluginClasspath().withDebug(withDebug) - } - - protected KonanProject(TemporaryFolder projectDir) { + protected KonanProject(File projectDir) { this.projectDir = projectDir + projectPath = projectDir.toPath() def konanHome = System.getProperty("konan.home") if (konanHome == null) { throw new IllegalStateException("konan.home isn't specified") @@ -42,16 +41,58 @@ class KonanProject { this.konanHome = konanHomeDir.canonicalPath.replace('\\', '\\\\') } - void generateFolders() { - projectDir.newFolder("src", "main", "kotlin") + GradleRunner createRunner(boolean withDebug = true) { + return GradleRunner.create().withProjectDir(projectDir).withPluginClasspath().withDebug(withDebug) } + /** Creates a subdirectory specified by the given path. */ + File createSubDir(String ... path) { + return createSubDir(Paths.get(*path)) + } + + /** Creates a subdirectory specified by the given path. */ + File createSubDir(Path path) { + return Files.createDirectories(projectPath.resolve(path)).toFile() + } + + /** Creates a file with the given content in project subdirectory specified by parentDirectory. */ + File createFile(Path parentDirectory, String fileName, String content) { + def result = Files.createFile(projectPath.resolve(parentDirectory).resolve(fileName)).toFile() + result.write(content) + return result + } + + /** Creates a file with the given content in project subdirectory specified by parentPath. */ + File createFile(List parentPath, String fileName, String content) { + return createFile(Paths.get(*parentPath), fileName, content) + } + + /** Creates a file with the given content in project root directory. */ + File createFile(String fileName, String content) { + return createFile(projectPath, fileName, content) + } + + /** Creates a folder for project source files (src/main/kotlin). */ + void generateFolders() { + createSubDir("src", "main", "kotlin") + } + + /** Generates a build.gradle file in root project directory with the given content. */ File generateBuildFile(String content) { - buildFile = projectDir.newFile("build.gradle") - buildFile.write(content) + buildFile = createFile(projectPath, "build.gradle", content) return buildFile } + /** + * Generates a build.gradle file in root project directory with the default content (see below) + * and fills the compilationTasks array. + * + * plugins { id 'konan' } + * + * konanArtifacts { + * $DEFAULT_ARTIFACT_NAME { } + * } + */ File generateBuildFile() { def result = generateBuildFile(""" plugins { id 'konan' } @@ -65,17 +106,31 @@ class KonanProject { return result } - File generateSrcFile(String directoryPath, String fileName, String content) { - def result = projectDir.newFile("$directoryPath/$fileName") - result.write(content) + /** Generates a source file with the given name and content in the given directory and adds it into srcFiles */ + File generateSrcFile(Path parentDirectory, String fileName, String content) { + def result = createFile(parentDirectory, fileName, content) srcFiles.add(result) return result } - File generateSrcFile(String fileName, String content) { - return generateSrcFile("src/main/kotlin",fileName, content) + /** Generates a source file with the given name and content in the given directory and adds it into srcFiles */ + File generateSrcFile(List parentPath, String fileName, String content) { + return generateSrcFile(Paths.get(*parentPath), fileName, content) } + /** Generates a source file with the given name and content in 'src/main/kotlin' and adds it into srcFiles */ + File generateSrcFile(String fileName, String content) { + return generateSrcFile(["src", "main", "kotlin"], fileName, content) + } + + /** + * Generates a source file with the given name and default content (see below) in src/main/kotlin + * and adds it into srcFiles. + * + * fun main(args: Array) { + * println(42) + * } + */ File generateSrcFile(String fileName) { return generateSrcFile(fileName, """ fun main(args: Array) { @@ -85,43 +140,58 @@ class KonanProject { ) } + /** Generates gradle.properties file with the konan.home property set. */ File generatePropertiesFile(String konanHome) { - propertiesFile = projectDir.newFile("gradle.properties") - propertiesFile.write("konan.home=$konanHome\n") + propertiesFile = createFile(projectPath, "gradle.properties", "konan.home=$konanHome\n") return propertiesFile } - File newFolder(String... path) { return projectDir.newFolder(path) } - + /** + * Sets the given setting of the given project extension. + * In other words adds the following string in the build file: + * + * $container['$section'].$parameter $value + */ protected void addSetting(String container, String section, String parameter, String value) { buildFile.append("$container['$section'].$parameter $value\n") } + /** + * Sets the given setting of the given project extension using the path of the file as a value. + * In other words adds the following string in the build file: + * + * $container['$section'].$parameter ${value.canonicalPath.replace(\, \\)} + */ protected void addSetting(String container, String section, String parameter, File value) { addSetting(container, section, parameter, "'${value.canonicalPath.replace('\\', '\\\\')}'") } + /** Sets the given setting of the given konanArtifact */ void addCompilationSetting(String artifactName = DEFAULT_ARTIFACT_NAME, String parameter, String value) { addSetting("konanArtifacts", artifactName, parameter, value) } + /** Sets the given setting of the given konanArtifact using the path of the file as a value. */ void addCompilationSetting(String artifactName = DEFAULT_ARTIFACT_NAME, String parameter, File value) { addSetting("konanArtifacts", artifactName, parameter, value) } - static KonanProject create(TemporaryFolder projectDir) { + /** Creates a project with default build and source files. */ + static KonanProject create(File projectDir) { return createEmpty(projectDir) { it.generateSrcFile("main.kt") } } - static KonanProject create(TemporaryFolder projectDir, Closure config) { + /** Creates a project with default build and source files. */ + static KonanProject create(File projectDir, Closure config) { def result = create(projectDir) config(result) return result } - static KonanProject createEmpty(TemporaryFolder projectDir) { + /** Creates a project with the default build file and without any source files. */ + static KonanProject createEmpty(File projectDir) { def result = new KonanProject(projectDir) result.with { generateFolders() @@ -131,7 +201,8 @@ class KonanProject { return result } - static KonanProject createEmpty(TemporaryFolder projectDir, Closure config) { + /** Creates a project with the default build file and without any source files. */ + static KonanProject createEmpty(File projectDir, Closure config) { def result = createEmpty(projectDir) config(result) return result @@ -147,15 +218,30 @@ class KonanInteropProject extends KonanProject { List interopTasks = [] - protected KonanInteropProject(TemporaryFolder projectDir) { super(projectDir) } + protected KonanInteropProject(File projectDir) { super(projectDir) } List getBuildingTasks() { return interopTasks + compilationTasks } + /** Creates a folder for project source files (src/main/kotlin) and a folder for def-files (src/main/c_interop). */ void generateFolders() { super.generateFolders() - projectDir.newFolder("src", "main", "c_interop") + createSubDir("src", "main", "c_interop") } + /** + * Generates a build.gradle file in root project directory with the default content (see below) + * and fills compilationTasks and interopTasks arrays. + * + * plugins { id 'konan' } + * + * konanInterop { + * $DEFAULT_INTEROP_NAME { } + * } + * + * konanArtifacts { + * $DEFAULT_ARTIFACT_NAME { useInterop '$DEFAULT_INTEROP_NAME' } + } + */ File generateBuildFile() { def result = generateBuildFile(""" plugins { id 'konan' } @@ -175,13 +261,19 @@ class KonanInteropProject extends KonanProject { return result } + /** Creates a def-file with the given name and content in src/main/c_interop directory and adds it to defFiles. */ File generateDefFile(String fileName, String content) { - def result = projectDir.newFile("src/main/c_interop/$fileName") - result.write(content) + def result = createFile(["src", "main", "c_interop"], fileName, content) defFiles.add(result) return result } + /** + * Creates a def-file with the given name and the default content (see below) in src/main/c_interop directory + * and adds it to defFiles. + * + * headers = stdio.h stdlib.h string.h + */ File generateDefFile(String fileName) { return generateDefFile(fileName, """ headers = stdio.h stdlib.h string.h @@ -189,28 +281,33 @@ class KonanInteropProject extends KonanProject { ) } + /** Sets the given setting of the given konanInterop */ void addInteropSetting(String interopName = DEFAULT_INTEROP_NAME, String parameter, String value) { addSetting("konanInterop", interopName, parameter, value) } + /** Sets the given setting of the given konanInterop using the path of the file as a value. */ void addInteropSetting(String interopName = DEFAULT_INTEROP_NAME, String parameter, File value) { addSetting("konanInterop", interopName, parameter, value) } - static KonanInteropProject create(TemporaryFolder projectDir) { + /** Creates a project with default build, source and def files. */ + static KonanInteropProject create(File projectDir) { return createEmpty(projectDir) { it.generateSrcFile("main.kt") it.generateDefFile("${DEFAULT_INTEROP_NAME}.def") } } - static KonanInteropProject create(TemporaryFolder projectDir, Closure config) { + /** Creates a project with default build, source and def files. */ + static KonanInteropProject create(File projectDir, Closure config) { def result = create(projectDir) config(result) return result } - static KonanInteropProject createEmpty(TemporaryFolder projectDir) { + /** Creates a project with the default build file and without any source or def files. */ + static KonanInteropProject createEmpty(File projectDir) { def result = new KonanInteropProject(projectDir) result.with { generateFolders() @@ -220,7 +317,8 @@ class KonanInteropProject extends KonanProject { return result } - static KonanInteropProject createEmpty(TemporaryFolder projectDir, Closure config) { + /** Creates a project with the default build file and without any source or def files. */ + static KonanInteropProject createEmpty(File projectDir, Closure config) { def result = createEmpty(projectDir) config(result) return result diff --git a/tools/kotlin-native-gradle-plugin/src/test/groovy/org/jetbrains/kotlin/gradle/plugin/test/PathSpecification.groovy b/tools/kotlin-native-gradle-plugin/src/test/groovy/org/jetbrains/kotlin/gradle/plugin/test/PathSpecification.groovy index 969cb44fa9d..f61e91462fd 100644 --- a/tools/kotlin-native-gradle-plugin/src/test/groovy/org/jetbrains/kotlin/gradle/plugin/test/PathSpecification.groovy +++ b/tools/kotlin-native-gradle-plugin/src/test/groovy/org/jetbrains/kotlin/gradle/plugin/test/PathSpecification.groovy @@ -6,17 +6,15 @@ import org.junit.rules.TemporaryFolder import spock.lang.Specification -class PathSpecification extends Specification { - @Rule - TemporaryFolder tmpFolder = new TemporaryFolder() +class PathSpecification extends BaseKonanSpecification { def 'Plugin should create all necessary directories'() { when: - def project = KonanInteropProject.create(tmpFolder) + def project = KonanInteropProject.create(projectDirectory) def result = project.createRunner().withArguments('build').build() then: - def konan = "${tmpFolder.root}/build/konan" + def konan = "$projectDirectory/build/konan" new File("$konan/bin").listFiles().findAll { File it -> it.file && it.name.matches('^main\\.[^.]+') }.size() > 0 @@ -32,8 +30,8 @@ class PathSpecification extends Specification { def 'Plugin should stop building if the compiler classpath is empty'() { when: - def project = KonanProject.createEmpty(tmpFolder) - project.propertiesFile.write("konan.home=${tmpFolder.root.canonicalPath}}") + def project = KonanProject.createEmpty(projectDirectory) + project.propertiesFile.write("konan.home=${projectDirectory.canonicalPath}}") def result = project.createRunner().withArguments('build').buildAndFail() then: @@ -42,8 +40,8 @@ class PathSpecification extends Specification { def 'Plugin should stop building if the stub generator classpath is empty'() { when: - def project = KonanInteropProject.createEmpty(tmpFolder) - project.propertiesFile.write("konan.home=${tmpFolder.root.canonicalPath}}") + def project = KonanInteropProject.createEmpty(projectDirectory) + project.propertiesFile.write("konan.home=${projectDirectory.canonicalPath}}") def result = project.createRunner().withArguments('build').buildAndFail() then: diff --git a/tools/kotlin-native-gradle-plugin/src/test/groovy/org/jetbrains/kotlin/gradle/plugin/test/TaskSpecification.groovy b/tools/kotlin-native-gradle-plugin/src/test/groovy/org/jetbrains/kotlin/gradle/plugin/test/TaskSpecification.groovy index 4a77be08414..c7c5fadccb8 100644 --- a/tools/kotlin-native-gradle-plugin/src/test/groovy/org/jetbrains/kotlin/gradle/plugin/test/TaskSpecification.groovy +++ b/tools/kotlin-native-gradle-plugin/src/test/groovy/org/jetbrains/kotlin/gradle/plugin/test/TaskSpecification.groovy @@ -6,14 +6,11 @@ import org.junit.rules.TemporaryFolder import spock.lang.Specification -class TaskSpecification extends Specification { - - @Rule - TemporaryFolder tmpFolder = new TemporaryFolder() +class TaskSpecification extends BaseKonanSpecification { def 'Configs should allow user to add dependencies to them'() { when: - def project = KonanInteropProject.createEmpty(tmpFolder) { KonanInteropProject it -> + def project = KonanInteropProject.createEmpty(projectDirectory) { KonanInteropProject it -> it.generateSrcFile("main.kt") } project.buildFile.append("""