Last active
July 11, 2019 14:44
-
-
Save starkej2/d778db06585ee4af9d5cb3b823b43144 to your computer and use it in GitHub Desktop.
RxErrorCollector.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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