WIP: feature/abstractions (#45)

* Abstraction layer backup

* Removed DataEntity, was unnecessary for now

* Separated network, persistence, entities and interaction, closes #29

* Renamed binding

* Removed build files, example tests

Removed build files, example tests

* Fixed build files were not being ignored all around app

* Updated CI ymls

* Small changes

* Fixed legacy repository package names

* Fixed CQ findings

* Updated Fastlane

* Packaging changes and version upgrades

* Removed core from interactors

* Version bumps

* Added new module graph
This commit is contained in:
Melih Aksoy
2019-10-30 17:27:53 +01:00
committed by GitHub
parent 83e39400a9
commit 88022629e1
103 changed files with 1098 additions and 921 deletions
@@ -0,0 +1,3 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.melih.abstractions" />
@@ -0,0 +1,3 @@
package com.melih.abstractions.data
interface ViewEntity
@@ -0,0 +1,6 @@
package com.melih.abstractions.deliverable
abstract class Reason : Throwable() {
abstract val messageRes: Int
}
@@ -0,0 +1,54 @@
package com.melih.abstractions.deliverable
/**
* Result class that wraps any [Success], [Failure] or [State]
*/
sealed class Result<out T>
//region Subclasses
class Success<out T>(val successData: T) : Result<T>()
class Failure(val errorData: Reason) : Result<Nothing>()
sealed class State : Result<Nothing>() {
class Loading : State()
class Loaded : State()
}
//endregion
//region Extensions
inline fun <T> Result<T>.handle(
stateBlock: (State) -> Unit,
failureBlock: (Reason) -> Unit,
successBlock: (T) -> Unit
) {
when (this) {
is Success -> successBlock(successData)
is Failure -> failureBlock(errorData)
is State -> stateBlock(this)
}
}
inline fun <T> Result<T>.onSuccess(successBlock: (T) -> Unit): Result<T> {
if (this is Success)
successBlock(successData)
return this
}
inline fun <T> Result<T>.onFailure(errorBlock: (Reason) -> Unit): Result<T> {
if (this is Failure)
errorBlock(errorData)
return this
}
inline fun <T> Result<T>.onState(stateBlock: (State) -> Unit): Result<T> {
if (this is State)
stateBlock(this)
return this
}
//endregion
@@ -0,0 +1,8 @@
package com.melih.abstractions.mapper
import com.melih.abstractions.data.ViewEntity
abstract class Mapper<in T, out R : ViewEntity> {
abstract fun convert(t: T): R
}
@@ -0,0 +1,73 @@
package com.melih.abstractions
import com.melih.abstractions.deliverable.Failure
import com.melih.abstractions.deliverable.Reason
import com.melih.abstractions.deliverable.State
import com.melih.abstractions.deliverable.Success
import com.melih.abstractions.deliverable.handle
import io.mockk.called
import io.mockk.spyk
import io.mockk.verify
import org.amshove.kluent.shouldBeInstanceOf
import org.amshove.kluent.shouldEqualTo
import org.junit.jupiter.api.Test
class ResultTest {
private val number = 10
private val success = Success(number)
private val failure = Failure(object : Reason() {
override val messageRes: Int
get() = 10
})
private val state = State.Loading()
private val emptyStateBlock = spyk({ _: State -> })
private val emptyFailureBlock = spyk({ _: Reason -> })
private val emptySuccessBlock = spyk({ _: Int -> })
@Test
fun `Success should only invoke successBlock with correct data`() {
val actualSuccessBlock = spyk({ data: Int ->
data shouldEqualTo number
Unit
})
success.handle(emptyStateBlock, emptyFailureBlock, actualSuccessBlock)
verify { emptyStateBlock wasNot called }
verify { emptyFailureBlock wasNot called }
verify(exactly = 1) { actualSuccessBlock.invoke(any()) }
}
@Test
fun `Failure should only invoke failureBlock with correct error`() {
val actualFailureBlock = spyk({ reason: Reason ->
reason.messageRes shouldEqualTo 10
Unit
})
failure.handle(emptyStateBlock, actualFailureBlock, emptySuccessBlock)
verify { emptySuccessBlock wasNot called }
verify { emptyStateBlock wasNot called }
verify(exactly = 1) { actualFailureBlock.invoke(any()) }
}
@Test
fun `State should only invoke stateBlock with correct state`() {
val actualSuccessBlock = spyk({ state: State ->
state shouldBeInstanceOf State.Loading::class
Unit
})
state.handle(actualSuccessBlock, emptyFailureBlock, emptySuccessBlock)
verify { emptySuccessBlock wasNot called }
verify { emptyFailureBlock wasNot called }
verify(exactly = 1) { actualSuccessBlock.invoke(any()) }
}
}