Kapt3: Add simple AP test with Kotlin

This commit is contained in:
Yan Zhulanow
2016-10-28 20:40:15 +03:00
committed by Yan Zhulanow
parent 5b780ec56c
commit 64046f1e40
10 changed files with 206 additions and 69 deletions
@@ -137,6 +137,7 @@ import org.jetbrains.kotlin.jvm.compiler.*
import org.jetbrains.kotlin.jvm.runtime.AbstractJvm8RuntimeDescriptorLoaderTest
import org.jetbrains.kotlin.jvm.runtime.AbstractJvmRuntimeDescriptorLoaderTest
import org.jetbrains.kotlin.kapt3.test.AbstractJCTreeConverterTest
import org.jetbrains.kotlin.kapt3.test.AbstractKotlinKaptRunnerTest
import org.jetbrains.kotlin.kdoc.AbstractKDocLexerTest
import org.jetbrains.kotlin.lang.resolve.android.test.AbstractAndroidBoxTest
import org.jetbrains.kotlin.lang.resolve.android.test.AbstractAndroidBytecodeShapeTest
@@ -1142,6 +1143,10 @@ fun main(args: Array<String>) {
testClass<AbstractJCTreeConverterTest> {
model("converter")
}
testClass<AbstractKotlinKaptRunnerTest> {
model("kotlinRunner")
}
}
testGroup("plugins/android-extensions/android-extensions-idea/tests", "plugins/android-extensions/android-extensions-idea/testData") {
@@ -23,6 +23,7 @@ import com.sun.tools.javac.main.Option
import com.sun.tools.javac.processing.AnnotationProcessingError
import com.sun.tools.javac.processing.JavacProcessingEnvironment
import com.sun.tools.javac.tree.JCTree
import com.sun.tools.javac.tree.TreeMaker
import com.sun.tools.javac.util.Context
import com.sun.tools.javac.util.Options
import java.io.File
@@ -51,6 +52,7 @@ class KaptError : RuntimeException {
class KaptRunner {
val context = Context()
val compiler: KaptJavaCompiler
val fileManager: JavacFileManager
private val options: Options
init {
@@ -58,11 +60,17 @@ class KaptRunner {
KaptTreeMaker.preRegister(context)
KaptJavaCompiler.preRegister(context)
fileManager = context.get(JavaFileManager::class.java) as JavacFileManager
compiler = JavaCompiler.instance(context) as KaptJavaCompiler
options = Options.instance(context)
}
fun close() {
compiler.close()
fileManager.close()
}
fun parseJavaFiles(
javaSourceFiles: List<File>,
classpath: List<File>
@@ -85,7 +93,8 @@ class KaptRunner {
processors: List<Processor>,
classpath: List<File>,
sourceOutputDir: File,
classOutputDir: File
classOutputDir: File,
additionalSources: JavacList<JCTree.JCCompilationUnit> = JavacList.nil()
) {
options.put(Option.PROC, "only") // Only process annotations
classpath.forEach { options.put(Option.CLASSPATH, it.canonicalPath) }
@@ -106,7 +115,7 @@ class KaptRunner {
val compilerAfterAnnotationProcessing: JavaCompiler? = null
try {
compiler.processAnnotations(compiler.enterTrees(parsedJavaFiles))
compiler.processAnnotations(compiler.enterTrees(parsedJavaFiles + additionalSources))
} catch (e: AnnotationProcessingError) {
throw KaptError(KaptError.Kind.EXCEPTION, e.cause ?: e)
}
@@ -36,11 +36,20 @@ class SyntheticJavaFileObject(
override fun inferBinaryName(path: MutableIterable<File>?) = throw UnsupportedOperationException()
override fun isNameCompatible(simpleName: String?, kind: JavaFileObject.Kind?) = true
override fun isNameCompatible(simpleName: String?, kind: JavaFileObject.Kind?): Boolean {
if (simpleName == null || kind == null) return false
return this.kind == kind && simpleName == clazz.simpleName.toString()
}
override fun getKind() = JavaFileObject.Kind.SOURCE
override fun getName() = compilationUnit.packageName.toString().replace('.', '/') + clazz.name + ".java"
override fun getName(): String {
val packageName = compilationUnit.packageName
if (packageName == null || packageName.toString() == "") {
return clazz.name.toString() + ".java"
}
return packageName.toString().replace('.', '/') + '/' + clazz.simpleName.toString() + ".java"
}
override fun getAccessLevel(): Modifier? {
val flags = clazz.modifiers.getFlags()
@@ -1,63 +0,0 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3.test
import com.intellij.openapi.util.text.StringUtil
import com.sun.tools.javac.comp.CompileStates
import org.jetbrains.kotlin.codegen.CodegenTestCase
import org.jetbrains.kotlin.codegen.CodegenTestUtil
import org.jetbrains.kotlin.kapt3.JCTreeConverter
import org.jetbrains.kotlin.kapt3.Kapt3BuilderFactory
import org.jetbrains.kotlin.kapt3.KaptRunner
import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.util.trimTrailingWhitespacesAndAddNewlineAtEOF
import java.io.File
abstract class AbstractJCTreeConverterTest : CodegenTestCase() {
override fun doMultiFileTest(wholeFile: File, files: List<TestFile>, javaFilesDir: File?) {
val javaSources = javaFilesDir?.let { arrayOf(it) } ?: emptyArray()
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.ALL, *javaSources)
loadMultiFiles(files)
val txtFile = File(wholeFile.parentFile, wholeFile.nameWithoutExtension + ".txt")
val classBuilderFactory = Kapt3BuilderFactory()
val factory = CodegenTestUtil.generateFiles(myEnvironment, myFiles, classBuilderFactory)
val typeMapper = factory.generationState.typeMapper
val kaptRunner = KaptRunner()
try {
val converter = JCTreeConverter(kaptRunner.context, typeMapper, classBuilderFactory.compiledClasses, classBuilderFactory.origins)
val javaFiles = converter.convert()
kaptRunner.compiler.enterTrees(javaFiles)
val actualRaw = javaFiles.joinToString ("\n\n////////////////////\n\n")
val actual = StringUtil.convertLineSeparators(actualRaw.trim({ it <= ' ' })).trimTrailingWhitespacesAndAddNewlineAtEOF()
if (kaptRunner.compiler.shouldStop(CompileStates.CompileState.ENTER)) {
error("There were errors during analysis. See errors above. Stubs:\n\n$actual")
}
KotlinTestUtils.assertEqualsToFile(txtFile, actual)
} finally {
kaptRunner.compiler.close()
}
}
}
@@ -0,0 +1,110 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3.test
import com.intellij.openapi.util.text.StringUtil
import com.sun.tools.javac.comp.CompileStates
import com.sun.tools.javac.tree.JCTree
import org.jetbrains.kotlin.codegen.CodegenTestCase
import org.jetbrains.kotlin.codegen.CodegenTestUtil
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.kapt3.JCTreeConverter
import org.jetbrains.kotlin.kapt3.Kapt3BuilderFactory
import org.jetbrains.kotlin.kapt3.KaptRunner
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.util.trimTrailingWhitespacesAndAddNewlineAtEOF
import org.jetbrains.org.objectweb.asm.tree.ClassNode
import com.sun.tools.javac.util.List as JavacList
import java.io.File
import java.nio.file.Files
abstract class AbstractKotlinKapt3Test : CodegenTestCase() {
protected companion object {
val FILE_SEPARATOR = "\n\n////////////////////\n\n"
}
override fun doMultiFileTest(wholeFile: File, files: List<TestFile>, javaFilesDir: File?) {
val javaSources = javaFilesDir?.let { arrayOf(it) } ?: emptyArray()
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.ALL, *javaSources)
loadMultiFiles(files)
val txtFile = File(wholeFile.parentFile, wholeFile.nameWithoutExtension + ".txt")
val classBuilderFactory = Kapt3BuilderFactory()
val factory = CodegenTestUtil.generateFiles(myEnvironment, myFiles, classBuilderFactory)
val typeMapper = factory.generationState.typeMapper
val kaptRunner = KaptRunner()
try {
check(kaptRunner, typeMapper, classBuilderFactory, txtFile)
} finally {
kaptRunner.close()
}
}
protected fun convert(
kaptRunner: KaptRunner,
typeMapper: KotlinTypeMapper,
compiledClasses: List<ClassNode>,
origins: Map<Any, JvmDeclarationOrigin>
): JavacList<JCTree.JCCompilationUnit> {
val converter = JCTreeConverter(kaptRunner.context, typeMapper, compiledClasses, origins)
return converter.convert()
}
protected abstract fun check(
kaptRunner: KaptRunner,
typeMapper: KotlinTypeMapper,
classBuilderFactory: Kapt3BuilderFactory,
txtFile: File)
}
abstract class AbstractJCTreeConverterTest : AbstractKotlinKapt3Test() {
override fun check(kaptRunner: KaptRunner, typeMapper: KotlinTypeMapper, classBuilderFactory: Kapt3BuilderFactory, txtFile: File) {
val javaFiles = convert(kaptRunner, typeMapper, classBuilderFactory.compiledClasses, classBuilderFactory.origins)
kaptRunner.compiler.enterTrees(javaFiles)
val actualRaw = javaFiles.joinToString (FILE_SEPARATOR)
val actual = StringUtil.convertLineSeparators(actualRaw.trim({ it <= ' ' })).trimTrailingWhitespacesAndAddNewlineAtEOF()
if (kaptRunner.compiler.shouldStop(CompileStates.CompileState.ENTER)) {
error("There were errors during analysis. See errors above. Stubs:\n\n$actual")
}
KotlinTestUtils.assertEqualsToFile(txtFile, actual)
}
}
abstract class AbstractKotlinKaptRunnerTest : AbstractKotlinKapt3Test() {
override fun check(kaptRunner: KaptRunner, typeMapper: KotlinTypeMapper, classBuilderFactory: Kapt3BuilderFactory, txtFile: File) {
val compilationUnits = convert(kaptRunner, typeMapper, classBuilderFactory.compiledClasses, classBuilderFactory.origins)
val sourceOutputDir = Files.createTempDirectory("kaptRunner").toFile()
try {
kaptRunner.doAnnotationProcessing(emptyList(), listOf(KaptRunnerTest.SIMPLE_PROCESSOR),
classpath = listOf(), sourceOutputDir = sourceOutputDir, classOutputDir = sourceOutputDir,
additionalSources = compilationUnits)
val javaFiles = sourceOutputDir.walkTopDown().filter { it.isFile && it.extension == "java" }
val actualRaw = javaFiles.sortedBy { it.name }.joinToString(FILE_SEPARATOR) { it.name + ":\n\n" + it.readText() }
val actual = StringUtil.convertLineSeparators(actualRaw.trim({ it <= ' ' })).trimTrailingWhitespacesAndAddNewlineAtEOF()
KotlinTestUtils.assertEqualsToFile(txtFile, actual)
} finally {
sourceOutputDir.deleteRecursively()
}
}
}
@@ -43,8 +43,8 @@ import javax.lang.model.element.TypeElement
*/
class KaptRunnerTest {
private companion object {
val TEST_DATA_DIR = File("plugins/kapt3/testData/runner")
companion object {
private val TEST_DATA_DIR = File("plugins/kapt3/testData/runner")
val SIMPLE_PROCESSOR = object : AbstractProcessor() {
override fun process(annotations: Set<TypeElement>, roundEnv: RoundEnvironment): Boolean {
@@ -0,0 +1,43 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.kapt3.test;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("plugins/kapt3/testData/kotlinRunner")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class KotlinKaptRunnerTestGenerated extends AbstractKotlinKaptRunnerTest {
public void testAllFilesPresentInKotlinRunner() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("plugins/kapt3/testData/kotlinRunner"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("Simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("plugins/kapt3/testData/kotlinRunner/Simple.kt");
doTest(fileName);
}
}
+19
View File
@@ -0,0 +1,19 @@
package test
internal class Simple {
@MyAnnotation
fun myMethod() {
// do nothing
}
}
internal annotation class MyAnnotation
internal enum class EnumClass {
BLACK, WHITE
}
internal enum class EnumClass2 private constructor(private val blah: String) {
WHITE("A"), RED("B")
}
+4
View File
@@ -0,0 +1,4 @@
MyMethodMyAnnotation.java:
package generated;
class MyMethodMyAnnotation {}
+1
View File
@@ -36,5 +36,6 @@
<orderEntry type="module" module-name="annotation-processing" scope="TEST" />
<orderEntry type="module" module-name="build-common" scope="TEST" />
<orderEntry type="module" module-name="jps-tests" scope="TEST" />
<orderEntry type="module" module-name="kapt3" scope="TEST" />
</component>
</module>