add ResultAssertions to logic and use in Kotlin 1.3 extension

which means:
- introduce a Kotlin 1.3 extension for atrium-logic
- adjust README installation, no need for the runtime dependency
  any more
- add module-info.java to atrium-logic and atrium-logic-kotlin_1_3
This commit is contained in:
Robert Stoll
2020-07-06 21:56:49 +02:00
parent 3610f31e03
commit 2fba44cc52
21 changed files with 182 additions and 21 deletions

View File

@@ -114,7 +114,6 @@ You can enable them as follows:
```
dependencies {
testImplementation "ch.tutteli.atrium:atrium-api-fluent-en_GB-kotlin_1_3:$atrium_version"
testRuntimeOnly "ch.tutteli.atrium:atrium-domain-robstoll-kotlin_1_3:$atrium_version"
}
```
@@ -140,7 +139,6 @@ And for the aforementioned extensions:
```
dependencies {
testImplementation "ch.tutteli.atrium:atrium-api-infix-en_GB-kotlin_1_3:$atrium_version"
testRuntimeOnly "ch.tutteli.atrium:atrium-domain-robstoll-kotlin_1_3:$atrium_version"
}
```

View File

@@ -3,12 +3,8 @@
package ch.tutteli.atrium.api.fluent.en_GB
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.domain.builders.ExpectImpl
import ch.tutteli.atrium.domain.builders.bigDecimal
import ch.tutteli.atrium.domain.builders.creating.PleaseUseReplacementException
import ch.tutteli.atrium.logic.*
import ch.tutteli.atrium.logic.isEqualIncludingScale
import ch.tutteli.atrium.logic.isNumericallyEqualTo
import java.math.BigDecimal
/**

View File

@@ -1,5 +1,5 @@
module ch.tutteli.atrium.api.fluent.en_GB {
requires ch.tutteli.atrium.domain.builders;
requires ch.tutteli.atrium.logic;
requires kotlin.stdlib;

View File

@@ -2,7 +2,7 @@ description = 'Kotlin 1.3 specific assertion functions and builders for fluent-e
dependencies {
api prefixedProject('api-fluent-en_GB-common')
api prefixedProject('domain-builders-kotlin_1_3-common')
api prefixedProject('logic-kotlin_1_3-common')
testImplementation prefixedProject('specs-common')
}

View File

@@ -1,8 +1,9 @@
package ch.tutteli.atrium.api.fluent.en_GB.kotlin_1_3
import ch.tutteli.atrium.creating.Expect
import ch.tutteli.atrium.domain.builders.ExpectImpl
import ch.tutteli.atrium.domain.builders.kotlin_1_3.result
import ch.tutteli.atrium.logic._logic
import ch.tutteli.atrium.logic.kotlin_1_3.isFailure
import ch.tutteli.atrium.logic.kotlin_1_3.isSuccess
/**
* Expects that the subject of the assertion (a [Result]) is a Success
@@ -13,7 +14,8 @@ import ch.tutteli.atrium.domain.builders.kotlin_1_3.result
*
* @since 0.9.0
*/
fun <E, T : Result<E>> Expect<T>.isSuccess(): Expect<E> = ExpectImpl.result.isSuccess(this).getExpectOfFeature()
fun <E, T : Result<E>> Expect<T>.isSuccess(): Expect<E> =
_logic.isSuccess().getExpectOfFeature()
/**
* Expects that the subject of the assertion (a [Result]) is a Success and
@@ -25,7 +27,7 @@ fun <E, T : Result<E>> Expect<T>.isSuccess(): Expect<E> = ExpectImpl.result.isSu
* @since 0.9.0
*/
fun <E, T : Result<E>> Expect<T>.isSuccess(assertionCreator: Expect<E>.() -> Unit): Expect<T> =
ExpectImpl.result.isSuccess(this).addToInitial(assertionCreator)
_logic.isSuccess().addToInitial(assertionCreator)
/**
* Expects that the subject of the assertion (a [Result]) is a Failure and
@@ -37,7 +39,7 @@ fun <E, T : Result<E>> Expect<T>.isSuccess(assertionCreator: Expect<E>.() -> Uni
* @since 0.9.0
*/
inline fun <reified TExpected : Throwable> Expect<out Result<*>>.isFailure(): Expect<TExpected> =
ExpectImpl.result.isFailure(this, TExpected::class).getExpectOfFeature()
_logic.isFailure(TExpected::class).getExpectOfFeature()
/**
* Expects that the subject of the assertion (a [Result]) is a Failure,
@@ -51,4 +53,4 @@ inline fun <reified TExpected : Throwable> Expect<out Result<*>>.isFailure(): Ex
*/
inline fun <reified TExpected : Throwable> Expect<out Result<*>>.isFailure(
noinline assertionCreator: Expect<TExpected>.() -> Unit
): Expect<TExpected> = ExpectImpl.result.isFailure(this, TExpected::class).addToFeature(assertionCreator)
): Expect<TExpected> = _logic.isFailure(TExpected::class).addToFeature(assertionCreator)

View File

@@ -2,7 +2,7 @@ description = 'Kotlin 1.3 specific assertion functions and builders for fluent-e
dependencies {
api prefixedProject('api-fluent-en_GB-js')
api prefixedProject('domain-builders-kotlin_1_3-js')
api prefixedProject('logic-kotlin_1_3-js')
testImplementation prefixedProject('specs-js')
}

View File

@@ -10,7 +10,7 @@ ext.jacoco_additional = [
dependencies {
api prefixedProject('api-fluent-en_GB-jvm')
api prefixedProject('domain-builders-kotlin_1_3-jvm')
api prefixedProject('logic-kotlin_1_3-jvm')
testImplementation prefixedProject('specs-jvm')
}

View File

@@ -1,6 +1,6 @@
module ch.tutteli.atrium.api.fluent.en_GB.kotlin_1_3 {
requires ch.tutteli.atrium.api.fluent.en_GB;
requires ch.tutteli.atrium.domain.builders.kotlin_1_3;
requires ch.tutteli.atrium.logic.kotlin_1_3;
requires ch.tutteli.kbox;
requires kotlin.stdlib;

View File

@@ -5,6 +5,9 @@ dependencies {
// it is up to the consumer which atrium-translations module is used at runtime
compileOnly prefixedProject('translations-en_GB-common')
testImplementation prefixedProject('api-fluent-en_GB-common')
testImplementation prefixedProject('specs-common')
}

View File

@@ -5,4 +5,7 @@ dependencies {
// it is up to the consumer which atrium-translations module is used at runtime
compileOnly prefixedProject('translations-en_GB-js')
testImplementation prefixedProject('api-fluent-en_GB-js')
testImplementation prefixedProject('specs-js')
}

View File

@@ -0,0 +1,9 @@
module ch.tutteli.atrium.logic {
requires ch.tutteli.atrium.domain.builders;
requires ch.tutteli.niok;
requires kotlin.stdlib;
exports ch.tutteli.atrium.logic;
exports ch.tutteli.atrium.logic.impl to ch.tutteli.atrium.logic.kotlin_1_3;
exports ch.tutteli.atrium.logic.impl.creating.changers to ch.tutteli.atrium.logic.kotlin_1_3;
}

View File

@@ -0,0 +1,20 @@
description = 'The domain logic of the Kotlin 1.3 extension for Atrium as common module.'
dependencies {
implementation prefixedProject('logic-common')
// it is up to the consumer which atrium-translations module is used at runtime
compileOnly prefixedProject('translations-en_GB-common')
testImplementation prefixedProject('api-fluent-en_GB-common')
testImplementation prefixedProject('specs-common')
}
apply from: "$project.projectDir/../../../generateLogic.gradle"
def generateLogic = createGenerateLogicTask(project, "impls", "kotlin_1_3")
compileKotlinCommon.dependsOn(generateLogic)
sourceSets {
main.kotlin.srcDirs += generatedFolder
}

View File

@@ -0,0 +1,20 @@
//---------------------------------------------------
// Generated content, modify:
// logic/generateLogic.gradle
// if necessary - enjoy the day 🙂
//---------------------------------------------------
@file:JvmMultifileClass
@file:JvmName("ImplsKt")
package ch.tutteli.atrium.logic.kotlin_1_3
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.logic.kotlin_1_3.impl.DefaultResultAssertions
@PublishedApi
internal inline val <T> AssertionContainer<T>._resultImpl
get() = getImpl(ResultAssertions::class) { DefaultResultAssertions() }

View File

@@ -0,0 +1,16 @@
//---------------------------------------------------
// Generated content, modify:
// logic/generateLogic.gradle
// if necessary - enjoy the day 🙂
//---------------------------------------------------
package ch.tutteli.atrium.logic.kotlin_1_3
import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.domain.creating.changers.ChangedSubjectPostStep
import ch.tutteli.atrium.domain.creating.changers.ExtractedFeaturePostStep
import kotlin.reflect.KClass
fun <E, T : Result<E>> AssertionContainer<T>.isSuccess(): ExtractedFeaturePostStep<T, E> = _resultImpl.isSuccess(this)
fun <TExpected : Throwable> AssertionContainer<out Result<*>>.isFailure(expectedType: KClass<TExpected>): ChangedSubjectPostStep<Throwable?, TExpected> = _resultImpl.isFailure(this, expectedType)

View File

@@ -0,0 +1,15 @@
package ch.tutteli.atrium.logic.kotlin_1_3
import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.domain.creating.changers.ChangedSubjectPostStep
import ch.tutteli.atrium.domain.creating.changers.ExtractedFeaturePostStep
import kotlin.reflect.KClass
interface ResultAssertions {
fun <E, T : Result<E>> isSuccess(container: AssertionContainer<T>): ExtractedFeaturePostStep<T, E>
fun <TExpected : Throwable> isFailure(
container: AssertionContainer<out Result<*>>,
expectedType: KClass<TExpected>
): ChangedSubjectPostStep<Throwable?, TExpected>
}

View File

@@ -0,0 +1,45 @@
package ch.tutteli.atrium.logic.kotlin_1_3.impl
import ch.tutteli.atrium.core.ExperimentalNewExpectTypes
import ch.tutteli.atrium.core.Option
import ch.tutteli.atrium.creating.AssertionContainer
import ch.tutteli.atrium.creating.FeatureExpect
import ch.tutteli.atrium.creating.FeatureExpectOptions
import ch.tutteli.atrium.domain.creating.changers.ChangedSubjectPostStep
import ch.tutteli.atrium.domain.creating.changers.ExtractedFeaturePostStep
import ch.tutteli.atrium.logic.changeSubject
import ch.tutteli.atrium.logic.extractFeature
import ch.tutteli.atrium.logic.impl.creating.changers.ThrowableThrownFailureHandler
import ch.tutteli.atrium.logic.kotlin_1_3.ResultAssertions
import ch.tutteli.atrium.logic.manualFeature
import ch.tutteli.atrium.logic.toAssertionContainer
import ch.tutteli.atrium.translations.DescriptionResultAssertion.*
import kotlin.reflect.KClass
class DefaultResultAssertions : ResultAssertions {
override fun <E, T : Result<E>> isSuccess(container: AssertionContainer<T>): ExtractedFeaturePostStep<T, E> =
container.extractFeature
.withDescription(VALUE)
.withRepresentationForFailure(IS_NOT_SUCCESS)
.withFeatureExtraction {
Option.someIf(it.isSuccess) { it.getOrThrow() }
}
.withoutOptions()
.build()
@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
@UseExperimental(ExperimentalNewExpectTypes::class)
override fun <TExpected : Throwable> isFailure(
container: AssertionContainer<out Result<*>>,
expectedType: KClass<TExpected>
): ChangedSubjectPostStep<Throwable?, TExpected> =
container.manualFeature(EXCEPTION) { exceptionOrNull() }.getExpectOfFeature().let { previousExpect ->
FeatureExpect(
previousExpect,
FeatureExpectOptions(representationInsteadOfFeature = { it ?: IS_NOT_FAILURE })
)
}.toAssertionContainer().changeSubject.reportBuilder()
.downCastTo(expectedType)
.withFailureHandler(ThrowableThrownFailureHandler())
.build()
}

View File

@@ -0,0 +1,11 @@
description = 'The domain logic of the Kotlin 1.3 extension for Atrium as JS module.'
dependencies {
api prefixedProject('logic-js')
// it is up to the consumer which atrium-translations module is used at runtime
compileOnly prefixedProject('translations-en_GB-js')
testImplementation prefixedProject('api-fluent-en_GB-js')
testImplementation prefixedProject('specs-js')
}

View File

@@ -0,0 +1,11 @@
description = 'The domain logic of the Kotlin 1.3 extension for Atrium as JVM module.'
dependencies {
api prefixedProject('logic-jvm')
// it is up to the consumer which atrium-translations module is used at runtime
compileOnly prefixedProject('translations-en_GB-jvm')
testImplementation prefixedProject('api-fluent-en_GB-jvm')
testImplementation prefixedProject('specs-jvm')
}

View File

@@ -0,0 +1,6 @@
module ch.tutteli.atrium.logic.kotlin_1_3 {
requires ch.tutteli.atrium.logic;
requires kotlin.stdlib;
exports ch.tutteli.atrium.logic.kotlin_1_3;
}

View File

@@ -18,8 +18,8 @@ static def getInterfaces(String path) {
}
}
def createGenerateLogicTask(Project project, String implsFileName) {
String packagePath = "ch/tutteli/atrium/logic"
def createGenerateLogicTask(Project project, String implsFileName, String suffix = '') {
String packagePath = "ch/tutteli/atrium/logic" + (suffix != '' ? "/" + suffix : '')
String generatedFolder = project.generatedFolder
return task('generateLogic', description: 'generates ext. methods for AssertionContainer based on interfaces') {
@@ -49,11 +49,12 @@ def createGenerateLogicTask(Project project, String implsFileName) {
""".stripIndent().replace("\n", ln)
new File("$generatedPath/${implsFileName}.kt").withWriter('utf-8') { w ->
def packageSuffix = suffix != '' ? '.' + suffix : ''
w << header
w << """\
@file:JvmMultifileClass
@file:JvmName("ImplsKt")
package ch.tutteli.atrium.logic
package ch.tutteli.atrium.logic$packageSuffix
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
@@ -63,7 +64,7 @@ def createGenerateLogicTask(Project project, String implsFileName) {
interfaces.forEach {
def type = getType(it)
w << "import ch.tutteli.atrium.logic.impl.Default${type}Assertions$ln"
w << "import ch.tutteli.atrium.logic${packageSuffix}.impl.Default${type}Assertions$ln"
}
w << "$ln"

View File

@@ -60,6 +60,11 @@ include {
}
kotlinJvmJs('logic')
logic('logic-') {
extensions {
kotlinJvmJs('kotlin_1_3')
}
}
translations('translations-') {
kotlinJvmJs('de_CH')