-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce Resolution Strategy pattern implementation
- Loading branch information
Showing
9 changed files
with
376 additions
and
0 deletions.
There are no files selected for viewing
20 changes: 20 additions & 0 deletions
20
app/src/main/java/pro/averin/anton/clean/android/cookbook/ui/common/resolution/Resolution.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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package pro.averin.anton.clean.android.cookbook.ui.common.resolution | ||
|
||
import retrofit2.adapter.rxjava.HttpException | ||
|
||
interface RxHttpResolution { | ||
fun onHttpException(httpException: HttpException) | ||
fun onGenericRxException(t: Throwable) | ||
} | ||
|
||
interface NetworkConnectivityResolution { | ||
fun onConnectivityAvailable() | ||
fun onConnectivityUnavailable() | ||
} | ||
|
||
interface LocationRequestResolution { | ||
fun onNetworkLocationError() | ||
} | ||
|
||
interface Resolution : RxHttpResolution, NetworkConnectivityResolution, LocationRequestResolution { | ||
} |
23 changes: 23 additions & 0 deletions
23
...ain/java/pro/averin/anton/clean/android/cookbook/ui/common/resolution/ResolutionByCase.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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package pro.averin.anton.clean.android.cookbook.ui.common.resolution | ||
|
||
import retrofit2.adapter.rxjava.HttpException | ||
|
||
|
||
abstract class ResolutionByCase : Resolution { | ||
|
||
override fun onHttpException(httpException: HttpException) { | ||
val code = httpException.code() | ||
when (code) { | ||
500 -> onInternalServerError() | ||
503 -> onServiceUnavailable() | ||
404 -> onNotFound() | ||
else -> onInternalServerError() | ||
} | ||
} | ||
|
||
abstract fun onInternalServerError() | ||
|
||
abstract fun onNotFound() | ||
|
||
abstract fun onServiceUnavailable() | ||
} |
36 changes: 36 additions & 0 deletions
36
...rc/main/java/pro/averin/anton/clean/android/cookbook/ui/common/resolution/UIResolution.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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package pro.averin.anton.clean.android.cookbook.ui.common.resolution | ||
|
||
import pro.averin.anton.clean.android.cookbook.R | ||
import javax.inject.Inject | ||
|
||
|
||
open class UIResolution @Inject constructor(val uiResolver: UIResolver) : ResolutionByCase() { | ||
|
||
override fun onConnectivityAvailable() { | ||
uiResolver.hidePersistentSnackBar() | ||
} | ||
|
||
override fun onConnectivityUnavailable() { | ||
uiResolver.showPersistentSnackBar(R.string.error_no_network_connection) | ||
} | ||
|
||
override fun onNotFound() { | ||
uiResolver.showSnackBar(R.string.error_not_found) | ||
} | ||
|
||
override fun onServiceUnavailable() { | ||
uiResolver.showSnackBar(R.string.error_service_unavailable) | ||
} | ||
|
||
override fun onInternalServerError() { | ||
uiResolver.showSnackBar(R.string.error_http_exception) | ||
} | ||
|
||
override fun onGenericRxException(t: Throwable) { | ||
t.printStackTrace() | ||
} | ||
|
||
override fun onNetworkLocationError() { | ||
uiResolver.showSnackBar(R.string.error_enable_gps) | ||
} | ||
} |
35 changes: 35 additions & 0 deletions
35
app/src/main/java/pro/averin/anton/clean/android/cookbook/ui/common/resolution/UIResolver.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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package pro.averin.anton.clean.android.cookbook.ui.common.resolution | ||
|
||
import android.R | ||
import android.support.design.widget.Snackbar | ||
import android.view.ViewGroup | ||
import pro.averin.anton.clean.android.cookbook.di.ActivityScope | ||
import pro.averin.anton.clean.android.cookbook.ui.common.view.BaseActivity | ||
import javax.inject.Inject | ||
|
||
|
||
@ActivityScope | ||
class UIResolver @Inject constructor(var baseActivity: BaseActivity) { | ||
|
||
private val snackbarRoot: ViewGroup | ||
|
||
init { | ||
snackbarRoot = baseActivity.findViewById(R.id.content) as ViewGroup | ||
} | ||
|
||
private var persistentSnackbar: Snackbar? = null | ||
|
||
fun showSnackBar(messageResource: Int) { | ||
Snackbar.make(snackbarRoot, messageResource, Snackbar.LENGTH_LONG).show() | ||
} | ||
|
||
fun showPersistentSnackBar(messageResource: Int) { | ||
persistentSnackbar = Snackbar.make(snackbarRoot, messageResource, Snackbar.LENGTH_INDEFINITE) | ||
persistentSnackbar?.show() | ||
} | ||
|
||
fun hidePersistentSnackBar() { | ||
persistentSnackbar?.dismiss() | ||
} | ||
|
||
} |
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
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
109 changes: 109 additions & 0 deletions
109
...java/pro/averin/anton/clean/android/cookbook/ui/common/resolution/ResolutionByCaseTest.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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package pro.averin.anton.clean.android.cookbook.ui.common.resolution | ||
|
||
import org.junit.Before | ||
import org.junit.Test | ||
import org.junit.runner.RunWith | ||
import org.mockito.BDDMockito | ||
import org.mockito.Mock | ||
import org.powermock.core.classloader.annotations.PrepareForTest | ||
import org.powermock.modules.junit4.PowerMockRunner | ||
import retrofit2.adapter.rxjava.HttpException | ||
|
||
@RunWith(PowerMockRunner::class) | ||
@PrepareForTest(HttpException::class) | ||
class ResolutionByCaseTest { | ||
|
||
@Mock lateinit var testStub: TestStub | ||
lateinit var classToTest: TestResolutionByCase | ||
|
||
@Mock lateinit var httpException: HttpException | ||
@Mock lateinit var genericRxException: Throwable | ||
|
||
val internalServerErrorMessage = "InternalServerError" | ||
val notFoundMessage = "NotFound" | ||
val serviceUnavailableMessage = "ServiceUnavailable" | ||
|
||
@Before | ||
fun setUp() { | ||
classToTest = TestResolutionByCase(testStub) | ||
} | ||
|
||
@Test | ||
fun httpExceptionWith500CallsOnInternalServerError() { | ||
// given | ||
BDDMockito.given(httpException.code()).willReturn(500) | ||
|
||
// when | ||
classToTest.onHttpException(httpException) | ||
|
||
// then | ||
BDDMockito.verify(testStub).callStub(internalServerErrorMessage) | ||
} | ||
|
||
@Test | ||
fun httpExceptionWith503CallsServiceUnavailable() { | ||
// given | ||
BDDMockito.given(httpException.code()).willReturn(503) | ||
|
||
// when | ||
classToTest.onHttpException(httpException) | ||
|
||
// then | ||
BDDMockito.verify(testStub).callStub(serviceUnavailableMessage) | ||
} | ||
|
||
@Test | ||
fun httpExceptionWith404CallsNotFound() { | ||
// given | ||
BDDMockito.given(httpException.code()).willReturn(404) | ||
|
||
// when | ||
classToTest.onHttpException(httpException) | ||
|
||
// then | ||
BDDMockito.verify(testStub).callStub(notFoundMessage) | ||
} | ||
|
||
@Test | ||
fun httpExceptionWithUnknownErrorCallInternalServerError() { | ||
// given | ||
BDDMockito.given(httpException.code()).willReturn(100500) | ||
|
||
// when | ||
classToTest.onHttpException(httpException) | ||
|
||
// then | ||
BDDMockito.verify(testStub).callStub(internalServerErrorMessage) | ||
} | ||
|
||
|
||
interface TestStub { | ||
fun callStub(message: String) | ||
} | ||
|
||
inner class TestResolutionByCase constructor(val testStub: TestStub) : ResolutionByCase() { | ||
override fun onNetworkLocationError() { | ||
} | ||
|
||
override fun onInternalServerError() { | ||
testStub.callStub(internalServerErrorMessage) | ||
} | ||
|
||
override fun onNotFound() { | ||
testStub.callStub(notFoundMessage) | ||
} | ||
|
||
override fun onServiceUnavailable() { | ||
testStub.callStub(serviceUnavailableMessage) | ||
} | ||
|
||
override fun onGenericRxException(t: Throwable) { | ||
} | ||
|
||
override fun onConnectivityAvailable() { | ||
} | ||
|
||
override fun onConnectivityUnavailable() { | ||
} | ||
} | ||
} |
145 changes: 145 additions & 0 deletions
145
...est/java/pro/averin/anton/clean/android/cookbook/ui/common/resolution/UIResolutionTest.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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
package pro.averin.anton.clean.android.cookbook.ui.common.resolution | ||
|
||
import org.junit.Test | ||
import org.junit.runner.RunWith | ||
import org.mockito.InjectMocks | ||
import org.mockito.Mock | ||
import org.powermock.core.classloader.annotations.PrepareForTest | ||
import org.powermock.modules.junit4.PowerMockRunner | ||
import pro.averin.anton.clean.android.cookbook.kotlin.test.any | ||
import pro.averin.anton.clean.android.cookbook.kotlin.test.given | ||
import pro.averin.anton.clean.android.cookbook.kotlin.test.mock | ||
import pro.averin.anton.clean.android.cookbook.kotlin.test.verify | ||
import retrofit2.adapter.rxjava.HttpException | ||
|
||
@RunWith(PowerMockRunner::class) | ||
@PrepareForTest( | ||
UIResolver::class, | ||
HttpException::class | ||
) | ||
class UIResolutionTest { | ||
|
||
@Mock lateinit var uiResolver: UIResolver | ||
|
||
@InjectMocks lateinit var classToTest: UIResolution | ||
|
||
@Test | ||
fun availableConnectivityHidesPersistentSnackBar() { | ||
// when | ||
classToTest.onConnectivityAvailable() | ||
|
||
// then | ||
verify(uiResolver).hidePersistentSnackBar() | ||
} | ||
|
||
@Test | ||
fun unavailableConnectivityShowsPersistentSnackBar() { | ||
// when | ||
classToTest.onConnectivityUnavailable() | ||
|
||
// then | ||
verify(uiResolver).showPersistentSnackBar(any()) | ||
} | ||
|
||
@Test | ||
fun internalServerErrorShowsSnackBar() { | ||
// when | ||
classToTest.onInternalServerError() | ||
|
||
// then | ||
verify(uiResolver).showSnackBar(any()) | ||
} | ||
|
||
@Test | ||
fun serviceUnavailableShowsSnackbar() { | ||
// when | ||
classToTest.onServiceUnavailable() | ||
|
||
// then | ||
verify(uiResolver).showSnackBar(any()) | ||
} | ||
|
||
|
||
@Test | ||
fun notFoundShowsSnackBar() { | ||
// when | ||
classToTest.onNotFound() | ||
|
||
// then | ||
verify(uiResolver).showSnackBar(any()) | ||
} | ||
|
||
@Test | ||
fun genericExceptionIsTracked() { | ||
//given | ||
val genericException = mock<Throwable>() | ||
|
||
// when | ||
classToTest.onGenericRxException(genericException) | ||
|
||
// then | ||
verify(genericException).printStackTrace() | ||
} | ||
|
||
@Test | ||
fun networkLocationErrorShowsSnackbar() { | ||
// when | ||
classToTest.onNetworkLocationError() | ||
|
||
// then | ||
verify(uiResolver).showSnackBar(any()) | ||
} | ||
|
||
@Test | ||
fun http500ExceptionHandledBySnackbarMessage() { | ||
// given | ||
val httpException = mock<HttpException>() | ||
given(httpException.code()).willReturn(500) | ||
|
||
// when | ||
classToTest.onHttpException(httpException) | ||
|
||
// then | ||
verify(uiResolver).showSnackBar(any()) | ||
} | ||
|
||
@Test | ||
fun http503ExceptionHandledBySnackbarMessage() { | ||
// given | ||
val httpException = mock<HttpException>() | ||
given(httpException.code()).willReturn(503) | ||
|
||
// when | ||
classToTest.onHttpException(httpException) | ||
|
||
// then | ||
verify(uiResolver).showSnackBar(any()) | ||
} | ||
|
||
@Test | ||
fun http404ExceptionHandledBySnackbarMessage() { | ||
// given | ||
val httpException = mock<HttpException>() | ||
given(httpException.code()).willReturn(404) | ||
|
||
// when | ||
classToTest.onHttpException(httpException) | ||
|
||
// then | ||
verify(uiResolver).showSnackBar(any()) | ||
} | ||
|
||
@Test | ||
fun httpUnknownExceptionHandeledAsInternalServerError() { | ||
// given | ||
val httpException = mock<HttpException>() | ||
given(httpException.code()).willReturn(505) | ||
|
||
// when | ||
classToTest.onHttpException(httpException) | ||
|
||
// then | ||
verify(uiResolver).showSnackBar(any()) | ||
} | ||
|
||
} |
Oops, something went wrong.