configurations { cli_bc } dependencies { cli_bc project(path: ':backend.native', configuration: 'cli_bc') } abstract class KonanTest extends DefaultTask { protected String source def backendNative = project.project(":backend.native") def runtimeProject = project.project(":runtime") def llvmLlc = llvmTool("llc") def runtimeBc = new File("${runtimeProject.buildDir.canonicalPath}/runtime.bc") def launcherBc = new File("${runtimeProject.buildDir.canonicalPath}/launcher.bc") def startKtBc = new File("${runtimeProject.buildDir.canonicalPath}/start.kt.bc") def stdlibKtBc = new File("${runtimeProject.buildDir.canonicalPath}/stdlib.kt.bc") def mainC = 'main.c' String goldValue = null String testData = null List arguments = null boolean enabled = true public void setDisabled(boolean value) { this.enabled = !value } public KonanTest(){ dependsOn([project.project(":runtime").tasks['build'], project.parent.tasks['build'], project.project(":backend.native").tasks['stdlib'], project.project(":backend.native").tasks['start'] ]) } abstract void compileTest(File sourceS, File runtimeS, File libraryPath, File out) private File kt2bc(String ktSource) { def sourceKt = project.file(ktSource) def sourceBc = new File("${sourceKt.absolutePath}.bc") println "${runtimeBc}" project.javaexec { main = 'org.jetbrains.kotlin.cli.bc.K2NativeKt' classpath = project.configurations.cli_bc jvmArgs "-ea" args "-output", "${sourceBc.absolutePath}", "-runtime", "${runtimeBc.absolutePath}", "-library", "${stdlibKtBc.absolutePath}", "${sourceKt.absolutePath}" String libraryPath = "${project.llvmDir}/lib:${backendNative.buildDir.canonicalPath}/nativelibs" environment 'LD_LIBRARY_PATH' : libraryPath environment 'DYLD_LIBRARY_PATH' : libraryPath } return sourceBc } @TaskAction void executeTest() { def sourceS = bc2s(kt2bc(source)) def exe = new File(sourceS.absolutePath.replace(".kt.S", ".kt.exe")) def libraryPath = new File("${runtimeProject.file('src/main/bc').absolutePath}") compileTest(sourceS, bc2s(runtimeBc), stdlibKtBc, exe) println "execution :${exe.absolutePath}" def out = null project.exec { commandLine "${exe.absolutePath}" if (arguments != null) { args arguments } if (testData != null) { standardInput = new ByteArrayInputStream(testData.bytes) } if (goldValue != null) { out = new ByteArrayOutputStream() standardOutput = out } } if (goldValue != null && goldValue != out.toString()) throw new RuntimeException("test failed") } private File bc2s(File bcFile) { def outputFile = new File("${bcFile.absolutePath.replace(".bc",".S")}") println "${bcFile.absolutePath} -> ${outputFile.absolutePath}" println "tool: ${llvmLlc}" project.exec { commandLine "${llvmLlc}", "-o", "${outputFile.absolutePath}" , "${bcFile}", '-disable-fp-elim' // currently required for stack traces } return outputFile } private String llvmTool(String tool) { return "${project.llvmDir}/bin/${tool}" } private linux() { return project.isLinux() } // TODO: stop copy-pasting protected String linkDl() { if (linux()) { return "-ldl" } else { return "" } } protected String linkM() { if (linux()) { return "-lm" } else { return "" } } protected String rdynamic() { if (linux()) { return "-rdynamic" } else { return "" } } } class UnitKonanTest extends KonanTest { void compileTest(File sourceS, File runtimeS, File stdlibKtBc, File exe) { def testC = sourceS.absolutePath.replace(".kt.S", "-test.c") project.execClang { commandLine "clang++", runtimeS.absolutePath, stdlibKtBc.absolutePath, sourceS.absolutePath, "-o", exe.absolutePath, linkDl(), linkM(), rdynamic(), '-xc', testC, mainC } } } class RunKonanTest extends KonanTest { void compileTest(File sourceS, File runtimeS, File libraryPath, File exe) { project.execClang { commandLine "clang++", launcherBc.absolutePath, startKtBc.absolutePath, runtimeS.absolutePath, stdlibKtBc.absolutePath, sourceS.absolutePath, "-o", exe.absolutePath, linkDl(), linkM(), rdynamic(), '-xc' } } } class LinkKonanTest extends KonanTest { protected String lib private File dir2bc(String ktSources) { def sourcesKt = project.file(ktSources) def libBc = new File("${sourcesKt.absolutePath}/libout.kt.bc") def libPath = "${libBc.absolutePath}" project.javaexec { main = 'org.jetbrains.kotlin.cli.bc.K2NativeKt' classpath = project.configurations.cli_bc jvmArgs "-ea" args "-output", "${libPath}", "-runtime", "${runtimeBc.absolutePath}", sourcesKt String libraryPath = "${project.llvmDir}/lib:${backendNative.buildDir.canonicalPath}/nativelibs" environment 'LD_LIBRARY_PATH' : libraryPath environment 'DYLD_LIBRARY_PATH' : libraryPath } return libBc } private File link(String ktSource, File libBc) { def sourceKt = project.file(ktSource) def outPath = "${sourceKt.absolutePath.replace('.kt', '.kt.bc')}" def outBc = new File(outPath) project.javaexec { main = 'org.jetbrains.kotlin.cli.bc.K2NativeKt' classpath = project.configurations.cli_bc jvmArgs "-ea" args "-output", outPath, "-runtime", "${runtimeBc.absolutePath}", "-library", "${libBc.absolutePath}", "${sourceKt.absolutePath}" String libraryPath = "${project.llvmDir}/lib:${backendNative.buildDir.canonicalPath}/nativelibs" environment 'LD_LIBRARY_PATH' : libraryPath environment 'DYLD_LIBRARY_PATH' : libraryPath } return outBc } void compileTest(File sourceS, File runtimeS, File stdlibKtBc, File exe) { def testC = sourceS.absolutePath.replace(".kt.S", "-test.c") project.execClang { commandLine "clang++", runtimeS.absolutePath, stdlibKtBc.absolutePath, sourceS.absolutePath, "-o", exe.absolutePath, linkDl(), rdynamic(), '-xc', testC, mainC } } @TaskAction void executeTest() { def libBc = dir2bc(lib) def outBc = link(source, libBc) } } task run() { dependsOn(tasks.withType(KonanTest).matching { it.enabled }) } task sum (type:UnitKonanTest) { source = "codegen/function/sum.kt" } task method_call(type: UnitKonanTest) { source = "codegen/object/method_call.kt" } task fields(type: UnitKonanTest) { source = "codegen/object/fields.kt" } task fields1(type: UnitKonanTest) { source = "codegen/object/fields1.kt" } task constructor(type: UnitKonanTest) { source = "codegen/object/constructor.kt" } task objectInitialization(type: UnitKonanTest) { source = "codegen/object/initialization.kt" } task objectBasic(type: UnitKonanTest) { disabled = true source = "codegen/klass/basic.kt" } task check_type(type: UnitKonanTest) { source = "codegen/basics/check_type.kt" } task safe_cast(type: RunKonanTest) { goldValue = "safe_cast_positive: true\n" + "safe_cast_negative: true\n" source = "codegen/basics/safe_cast.kt" } task aritmetic(type: UnitKonanTest) { source = "codegen/function/arithmetic.kt" } task sum1(type: UnitKonanTest) { source = "codegen/function/sum_foo_bar.kt" } task sum2(type: UnitKonanTest) { source = "codegen/function/sum_imm.kt" } task sum_3const(type: UnitKonanTest) { source = "codegen/function/sum_3const.kt" } task local_variable(type: UnitKonanTest) { source = "codegen/basics/local_variable.kt" } task canonical_name(type: RunKonanTest) { goldValue = "A:foo\nA:qux\n" source = "codegen/basics/canonical_name.kt" } task cast_simple(type: UnitKonanTest) { source = "codegen/basics/cast_simple.kt" } task null_check(type: UnitKonanTest) { source = "codegen/basics/null_check.kt" } task array_to_any(type: RunKonanTest) { disabled = true source = "codegen/basics/array_to_any.kt" } task hello0(type: RunKonanTest) { goldValue = "Hello, world!\n" source = "runtime/basic/hello0.kt" } task hello1(type: RunKonanTest) { goldValue = "Hello World" testData = "Hello World" source = "runtime/basic/hello1.kt" } task hello2(type: RunKonanTest) { goldValue = "you entered 'Hello World'" testData = "Hello World" source = "runtime/basic/hello2.kt" } task hello3(type: RunKonanTest) { goldValue = "239\ntrue\n3.14159\nA\n" source = "runtime/basic/hello3.kt" } task hello4(type: RunKonanTest) { goldValue = "Hello\nПока\n" source = "runtime/basic/hello4.kt" } task tostring0(type: RunKonanTest) { goldValue = "127\n-1\n239\nA\n1122334455\n112233445566778899\n3.14159\n1E+27\n1E-300\ntrue\nfalse\n" source = "runtime/basic/tostring0.kt" } task tostring1(type: RunKonanTest) { goldValue = "ello\n" source = "runtime/basic/tostring1.kt" } task tostring2(type: RunKonanTest) { goldValue = "H e l l o \nHello\n" source = "runtime/basic/tostring2.kt" } task empty_substring(type: RunKonanTest) { goldValue = "\n" source = "runtime/basic/empty_substring.kt" } task array0(type: RunKonanTest) { goldValue = "5\n6\n7\n8\n9\n10\n11\n12\n13\n" source = "runtime/basic/array0.kt" } task array1(type: RunKonanTest) { goldValue = "4 2\n1-1\n69\n38\n" source = "runtime/basic/array1.kt" } task if_else(type: UnitKonanTest) { source = "codegen/branching/if_else.kt" } task when2(type: UnitKonanTest) { source = "codegen/branching/when2.kt" } task when5(type: UnitKonanTest) { source = "codegen/branching/when5.kt" } task when_through(type: UnitKonanTest) { source = "codegen/branching/when_through.kt" } task advanced_when2(type: UnitKonanTest) { source = "codegen/branching/advanced_when2.kt" } task advanced_when5(type: UnitKonanTest) { source = "codegen/branching/advanced_when5.kt" } task bool_yes(type: UnitKonanTest) { source = "codegen/function/boolean.kt" } task plus_eq(type: UnitKonanTest) { source = "codegen/function/plus_eq.kt" } task minus_eq(type: UnitKonanTest) { source = "codegen/function/minus_eq.kt" } task eqeq(type: UnitKonanTest) { source = "codegen/function/eqeq.kt" } task cycle(type: UnitKonanTest) { source = "codegen/cycles/cycle.kt" } task cycle_do(type: UnitKonanTest) { source = "codegen/cycles/cycle_do.kt" } task abstract_super(type: UnitKonanTest) { source = "datagen/rtti/abstract_super.kt" } task vtable1(type: UnitKonanTest) { source = "datagen/rtti/vtable1.kt" } task strdedup1(type: RunKonanTest) { goldValue = "true\ntrue\n" source = "datagen/literals/strdedup1.kt" } task strdedup2(type: RunKonanTest) { // TODO: string deduplication across several components seems to require // linking them as bitcode modules before translating to machine code. disabled = true goldValue = "true\ntrue\n" source = "datagen/literals/strdedup2.kt" } task empty_string(type: RunKonanTest) { goldValue = "\n" source = "datagen/literals/empty_string.kt" } task intrinsic(type: UnitKonanTest) { source = "codegen/function/intrinsic.kt" } task link(type: LinkKonanTest) { source = "link/src/bar.kt" lib = "link/lib" } task for0(type: RunKonanTest) { goldValue = "2\n3\n4\n" source = "runtime/basic/for0.kt" } task throw0(type: RunKonanTest) { goldValue = "Done\n" source = "runtime/basic/throw0.kt" } task statements0(type: RunKonanTest) { goldValue = "239\n238\n30\n29\n" source = "runtime/basic/statements0.kt" } task boxing0(type: RunKonanTest) { disabled = true goldValue = "17\n" source = "runtime/basic/boxing0.kt" } task interface0(type: RunKonanTest) { goldValue = "PASSED\n" source = "runtime/basic/interface0.kt" } task hash0(type: RunKonanTest) { goldValue = "239\n0\n97\n1065353216\n1072693248\n1\n0\ntrue\ntrue\n" source = "runtime/basic/hash0.kt" } task array_list1(type: RunKonanTest) { goldValue = "OK\n" source = "runtime/collections/array_list1.kt" } task listof0(type: RunKonanTest) { goldValue = "abc\n[a, b, c, d]\n[n, s, a]\n" source = "runtime/collections/listof0.kt" } task moderately_large_array(type: RunKonanTest) { goldValue = "0\n" source = "runtime/collections/moderately_large_array.kt" } task string_builder0(type: RunKonanTest) { goldValue = "OK\n" source = "runtime/text/string_builder0.kt" } task catch1(type: RunKonanTest) { goldValue = "Before\nCaught Throwable\nDone\n" source = "runtime/exceptions/catch1.kt" } task catch2(type: RunKonanTest) { goldValue = "Before\nCaught Error\nDone\n" source = "runtime/exceptions/catch2.kt" } task catch7(type: RunKonanTest) { goldValue = "Error happens\n" source = "runtime/exceptions/catch7.kt" } task catch3(type: RunKonanTest) { goldValue = "Before\nCaught Throwable\nDone\n" source = "codegen/try/catch3.kt" } task catch4(type: RunKonanTest) { goldValue = "Before\nCaught Error\nDone\n" source = "codegen/try/catch4.kt" } task catch5(type: RunKonanTest) { goldValue = "Before\nCaught Error\nDone\n" source = "codegen/try/catch5.kt" } task catch6(type: RunKonanTest) { goldValue = "Before\nCaught Error\nDone\n" source = "codegen/try/catch6.kt" } task catch8(type: RunKonanTest) { goldValue = "Error happens\n" source = "codegen/try/catch8.kt" } task finally1(type: RunKonanTest) { goldValue = "Try\nFinally\nDone\n" source = "codegen/try/finally1.kt" } task finally2(type: RunKonanTest) { goldValue = "Try\nCaught Error\nFinally\nDone\n" source = "codegen/try/finally2.kt" } task finally3(type: RunKonanTest) { goldValue = "Try\nFinally\nCaught Error\nDone\n" source = "codegen/try/finally3.kt" } task finally4(type: RunKonanTest) { goldValue = "Try\nCatch\nFinally\nCaught Exception\nDone\n" source = "codegen/try/finally4.kt" } task finally5(type: RunKonanTest) { goldValue = "Done\nFinally\n0\n" source = "codegen/try/finally5.kt" } task finally6(type: RunKonanTest) { goldValue = "Done\nFinally\n1\n" source = "codegen/try/finally6.kt" } task finally7(type: RunKonanTest) { goldValue = "Done\nFinally\n1\n" source = "codegen/try/finally7.kt" } task finally8(type: RunKonanTest) { goldValue = "Finally 1\nFinally 2\n42\n" source = "codegen/try/finally8.kt" } task finally9(type: RunKonanTest) { disabled = true goldValue = "Finally 1\nFinally 2\nAfter\n" source = "codegen/try/finally9.kt" } task scope1(type: RunKonanTest) { goldValue = "1\n" source = "codegen/dataflow/scope1.kt" } task try1(type: RunKonanTest) { goldValue = "5\n" source = "codegen/try/try1.kt" } task try2(type: RunKonanTest) { goldValue = "6\n" source = "codegen/try/try2.kt" } task try3(type: RunKonanTest) { goldValue = "6\n" source = "codegen/try/try3.kt" } task try4(type: RunKonanTest) { goldValue = "Try\n5\n" source = "codegen/try/try4.kt" } task unreachable1(type: RunKonanTest) { goldValue = "1\n" source = "codegen/controlflow/unreachable1.kt" } task break_continue(type: RunKonanTest) { goldValue = "foo@l1\nfoo@l2\nfoo@l2\nfoo@l2\nbar@l1\nbar@l2\nbar@l2\nbar@l2\nqux@t1\nqux@l2\nqux@l2\nqux@l2\n" source = "codegen/controlflow/break.kt" } task range0(type: RunKonanTest) { goldValue = "123\nabcd\n" source = "runtime/collections/range0.kt" } task args0(type: RunKonanTest) { arguments = ["AAA", "BB", "C"] goldValue = "AAA\nBB\nC\n" source = "runtime/basic/args0.kt" } task main_exception(type: RunKonanTest) { // TODO: cannot currently check the output because the exact stacktrace strings are unpredictable. // goldValue = "Uncaught exception from Kotlin's main: Throwable\n" source = "runtime/basic/main_exception.kt" }