Skip to content

Instantly share code, notes, and snippets.

@starkej2
Last active July 11, 2019 14:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save starkej2/d778db06585ee4af9d5cb3b823b43144 to your computer and use it in GitHub Desktop.
Save starkej2/d778db06585ee4af9d5cb3b823b43144 to your computer and use it in GitHub Desktop.
RxErrorCollector.kt
/**
* Collects any out-of-lifecycle, undeliverable exceptions that are thrown by RxJava streams.
* If [verifyAutomatically] is true, any tests running under this rule will automatically fail if
* any errors are collected. Alternatively, individual test methods can be checked manually using
* methods such as [assertNoErrors] and [assertFailsWith].
*
* This class was inspired by ideas from: https://github.com/ReactiveX/RxJava/issues/5234
*/
class RxErrorCollector(private val verifyAutomatically: Boolean = true) : TestRule {
private lateinit var errors: List<Throwable>
override fun apply(base: Statement, description: Description): Statement {
return object : Statement() {
override fun evaluate() {
try {
errors = trackPluginErrors()
base.evaluate()
if (verifyAutomatically && !errors.isEmpty()
&& description.getAnnotation(DontAutoVerifyRxErrors::class.java) == null) {
assertNoErrors()
}
} finally {
RxJavaPlugins.reset()
}
}
}
}
private fun trackPluginErrors(): List<Throwable> {
val list = Collections.synchronizedList(ArrayList<Throwable>())
RxJavaPlugins.setErrorHandler { list.add(it) }
return list
}
fun assertNoErrors() {
if (!errors.isEmpty()) {
fail("[${RxErrorCollector::class.simpleName}] ${getErrorMessages()}")
}
}
fun <T : Throwable> assertFailsWith(exceptionClass: KClass<T>) {
if (errors.isEmpty()) {
fail("Expected an exception of $exceptionClass to be thrown, but was completed successfully.")
}
if (errors.size > 1) {
fail("Expected an exception of $exceptionClass to be thrown.\n${getErrorMessages()}")
}
val e = errors.first()
var didExpectedErrorOccur = false
if (e is CompositeException) {
if (e.exceptions.map { it::class }.contains(exceptionClass)) {
didExpectedErrorOccur = true
}
} else if (exceptionClass.isInstance(e)) {
didExpectedErrorOccur = true
}
if (!didExpectedErrorOccur) {
fail("Expected an exception of $exceptionClass to be thrown. \n${getErrorMessages()}")
}
}
private fun getErrorMessages(): String? {
val stringWriter = StringWriter()
errors.forEach { it.printStackTrace(PrintWriter(stringWriter)) }
return "There were ${errors.size} errors: $stringWriter"
}
}
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER,
AnnotationTarget.CLASS,
AnnotationTarget.FILE)
annotation class DontAutoVerifyRxErrors
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment