Add special tests for interceptRun support

Basically they're built upon basic coroutine tests, but for each of them
different interceptResume implementation are injected
(currently there are 12 of them).

It might be more simple just to generated additional testData, but I see this
more problematic in a sense of further maintenance

Note that all tests add idempotent 'interceptRun' operators,
which just execute given lambda in the current thread

 #KT-14891 Fixed
This commit is contained in:
Denis Zharkov
2016-11-22 12:02:20 +03:00
parent 5ff71e1330
commit 01c21e218a
84 changed files with 780 additions and 37 deletions
+2 -1
View File
@@ -18,5 +18,6 @@
<orderEntry type="module" module-name="descriptor.loader.java" scope="TEST" /> <orderEntry type="module" module-name="descriptor.loader.java" scope="TEST" />
<orderEntry type="module" module-name="frontend.java" scope="TEST" /> <orderEntry type="module" module-name="frontend.java" scope="TEST" />
<orderEntry type="module" module-name="jps-tests" scope="TEST" /> <orderEntry type="module" module-name="jps-tests" scope="TEST" />
<orderEntry type="module" module-name="compiler-tests" scope="TEST" />
</component> </component>
</module> </module>
@@ -31,20 +31,25 @@ private val packagePattern = Pattern.compile("(?m)^\\s*package[ |\t]+([\\w|\\.]*
private val importPattern = Pattern.compile("import[ |\t]([\\w|]*\\.)") private val importPattern = Pattern.compile("import[ |\t]([\\w|]*\\.)")
internal fun genFiles(file: File, fileContent: String, filesHolder: CodegenTestsOnAndroidGenerator.FilesWriter): FqName? { internal fun genFiles(
val testFiles = createTestFiles(file, fileContent) testFileName: String,
filePath: String,
fileContent: String,
filesHolder: CodegenTestsOnAndroidGenerator.FilesWriter
): FqName? {
val testFiles = createTestFiles(testFileName, fileContent)
if (testFiles.filter { it.name.endsWith(".java") }.isNotEmpty()) { if (testFiles.filter { it.name.endsWith(".java") }.isNotEmpty()) {
//TODO support java files //TODO support java files
return null; return null
} }
val ktFiles = testFiles.filter { it.name.endsWith(".kt") } val ktFiles = testFiles.filter { it.name.endsWith(".kt") }
if (ktFiles.isEmpty()) return null if (ktFiles.isEmpty()) return null
val newPackagePrefix = file.path.replace("\\\\|-|\\.|/".toRegex(), "_") val newPackagePrefix = filePath.replace("\\\\|-|\\.|/".toRegex(), "_")
val oldPackage = Ref<FqName>() val oldPackage = Ref<FqName>()
val isSingle = testFiles.size == 1 val isSingle = testFiles.size == 1
val resultFiles = testFiles.map { val resultFiles = testFiles.map {
val fileName = if (isSingle) it.name else file.name.substringBeforeLast(".kt") + "/" + it.name val fileName = if (isSingle) it.name else testFileName.substringBeforeLast(".kt") + "/" + it.name
TestClassInfo( TestClassInfo(
fileName, fileName,
changePackage(newPackagePrefix, it.content, oldPackage), changePackage(newPackagePrefix, it.content, oldPackage),
@@ -77,14 +82,14 @@ internal fun genFiles(file: File, fileContent: String, filesHolder: CodegenTests
val boxFiles = resultFiles.filter { hasBoxMethod(it.content) } val boxFiles = resultFiles.filter { hasBoxMethod(it.content) }
if (boxFiles.size != 1) { if (boxFiles.size != 1) {
println("Several box methods in $file") println("Several box methods in $filePath")
} }
return boxFiles.last().newClassId return boxFiles.last().newClassId
} }
private fun createTestFiles(file: File, expectedText: String): List<CodegenTestCase.TestFile> { private fun createTestFiles(fileName: String, expectedText: String): List<CodegenTestCase.TestFile> {
val files = KotlinTestUtils.createTestFiles(file.name, expectedText, object : KotlinTestUtils.TestFileFactoryNoModules<CodegenTestCase.TestFile>() { val files = KotlinTestUtils.createTestFiles(fileName, expectedText, object : KotlinTestUtils.TestFileFactoryNoModules<CodegenTestCase.TestFile>() {
override fun create(fileName: String, text: String, directives: Map<String, String>): CodegenTestCase.TestFile { override fun create(fileName: String, text: String, directives: Map<String, String>): CodegenTestCase.TestFile {
return CodegenTestCase.TestFile(fileName, text) return CodegenTestCase.TestFile(fileName, text)
} }
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.backend.common.output.OutputFileCollection;
import org.jetbrains.kotlin.cli.common.output.outputUtils.OutputUtilsKt; import org.jetbrains.kotlin.cli.common.output.outputUtils.OutputUtilsKt;
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles; import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles;
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment; import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment;
import org.jetbrains.kotlin.codegen.AbstractAdditionalCoroutineBlackBoxCodegenTest;
import org.jetbrains.kotlin.codegen.CodegenTestFiles; import org.jetbrains.kotlin.codegen.CodegenTestFiles;
import org.jetbrains.kotlin.codegen.GenerationUtils; import org.jetbrains.kotlin.codegen.GenerationUtils;
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime; import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime;
@@ -252,17 +253,46 @@ public class CodegenTestsOnAndroidGenerator extends KtUsefulTestCase {
InTextDirectivesUtils.isDirectiveDefined(fullFileText, "WITH_REFLECT") ? holderFull : holderMock; InTextDirectivesUtils.isDirectiveDefined(fullFileText, "WITH_REFLECT") ? holderFull : holderMock;
filesHolder = fullFileText.contains("+JVM.INHERIT_MULTIFILE_PARTS") ? holderInheritMFP : filesHolder; filesHolder = fullFileText.contains("+JVM.INHERIT_MULTIFILE_PARTS") ? holderInheritMFP : filesHolder;
FqName classWithBoxMethod = AndroidTestGeneratorKt.genFiles(file, fullFileText, filesHolder); if (!generateTest(file.getName(), file.getPath(), fullFileText, printer, filesHolder)) continue;
if (classWithBoxMethod == null)
continue; if (fullFileText.contains(AbstractAdditionalCoroutineBlackBoxCodegenTest.INTERCEPT_RESUME_PLACEHOLDER)) {
int counter = 1;
for (String replacement : AbstractAdditionalCoroutineBlackBoxCodegenTest.ALL_REPLACEMENTS) {
String testFileName = file.getName().replace(".kt", "_" + counter + ".kt");
String filePath = file.getPath().replace(".kt", "_" + counter + ".kt");
generateTest(
testFileName,
filePath,
fullFileText.replace(
AbstractAdditionalCoroutineBlackBoxCodegenTest.INTERCEPT_RESUME_PLACEHOLDER, replacement
),
printer,
filesHolder
);
counter++;
}
}
String generatedTestName = generateTestName(file.getName());
generateTestMethod(printer, generatedTestName, classWithBoxMethod.asString(), StringUtil.escapeStringCharacters(file.getPath()));
} }
} }
} }
} }
private boolean generateTest(
@NotNull String testFileName,
@NotNull String filePath,
@NotNull String fullFileText,
@NotNull Printer printer,
@NotNull FilesWriter filesHolder
) {
FqName classWithBoxMethod = AndroidTestGeneratorKt.genFiles(testFileName, filePath, fullFileText, filesHolder);
if (classWithBoxMethod == null) return false;
String generatedTestName = generateTestName(testFileName);
generateTestMethod(printer, generatedTestName, classWithBoxMethod.asString(), StringUtil.escapeStringCharacters(filePath));
return true;
}
private static boolean hasBoxMethod(String text) { private static boolean hasBoxMethod(String text) {
@@ -7,6 +7,8 @@ class Controller {
} }
suspend fun suspendHere(x: Continuation<Any>) {} suspend fun suspendHere(x: Continuation<Any>) {}
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -1,6 +1,8 @@
// WITH_RUNTIME // WITH_RUNTIME
class Controller { class Controller {
suspend fun suspendHere(x: Continuation<Any>) {} suspend fun suspendHere(x: Continuation<Any>) {}
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -7,6 +7,8 @@ class Controller {
suspend fun <T> await(t: T, c: Continuation<T>) { suspend fun <T> await(t: T, c: Continuation<T>) {
c.resume(t) c.resume(t)
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>): String { fun builder(coroutine c: Controller.() -> Continuation<Unit>): String {
@@ -1,4 +1,5 @@
// WITH_RUNTIME // WITH_RUNTIME
// NO_INTERCEPT_RESUME_TESTS
class Controller { class Controller {
var result = "" var result = ""
@@ -48,4 +49,4 @@ fun box(): String {
if (value != "AC!ED!@*finally.") return "fail: $value" if (value != "AC!ED!@*finally.") return "fail: $value"
return "OK" return "OK"
} }
@@ -1,4 +1,5 @@
// WITH_RUNTIME // WITH_RUNTIME
// NO_INTERCEPT_RESUME_TESTS
class Controller { class Controller {
var result = "" var result = ""
@@ -44,4 +45,4 @@ fun box(): String {
if (value != "OQKQ.") return "fail: break inner loop: $value" if (value != "OQKQ.") return "fail: break inner loop: $value"
return "OK" return "OK"
} }
@@ -1,4 +1,5 @@
// WITH_RUNTIME // WITH_RUNTIME
// NO_INTERCEPT_RESUME_TESTS
class Controller { class Controller {
var result = "" var result = ""
@@ -35,4 +36,4 @@ fun box(): String {
if (value != "1;2;3;.") return "fail: suspend in do..while body: $value" if (value != "1;2;3;.") return "fail: suspend in do..while body: $value"
return "OK" return "OK"
} }
@@ -1,4 +1,5 @@
// WITH_RUNTIME // WITH_RUNTIME
// NO_INTERCEPT_RESUME_TESTS
class Controller { class Controller {
var result = "" var result = ""
@@ -25,4 +26,4 @@ fun box(): String {
if (value != "OK.") return "fail: suspend in for body: $value" if (value != "OK.") return "fail: suspend in for body: $value"
return "OK" return "OK"
} }
@@ -1,4 +1,5 @@
// WITH_RUNTIME // WITH_RUNTIME
// NO_INTERCEPT_RESUME_TESTS
class Controller { class Controller {
var result = "" var result = ""
@@ -24,4 +25,4 @@ fun box(): String {
if (value != "OK.") return "fail: suspend in for body: $value" if (value != "OK.") return "fail: suspend in for body: $value"
return "OK" return "OK"
} }
@@ -1,4 +1,5 @@
// WITH_RUNTIME // WITH_RUNTIME
// NO_INTERCEPT_RESUME_TESTS
class Controller { class Controller {
var result = "" var result = ""
@@ -69,4 +70,4 @@ fun box(): String {
if (value != "O;;") return "fail: suspend in then branch without else: $value" if (value != "O;;") return "fail: suspend in then branch without else: $value"
return "OK" return "OK"
} }
@@ -1,4 +1,5 @@
// WITH_RUNTIME // WITH_RUNTIME
// NO_INTERCEPT_RESUME_TESTS
// Does not work in JVM backend, probably due to bug. It's not clear which behaviour is right. // Does not work in JVM backend, probably due to bug. It's not clear which behaviour is right.
// TODO: fix the bug and enable for JVM backend // TODO: fix the bug and enable for JVM backend
@@ -41,4 +42,4 @@ fun box(): String {
if (value != "suspend(OK);finally;return(OK);") return "fail: $value" if (value != "suspend(OK);finally;return(OK);") return "fail: $value"
return "OK" return "OK"
} }
@@ -1,4 +1,5 @@
// WITH_RUNTIME // WITH_RUNTIME
// NO_INTERCEPT_RESUME_TESTS
// TODO: fix bug in JVM backend and remove this directive // TODO: fix bug in JVM backend and remove this directive
// TARGET_BACKEND: JS // TARGET_BACKEND: JS
@@ -31,4 +32,4 @@ fun box(): String {
if (value != "A;[B][C]!") return "fail: suspend as if condition: $value" if (value != "A;[B][C]!") return "fail: suspend as if condition: $value"
return "OK" return "OK"
} }
@@ -1,4 +1,5 @@
// WITH_RUNTIME // WITH_RUNTIME
// NO_INTERCEPT_RESUME_TESTS
class Controller { class Controller {
var result = "" var result = ""
@@ -45,4 +46,4 @@ fun box(): String {
} }
return "OK" return "OK"
} }
@@ -1,4 +1,5 @@
// WITH_RUNTIME // WITH_RUNTIME
// NO_INTERCEPT_RESUME_TESTS
class Controller { class Controller {
var result = "" var result = ""
@@ -35,4 +36,4 @@ fun box(): String {
if (value != "1;2;3;.") return "fail: suspend in while body: $value" if (value != "1;2;3;.") return "fail: suspend in while body: $value"
return "OK" return "OK"
} }
@@ -7,6 +7,8 @@ class Controller {
fun foo() { fun foo() {
result = true result = true
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -2,6 +2,8 @@ class Controller {
suspend fun suspendHere(a: String = "abc", i: Int = 2, x: Continuation<String>) { suspend fun suspendHere(a: String = "abc", i: Int = 2, x: Continuation<String>) {
x.resume(a + "#" + (i + 1)) x.resume(a + "#" + (i + 1))
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -5,6 +5,8 @@ class Controller {
result++ result++
x.resume("OK") x.resume("OK")
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
@@ -2,6 +2,8 @@ class Controller {
suspend fun <T> suspendHere(v: T, x: Continuation<T>) { suspend fun <T> suspendHere(v: T, x: Continuation<T>) {
x.resume(v) x.resume(v)
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
+2
View File
@@ -51,4 +51,6 @@ class GeneratorController<T>() : AbstractIterator<T>() {
operator fun handleResult(result: Unit, c: Continuation<Nothing>) { operator fun handleResult(result: Unit, c: Continuation<Nothing>) {
done() done()
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
@@ -26,6 +26,8 @@ class Controller {
postponedActions.removeAt(0) postponedActions.removeAt(0)
} }
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -4,6 +4,8 @@ class Controller {
operator fun handleResult(u: Unit, v: Continuation<Nothing>) { operator fun handleResult(u: Unit, v: Continuation<Nothing>) {
ok = true ok = true
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>): String { fun builder(coroutine c: Controller.() -> Continuation<Unit>): String {
@@ -7,6 +7,8 @@ class Controller {
operator fun handleResult(x: Unit, y: Continuation<Nothing>) { operator fun handleResult(x: Unit, y: Continuation<Nothing>) {
isCompleted = true isCompleted = true
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -9,6 +9,8 @@ class Controller {
operator fun handleResult(value: String, y: Continuation<Nothing>) { operator fun handleResult(value: String, y: Continuation<Nothing>) {
log += "return($value);" log += "return($value);"
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>): String { fun builder(coroutine c: Controller.() -> Continuation<Unit>): String {
@@ -1,5 +1,6 @@
// WITH_RUNTIME // WITH_RUNTIME
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// NO_INTERCEPT_RESUME_TESTS
class Controller { class Controller {
suspend fun suspendHere(x: Continuation<Unit>) { suspend fun suspendHere(x: Continuation<Unit>) {
x.resume(Unit) x.resume(Unit)
@@ -16,6 +16,8 @@ class Controller {
suspend inline fun <reified T : Any> suspendInline(x: Continuation<String>) { suspend inline fun <reified T : Any> suspendInline(x: Continuation<String>) {
suspendInline({ T::class.simpleName!! }, x) suspendInline({ T::class.simpleName!! }, x)
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -27,6 +27,8 @@ class Controller {
postponedActions.removeAt(0) postponedActions.removeAt(0)
} }
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(expectException: Boolean = false, coroutine c: Controller.() -> Continuation<Unit>) { fun builder(expectException: Boolean = false, coroutine c: Controller.() -> Continuation<Unit>) {
@@ -3,6 +3,8 @@ class Controller {
suspend fun suspendHere(x: Continuation<String>) { suspend fun suspendHere(x: Continuation<String>) {
x.resume((i++).toString()) x.resume((i++).toString())
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -11,6 +11,8 @@ class Controller {
val y: Any = x val y: Any = x
x.resume(Continuation::class.isInstance(y as Continuation<*>)) x.resume(Continuation::class.isInstance(y as Continuation<*>))
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -2,6 +2,8 @@ class Controller {
suspend fun suspendHere(x: Continuation<Unit>) { suspend fun suspendHere(x: Continuation<Unit>) {
x.resume(Unit) x.resume(Unit)
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -2,6 +2,8 @@ class Controller {
suspend fun suspendHere(x: Continuation<Unit>) { suspend fun suspendHere(x: Continuation<Unit>) {
x.resume(Unit) x.resume(Unit)
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -2,6 +2,8 @@ class Controller {
suspend fun suspendHere(x: Continuation<Unit>) { suspend fun suspendHere(x: Continuation<Unit>) {
x.resume(Unit) x.resume(Unit)
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -2,6 +2,8 @@ class Controller {
suspend fun suspendHere(x: Continuation<Unit>) { suspend fun suspendHere(x: Continuation<Unit>) {
x.resume(Unit) x.resume(Unit)
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -2,6 +2,8 @@ class Controller {
suspend fun suspendHere(x: Continuation<Unit>) { suspend fun suspendHere(x: Continuation<Unit>) {
x.resume(Unit) x.resume(Unit)
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -2,6 +2,8 @@ class Controller {
suspend fun suspendHere(x: Continuation<Unit>) { suspend fun suspendHere(x: Continuation<Unit>) {
x.resume(Unit) x.resume(Unit)
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -4,6 +4,8 @@ class Controller {
suspend fun suspendHere(x: Continuation<Unit>) { suspend fun suspendHere(x: Continuation<Unit>) {
x.resume(Unit) x.resume(Unit)
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -2,6 +2,8 @@ class Controller {
suspend fun suspendHere(x: Continuation<Unit>) { suspend fun suspendHere(x: Continuation<Unit>) {
x.resume(Unit) x.resume(Unit)
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -4,6 +4,8 @@ class Controller {
suspend fun suspendHere(x: Continuation<Unit>) { suspend fun suspendHere(x: Continuation<Unit>) {
x.resume(Unit) x.resume(Unit)
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -2,6 +2,8 @@ class Controller {
suspend fun suspendHere(x: Continuation<Unit>) { suspend fun suspendHere(x: Continuation<Unit>) {
x.resume(Unit) x.resume(Unit)
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -2,6 +2,8 @@ class Controller {
suspend fun suspendHere(x: Continuation<String>) { suspend fun suspendHere(x: Continuation<String>) {
x.resume("OK") x.resume("OK")
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
+2
View File
@@ -7,6 +7,8 @@ class Controller {
operator fun handleResult(x: String, c: Continuation<Nothing>) { operator fun handleResult(x: String, c: Continuation<Nothing>) {
result = x result = x
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>): String { fun builder(coroutine c: Controller.() -> Continuation<Unit>): String {
@@ -2,6 +2,8 @@ class Controller {
suspend fun suspendHere(v: String, x: Continuation<String>) { suspend fun suspendHere(v: String, x: Continuation<String>) {
x.resume(v) x.resume(v)
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.(Long, String) -> Continuation<Unit>) { fun builder(coroutine c: Controller.(Long, String) -> Continuation<Unit>) {
@@ -9,6 +9,8 @@ class Controller {
operator fun handleResult(u: Unit, v: Continuation<Nothing>) { operator fun handleResult(u: Unit, v: Continuation<Nothing>) {
ok = true ok = true
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>): String { fun builder(coroutine c: Controller.() -> Continuation<Unit>): String {
@@ -7,6 +7,8 @@ class Controller {
operator fun handleResult(x: Unit, y: Continuation<Nothing>) { operator fun handleResult(x: Unit, y: Continuation<Nothing>) {
wasHandleResultCalled = true wasHandleResultCalled = true
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -7,6 +7,8 @@ class Controller {
operator fun handleResult(x: Unit, y: Continuation<Nothing>) { operator fun handleResult(x: Unit, y: Continuation<Nothing>) {
wasHandleResultCalled = true wasHandleResultCalled = true
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -9,6 +9,8 @@ class Controller {
operator fun handleResult(u: Unit, v: Continuation<Nothing>) { operator fun handleResult(u: Unit, v: Continuation<Nothing>) {
ok = true ok = true
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>): String { fun builder(coroutine c: Controller.() -> Continuation<Unit>): String {
@@ -2,6 +2,8 @@ class Controller {
suspend fun suspendHere(x: Continuation<String>) { suspend fun suspendHere(x: Continuation<String>) {
x.resume("OK") x.resume("OK")
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -6,6 +6,8 @@ class Controller {
suspend fun suspendHere(x: Continuation<String>) { suspend fun suspendHere(x: Continuation<String>) {
x.resume("OK") x.resume("OK")
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
// MODULE: main(controller) // MODULE: main(controller)
@@ -11,6 +11,8 @@ class Controller {
inline suspend fun String.inlineSuspendHere(x: Continuation<String>) { inline suspend fun String.inlineSuspendHere(x: Continuation<String>) {
suspendHere(x) suspendHere(x)
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
suspend fun Controller.suspendExtension(v: String, x: Continuation<String>) { suspend fun Controller.suspendExtension(v: String, x: Continuation<String>) {
@@ -11,6 +11,8 @@ class Controller {
lastSuspension = null lastSuspension = null
x.resume("56") x.resume("56")
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -11,6 +11,8 @@ class Controller {
lastSuspension = null lastSuspension = null
x.resume("56") x.resume("56")
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -11,6 +11,8 @@ class Controller {
lastSuspension = null lastSuspension = null
x.resume("56") x.resume("56")
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -11,6 +11,8 @@ class Controller {
lastSuspension = null lastSuspension = null
x.resume("56") x.resume("56")
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -27,6 +27,8 @@ class Controller {
postponedActions.removeAt(0) postponedActions.removeAt(0)
} }
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(expectException: Boolean = false, coroutine c: Controller.() -> Continuation<Unit>) { fun builder(expectException: Boolean = false, coroutine c: Controller.() -> Continuation<Unit>) {
@@ -3,6 +3,8 @@ class Controller {
operator fun handleResult(x: Int, y: Continuation<Nothing>) { operator fun handleResult(x: Int, y: Continuation<Nothing>) {
res = x res = x
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>): Int { fun builder(coroutine c: Controller.() -> Continuation<Unit>): Int {
@@ -7,6 +7,8 @@ class Controller {
operator fun handleResult(x: Int, y: Continuation<Nothing>) { operator fun handleResult(x: Int, y: Continuation<Nothing>) {
cResult = x cResult = x
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>): Controller { fun builder(coroutine c: Controller.() -> Continuation<Unit>): Controller {
@@ -9,6 +9,8 @@ class Controller {
operator fun handleResult(x: Int, y: Continuation<Nothing>) { operator fun handleResult(x: Int, y: Continuation<Nothing>) {
cResult = x cResult = x
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>): Controller { fun builder(coroutine c: Controller.() -> Continuation<Unit>): Controller {
@@ -7,6 +7,8 @@ class Controller {
operator fun handleResult(x: Int, y: Continuation<Nothing>) { operator fun handleResult(x: Int, y: Continuation<Nothing>) {
res = x res = x
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>): Int { fun builder(coroutine c: Controller.() -> Continuation<Unit>): Int {
+2
View File
@@ -2,6 +2,8 @@ class Controller {
suspend fun suspendHere(x: Continuation<String>) { suspend fun suspendHere(x: Continuation<String>) {
x.resume("OK") x.resume("OK")
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -2,6 +2,8 @@ class Controller {
suspend fun suspendHere(x: Continuation<String>) { suspend fun suspendHere(x: Continuation<String>) {
x.resumeWithException(RuntimeException("OK")) x.resumeWithException(RuntimeException("OK"))
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -7,6 +7,8 @@ class Controller {
operator fun handleResult(x: Int, y: Continuation<Nothing>) { operator fun handleResult(x: Int, y: Continuation<Nothing>) {
res = x res = x
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>): Int { fun builder(coroutine c: Controller.() -> Continuation<Unit>): Int {
@@ -7,6 +7,8 @@ class Controller {
operator fun handleResult(x: String, c: Continuation<Nothing>) { operator fun handleResult(x: String, c: Continuation<Nothing>) {
globalResult = x globalResult = x
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -6,6 +6,8 @@ class Controller {
suspend fun suspendThere(x: Continuation<String>) { suspend fun suspendThere(x: Continuation<String>) {
x.resume("OK") x.resume("OK")
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -7,6 +7,8 @@ class Controller {
inline suspend fun String.inlineSuspendHere(x: Continuation<String>) { inline suspend fun String.inlineSuspendHere(x: Continuation<String>) {
suspendHere(x) suspendHere(x)
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
suspend fun Controller.suspendExtension(v: String, x: Continuation<String>) { suspend fun Controller.suspendExtension(v: String, x: Continuation<String>) {
@@ -2,6 +2,8 @@ class Controller {
suspend fun suspendHere(v: Int, x: Continuation<Int>) { suspend fun suspendHere(v: Int, x: Continuation<Int>) {
x.resume(v * 2) x.resume(v * 2)
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -6,6 +6,8 @@ class Controller {
suspend fun suspendThere(x: Continuation<String>) { suspend fun suspendThere(x: Continuation<String>) {
x.resume("?") x.resume("?")
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -10,6 +10,8 @@ class Controller {
suspend fun suspendWithDouble(v: Double, x: Continuation<Double>) { suspend fun suspendWithDouble(v: Double, x: Continuation<Double>) {
x.resume(v) x.resume(v)
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -27,6 +27,8 @@ class Controller {
postponedActions.removeAt(0) postponedActions.removeAt(0)
} }
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(expectException: Boolean = false, coroutine c: Controller.() -> Continuation<Unit>) { fun builder(expectException: Boolean = false, coroutine c: Controller.() -> Continuation<Unit>) {
@@ -27,6 +27,8 @@ class Controller {
postponedActions.removeAt(0) postponedActions.removeAt(0)
} }
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(expectException: Boolean = false, coroutine c: Controller.() -> Continuation<Unit>) { fun builder(expectException: Boolean = false, coroutine c: Controller.() -> Continuation<Unit>) {
@@ -2,6 +2,8 @@ class Controller {
suspend fun suspendHere(v: String, x: Continuation<String>) { suspend fun suspendHere(v: String, x: Continuation<String>) {
x.resume(v) x.resume(v)
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -27,6 +27,8 @@ class Controller {
postponedActions.removeAt(0) postponedActions.removeAt(0)
} }
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(expectException: Boolean = false, coroutine c: Controller.() -> Continuation<Unit>) { fun builder(expectException: Boolean = false, coroutine c: Controller.() -> Continuation<Unit>) {
@@ -2,6 +2,8 @@ class Controller {
suspend fun suspendHere(x: Continuation<String>) { suspend fun suspendHere(x: Continuation<String>) {
x.resume("OK") x.resume("OK")
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -2,6 +2,8 @@ class Controller {
suspend fun suspendHere(x: Continuation<String>) { suspend fun suspendHere(x: Continuation<String>) {
x.resume("OK") x.resume("OK")
} }
// INTERCEPT_RESUME_PLACEHOLDER
} }
fun builder(coroutine c: Controller.() -> Continuation<Unit>) { fun builder(coroutine c: Controller.() -> Continuation<Unit>) {
@@ -863,13 +863,24 @@ public class KotlinTestUtils {
assertTestClassPresentByMetadata(testCaseClass, file); assertTestClassPresentByMetadata(testCaseClass, file);
} }
} }
else if (filenamePattern.matcher(file.getName()).matches() && isCompatibleTarget(targetBackend, file)) { else if (filenamePattern.matcher(file.getName()).matches() && isCompatibleTarget(targetBackend, file) &&
!isThereCustomReasonToSkip(file, testCaseClass)) {
assertFilePathPresent(file, rootFile, filePaths); assertFilePathPresent(file, rootFile, filePaths);
} }
} }
} }
} }
private static boolean isThereCustomReasonToSkip(File file, Class<?> aClass) {
if (!aClass.getSuperclass().getSimpleName().equals("AbstractAdditionalCoroutineBlackBoxCodegenTest")) return false;
try {
return InTextDirectivesUtils.isDirectiveDefined(FileUtil.loadFile(file), "// NO_INTERCEPT_RESUME_TESTS");
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
public static void assertAllTestsPresentInSingleGeneratedClass( public static void assertAllTestsPresentInSingleGeneratedClass(
@NotNull Class<?> testCaseClass, @NotNull Class<?> testCaseClass,
@NotNull File testDataDir, @NotNull File testDataDir,
@@ -27,13 +27,15 @@ class ModulesDependenciesTest : TestCase() {
val GENERATORS_MODULE_FILE = File("generators/generators.iml") val GENERATORS_MODULE_FILE = File("generators/generators.iml")
val COMPILER_TESTS_JAVA8_MODULE_FILE = File("compiler/tests-java8/compiler-tests-java8.iml") val COMPILER_TESTS_JAVA8_MODULE_FILE = File("compiler/tests-java8/compiler-tests-java8.iml")
val NON_COMPILER_TESTS_MODULE_FILE = File("non-compiler-tests/non-compiler-tests.iml") val NON_COMPILER_TESTS_MODULE_FILE = File("non-compiler-tests/non-compiler-tests.iml")
val ANDROID_TESTS_MODULE_FILE = File("compiler/android-tests/android-tests.iml")
val COMPILER_TESTS_MODULE_NAME = COMPILER_TESTS_MODULE_FILE.nameWithoutExtension val COMPILER_TESTS_MODULE_NAME = COMPILER_TESTS_MODULE_FILE.nameWithoutExtension
val MODULES_CAN_DEPEND_ON_COMPILER_TESTS = listOf(COMPILER_TESTS_JAVA8_MODULE_FILE, GENERATORS_MODULE_FILE) val MODULES_CAN_DEPEND_ON_COMPILER_TESTS = listOf(COMPILER_TESTS_JAVA8_MODULE_FILE, GENERATORS_MODULE_FILE, ANDROID_TESTS_MODULE_FILE)
fun testModulesPresent() { fun testModulesPresent() {
val modules = listOf( val modules = listOf(
COMPILER_TESTS_MODULE_FILE, GENERATORS_MODULE_FILE, COMPILER_TESTS_JAVA8_MODULE_FILE, NON_COMPILER_TESTS_MODULE_FILE COMPILER_TESTS_MODULE_FILE, GENERATORS_MODULE_FILE, COMPILER_TESTS_JAVA8_MODULE_FILE, NON_COMPILER_TESTS_MODULE_FILE,
ANDROID_TESTS_MODULE_FILE
) )
for (module in modules) { for (module in modules) {
@@ -0,0 +1,120 @@
/*
* 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.codegen
import org.junit.Assert
import java.io.File
abstract class AbstractAdditionalCoroutineBlackBoxCodegenTest : AbstractBlackBoxCodegenTest() {
companion object {
private val callLambda = """
| operator inline fun interceptResume(crossinline x: () -> Unit) {
| x()
| }
""".trimMargin()
private val sendToLambda = """
| operator inline fun interceptResume(crossinline x: () -> Unit) {
| myInvokeLater { x() }
| }
|
| fun myInvokeLater(block: () -> Unit) {
| block()
| }
""".trimMargin()
private val makeRunnableSamConstructor = """
| operator inline fun interceptResume(crossinline x: () -> Unit) {
| myInvokeLater(Runnable { x() })
| }
|
| fun myInvokeLater(r: java.lang.Runnable) {
| r.run()
| }
""".trimMargin()
private val makeRunnableSamAdapter = """
| operator inline fun interceptResume(crossinline x: () -> Unit) {
| val t = Thread { x() }
| t.run() // run in same Thread
| }
|
""".trimMargin()
// That's how asyncUI's implementation should look like (but it should call SwingUtilities.invokeLater instead if Thread)
private val bothSamAndPlainExecution1 = """
| val TRUE = hashCode() % 2 == 0 || hashCode() xor 1 == 1
| operator inline fun interceptResume(crossinline x: () -> Unit) {
| if (TRUE) {
| x()
| } else {
| val t = Thread { x() }
| t.run()
| }
| }
|
""".trimMargin()
private val bothSamAndPlainExecution2 = """
| val FALSE = !(hashCode() % 2 == 0 || hashCode() xor 1 == 1)
| operator inline fun interceptResume(crossinline x: () -> Unit) {
| if (FALSE) {
| x()
| } else {
| val t = Thread { x() }
| t.run()
| }
| }
|
""".trimMargin()
private val noInline = """
| operator fun interceptResume(x: () -> Unit) {
| x()
| }
""".trimMargin()
@JvmField
val ALL_REPLACEMENTS =
listOf(callLambda, sendToLambda, makeRunnableSamConstructor, makeRunnableSamAdapter, bothSamAndPlainExecution1,
bothSamAndPlainExecution2, noInline
)
const val INTERCEPT_RESUME_PLACEHOLDER = "// INTERCEPT_RESUME_PLACEHOLDER"
}
override fun doMultiFileTest(wholeFile: File, files: MutableList<TestFile>, javaFilesDir: File?) {
// add "// NO_INTERCEPT_RESUME_TESTS" directive and run "Generate tests"
// if you think that interceptResume is irrelevant for the test
Assert.assertTrue("No placeholder in $wholeFile", files.any { it.content.contains(INTERCEPT_RESUME_PLACEHOLDER) })
for (replacement in ALL_REPLACEMENTS) {
try {
super.doMultiFileTest(
wholeFile,
files.map { TestFile(it.name, it.content.replace(INTERCEPT_RESUME_PLACEHOLDER, replacement)) },
javaFilesDir
)
}
catch(t: Throwable) {
throw RuntimeException("Fail for replacement: \n$replacement", t)
}
this.initializedClassLoader = null
}
}
}
@@ -0,0 +1,426 @@
/*
* 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.codegen;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TargetBackend;
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("compiler/testData/codegen/box/coroutines")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class AdditionalCoroutineBlackBoxCodegenTestGenerated extends AbstractAdditionalCoroutineBlackBoxCodegenTest {
public void testAllFilesPresentInCoroutines() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("beginWithException.kt")
public void testBeginWithException() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/beginWithException.kt");
doTest(fileName);
}
@TestMetadata("beginWithExceptionNoHandleException.kt")
public void testBeginWithExceptionNoHandleException() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/beginWithExceptionNoHandleException.kt");
doTest(fileName);
}
@TestMetadata("coercionToUnit.kt")
public void testCoercionToUnit() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/coercionToUnit.kt");
doTest(fileName);
}
@TestMetadata("controllerAccessFromInnerLambda.kt")
public void testControllerAccessFromInnerLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/controllerAccessFromInnerLambda.kt");
doTest(fileName);
}
@TestMetadata("defaultParametersInSuspend.kt")
public void testDefaultParametersInSuspend() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/defaultParametersInSuspend.kt");
doTest(fileName);
}
@TestMetadata("emptyClosure.kt")
public void testEmptyClosure() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/emptyClosure.kt");
doTest(fileName);
}
@TestMetadata("falseUnitCoercion.kt")
public void testFalseUnitCoercion() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/falseUnitCoercion.kt");
doTest(fileName);
}
@TestMetadata("generate.kt")
public void testGenerate() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/generate.kt");
doTest(fileName);
}
@TestMetadata("handleException.kt")
public void testHandleException() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/handleException.kt");
doTest(fileName);
}
@TestMetadata("handleResultCallEmptyBody.kt")
public void testHandleResultCallEmptyBody() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/handleResultCallEmptyBody.kt");
doTest(fileName);
}
@TestMetadata("handleResultNonUnitExpression.kt")
public void testHandleResultNonUnitExpression() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/handleResultNonUnitExpression.kt");
doTest(fileName);
}
@TestMetadata("handleResultSuspended.kt")
public void testHandleResultSuspended() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/handleResultSuspended.kt");
doTest(fileName);
}
@TestMetadata("inlineSuspendFunction.kt")
public void testInlineSuspendFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/inlineSuspendFunction.kt");
doTest(fileName);
}
@TestMetadata("inlinedTryCatchFinally.kt")
public void testInlinedTryCatchFinally() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/inlinedTryCatchFinally.kt");
doTest(fileName);
}
@TestMetadata("innerSuspensionCalls.kt")
public void testInnerSuspensionCalls() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/innerSuspensionCalls.kt");
doTest(fileName);
}
@TestMetadata("instanceOfContinuation.kt")
public void testInstanceOfContinuation() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/instanceOfContinuation.kt");
doTest(fileName);
}
@TestMetadata("iterateOverArray.kt")
public void testIterateOverArray() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/iterateOverArray.kt");
doTest(fileName);
}
@TestMetadata("kt12958.kt")
public void testKt12958() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/kt12958.kt");
doTest(fileName);
}
@TestMetadata("lambdaParameters.kt")
public void testLambdaParameters() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lambdaParameters.kt");
doTest(fileName);
}
@TestMetadata("lastExpressionIsLoop.kt")
public void testLastExpressionIsLoop() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lastExpressionIsLoop.kt");
doTest(fileName);
}
@TestMetadata("lastStatementInc.kt")
public void testLastStatementInc() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lastStatementInc.kt");
doTest(fileName);
}
@TestMetadata("lastStementAssignment.kt")
public void testLastStementAssignment() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lastStementAssignment.kt");
doTest(fileName);
}
@TestMetadata("lastUnitExpression.kt")
public void testLastUnitExpression() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lastUnitExpression.kt");
doTest(fileName);
}
@TestMetadata("manualContinuationImpl.kt")
public void testManualContinuationImpl() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/manualContinuationImpl.kt");
doTest(fileName);
}
@TestMetadata("multipleInvokeCalls.kt")
public void testMultipleInvokeCalls() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multipleInvokeCalls.kt");
doTest(fileName);
}
@TestMetadata("multipleInvokeCallsInsideInlineLambda1.kt")
public void testMultipleInvokeCallsInsideInlineLambda1() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multipleInvokeCallsInsideInlineLambda1.kt");
doTest(fileName);
}
@TestMetadata("multipleInvokeCallsInsideInlineLambda2.kt")
public void testMultipleInvokeCallsInsideInlineLambda2() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multipleInvokeCallsInsideInlineLambda2.kt");
doTest(fileName);
}
@TestMetadata("multipleInvokeCallsInsideInlineLambda3.kt")
public void testMultipleInvokeCallsInsideInlineLambda3() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multipleInvokeCallsInsideInlineLambda3.kt");
doTest(fileName);
}
@TestMetadata("nestedTryCatch.kt")
public void testNestedTryCatch() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/nestedTryCatch.kt");
doTest(fileName);
}
@TestMetadata("noSuspensionPoints.kt")
public void testNoSuspensionPoints() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/noSuspensionPoints.kt");
doTest(fileName);
}
@TestMetadata("nonLocalReturnFromInlineLambda.kt")
public void testNonLocalReturnFromInlineLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/nonLocalReturnFromInlineLambda.kt");
doTest(fileName);
}
@TestMetadata("nonLocalReturnFromInlineLambdaDeep.kt")
public void testNonLocalReturnFromInlineLambdaDeep() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/nonLocalReturnFromInlineLambdaDeep.kt");
doTest(fileName);
}
@TestMetadata("returnByLabel.kt")
public void testReturnByLabel() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/returnByLabel.kt");
doTest(fileName);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/simple.kt");
doTest(fileName);
}
@TestMetadata("simpleException.kt")
public void testSimpleException() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/simpleException.kt");
doTest(fileName);
}
@TestMetadata("simpleWithHandleResult.kt")
public void testSimpleWithHandleResult() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/simpleWithHandleResult.kt");
doTest(fileName);
}
@TestMetadata("statementLikeLastExpression.kt")
public void testStatementLikeLastExpression() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/statementLikeLastExpression.kt");
doTest(fileName);
}
@TestMetadata("suspendDelegation.kt")
public void testSuspendDelegation() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendDelegation.kt");
doTest(fileName);
}
@TestMetadata("suspendExtension.kt")
public void testSuspendExtension() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendExtension.kt");
doTest(fileName);
}
@TestMetadata("suspendFromInlineLambda.kt")
public void testSuspendFromInlineLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendFromInlineLambda.kt");
doTest(fileName);
}
@TestMetadata("suspendInCycle.kt")
public void testSuspendInCycle() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendInCycle.kt");
doTest(fileName);
}
@TestMetadata("suspendInTheMiddleOfObjectConstruction.kt")
public void testSuspendInTheMiddleOfObjectConstruction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/suspendInTheMiddleOfObjectConstruction.kt");
doTest(fileName);
}
@TestMetadata("tryCatchFinallyWithHandleResult.kt")
public void testTryCatchFinallyWithHandleResult() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tryCatchFinallyWithHandleResult.kt");
doTest(fileName);
}
@TestMetadata("tryCatchWithHandleResult.kt")
public void testTryCatchWithHandleResult() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tryCatchWithHandleResult.kt");
doTest(fileName);
}
@TestMetadata("tryFinallyInsideInlineLambda.kt")
public void testTryFinallyInsideInlineLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tryFinallyInsideInlineLambda.kt");
doTest(fileName);
}
@TestMetadata("tryFinallyWithHandleResult.kt")
public void testTryFinallyWithHandleResult() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/tryFinallyWithHandleResult.kt");
doTest(fileName);
}
@TestMetadata("varValueConflictsWithTable.kt")
public void testVarValueConflictsWithTable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/varValueConflictsWithTable.kt");
doTest(fileName);
}
@TestMetadata("varValueConflictsWithTableSameSort.kt")
public void testVarValueConflictsWithTableSameSort() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/varValueConflictsWithTableSameSort.kt");
doTest(fileName);
}
@TestMetadata("compiler/testData/codegen/box/coroutines/controlFlow")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ControlFlow extends AbstractAdditionalCoroutineBlackBoxCodegenTest {
public void testAllFilesPresentInControlFlow() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/controlFlow"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
}
@TestMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class IntLikeVarSpilling extends AbstractAdditionalCoroutineBlackBoxCodegenTest {
public void testAllFilesPresentInIntLikeVarSpilling() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/intLikeVarSpilling"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("complicatedMerge.kt")
public void testComplicatedMerge() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling/complicatedMerge.kt");
doTest(fileName);
}
@TestMetadata("i2bResult.kt")
public void testI2bResult() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling/i2bResult.kt");
doTest(fileName);
}
@TestMetadata("loadFromBooleanArray.kt")
public void testLoadFromBooleanArray() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling/loadFromBooleanArray.kt");
doTest(fileName);
}
@TestMetadata("loadFromByteArray.kt")
public void testLoadFromByteArray() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling/loadFromByteArray.kt");
doTest(fileName);
}
@TestMetadata("noVariableInTable.kt")
public void testNoVariableInTable() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling/noVariableInTable.kt");
doTest(fileName);
}
@TestMetadata("sameIconst1ManyVars.kt")
public void testSameIconst1ManyVars() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling/sameIconst1ManyVars.kt");
doTest(fileName);
}
@TestMetadata("usedInArrayStore.kt")
public void testUsedInArrayStore() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling/usedInArrayStore.kt");
doTest(fileName);
}
@TestMetadata("usedInMethodCall.kt")
public void testUsedInMethodCall() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling/usedInMethodCall.kt");
doTest(fileName);
}
@TestMetadata("usedInPutfield.kt")
public void testUsedInPutfield() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling/usedInPutfield.kt");
doTest(fileName);
}
@TestMetadata("usedInVarStore.kt")
public void testUsedInVarStore() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intLikeVarSpilling/usedInVarStore.kt");
doTest(fileName);
}
}
@TestMetadata("compiler/testData/codegen/box/coroutines/multiModule")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class MultiModule extends AbstractAdditionalCoroutineBlackBoxCodegenTest {
public void testAllFilesPresentInMultiModule() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/multiModule"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/simple.kt");
doTest(fileName);
}
@TestMetadata("suspendExtension.kt")
public void testSuspendExtension() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/suspendExtension.kt");
doTest(fileName);
}
}
}
@@ -240,6 +240,10 @@ fun main(args: Array<String>) {
model("codegen/boxAgainstJava") model("codegen/boxAgainstJava")
} }
testClass<AbstractAdditionalCoroutineBlackBoxCodegenTest> {
model("codegen/box/coroutines")
}
testClass<AbstractScriptCodegenTest>() { testClass<AbstractScriptCodegenTest>() {
model("codegen/script", extension = "kts") model("codegen/script", extension = "kts")
} }
@@ -1118,7 +1122,7 @@ fun main(args: Array<String>) {
testClass<AbstractAnnotationProcessingTest>() { testClass<AbstractAnnotationProcessingTest>() {
model("wrappers", recursive = true, extension = "kt") model("wrappers", recursive = true, extension = "kt")
} }
testClass<AbstractBytecodeListingTestForSourceRetention>() { testClass<AbstractBytecodeListingTestForSourceRetention>() {
model("sourceRetention", extension = "kt") model("sourceRetention", extension = "kt")
} }
@@ -235,7 +235,7 @@ public class SimpleTestClassModel implements TestClassModel {
} }
@Override @Override
public boolean shouldBeGenerated() { public boolean shouldBeGenerated(@NotNull String baseClassName) {
return true; return true;
} }
} }
@@ -20,12 +20,14 @@ import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.codegen.AbstractAdditionalCoroutineBlackBoxCodegenTest;
import org.jetbrains.kotlin.test.InTextDirectivesUtils; import org.jetbrains.kotlin.test.InTextDirectivesUtils;
import org.jetbrains.kotlin.test.KotlinTestUtils; import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TargetBackend; import org.jetbrains.kotlin.test.TargetBackend;
import org.jetbrains.kotlin.utils.Printer; import org.jetbrains.kotlin.utils.Printer;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@@ -102,8 +104,19 @@ public class SimpleTestMethodModel implements TestMethodModel {
} }
@Override @Override
public boolean shouldBeGenerated() { public boolean shouldBeGenerated(@NotNull String baseClassName) {
return InTextDirectivesUtils.isCompatibleTarget(targetBackend, file); if (!InTextDirectivesUtils.isCompatibleTarget(targetBackend, file)) {
return false;
}
if (!baseClassName.equals(AbstractAdditionalCoroutineBlackBoxCodegenTest.class.getSimpleName())) return true;
try {
return !InTextDirectivesUtils.isDirectiveDefined(FileUtil.loadFile(file), "// NO_INTERCEPT_RESUME_TESTS");
}
catch (IOException e) {
throw new RuntimeException(e);
}
} }
@NotNull @NotNull
@@ -162,7 +162,7 @@ public class SingleClassTestModel implements TestClassModel {
} }
@Override @Override
public boolean shouldBeGenerated() { public boolean shouldBeGenerated(@NotNull String baseClassName) {
return true; return true;
} }
} }
@@ -164,7 +164,7 @@ public class TestGenerator {
for (Iterator<MethodModel> iterator = testMethods.iterator(); iterator.hasNext(); ) { for (Iterator<MethodModel> iterator = testMethods.iterator(); iterator.hasNext(); ) {
MethodModel methodModel = iterator.next(); MethodModel methodModel = iterator.next();
if (!methodModel.shouldBeGenerated()) continue; if (!methodModel.shouldBeGenerated(baseTestClassName)) continue;
generateTestMethod(p, methodModel); generateTestMethod(p, methodModel);
if (iterator.hasNext() || !innerTestClasses.isEmpty()) { if (iterator.hasNext() || !innerTestClasses.isEmpty()) {
@@ -188,11 +188,11 @@ public class TestGenerator {
private static void generateTestMethod(Printer p, MethodModel methodModel) { private static void generateTestMethod(Printer p, MethodModel methodModel) {
generateMetadata(p, methodModel); generateMetadata(p, methodModel);
methodModel.generateSignature(p); methodModel.generateSignature(p);
p.printWithNoIndent(" {"); p.printWithNoIndent(" {");
p.println(); p.println();
p.pushIndent(); p.pushIndent();
methodModel.generateBody(p); methodModel.generateBody(p);
@@ -31,7 +31,7 @@ interface TestClassModel : TestEntityModel {
} }
interface MethodModel : TestEntityModel { interface MethodModel : TestEntityModel {
fun shouldBeGenerated(): Boolean = true fun shouldBeGenerated(baseClassName: String): Boolean = true
fun generateSignature(p: Printer) fun generateSignature(p: Printer)
fun generateBody(p: Printer) fun generateBody(p: Printer)
} }
@@ -40,4 +40,4 @@ interface TestMethodModel : MethodModel {
override fun generateSignature(p: Printer) { override fun generateSignature(p: Printer) {
p.print("public void $name() throws Exception") p.print("public void $name() throws Exception")
} }
} }