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

1
abstractions/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

17
abstractions/build.gradle Normal file
View File

@@ -0,0 +1,17 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: "de.mannodermaus.android-junit5"
apply from: "$rootProject.projectDir/scripts/module.gradle"
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation libraries.kotlin
testImplementation testLibraries.jUnitApi
testImplementation testLibraries.mockk
testImplementation testLibraries.kluent
testRuntimeOnly testLibraries.jUnitEngine
}

View File

21
abstractions/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -0,0 +1,3 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.melih.abstractions" />

View File

@@ -0,0 +1,3 @@
package com.melih.abstractions.data
interface ViewEntity

View File

@@ -0,0 +1,6 @@
package com.melih.abstractions.deliverable
abstract class Reason : Throwable() {
abstract val messageRes: Int
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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()) }
}
}