Как запустить тесты, компилирующие файл kotlin в память и проверить результат?

До сих пор

import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler MyProjectCompiler.initialize("SampleKtFileOutput") .packageName("com.test.sample") .compile(File(someFile.path)) .result { ktSource: String -> K2JVMCompiler() .exec(System.out, /** arguments here?*/) } 

Это вручную запускает компилятор, но я хотел бы скомпилировать полученную String из первого компилятора ( MyProjectCompiler который генерирует источник kotlin) в памяти и проверить результат без записи в файл.

Я хотел бы включить все в текущий класс, если это возможно.

Я нашел самый простой способ сделать это – использовать что-то вроде кода в исходном вопросе и использовать java.io.tmpdir . Вот решение для повторного использования:

Добавьте компилятор kotlin в качестве тестовой зависимости:

 testCompile group: 'org.jetbrains.kotlin', name: 'kotlin-compiler', version: "$kotlin_version" 

Обертка для компилятора:

 object JvmCompile { fun exe(input: File, output: File): Boolean = K2JVMCompiler().run { val args = K2JVMCompilerArguments().apply { freeArgs = listOf(input.absolutePath) loadBuiltInsFromDependencies = true destination = output.absolutePath classpath = System.getProperty("java.class.path") .split(System.getProperty("path.separator")) .filter { it.asFile().exists() && it.asFile().canRead() }.joinToString(":") noStdlib = true noReflect = true skipRuntimeVersionCheck = true reportPerf = true } output.deleteOnExit() execImpl( PrintingMessageCollector( System.out, MessageRenderer.WITHOUT_PATHS, true), Services.EMPTY, args) }.code == 0 } 

Classloader для создания объектов из скомпилированных классов:

 class Initializer(private val root: File) { val loader = URLClassLoader( listOf(root.toURI().toURL()).toTypedArray(), this::class.java.classLoader) @Suppress("UNCHECKED_CAST") inline fun <reified T> loadCompiledObject(clazzName: String): T? = loader.loadClass(clazzName).kotlin.objectInstance as T @Suppress("UNCHECKED_CAST") inline fun <reified T> createInstance(clazzName: String): T? = loader.loadClass(clazzName).kotlin.createInstance() as T } 

Пример тестового примера:

Сначала создайте исходный файл kotlin

 MockClasswriter(""" | |package com.test | |class Example : Consumer<String> { | override fun accept(value: String) { | println("found: '$\value'") | } |} """.trimMargin("|")) .writeToFile(codegenOutputFile) 

Убедитесь, что он компилируется:

 assertTrue(JvmCompile.exe(codegenOutputFile, compileOutputDir)) 

Загрузите класс как экземпляр интерфейса

 Initializer(compileOutputDir) .createInstance<Consumer<String>>("com.test.Example") ?.accept("Hello, world!") 

Результат будет таким, как ожидалось: found: 'Hello, world!'

Читая исходный K2JVMCompiler класса K2JVMCompiler , кажется, что компилятор поддерживает только компиляцию файлов. Копаем глубже, кажется сложнее подделать записи org.jetbrains.kotlin.codegen.KotlinCodegenFacade static method compileCorrectFiles .

Подумайте, как использовать файловую систему для этого. Временный RAM-диск может удовлетворить ваши потребности. ( Например, это встроенный macOS)