Skip to content

Commit 810f28f

Browse files
authored
Verify that tests haven't written anything in the System.out (Kotlin#2882)
* Remove LF tests, each test has its stress on lincheck counterpart * Adjust failing tests, allow junit4 test printing to console
1 parent 4508b13 commit 810f28f

9 files changed

+42
-394
lines changed

kotlinx-coroutines-core/jvm/test/FieldWalker.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import java.util.*
1111
import java.util.Collections.*
1212
import java.util.concurrent.atomic.*
1313
import java.util.concurrent.locks.*
14-
import kotlin.collections.ArrayList
1514
import kotlin.test.*
1615

1716
object FieldWalker {
@@ -154,8 +153,9 @@ object FieldWalker {
154153
while (true) {
155154
val fields = type.declaredFields.filter {
156155
!it.type.isPrimitive
157-
&& (statics || !Modifier.isStatic(it.modifiers))
158-
&& !(it.type.isArray && it.type.componentType.isPrimitive)
156+
&& (statics || !Modifier.isStatic(it.modifiers))
157+
&& !(it.type.isArray && it.type.componentType.isPrimitive)
158+
&& it.name != "previousOut" // System.out from TestBase that we store in a field to restore later
159159
}
160160
fields.forEach { it.isAccessible = true } // make them all accessible
161161
result.addAll(fields)

kotlinx-coroutines-core/jvm/test/TestBase.kt

+34-9
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@ package kotlinx.coroutines
77
import kotlinx.coroutines.internal.*
88
import kotlinx.coroutines.scheduling.*
99
import org.junit.*
10-
import java.lang.Math.*
10+
import java.io.*
1111
import java.util.*
1212
import java.util.concurrent.atomic.*
1313
import kotlin.coroutines.*
14-
import kotlin.math.*
1514
import kotlin.test.*
1615

1716
private val VERBOSE = systemProp("test.verbose", false)
@@ -23,13 +22,13 @@ public actual val isStressTest = System.getProperty("stressTest")?.toBoolean() ?
2322

2423
public val stressTestMultiplierSqrt = if (isStressTest) 5 else 1
2524

25+
private const val SHUTDOWN_TIMEOUT = 1_000L // 1s at most to wait per thread
26+
2627
/**
2728
* Multiply various constants in stress tests by this factor, so that they run longer during nightly stress test.
2829
*/
2930
public actual val stressTestMultiplier = stressTestMultiplierSqrt * stressTestMultiplierSqrt
3031

31-
public val stressTestMultiplierCbrt = cbrt(stressTestMultiplier.toDouble()).roundToInt()
32-
3332
@Suppress("ACTUAL_WITHOUT_EXPECT")
3433
public actual typealias TestResult = Unit
3534

@@ -52,7 +51,10 @@ public actual typealias TestResult = Unit
5251
* }
5352
* ```
5453
*/
55-
public actual open class TestBase actual constructor() {
54+
public actual open class TestBase(private var disableOutCheck: Boolean) {
55+
56+
actual constructor(): this(false)
57+
5658
public actual val isBoundByJsTestTimeout = false
5759
private var actionIndex = AtomicInteger()
5860
private var finished = AtomicBoolean()
@@ -62,9 +64,15 @@ public actual open class TestBase actual constructor() {
6264
private lateinit var threadsBefore: Set<Thread>
6365
private val uncaughtExceptions = Collections.synchronizedList(ArrayList<Throwable>())
6466
private var originalUncaughtExceptionHandler: Thread.UncaughtExceptionHandler? = null
65-
private val SHUTDOWN_TIMEOUT = 1_000L // 1s at most to wait per thread
67+
/*
68+
* System.out that we redefine in order to catch any debugging/diagnostics
69+
* 'println' from main source set.
70+
* NB: We do rely on the name 'previousOut' in the FieldWalker in order to skip its
71+
* processing
72+
*/
73+
private lateinit var previousOut: PrintStream
6674

67-
/**
75+
/**
6876
* Throws [IllegalStateException] like `error` in stdlib, but also ensures that the test will not
6977
* complete successfully even if this exception is consumed somewhere in the test.
7078
*/
@@ -117,7 +125,7 @@ public actual open class TestBase actual constructor() {
117125
}
118126

119127
/**
120-
* Asserts that this it the last action in the test. It must be invoked by any test that used [expect].
128+
* Asserts that this is the last action in the test. It must be invoked by any test that used [expect].
121129
*/
122130
public actual fun finish(index: Int) {
123131
expect(index)
@@ -137,6 +145,16 @@ public actual open class TestBase actual constructor() {
137145
finished.set(false)
138146
}
139147

148+
private object TestOutputStream : PrintStream(object : OutputStream() {
149+
override fun write(b: Int) {
150+
error("Detected unexpected call to 'println' from source code")
151+
}
152+
})
153+
154+
fun println(message: Any?) {
155+
previousOut.println(message)
156+
}
157+
140158
@Before
141159
fun before() {
142160
initPoolsBeforeTest()
@@ -147,6 +165,10 @@ public actual open class TestBase actual constructor() {
147165
e.printStackTrace()
148166
uncaughtExceptions.add(e)
149167
}
168+
if (!disableOutCheck) {
169+
previousOut = System.out
170+
System.setOut(TestOutputStream)
171+
}
150172
}
151173

152174
@After
@@ -158,14 +180,17 @@ public actual open class TestBase actual constructor() {
158180
}
159181
// Shutdown all thread pools
160182
shutdownPoolsAfterTest()
161-
// Check that that are now leftover threads
183+
// Check that are now leftover threads
162184
runCatching {
163185
checkTestThreads(threadsBefore)
164186
}.onFailure {
165187
setError(it)
166188
}
167189
// Restore original uncaught exception handler
168190
Thread.setDefaultUncaughtExceptionHandler(originalUncaughtExceptionHandler)
191+
if (!disableOutCheck) {
192+
System.setOut(previousOut)
193+
}
169194
if (uncaughtExceptions.isNotEmpty()) {
170195
makeError("Expected no uncaught exceptions, but got $uncaughtExceptions")
171196
}

kotlinx-coroutines-core/jvm/test/channels/ChannelLFStressTest.kt

-107
This file was deleted.

0 commit comments

Comments
 (0)