mirror of
https://github.com/melihaksoy/Android-Kotlin-Modulerized-CleanArchitecture.git
synced 2026-06-28 04:46:34 +02:00
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:
@@ -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()) }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user