Repository: Kotlin/kotlinx.coroutines
File: kotlinx-coroutines-test/common/src/TestCoroutineScope.kt (Kotlin)

Code before:
        is TestDispatcher -> {
            scheduler = dispatcher.scheduler
            val ctxScheduler = context[TestCoroutineScheduler]
            if (ctxScheduler != null) {
                require(dispatcher.scheduler === ctxScheduler) {
                    "Both a TestCoroutineScheduler $ctxScheduler and TestDispatcher $dispatcher linked to " +
                        "another scheduler were passed."
                }
            }
            dispatcher
        }
        null -> {
            scheduler = context[TestCoroutineScheduler] ?: TestCoroutineScheduler()
            TestCoroutineDispatcher(scheduler)
        }
        else -> throw IllegalArgumentException("Dispatcher must implement TestDispatcher: $dispatcher")
    }
    val exceptionHandler = context[CoroutineExceptionHandler].run {
        this?.let {
            require(this is UncaughtExceptionCaptor) {
                "coroutineExceptionHandler must implement UncaughtExceptionCaptor: $context"
            }
        }
        this ?: TestCoroutineExceptionHandler()
    }
    val job: Job
    val ownJob: CompletableJob?
    if (context[Job] == null) {
        ownJob = SupervisorJob()
        job = ownJob
    } else {
        ownJob = null
        job = context[Job]!!
    }
    return TestCoroutineScopeImpl(context + scheduler + dispatcher + exceptionHandler + job, ownJob)
}

private inline val CoroutineContext.uncaughtExceptionCaptor: UncaughtExceptionCaptor
    get() {
        val handler = this[CoroutineExceptionHandler]
        return handler as? UncaughtExceptionCaptor ?: throw IllegalArgumentException(
            "TestCoroutineScope requires a UncaughtExceptionCaptor such as " +
                "TestCoroutineExceptionHandler as the CoroutineExceptionHandler"
        )
    }

private inline val CoroutineContext.delayController: DelayController?
    get() {
        val handler = this[ContinuationInterceptor]
        return handler as? DelayController
    }

Review comment (suggestion):
I'm okay with the changes in general.
What puzzles me is the overall sense of passing your own job to `TestCoroutineScope` that does not complete when the scope _semantically_ completes.

Let's not prevent my comment from merging it though, I'll return to it later (it's much easier to review the whole picture again when one has all the details incorporated) 


Code after:
        }
        null -> {
            scheduler = context[TestCoroutineScheduler] ?: TestCoroutineScheduler()
            TestCoroutineDispatcher(scheduler)
        }
        else -> throw IllegalArgumentException("Dispatcher must implement TestDispatcher: $dispatcher")
    }
    val exceptionHandler = context[CoroutineExceptionHandler].run {
        this?.let {
            require(this is UncaughtExceptionCaptor) {
                "coroutineExceptionHandler must implement UncaughtExceptionCaptor: $context"
            }
        }
        this ?: TestCoroutineExceptionHandler()
    }
    val job: Job = context[Job] ?: SupervisorJob()
    return TestCoroutineScopeImpl(context + scheduler + dispatcher + exceptionHandler + job)
}

private inline val CoroutineContext.uncaughtExceptionCaptor: UncaughtExceptionCaptor
    get() {
        val handler = this[CoroutineExceptionHandler]
        return handler as? UncaughtExceptionCaptor ?: throw IllegalArgumentException(
            "TestCoroutineScope requires a UncaughtExceptionCaptor such as " +
                "TestCoroutineExceptionHandler as the CoroutineExceptionHandler"
        )
    }

private inline val CoroutineContext.delayController: DelayController?
    get() {
        val handler = this[ContinuationInterceptor]
        return handler as? DelayController
    }


/**
 * The current virtual time on [testScheduler][TestCoroutineScope.testScheduler].
 * @see TestCoroutineScheduler.currentTime
 */
@ExperimentalCoroutinesApi
public val TestCoroutineScope.currentTime: Long
    get() = coroutineContext.delayController?.currentTime ?: testScheduler.currentTime

/**
 * Advances the [testScheduler][TestCoroutineScope.testScheduler] by [delayTimeMillis] and runs the tasks up to that
 * moment (inclusive).
 *
 * @see TestCoroutineScheduler.advanceTimeBy
 */
@ExperimentalCoroutinesApi
@Deprecated("The name of this function is misleading: it not only advances the time, but also runs the tasks " +