如何 运行 测试在内存中编译 kotlin 文件并检查结果?
How do I run tests compiling a kotlin file in memory and check the result?
到目前为止我有
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?*/) }
这会手动启动编译器,但我想在内存中编译第一个编译器(MyProjectCompiler
生成 kotlin 源代码)生成的字符串,并在不写入文件的情况下检查结果。
如果可能,我想包含当前类路径中的所有内容。
看了K2JVMCompiler
class的源码,好像编译器只支持文件编译。深入挖掘,伪造 org.jetbrains.kotlin.codegen.KotlinCodegenFacade
静态方法 compileCorrectFiles
.
的条目似乎过于复杂
您最好猜测是使用文件系统来执行此操作。临时 RAM 磁盘可能适合您的需要。 (这是内置的 macOS for example)
我发现最简单的方法是使用类似于原始问题中的代码的东西并使用 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
}
用于从已编译的 classes:
创建对象的类加载器
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))
加载class作为接口实例
Initializer(compileOutputDir)
.createInstance<Consumer<String>>("com.test.Example")
?.accept("Hello, world!")
输出将符合预期:found: 'Hello, world!'
到目前为止我有
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?*/) }
这会手动启动编译器,但我想在内存中编译第一个编译器(MyProjectCompiler
生成 kotlin 源代码)生成的字符串,并在不写入文件的情况下检查结果。
如果可能,我想包含当前类路径中的所有内容。
看了K2JVMCompiler
class的源码,好像编译器只支持文件编译。深入挖掘,伪造 org.jetbrains.kotlin.codegen.KotlinCodegenFacade
静态方法 compileCorrectFiles
.
您最好猜测是使用文件系统来执行此操作。临时 RAM 磁盘可能适合您的需要。 (这是内置的 macOS for example)
我发现最简单的方法是使用类似于原始问题中的代码的东西并使用 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
}
用于从已编译的 classes:
创建对象的类加载器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))
加载class作为接口实例
Initializer(compileOutputDir)
.createInstance<Consumer<String>>("com.test.Example")
?.accept("Hello, world!")
输出将符合预期:found: 'Hello, world!'