如何运行在内存中编译kotlin文件的测试并检查结果?

时间:2017-08-25 19:12:08

标签: java android jvm kotlin kotlinc

到目前为止我已经

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源)编译生成的String,并检查结果而不写入文件。

如果可能,我想在当前类路径中包含所有内容。

2 个答案:

答案 0 :(得分:4)

我发现最简单的方法是使用类似原始问题中的代码并使用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!'

答案 1 :(得分:0)

读取K2JVMCompiler类的源代码,似乎编译器只支持文件编译。深入挖掘,伪造org.jetbrains.kotlin.codegen.KotlinCodegenFacade静态方法compileCorrectFiles的条目似乎过于复杂。

您最好猜测使用文件系统来执行此操作。临时RAM磁盘可能适合您的需求。 (这是内置的macOS for example