如何在内存中运行编译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?*/) }
这个手动启动编译器,但我想从第一个编译器(生成kotlin源的MyProjectCompiler
生成的字符串在内存中,并检查结果而不写入文件。
如果可能的话,我想包括当前类路径中的所有内容。
读取K2JVMCompiler
类的源代码,似乎编译器只支持编译文件。 深入挖掘,似乎过于复杂,假的org.jetbrains.kotlin.codegen.KotlinCodegenFacade
静态方法的条目compileCorrectFiles
。
你最好猜测它使用文件系统来做到这一点。 临时的RAM磁盘可能适合您的需求。 (例如,这是内置的macOS)
我发现最简单的方法是使用原始问题中的代码,并使用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 }
用于从编译的类创建对象的类加载器:
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!'