From 448910d4d1046594c031f40a20c69dddc97e5543 Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Fri, 5 Mar 2021 12:22:23 -0800 Subject: [PATCH] Refactoring for integration-tests So that more files can be shared among similar projects. --- .../com/google/devtools/ksp/test/AndroidIT.kt | 2 +- .../devtools/ksp/test/TemporaryTestProject.kt | 15 +- .../test-processor/src/main/kotlin/Builder.kt | 4 - .../src/main/kotlin/BuilderProcessor.kt | 76 ----- .../src/main/kotlin/TestProcessor.kt | 260 ------------------ ...le.devtools.ksp.processing.SymbolProcessor | 2 - .../workload/src/main/java/com/example/A.kt | 18 -- .../src/main/java/com/example/AClass.kt | 10 - 8 files changed, 13 insertions(+), 374 deletions(-) delete mode 100644 integration-tests/src/test/resources/playground-android/test-processor/src/main/kotlin/Builder.kt delete mode 100644 integration-tests/src/test/resources/playground-android/test-processor/src/main/kotlin/BuilderProcessor.kt delete mode 100644 integration-tests/src/test/resources/playground-android/test-processor/src/main/kotlin/TestProcessor.kt delete mode 100644 integration-tests/src/test/resources/playground-android/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessor delete mode 100644 integration-tests/src/test/resources/playground-android/workload/src/main/java/com/example/A.kt delete mode 100644 integration-tests/src/test/resources/playground-android/workload/src/main/java/com/example/AClass.kt diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/AndroidIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/AndroidIT.kt index 15b573b938..c551065171 100644 --- a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/AndroidIT.kt +++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/AndroidIT.kt @@ -11,7 +11,7 @@ import java.util.jar.* class AndroidIT { @Rule @JvmField - val project: TemporaryTestProject = TemporaryTestProject("playground-android") + val project: TemporaryTestProject = TemporaryTestProject("playground-android", "playground") @Test fun testPlaygroundAndroid() { diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/TemporaryTestProject.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/TemporaryTestProject.kt index b449c4a900..e8dc72aa43 100644 --- a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/TemporaryTestProject.kt +++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/TemporaryTestProject.kt @@ -3,13 +3,15 @@ package com.google.devtools.ksp.test import org.junit.rules.TemporaryFolder import java.io.File -class TemporaryTestProject(projectName: String) : TemporaryFolder() { +class TemporaryTestProject(projectName: String, baseProject: String? = null) : TemporaryFolder() { private val testProjectSrc = File("src/test/resources", projectName) + private val baseProjectSrc = baseProject?.let { File("src/test/resources", baseProject) } override fun before() { super.before() - testProjectSrc.copyRecursively(root) + baseProjectSrc?.copyRecursively(root) + testProjectSrc.copyRecursively(root, true) val kotlinVersion = System.getProperty("kotlinVersion") val kspVersion = System.getProperty("kspVersion") @@ -23,6 +25,13 @@ class TemporaryTestProject(projectName: String) : TemporaryFolder() { } fun restore(file: String) { - File(testProjectSrc, file).copyTo(File(root, file), true) + fun copySafe(src: File, dst: File) { + if (src.exists()) + src.copyTo(dst, true) + } + baseProjectSrc?.let { + copySafe(File(baseProjectSrc, file), File(root, file)) + } + copySafe(File(testProjectSrc, file), File(root, file)) } } \ No newline at end of file diff --git a/integration-tests/src/test/resources/playground-android/test-processor/src/main/kotlin/Builder.kt b/integration-tests/src/test/resources/playground-android/test-processor/src/main/kotlin/Builder.kt deleted file mode 100644 index b7e0697fde..0000000000 --- a/integration-tests/src/test/resources/playground-android/test-processor/src/main/kotlin/Builder.kt +++ /dev/null @@ -1,4 +0,0 @@ -package com.example.annotation - -annotation class Builder { -} \ No newline at end of file diff --git a/integration-tests/src/test/resources/playground-android/test-processor/src/main/kotlin/BuilderProcessor.kt b/integration-tests/src/test/resources/playground-android/test-processor/src/main/kotlin/BuilderProcessor.kt deleted file mode 100644 index 0f3b2ab55f..0000000000 --- a/integration-tests/src/test/resources/playground-android/test-processor/src/main/kotlin/BuilderProcessor.kt +++ /dev/null @@ -1,76 +0,0 @@ -import com.google.devtools.ksp.processing.* -import com.google.devtools.ksp.symbol.* -import com.google.devtools.ksp.validate -import java.io.File -import java.io.OutputStream - -fun OutputStream.appendText(str: String) { - this.write(str.toByteArray()) -} -class BuilderProcessor : SymbolProcessor { - lateinit var codeGenerator: CodeGenerator - lateinit var logger: KSPLogger - - override fun init(options: Map, kotlinVersion: KotlinVersion, codeGenerator: CodeGenerator, logger: KSPLogger) { - this.codeGenerator = codeGenerator - this.logger = logger - } - - override fun process(resolver: Resolver): List { - val symbols = resolver.getSymbolsWithAnnotation("com.example.annotation.Builder") - val ret = symbols.filter { !it.validate() } - symbols - .filter { it is KSClassDeclaration && it.validate() } - .map { it.accept(BuilderVisitor(), Unit) } - return ret - } - - inner class BuilderVisitor : KSVisitorVoid() { - override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) { - classDeclaration.primaryConstructor!!.accept(this, data) - } - - override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: Unit) { - val parent = function.parentDeclaration as KSClassDeclaration - val packageName = parent.containingFile!!.packageName.asString() - val className = "${parent.simpleName.asString()}Builder" - val file = codeGenerator.createNewFile(Dependencies(true, function.containingFile!!), packageName , className) - file.appendText("package $packageName\n\n") - file.appendText("import HELLO\n\n") - file.appendText("class $className{\n") - function.parameters.forEach { - val name = it.name!!.asString() - val typeName = StringBuilder(it.type.resolve().declaration.qualifiedName?.asString() ?: "") - val typeArgs = it.type.element!!.typeArguments - if (it.type.element!!.typeArguments.isNotEmpty()) { - typeName.append("<") - typeName.append( - typeArgs.map { - val type = it.type?.resolve() - "${it.variance.label} ${type?.declaration?.qualifiedName?.asString() ?: "ERROR"}" + - if (type?.nullability == Nullability.NULLABLE) "?" else "" - }.joinToString(", ") - ) - typeName.append(">") - } - file.appendText(" private var $name: $typeName? = null\n") - file.appendText(" internal fun with${name.capitalize()}($name: $typeName): $className {\n") - file.appendText(" this.$name = $name\n") - file.appendText(" return this\n") - file.appendText(" }\n\n") - } - file.appendText(" internal fun build(): ${parent.qualifiedName!!.asString()} {\n") - file.appendText(" return ${parent.qualifiedName!!.asString()}(") - file.appendText( - function.parameters.map { - "${it.name!!.asString()}!!" - }.joinToString(", ") - ) - file.appendText(")\n") - file.appendText(" }\n") - file.appendText("}\n") - file.close() - } - } - -} \ No newline at end of file diff --git a/integration-tests/src/test/resources/playground-android/test-processor/src/main/kotlin/TestProcessor.kt b/integration-tests/src/test/resources/playground-android/test-processor/src/main/kotlin/TestProcessor.kt deleted file mode 100644 index 59e78d0d20..0000000000 --- a/integration-tests/src/test/resources/playground-android/test-processor/src/main/kotlin/TestProcessor.kt +++ /dev/null @@ -1,260 +0,0 @@ -import com.google.devtools.ksp.processing.* -import com.google.devtools.ksp.symbol.* -import com.google.devtools.ksp.validate -import java.io.File -import java.io.OutputStream - - -class TestProcessor : SymbolProcessor { - lateinit var codeGenerator: CodeGenerator - lateinit var file: OutputStream - var invoked = false - - fun emit(s: String, indent: String) { - file.appendText("$indent$s\n") - } - - override fun init(options: Map, kotlinVersion: KotlinVersion, codeGenerator: CodeGenerator, logger: KSPLogger) { - this.codeGenerator = codeGenerator - file = codeGenerator.createNewFile(Dependencies(false), "", "TestProcessor", "log") - emit("TestProcessor: init($options)", "") - - val javaFile = codeGenerator.createNewFile(Dependencies(false), "", "Generated", "java") - javaFile.appendText("class Generated {}") - } - - override fun process(resolver: Resolver): List { - if (invoked) { - return emptyList() - } - val fileKt = codeGenerator.createNewFile(Dependencies(false), "", "HELLO", "java") - fileKt.appendText("public class HELLO{\n") - fileKt.appendText("public int foo() { return 1234; }\n") - fileKt.appendText("}") - - val files = resolver.getAllFiles() - emit("TestProcessor: process()", "") - val visitor = TestVisitor() - for (file in files) { - emit("TestProcessor: processing ${file.fileName}", "") - file.accept(visitor, "") - } - invoked = true - return emptyList() - } - - inner class TestVisitor : KSVisitor { - - override fun visitReferenceElement(element: KSReferenceElement, data: String) { - } - - override fun visitModifierListOwner(modifierListOwner: KSModifierListOwner, data: String) { - TODO("Not yet implemented") - } - - override fun visitNode(node: KSNode, data: String) { - TODO("Not yet implemented") - } - - override fun visitPropertyAccessor(accessor: KSPropertyAccessor, data: String) { - TODO("Not yet implemented") - } - - override fun visitDynamicReference(reference: KSDynamicReference, data: String) { - TODO("Not yet implemented") - } - val visited = HashSet() - - private fun checkVisited(symbol: Any): Boolean { - return if (visited.contains(symbol)) { - true - } else { - visited.add(symbol) - false - } - } - - private fun invokeCommonDeclarationApis(declaration: KSDeclaration, indent: String) { - emit( - "${declaration.modifiers.joinToString(" ")} ${declaration.simpleName.asString()}", indent - ) - declaration.annotations.map { it.accept(this, "$indent ") } - if (declaration.parentDeclaration != null) - emit(" enclosing: ${declaration.parentDeclaration!!.qualifiedName?.asString()}", indent) - declaration.containingFile?.let { emit("${it.packageName.asString()}.${it.fileName}", indent) } - declaration.typeParameters.map { it.accept(this, "$indent ") } - } - - override fun visitFile(file: KSFile, data: String) { -// if (!file.packageName.asString().startsWith("eu.kanade.tachiyomi.data")) { -// return -// } - if (checkVisited(file)) return - file.annotations.map{ it.accept(this, "$data ") } - emit(file.packageName.asString(), data) - for (declaration in file.declarations) { - declaration.accept(this, data) - } - } - - override fun visitAnnotation(annotation: KSAnnotation, data: String) { - if (checkVisited(annotation)) return - emit("annotation", data) - annotation.annotationType.accept(this, "$data ") - annotation.arguments.map { it.accept(this, "$data ") } - } - - override fun visitCallableReference(reference: KSCallableReference, data: String) { - if (checkVisited(reference)) return - emit("element: ", data) - reference.functionParameters.map { it.accept(this, "$data ") } - reference.receiverType?.accept(this, "$data receiver") - reference.returnType.accept(this, "$data ") - } - - override fun visitPropertyGetter(getter: KSPropertyGetter, data: String) { - if (checkVisited(getter)) return - emit("propertyGetter: ", data) - getter.annotations.map { it.accept(this, "$data ") } - emit(getter.modifiers.joinToString(" "), data) - getter.returnType?.accept(this, "$data ") - } - - override fun visitPropertySetter(setter: KSPropertySetter, data: String) { - if (checkVisited(setter)) return - emit("propertySetter: ", data) - setter.annotations.map { it.accept(this, "$data ") } - emit(setter.modifiers.joinToString(" "), data) -// setter.parameter.accept(this, "$data ") - } - - override fun visitTypeArgument(typeArgument: KSTypeArgument, data: String) { - if (checkVisited(typeArgument)) return - typeArgument.annotations.map{ it.accept(this, "$data ") } - emit( - when (typeArgument.variance) { - Variance.STAR -> "*" - Variance.COVARIANT -> "out" - Variance.CONTRAVARIANT -> "in" - else -> "" - }, data - ) - typeArgument.type?.accept(this, "$data ") - } - - override fun visitTypeParameter(typeParameter: KSTypeParameter, data: String) { - if (checkVisited(typeParameter)) return - typeParameter.annotations.map{ it.accept(this, "$data ") } - if (typeParameter.isReified) { - emit("reified ", data) - } - emit( - when (typeParameter.variance) { - Variance.COVARIANT -> "out " - Variance.CONTRAVARIANT -> "in " - else -> "" - } + typeParameter.name.asString(), data - ) - if (typeParameter.bounds.isNotEmpty()) { - typeParameter.bounds.map { it.accept(this, "$data ") } - } - } - - override fun visitValueParameter(valueParameter: KSValueParameter, data: String) { - if (checkVisited(valueParameter)) return - valueParameter.annotations.map { it.accept(this, "$data ") } - if (valueParameter.isVararg) { - emit("vararg", "$data ") - } - if (valueParameter.isNoInline) { - emit("noinline", "$data ") - } - if (valueParameter.isCrossInline) { - emit("crossinline ", "$data ") - } - emit(valueParameter.name?.asString() ?: "_", "$data ") - valueParameter.type.accept(this, "$data ") - } - - override fun visitFunctionDeclaration(function: KSFunctionDeclaration, data: String) { - if (checkVisited(function)) return - invokeCommonDeclarationApis(function, data) - for (declaration in function.declarations) { - declaration.accept(this, "$data ") - } - function.parameters.map { it.accept(this, "$data ") } - function.typeParameters.map { it.accept(this, "$data ") } - function.extensionReceiver?.accept(this, "$data extension:") - emit("returnType:", data) - function.returnType?.accept(this, "$data ") - } - - override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: String) { - if (checkVisited(classDeclaration)) return - invokeCommonDeclarationApis(classDeclaration, data) - emit(classDeclaration.classKind.type, data) - for (declaration in classDeclaration.declarations) { - declaration.accept(this, "$data ") - } - classDeclaration.superTypes.map { it.accept(this, "$data ") } - classDeclaration.primaryConstructor?.accept(this, "$data ") - } - - override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: String) { - if (checkVisited(property)) return - invokeCommonDeclarationApis(property, data) - property.type.accept(this, "$data ") - property.extensionReceiver?.accept(this, "$data extension:") - property.setter?.accept(this, "$data ") - property.getter?.accept(this, "$data ") - } - - override fun visitTypeReference(typeReference: KSTypeReference, data: String) { - if (checkVisited(typeReference)) return - typeReference.annotations.map{ it.accept(this, "$data ") } - val type = typeReference.resolve() - type.let { - emit("resolved to: ${it.declaration.qualifiedName?.asString()}", data) - } - //resolved.accept(this, "$data ") - // TODO: KSTypeReferenceJavaImpl hasn't completed yet. - try { - typeReference.element?.accept(this, "$data ") - } catch (e: IllegalStateException) { - emit("TestProcessor: exception: $e", data) - } - } - - override fun visitAnnotated(annotated: KSAnnotated, data: String) { - } - - override fun visitDeclaration(declaration: KSDeclaration, data: String) { - } - - override fun visitDeclarationContainer(declarationContainer: KSDeclarationContainer, data: String) { - } - - override fun visitParenthesizedReference(reference: KSParenthesizedReference, data: String) { - } - - override fun visitClassifierReference(reference: KSClassifierReference, data: String) { - if (checkVisited(reference)) return - if (reference.typeArguments.isNotEmpty()) { - reference.typeArguments.map { it.accept(this, "$data ") } - } - } - - override fun visitTypeAlias(typeAlias: KSTypeAlias, data: String) { - } - - override fun visitValueArgument(valueArgument: KSValueArgument, data: String) { - if (checkVisited(valueArgument)) return - val name = valueArgument.name?.asString() ?: "" - emit("$name: ${valueArgument.value}", data) - valueArgument.annotations.map { it.accept(this, "$data ") } - } - } - -} - - diff --git a/integration-tests/src/test/resources/playground-android/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessor b/integration-tests/src/test/resources/playground-android/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessor deleted file mode 100644 index 3a379b9eaa..0000000000 --- a/integration-tests/src/test/resources/playground-android/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessor +++ /dev/null @@ -1,2 +0,0 @@ -TestProcessor -BuilderProcessor diff --git a/integration-tests/src/test/resources/playground-android/workload/src/main/java/com/example/A.kt b/integration-tests/src/test/resources/playground-android/workload/src/main/java/com/example/A.kt deleted file mode 100644 index 30f65c1a2d..0000000000 --- a/integration-tests/src/test/resources/playground-android/workload/src/main/java/com/example/A.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.example - -import HELLO - -fun main() { - val hello = HELLO() - println(hello.foo()) - - val builder = AClassBuilder() - builder - .withA(1) - .withB("foo") - .withC(2.3) - val aClass : AClass = builder.build() - println(aClass.foo()) -} - - diff --git a/integration-tests/src/test/resources/playground-android/workload/src/main/java/com/example/AClass.kt b/integration-tests/src/test/resources/playground-android/workload/src/main/java/com/example/AClass.kt deleted file mode 100644 index 578b8a38a8..0000000000 --- a/integration-tests/src/test/resources/playground-android/workload/src/main/java/com/example/AClass.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.example - -import com.example.annotation.Builder -import HELLO - -@Builder -class AClass(private val a: Int, val b: String, val c: Double, val d: HELLO) { - val p = "$a, $b, $c" - fun foo() = p -} \ No newline at end of file