Skip to content

Instantly share code, notes, and snippets.

@timfreiheit
Created February 6, 2018 13:08
Show Gist options
  • Save timfreiheit/be07970ecd09bff7c5291125362e2c57 to your computer and use it in GitHub Desktop.
Save timfreiheit/be07970ecd09bff7c5291125362e2c57 to your computer and use it in GitHub Desktop.
DynamicIntending.kt
import android.app.Activity
import android.app.Instrumentation.ActivityResult
import android.content.Intent
import android.support.test.espresso.intent.Intents
import android.support.test.espresso.intent.Intents.intending
import android.support.test.espresso.matcher.ViewMatchers.assertThat
import org.hamcrest.CoreMatchers.allOf
import org.hamcrest.Description
import org.hamcrest.Matcher
import org.hamcrest.StringDescription
import org.hamcrest.TypeSafeMatcher
import java.util.*
/**
* replacement for [Intents.intending]
* to provide a more flexible way handling and checking intents
*
* usage is basically the same as [Intents.intending]: intents are only captured when any respondWith* method is called on [OngoingStubbing]
*/
fun dynamicIntending(matcher: Matcher<Intent>): OngoingStubbing {
return OngoingStubbing(matcher)
}
class OngoingStubbing internal constructor(private val catchIntentMatcher: Matcher<Intent>) {
private val checkIntentMatchers = ArrayList<Matcher<Intent>>()
fun check(intentMatcher: Matcher<Intent>): OngoingStubbing {
checkIntentMatchers.add(intentMatcher)
return this
}
fun respondWithResultOk(): IntentValidator {
return respondWith(ActivityResult(Activity.RESULT_OK, null))
}
fun respondWithResultCanceled(): IntentValidator {
return respondWith(ActivityResult(Activity.RESULT_CANCELED, null))
}
fun respondWith(resultCode: Int, data: Intent? = null): IntentValidator {
return respondWith(ActivityResult(resultCode, data))
}
/**
* Sets a static response for the intent being stubbed.
*/
fun respondWith(result: ActivityResult): IntentValidator {
val validator = IntentValidator(catchIntentMatcher)
intending(object : TypeSafeMatcher<Intent>() {
override fun matchesSafely(item: Intent): Boolean {
val matches = catchIntentMatcher.matches(item)
if (matches) {
validator.intentWasCalled = true
checkIntent(item)
}
return matches
}
override fun describeTo(description: Description) {
catchIntentMatcher.describeTo(description)
}
}).respondWith(result)
return validator
}
/**
* Sets a response for the intent being stubbed.
*/
fun respondWith(resultCode: Int, prepareResultIntent: (input: Intent, output: Intent) -> Unit): IntentValidator {
val validator = IntentValidator(catchIntentMatcher)
val outputIntent = Intent()
intending(object : TypeSafeMatcher<Intent>() {
override fun matchesSafely(item: Intent): Boolean {
val matches = catchIntentMatcher.matches(item)
if (matches) {
validator.intentWasCalled = true
if (outputIntent.extras != null) {
outputIntent.extras.clear()
}
checkIntent(item)
prepareResultIntent(item, outputIntent)
}
return matches
}
override fun describeTo(description: Description) {
catchIntentMatcher.describeTo(description)
}
}).respondWith(ActivityResult(resultCode, outputIntent))
return validator
}
private fun checkIntent(intent: Intent) {
if (checkIntentMatchers.size == 0) {
return
}
val intentMatcher = allOf(*checkIntentMatchers.toTypedArray())
val description = StringDescription()
description.appendText("'")
intentMatcher.describeTo(description)
description.appendText("' doesn't match the fired intent.")
assertThat<Intent>(description.toString(), intent, intentMatcher)
}
}
/**
* used to check if the intent was fired by the app
*/
class IntentValidator internal constructor(private val matcher: Matcher<Intent>) {
var intentWasCalled = false
fun verifyIntentWasFired() {
if (intentWasCalled) {
return
}
val description = StringDescription()
description.appendText("'")
matcher.describeTo(description)
description.appendText("' was not fired.")
throw AssertionError(description.toString())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment