mirror of
https://github.com/jlengrand/atrium.git
synced 2026-03-10 08:01:19 +00:00
deprecate ExpectBuilder and introduce RootExpectBuilder in logic
This commit is contained in:
@@ -3,8 +3,8 @@ package ch.tutteli.atrium.api.fluent.en_GB
|
||||
import ch.tutteli.atrium.core.ExperimentalNewExpectTypes
|
||||
import ch.tutteli.atrium.core.None
|
||||
import ch.tutteli.atrium.creating.*
|
||||
import ch.tutteli.atrium.domain.builders.reporting.ExpectBuilder
|
||||
import ch.tutteli.atrium.domain.builders.reporting.ExpectOptions
|
||||
import ch.tutteli.atrium.logic.creating.RootExpectBuilder
|
||||
import ch.tutteli.atrium.logic.creating.RootExpectOptions
|
||||
import ch.tutteli.atrium.reporting.Text
|
||||
|
||||
@Suppress("DEPRECATION" /* RequiresOptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
|
||||
@@ -20,7 +20,7 @@ annotation class ExperimentalWithOptions
|
||||
* In case the subject of `this` expectation is not defined (i.e. `_logic.maybeSubject` is [None]),
|
||||
* then the previous representation is used.
|
||||
*
|
||||
* @return an [Expect] for the subject of `this` expectation.
|
||||
* @return An new [Expect] with the specified options for subject of `this` expectation.
|
||||
*/
|
||||
@ExperimentalWithOptions
|
||||
fun <T> RootExpect<T>.withRepresentation(textRepresentation: String): Expect<T> =
|
||||
@@ -39,32 +39,34 @@ fun <T> RootExpect<T>.withRepresentation(textRepresentation: String): Expect<T>
|
||||
* In case the subject of `this` expectation is not defined (i.e. `_logic.maybeSubject` is [None]),
|
||||
* then the previous representation is used.
|
||||
*
|
||||
* @return an [Expect] for the subject of `this` expectation.
|
||||
* @return An new [Expect] with the specified options for subject of `this` expectation.
|
||||
*/
|
||||
@ExperimentalWithOptions
|
||||
fun <T> RootExpect<T>.withRepresentation(representationProvider: (T) -> Any): Expect<T> =
|
||||
withOptions { withRepresentation(representationProvider) }
|
||||
|
||||
/**
|
||||
* Uses the given [configuration]-lambda to create an [ExpectOptions] which in turn is used
|
||||
* to override (parts) of the existing configuration.
|
||||
* Uses the given [configuration]-lambda to create an [RootExpectOptions] which in turn is used
|
||||
* to re-define (parts) of the existing configuration.
|
||||
*
|
||||
* @return an [Expect] for the subject of `this` expectation.
|
||||
*/
|
||||
@ExperimentalWithOptions
|
||||
fun <T> RootExpect<T>.withOptions(configuration: ExpectBuilder.OptionsChooser<T>.() -> Unit): Expect<T> =
|
||||
withOptions(ExpectBuilder.OptionsChooser.createAndBuild(configuration))
|
||||
|
||||
/**
|
||||
* Uses the given [options] to override (parts) of the existing configuration.
|
||||
*
|
||||
* @return an [Expect] for the subject of `this` expectation.
|
||||
* @return An new [Expect] with the specified options for subject of `this` expectation.
|
||||
*/
|
||||
@ExperimentalWithOptions
|
||||
@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
|
||||
@UseExperimental(ExperimentalNewExpectTypes::class)
|
||||
fun <T> RootExpect<T>.withOptions(options: ExpectOptions<T>): Expect<T> =
|
||||
RootExpect(this, options.toRootExpectOptions())
|
||||
fun <T> RootExpect<T>.withOptions(configuration: RootExpectBuilder.OptionsChooser<T>.() -> Unit): Expect<T> =
|
||||
withOptions(RootExpectOptions(configuration))
|
||||
|
||||
/**
|
||||
* Uses the given [options] to override (parts) of the existing configuration.
|
||||
*
|
||||
* @return An new [Expect] with the specified options for subject of `this` expectation.
|
||||
*/
|
||||
@ExperimentalWithOptions
|
||||
@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
|
||||
@UseExperimental(ExperimentalNewExpectTypes::class)
|
||||
fun <T> RootExpect<T>.withOptions(options: RootExpectOptions<T>): Expect<T> =
|
||||
RootExpect(this, options)
|
||||
|
||||
/**
|
||||
* Wraps the given [textRepresentation] into a [Text] and uses it as representation of the subject
|
||||
@@ -73,7 +75,7 @@ fun <T> RootExpect<T>.withOptions(options: ExpectOptions<T>): Expect<T> =
|
||||
* In case the subject of `this` expectation is not defined (i.e. `_logic.maybeSubject` is [None]),
|
||||
* then the previous representation is used.
|
||||
*
|
||||
* @return an [Expect] for the subject of `this` expectation.
|
||||
* @return An new [Expect] with the specified options for subject of `this` expectation.
|
||||
*/
|
||||
@ExperimentalWithOptions
|
||||
@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
|
||||
@@ -94,7 +96,7 @@ fun <T, R> FeatureExpect<T, R>.withRepresentation(textRepresentation: String): E
|
||||
* In case the subject of `this` expectation is not defined (i.e. `_logic.maybeSubject` is [None]),
|
||||
* then the previous representation is used.
|
||||
*
|
||||
* @return an [Expect] for the subject of `this` expectation.
|
||||
* @return An new [Expect] with the specified options for subject of `this` expectation.
|
||||
*/
|
||||
@ExperimentalWithOptions
|
||||
@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
|
||||
@@ -106,7 +108,7 @@ fun <T, R> FeatureExpect<T, R>.withRepresentation(representationProvider: (R) ->
|
||||
* Uses the given [configuration]-lambda to create an [FeatureExpectOptions] which in turn is used
|
||||
* to override (parts) of the existing configuration.
|
||||
*
|
||||
* @return an [Expect] for the subject of `this` expectation.
|
||||
* @return An new [Expect] with the specified options for subject of `this` expectation.
|
||||
*/
|
||||
@ExperimentalWithOptions
|
||||
@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
|
||||
@@ -117,7 +119,7 @@ fun <T, R> FeatureExpect<T, R>.withOptions(configuration: FeatureExpectOptionsCh
|
||||
/**
|
||||
* Uses the given [options] to override (parts) of the existing configuration.
|
||||
*
|
||||
* @return an [Expect] for the subject of `this` expectation.
|
||||
* @return An new [Expect] with the specified options for subject of `this` expectation.
|
||||
*/
|
||||
@ExperimentalWithOptions
|
||||
@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
|
||||
|
||||
@@ -3,8 +3,8 @@ package ch.tutteli.atrium.api.infix.en_GB
|
||||
import ch.tutteli.atrium.core.ExperimentalNewExpectTypes
|
||||
import ch.tutteli.atrium.core.None
|
||||
import ch.tutteli.atrium.creating.*
|
||||
import ch.tutteli.atrium.domain.builders.reporting.ExpectBuilder
|
||||
import ch.tutteli.atrium.domain.builders.reporting.ExpectOptions
|
||||
import ch.tutteli.atrium.logic.creating.RootExpectBuilder
|
||||
import ch.tutteli.atrium.logic.creating.RootExpectOptions
|
||||
import ch.tutteli.atrium.reporting.Text
|
||||
|
||||
@Suppress("DEPRECATION" /* RequiresOptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
|
||||
@@ -42,12 +42,15 @@ infix fun <T> RootExpect<T>.withRepresentation(representationProvider: (T) -> An
|
||||
withOptions { withRepresentation(representationProvider) }
|
||||
|
||||
/**
|
||||
* Uses the given [configuration]-lambda to create an [ExpectOptions] which in turn is used
|
||||
* Uses the given [configuration]-lambda to create an [RootExpectOptions] which in turn is used
|
||||
* to override (parts) of the existing configuration.
|
||||
*/
|
||||
@ExperimentalWithOptions
|
||||
infix fun <T> RootExpect<T>.withOptions(configuration: ExpectBuilder.OptionsChooser<T>.() -> Unit): Expect<T> =
|
||||
withOptions(ExpectBuilder.OptionsChooser.createAndBuild(configuration))
|
||||
@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
|
||||
@UseExperimental(ExperimentalNewExpectTypes::class)
|
||||
infix fun <T> RootExpect<T>.withOptions(configuration: RootExpectBuilder.OptionsChooser<T>.() -> Unit): Expect<T> =
|
||||
withOptions(RootExpectOptions(configuration))
|
||||
|
||||
|
||||
/**
|
||||
* Uses the given [options] to override (parts) of the existing configuration.
|
||||
@@ -55,8 +58,8 @@ infix fun <T> RootExpect<T>.withOptions(configuration: ExpectBuilder.OptionsChoo
|
||||
@ExperimentalWithOptions
|
||||
@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
|
||||
@UseExperimental(ExperimentalNewExpectTypes::class)
|
||||
infix fun <T> RootExpect<T>.withOptions(options: ExpectOptions<T>): Expect<T> =
|
||||
RootExpect(this, options.toRootExpectOptions())
|
||||
infix fun <T> RootExpect<T>.withOptions(options: RootExpectOptions<T>): Expect<T> =
|
||||
RootExpect(this, options)
|
||||
|
||||
/**
|
||||
* Wraps the given [textRepresentation] into a [Text] and uses it as representation of the subject
|
||||
@@ -65,7 +68,7 @@ infix fun <T> RootExpect<T>.withOptions(options: ExpectOptions<T>): Expect<T> =
|
||||
* In case the subject of `this` expectation is not defined (i.e. `_logic.maybeSubject` is [None]),
|
||||
* then the previous representation is used.
|
||||
*
|
||||
* @return an [Expect] for the subject of `this` expectation.
|
||||
* @return An new [Expect] with the specified options for subject of `this` expectation.
|
||||
*/
|
||||
@ExperimentalWithOptions
|
||||
@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
|
||||
@@ -86,7 +89,7 @@ infix fun <T, R> FeatureExpect<T, R>.withRepresentation(textRepresentation: Stri
|
||||
* In case the subject of `this` expectation is not defined (i.e. `_logic.maybeSubject` is [None]),
|
||||
* then the previous representation is used.
|
||||
*
|
||||
* @return an [Expect] for the subject of `this` expectation.
|
||||
* @return An new [Expect] with the specified options for subject of `this` expectation.
|
||||
*/
|
||||
@ExperimentalWithOptions
|
||||
@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
|
||||
@@ -98,7 +101,7 @@ infix fun <T, R> FeatureExpect<T, R>.withRepresentation(representationProvider:
|
||||
* Uses the given [configuration]-lambda to create an [FeatureExpectOptions] which in turn is used
|
||||
* to override (parts) of the existing configuration.
|
||||
*
|
||||
* @return an [Expect] for the subject of `this` expectation.
|
||||
* @return An new [Expect] with the specified options for subject of `this` expectation.
|
||||
*/
|
||||
@ExperimentalWithOptions
|
||||
@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
|
||||
@@ -109,7 +112,7 @@ infix fun <T, R> FeatureExpect<T, R>.withOptions(configuration: FeatureExpectOpt
|
||||
/**
|
||||
* Uses the given [options] to override (parts) of the existing configuration.
|
||||
*
|
||||
* @return an [Expect] for the subject of `this` expectation.
|
||||
* @return An new [Expect] with the specified options for subject of `this` expectation.
|
||||
*/
|
||||
@ExperimentalWithOptions
|
||||
@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
|
||||
|
||||
@@ -10,7 +10,7 @@ import ch.tutteli.atrium.reporting.ObjectFormatter
|
||||
* As it is a child of an [AssertionGroup] with an [ExplanatoryAssertionGroupType], it is not of importance
|
||||
* whether the assertions holds or not; thus it overrides [holds] which always returns `true`.
|
||||
*
|
||||
* This assertion will be turned into a `Reportable` with 1.0.0 and eventually be removed with 1.0.0
|
||||
* This assertion will be turned into a `Reportable` with 1.0.0 and eventually/latest be removed with 1.0.0
|
||||
* See https://github.com/robstoll/atrium-roadmap/issues/1 for more information.
|
||||
*/
|
||||
interface ExplanatoryAssertion : Assertion {
|
||||
|
||||
@@ -10,7 +10,7 @@ import kotlin.reflect.KClass
|
||||
/**
|
||||
* Represents the extension point of the logic level for subjects of type [T].
|
||||
*
|
||||
* In contrast to assertion function defined for [Expect] which usually return [Expect], functions defined for
|
||||
* In contrast to expectation functions defined for [Expect] which usually return [Expect], functions defined for
|
||||
* [AssertionContainer] return [Assertion] so that they can be appended to whatever we want.
|
||||
*
|
||||
* Note, do not use [SubjectProvider] as this interface will be removed with 0.17.0.
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package ch.tutteli.atrium.creating
|
||||
|
||||
import ch.tutteli.atrium.assertions.Assertion
|
||||
import ch.tutteli.atrium.core.ExperimentalNewExpectTypes
|
||||
import ch.tutteli.atrium.core.Option
|
||||
import ch.tutteli.atrium.creating.impl.DelegatingExpectImpl
|
||||
|
||||
/**
|
||||
* Represents an [Expect] which passes on appended assertions to a given [Expect].
|
||||
* Represents an [Expect] which passes on appended [Assertion]s to a given [Expect].
|
||||
*/
|
||||
interface DelegatingExpect<T> : Expect<T> {
|
||||
companion object {
|
||||
|
||||
@@ -7,6 +7,7 @@ import ch.tutteli.atrium.reporting.translating.StringBasedTranslatable
|
||||
*/
|
||||
enum class ErrorMessages(override val value: String) : StringBasedTranslatable {
|
||||
AT_LEAST_ONE_ASSERTION_DEFINED("at least one assertion defined"),
|
||||
//TODO 0.16.0 deprecate and replace with FORGOT_DO_DEFINE_EXPECTATION
|
||||
FORGOT_DO_DEFINE_ASSERTION("You forgot to define assertions in the assertionCreator-lambda"),
|
||||
HINT_AT_LEAST_ONE_ASSERTION_DEFINED("Sometimes you can use an alternative to `{ }` For instance, instead of `toThrow<..> { }` you should use `toThrow<..>()`"),
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@ interface Expect<T> : @kotlin.Suppress("DEPRECATION") SubjectProvider<T> {
|
||||
ReplaceWith("this._logic.maybeSubject", "ch.tutteli.atrium.logic._logic")
|
||||
)
|
||||
override val maybeSubject: Option<T>
|
||||
get() = TODO("Not yet implemented")
|
||||
|
||||
/**
|
||||
* Adds the assertions created by the [assertionCreator] lambda to this container and
|
||||
|
||||
@@ -33,7 +33,7 @@ data class FeatureExpectOptions<R>(
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
//TODO 0.16.0 deprecate and move to logic
|
||||
/**
|
||||
* Define additional (non-mandatory) options to create a [FeatureExpect] based on a given
|
||||
* [FeatureExpectOptionsChooser]-lambda.
|
||||
@@ -44,6 +44,7 @@ data class FeatureExpectOptions<R>(
|
||||
fun <R> FeatureExpectOptions(configuration: FeatureExpectOptionsChooser<R>.() -> Unit): FeatureExpectOptions<R> =
|
||||
FeatureExpectOptionsChooser(configuration)
|
||||
|
||||
//TODO 0.16.0 deprecate and move to logic
|
||||
/**
|
||||
* Helper lambda to specify [FeatureExpectOptions] via convenience methods.
|
||||
*
|
||||
|
||||
@@ -17,8 +17,8 @@ interface RootExpect<T> : Expect<T> {
|
||||
operator fun <T> invoke(
|
||||
maybeSubject: Option<T>,
|
||||
assertionVerb: Translatable,
|
||||
expectOptions: RootExpectOptions<T>?
|
||||
): RootExpect<T> = RootExpectImpl(maybeSubject, assertionVerb, expectOptions)
|
||||
options: RootExpectOptions<T>?
|
||||
): RootExpect<T> = RootExpectImpl(maybeSubject, assertionVerb, options)
|
||||
|
||||
@ExperimentalNewExpectTypes
|
||||
/**
|
||||
@@ -26,9 +26,9 @@ interface RootExpect<T> : Expect<T> {
|
||||
*/
|
||||
operator fun <T> invoke(
|
||||
rootExpect: RootExpect<T>,
|
||||
expectOptions: RootExpectOptions<T>
|
||||
options: RootExpectOptions<T>
|
||||
): RootExpect<T> = when (rootExpect) {
|
||||
is RootExpectImpl -> RootExpectImpl(rootExpect, expectOptions)
|
||||
is RootExpectImpl -> RootExpectImpl(rootExpect, options)
|
||||
else -> throw UnsupportedOperationException("Please open an issue that a hook shall be implemented: $BUG_REPORT_URL?template=feature_request&title=Hook%20for%20RootExpect%20creation")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,16 +7,22 @@ import ch.tutteli.atrium.reporting.translating.Translatable
|
||||
/**
|
||||
* Additional (non-mandatory) options to create a [RootExpect].
|
||||
*
|
||||
* @property assertionVerb Defines a custom assertion verb if not null.
|
||||
* See atrium-logic for helper functions to create an instance for this. Core is kept simple on purpose because
|
||||
* it is also used in other JVM languages than Kotlin.
|
||||
*
|
||||
* @property expectationVerb Defines a custom assertion verb if not null.
|
||||
* @property representationInsteadOfSubject Defines a custom representation based on a present subject if not null.
|
||||
* @property reporter Defines a custom reporter if not null.
|
||||
*/
|
||||
@ExperimentalNewExpectTypes
|
||||
data class RootExpectOptions<T>(
|
||||
val assertionVerb: Translatable?,
|
||||
val expectationVerb: Translatable?,
|
||||
val representationInsteadOfSubject: ((T) -> Any)?,
|
||||
val reporter: Reporter?
|
||||
) {
|
||||
@Deprecated("Use expectationVerb; will be removed latest with 1.0.0 (maybe earlier)")
|
||||
val assertionVerb = expectationVerb
|
||||
|
||||
/**
|
||||
* Merges the given [options] with this object creating a new [RootExpectOptions]
|
||||
* where defined properties in [options] will have precedence over properties defined in this instance.
|
||||
@@ -27,7 +33,7 @@ data class RootExpectOptions<T>(
|
||||
*/
|
||||
fun merge(options: RootExpectOptions<T>): RootExpectOptions<T> =
|
||||
RootExpectOptions(
|
||||
options.assertionVerb ?: assertionVerb,
|
||||
options.expectationVerb ?: expectationVerb,
|
||||
options.representationInsteadOfSubject ?: representationInsteadOfSubject,
|
||||
options.reporter ?: reporter
|
||||
)
|
||||
|
||||
@@ -15,7 +15,7 @@ import ch.tutteli.atrium.reporting.translating.Translatable
|
||||
@ExperimentalNewExpectTypes
|
||||
internal class RootExpectImpl<T>(
|
||||
maybeSubject: Option<T>,
|
||||
private val assertionVerb: Translatable,
|
||||
private val expectationVerb: Translatable,
|
||||
private val representation: Any?,
|
||||
private val reporter: Reporter
|
||||
) : BaseExpectImpl<T>(maybeSubject), RootExpect<T> {
|
||||
@@ -26,7 +26,7 @@ internal class RootExpectImpl<T>(
|
||||
options: RootExpectOptions<T>?
|
||||
) : this(
|
||||
maybeSubject,
|
||||
options?.assertionVerb ?: assertionVerb,
|
||||
options?.expectationVerb ?: assertionVerb,
|
||||
determineRepresentation(
|
||||
options?.representationInsteadOfSubject,
|
||||
maybeSubject
|
||||
@@ -36,7 +36,7 @@ internal class RootExpectImpl<T>(
|
||||
|
||||
constructor(previous: RootExpectImpl<T>, options: RootExpectOptions<T>) : this(
|
||||
previous.maybeSubject,
|
||||
previous.assertionVerb,
|
||||
previous.expectationVerb,
|
||||
options
|
||||
)
|
||||
|
||||
@@ -50,7 +50,7 @@ internal class RootExpectImpl<T>(
|
||||
assertions.add(assertion)
|
||||
if (!assertion.holds()) {
|
||||
val assertionGroup = assertionBuilder.root
|
||||
.withDescriptionAndRepresentation(assertionVerb, representation)
|
||||
.withDescriptionAndRepresentation(expectationVerb, representation)
|
||||
.withAssertion(assertion)
|
||||
.build()
|
||||
|
||||
|
||||
@@ -3,10 +3,11 @@ package ch.tutteli.atrium.core.robstoll.lib.reporting
|
||||
import ch.tutteli.atrium.api.fluent.en_GB.*
|
||||
import ch.tutteli.atrium.api.verbs.internal.AssertionVerb
|
||||
import ch.tutteli.atrium.api.verbs.internal.expect
|
||||
import ch.tutteli.atrium.core.ExperimentalNewExpectTypes
|
||||
import ch.tutteli.atrium.core.coreFactory
|
||||
import ch.tutteli.atrium.core.polyfills.stackBacktrace
|
||||
import ch.tutteli.atrium.domain.builders.reporting.ExpectBuilder
|
||||
import ch.tutteli.atrium.domain.builders.reporting.ExpectOptions
|
||||
import ch.tutteli.atrium.logic.creating.RootExpectBuilder
|
||||
import ch.tutteli.atrium.logic.creating.RootExpectOptions
|
||||
import ch.tutteli.atrium.reporting.AtriumErrorAdjuster
|
||||
import ch.tutteli.atrium.reporting.reporter
|
||||
import kotlin.test.Test
|
||||
@@ -79,9 +80,11 @@ class AdjustStackTest {
|
||||
subject, coreFactory.newRemoveAtriumFromAtriumErrorAdjuster()
|
||||
)
|
||||
|
||||
@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
|
||||
@UseExperimental(ExperimentalNewExpectTypes::class)
|
||||
private fun <T : Any> createExpect(subject: T, adjuster: AtriumErrorAdjuster) =
|
||||
ExpectBuilder.forSubject(subject)
|
||||
RootExpectBuilder.forSubject(subject)
|
||||
.withVerb(AssertionVerb.EXPECT)
|
||||
.withOptions(ExpectOptions(reporter = DelegatingReporter(reporter, adjuster)))
|
||||
.withOptions(RootExpectOptions(reporter = DelegatingReporter(reporter, adjuster)))
|
||||
.build()
|
||||
}
|
||||
|
||||
@@ -3,11 +3,12 @@ package ch.tutteli.atrium.core.robstoll.lib.reporting
|
||||
import ch.tutteli.atrium.api.fluent.en_GB.*
|
||||
import ch.tutteli.atrium.api.verbs.internal.AssertionVerb
|
||||
import ch.tutteli.atrium.api.verbs.internal.expect
|
||||
import ch.tutteli.atrium.core.ExperimentalNewExpectTypes
|
||||
import ch.tutteli.atrium.core.coreFactory
|
||||
import ch.tutteli.atrium.core.polyfills.stackBacktrace
|
||||
import ch.tutteli.atrium.creating.Expect
|
||||
import ch.tutteli.atrium.domain.builders.reporting.ExpectBuilder
|
||||
import ch.tutteli.atrium.domain.builders.reporting.ExpectOptions
|
||||
import ch.tutteli.atrium.logic.creating.RootExpectBuilder
|
||||
import ch.tutteli.atrium.logic.creating.RootExpectOptions
|
||||
import ch.tutteli.atrium.logic.utils.expectLambda
|
||||
import ch.tutteli.atrium.reporting.AtriumErrorAdjuster
|
||||
import ch.tutteli.atrium.reporting.reporter
|
||||
@@ -177,8 +178,10 @@ class AdjustStackSpec : Spek({
|
||||
}
|
||||
})
|
||||
|
||||
@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
|
||||
@UseExperimental(ExperimentalNewExpectTypes::class)
|
||||
private fun <T : Any> createExpect(subject: T, adjuster: AtriumErrorAdjuster) =
|
||||
ExpectBuilder.forSubject(subject)
|
||||
RootExpectBuilder.forSubject(subject)
|
||||
.withVerb(AssertionVerb.EXPECT)
|
||||
.withOptions(ExpectOptions(reporter = DelegatingReporter(reporter, adjuster)))
|
||||
.withOptions(RootExpectOptions(reporter = DelegatingReporter(reporter, adjuster)))
|
||||
.build()
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
package ch.tutteli.atrium.logic.creating
|
||||
|
||||
import ch.tutteli.atrium.core.ExperimentalNewExpectTypes
|
||||
import ch.tutteli.atrium.creating.Expect
|
||||
import ch.tutteli.atrium.creating.RootExpect
|
||||
import ch.tutteli.atrium.creating.RootExpectOptions
|
||||
import ch.tutteli.atrium.logic.creating.impl.*
|
||||
import ch.tutteli.atrium.reporting.Reporter
|
||||
import ch.tutteli.atrium.reporting.Text
|
||||
import ch.tutteli.atrium.reporting.translating.Translatable
|
||||
import ch.tutteli.atrium.reporting.translating.Untranslatable
|
||||
|
||||
/**
|
||||
* Defines the contract to create custom expectation verbs, `RootExpect<T>` respectively.
|
||||
*/
|
||||
interface RootExpectBuilder {
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* Entry point to use the [RootExpectBuilder] which helps in creating
|
||||
* an expectation verb for the given [subject] or in other words a [RootExpect] for the given [subject].
|
||||
*/
|
||||
fun <T> forSubject(subject: T): ExpectationVerbStep<T> = ExpectationVerbStepImpl(subject)
|
||||
}
|
||||
|
||||
/**
|
||||
* Step which allows to specify the expectation verb which shall be used.
|
||||
*
|
||||
* @param T the type of the subject.
|
||||
*/
|
||||
interface ExpectationVerbStep<T> {
|
||||
/**
|
||||
* The previously specified subject of the expectation.
|
||||
*/
|
||||
val subject: T
|
||||
|
||||
/**
|
||||
* Wraps the given [verb] into an [Untranslatable] and uses it as expectation verb.
|
||||
*/
|
||||
fun withVerb(verb: String): OptionsStep<T> = withVerb(Untranslatable(verb))
|
||||
|
||||
/**
|
||||
* Uses the given [verb] as expectation verb.
|
||||
*/
|
||||
fun withVerb(verb: Translatable): OptionsStep<T>
|
||||
}
|
||||
|
||||
/**
|
||||
* Step which allows to override previously defined properties -- such as use a different expectation verb -- but
|
||||
* also allows to define options where usually a default value is used, such as use a custom [Reporter].
|
||||
*
|
||||
* @param T the type of the subject.
|
||||
*/
|
||||
interface OptionsStep<T> {
|
||||
/**
|
||||
* The previously specified subject of the expectation.
|
||||
*/
|
||||
val subject: T
|
||||
|
||||
/**
|
||||
* The previously defined expectation verb.
|
||||
*/
|
||||
val expectationVerb: Translatable
|
||||
|
||||
|
||||
/**
|
||||
* Allows to define the [RootExpectOptions] via an [OptionsChooser]-lambda which provides convenience functions.
|
||||
*
|
||||
* The functions usually start with `set...` and are sometimes overloaded to ease the configuration.
|
||||
* Note that the last configuration
|
||||
*/
|
||||
@ExperimentalNewExpectTypes
|
||||
fun withOptions(configuration: OptionsChooser<T>.() -> Unit): FinalStep<T> =
|
||||
withOptions(RootExpectOptions(configuration))
|
||||
|
||||
/**
|
||||
* Uses the given [rootExpectOptions].
|
||||
*/
|
||||
@ExperimentalNewExpectTypes
|
||||
fun withOptions(rootExpectOptions: RootExpectOptions<T>): FinalStep<T>
|
||||
|
||||
/**
|
||||
* States explicitly that no optional [RootExpectOptions] are defined, which means, `build` will create
|
||||
* a new [Expect] based on the previously defined mandatory options but without any optional options or
|
||||
* in other words, the default values are used for the optional options.
|
||||
*
|
||||
* Use [withOptions] if you want to define optional [RootExpectOptions] such as, override the
|
||||
* verb, define an own representation or use an own [Reporter].
|
||||
*/
|
||||
fun withoutOptions(): FinalStep<T>
|
||||
|
||||
companion object {
|
||||
fun <T> create(
|
||||
subject: T,
|
||||
expectationVerb: Translatable
|
||||
): OptionsStep<T> = OptionsStepImpl(subject, expectationVerb)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper lambda to specify [RootExpectOptions] via convenience methods.
|
||||
*
|
||||
* Calling multiple times the same method overrides the previously defined value.
|
||||
*/
|
||||
interface OptionsChooser<T> {
|
||||
|
||||
/**
|
||||
* Wraps the given [verb] into an [Untranslatable] and passes it to the overload
|
||||
* which expects a [Translatable] -- this is then used as custom expectation verb
|
||||
* instead of the previously defined verb.
|
||||
*
|
||||
*/
|
||||
fun withVerb(verb: String) {
|
||||
withVerb(Untranslatable(verb))
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the given [verb] as expectation verb instead of the previously defined verb.
|
||||
*/
|
||||
fun withVerb(verb: Translatable)
|
||||
|
||||
/**
|
||||
* Wraps the given [textRepresentation] into a [Text] and uses it as representation of the subject
|
||||
* instead of the representation that has been defined so far (which defaults to the subject itself).
|
||||
*/
|
||||
fun withRepresentation(textRepresentation: String): Unit =
|
||||
withRepresentation { Text(textRepresentation) }
|
||||
|
||||
/**
|
||||
* Uses the given [representationProvider] to retrieve a representation which can be based on the current
|
||||
* subject where it is used as new representation of the subject
|
||||
* instead of the representation that has been defined so far (which defaults to the subject itself).
|
||||
*
|
||||
* Notice, if you want to use text (a [String] which is treated as raw string in reporting) as representation,
|
||||
* then wrap it into a [Text] and pass it instead.
|
||||
* If your text does not include the current subject, then we recommend to use the other overload which expects
|
||||
* a `String` and does the wrapping for you.
|
||||
*/
|
||||
fun withRepresentation(representationProvider: (T) -> Any)
|
||||
|
||||
/**
|
||||
* Uses the given [reporter] instead of the default reporter.
|
||||
*/
|
||||
fun withReporter(reporter: Reporter)
|
||||
|
||||
companion object {
|
||||
@ExperimentalNewExpectTypes
|
||||
fun <T> createAndBuild(configuration: OptionsChooser<T>.() -> Unit): RootExpectOptions<T> =
|
||||
OptionsChooserImpl<T>().apply(configuration).build()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Final step in the [RootExpect] building process which creates a new [RootExpect] based
|
||||
* on the so far specified options.
|
||||
*
|
||||
* @param T the type of the subject.
|
||||
*/
|
||||
interface FinalStep<T> {
|
||||
/**
|
||||
* The previously specified subject of the expectation.
|
||||
*/
|
||||
val subject: T
|
||||
|
||||
/**
|
||||
* The previously defined expectation verb.
|
||||
*/
|
||||
val expectationVerb: Translatable
|
||||
|
||||
/**
|
||||
* Either the previously specified [RootExpectOptions] or `null`.
|
||||
*/
|
||||
@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
|
||||
@UseExperimental(ExperimentalNewExpectTypes::class)
|
||||
val options: RootExpectOptions<T>?
|
||||
|
||||
/**
|
||||
* Creates a new [Expect] based on the previously defined maybeOptions.
|
||||
*/
|
||||
fun build(): RootExpect<T>
|
||||
|
||||
companion object {
|
||||
@ExperimentalNewExpectTypes
|
||||
fun <T> create(
|
||||
subject: T,
|
||||
expectationVerb: Translatable,
|
||||
options: RootExpectOptions<T>?
|
||||
): FinalStep<T> = FinalStepImpl(subject, expectationVerb, options)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create a [RootExpectOptions] via
|
||||
*/
|
||||
@ExperimentalNewExpectTypes
|
||||
@Suppress("FunctionName")
|
||||
fun <T> RootExpectOptions(configuration: RootExpectBuilder.OptionsChooser<T>.() -> Unit): RootExpectOptions<T> =
|
||||
RootExpectBuilder.OptionsChooser.createAndBuild(configuration)
|
||||
|
||||
/**
|
||||
* Helper function to create a [RootExpectOptions] by specifying components via named parameters.
|
||||
*
|
||||
* You can use it as follows: `RootExpectOptions(reporter = myReporter)`
|
||||
*/
|
||||
@ExperimentalNewExpectTypes
|
||||
@Suppress("FunctionName")
|
||||
fun <T> RootExpectOptions(
|
||||
expectationVerb: Translatable? = null,
|
||||
representationInsteadOfSubject: ((T) -> Any)? = null,
|
||||
reporter: Reporter? = null
|
||||
): RootExpectOptions<T> = RootExpectOptions(
|
||||
expectationVerb,
|
||||
representationInsteadOfSubject,
|
||||
reporter
|
||||
)
|
||||
@@ -0,0 +1,28 @@
|
||||
package ch.tutteli.atrium.logic.creating.impl
|
||||
|
||||
import ch.tutteli.atrium.core.ExperimentalNewExpectTypes
|
||||
import ch.tutteli.atrium.creating.RootExpectOptions
|
||||
import ch.tutteli.atrium.logic.creating.RootExpectBuilder
|
||||
import ch.tutteli.atrium.reporting.Reporter
|
||||
import ch.tutteli.atrium.reporting.translating.Translatable
|
||||
|
||||
@ExperimentalNewExpectTypes
|
||||
class OptionsChooserImpl<T> : RootExpectBuilder.OptionsChooser<T> {
|
||||
private var description: Translatable? = null
|
||||
private var representationInsteadOfSubject: ((T) -> Any)? = null
|
||||
private var reporter: Reporter? = null
|
||||
|
||||
override fun withVerb(verb: Translatable) {
|
||||
this.description = verb
|
||||
}
|
||||
|
||||
override fun withRepresentation(representationProvider: (T) -> Any) {
|
||||
this.representationInsteadOfSubject = representationProvider
|
||||
}
|
||||
|
||||
override fun withReporter(reporter: Reporter) {
|
||||
this.reporter = reporter
|
||||
}
|
||||
|
||||
fun build(): RootExpectOptions<T> = RootExpectOptions(description, representationInsteadOfSubject, reporter)
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package ch.tutteli.atrium.logic.creating.impl
|
||||
|
||||
import ch.tutteli.atrium.core.ExperimentalNewExpectTypes
|
||||
import ch.tutteli.atrium.core.Some
|
||||
import ch.tutteli.atrium.creating.RootExpect
|
||||
import ch.tutteli.atrium.creating.RootExpectOptions
|
||||
import ch.tutteli.atrium.logic.creating.RootExpectBuilder
|
||||
import ch.tutteli.atrium.reporting.translating.Translatable
|
||||
|
||||
class ExpectationVerbStepImpl<T>(override val subject: T) : RootExpectBuilder.ExpectationVerbStep<T> {
|
||||
override fun withVerb(verb: Translatable): RootExpectBuilder.OptionsStep<T> =
|
||||
RootExpectBuilder.OptionsStep.create(subject, verb)
|
||||
}
|
||||
|
||||
class OptionsStepImpl<T>(
|
||||
override val subject: T,
|
||||
override val expectationVerb: Translatable
|
||||
) : RootExpectBuilder.OptionsStep<T> {
|
||||
|
||||
@ExperimentalNewExpectTypes
|
||||
override fun withOptions(rootExpectOptions: RootExpectOptions<T>): RootExpectBuilder.FinalStep<T> =
|
||||
toFinalStep(rootExpectOptions)
|
||||
|
||||
@ExperimentalNewExpectTypes
|
||||
override fun withoutOptions(): RootExpectBuilder.FinalStep<T> = toFinalStep(null)
|
||||
|
||||
@ExperimentalNewExpectTypes
|
||||
private fun toFinalStep(rootExpectOptions: RootExpectOptions<T>?) =
|
||||
RootExpectBuilder.FinalStep.create(subject, expectationVerb, rootExpectOptions)
|
||||
}
|
||||
|
||||
@ExperimentalNewExpectTypes
|
||||
class FinalStepImpl<T>(
|
||||
override val subject: T,
|
||||
override val expectationVerb: Translatable,
|
||||
override val options: RootExpectOptions<T>?
|
||||
) : RootExpectBuilder.FinalStep<T> {
|
||||
|
||||
override fun build(): RootExpect<T> = RootExpect(Some(subject), expectationVerb, options)
|
||||
}
|
||||
@@ -4,6 +4,7 @@ module ch.tutteli.atrium.logic {
|
||||
requires kotlin.stdlib;
|
||||
|
||||
exports ch.tutteli.atrium.logic;
|
||||
exports ch.tutteli.atrium.logic.creating;
|
||||
exports ch.tutteli.atrium.logic.creating.basic.contains;
|
||||
|
||||
exports ch.tutteli.atrium.logic.creating.charsequence.contains;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
//TODO remove latest with 1.0.0
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package ch.tutteli.atrium.domain.builders.reporting
|
||||
|
||||
import ch.tutteli.atrium.core.ExperimentalNewExpectTypes
|
||||
@@ -19,7 +22,10 @@ import ch.tutteli.atrium.reporting.translating.Untranslatable
|
||||
/**
|
||||
* Defines the contract to create custom assertion verbs, `Expect<T>` respectively.
|
||||
*/
|
||||
//TODO move to atrium-logic with 0.16.0
|
||||
@Deprecated(
|
||||
"Use RootExpectBuilder from atrium-logic; will be removed latest with 1.0.0 (maybe earlier)",
|
||||
ReplaceWith("RootExpectBuilder", "ch.tutteli.atrium.logic.creating.RootExpectBuilder")
|
||||
)
|
||||
interface ExpectBuilder {
|
||||
companion object {
|
||||
|
||||
@@ -27,6 +33,13 @@ interface ExpectBuilder {
|
||||
* Entry point to use the [ExpectBuilder] which helps in creating
|
||||
* an assertion verb for the given [subject] or in other words an [Expect] for the given [subject].
|
||||
*/
|
||||
@Deprecated(
|
||||
"Use RootExpectBuilder from atrium-logic; will be removed latest with 1.0.0 (maybe earlier)",
|
||||
ReplaceWith(
|
||||
"RootExpectBuilder.forSubject<T>(subject)",
|
||||
"ch.tutteli.atrium.logic.creating.RootExpectBuilder"
|
||||
)
|
||||
)
|
||||
fun <T> forSubject(subject: T): AssertionVerbStep<T> = AssertionVerbStepImpl(Some(subject))
|
||||
}
|
||||
|
||||
@@ -35,6 +48,7 @@ interface ExpectBuilder {
|
||||
*
|
||||
* @param T the type of the subject.
|
||||
*/
|
||||
@Deprecated("Use RootExpectBuilder.ExpectationVerbStep from atrium-logic; will be removed latest with 1.0.0 (maybe earlier)")
|
||||
interface AssertionVerbStep<T> {
|
||||
/**
|
||||
* The previously specified subject of `this` expectation.
|
||||
@@ -58,6 +72,7 @@ interface ExpectBuilder {
|
||||
*
|
||||
* @param T the type of the subject.
|
||||
*/
|
||||
@Deprecated("Use RootExpectBuilder.OptionsStep from atrium-logic; will be removed latest with 1.0.0 (maybe earlier)")
|
||||
interface OptionsStep<T> {
|
||||
/**
|
||||
* The previously specified subject of `this` expectation.
|
||||
@@ -94,6 +109,10 @@ interface ExpectBuilder {
|
||||
fun withoutOptions(): FinalStep<T>
|
||||
|
||||
companion object {
|
||||
@Deprecated(
|
||||
"Use OptionsStep from atrium-logic; will be removed with 0.17.0",
|
||||
ReplaceWith("ch.tutteli.atrium.logic.creating.ExpectBuilder.OptionsStep.create(maybeSubject, assertionVerb)")
|
||||
)
|
||||
fun <T> create(
|
||||
maybeSubject: Option<T>,
|
||||
assertionVerb: Translatable
|
||||
@@ -106,7 +125,10 @@ interface ExpectBuilder {
|
||||
*
|
||||
* Calling multiple times the same method overrides the previously defined value.
|
||||
*/
|
||||
//TODO move to atrium-core with 0.16.0 (or to logic and move FeatureExpectOptionsChooser to logic as well?)
|
||||
@Deprecated(
|
||||
"Use RootExpectBuilder.OptionsChooser from atrium-logic; will be removed latest with 1.0.0 (maybe earlier)",
|
||||
ReplaceWith(" RootExpectBuilder.OptionsChooser", "ch.tutteli.atrium.logic.creating.RootExpectBuilder")
|
||||
)
|
||||
interface OptionsChooser<T> {
|
||||
|
||||
/**
|
||||
@@ -153,6 +175,10 @@ interface ExpectBuilder {
|
||||
fun withReporter(reporter: Reporter)
|
||||
|
||||
companion object {
|
||||
@Deprecated(
|
||||
"Use the helper function OptionsChooser from atrium-logic",
|
||||
ReplaceWith("RootExpectOptions(configuration)", "ch.tutteli.atrium.logic.creating.RootExpectOptions")
|
||||
)
|
||||
fun <T> createAndBuild(configuration: OptionsChooser<T>.() -> Unit): ExpectOptions<T> =
|
||||
OptionsChooserImpl<T>().apply(configuration).build()
|
||||
}
|
||||
@@ -163,6 +189,7 @@ interface ExpectBuilder {
|
||||
*
|
||||
* @param T the type of the subject.
|
||||
*/
|
||||
@Deprecated("Use RootExpectBuilder.FinalStep from atrium-logic; will be removed latest with 1.0.0 (maybe earlier)")
|
||||
interface FinalStep<T> {
|
||||
/**
|
||||
* The previously specified subject of `this` expectation.
|
||||
@@ -185,6 +212,10 @@ interface ExpectBuilder {
|
||||
fun build(): RootExpect<T>
|
||||
|
||||
companion object {
|
||||
@Deprecated(
|
||||
"Use OptionsStep from atrium-logic; will be removed with 0.17.0",
|
||||
ReplaceWith("ch.tutteli.atrium.logic.creating.ExpectBuilder.FinalStep.create(maybeSubject, assertionVerb, options)")
|
||||
)
|
||||
fun <T> create(
|
||||
maybeSubject: Option<T>,
|
||||
assertionVerb: Translatable,
|
||||
@@ -201,6 +232,13 @@ interface ExpectBuilder {
|
||||
* @property representationInsteadOfSubject Defines a custom representation based on a present subject if not null.
|
||||
* @property reporter Defines a custom reporter if not null.
|
||||
*/
|
||||
@Deprecated(
|
||||
"Use RootExpectOptions instead; will be removed latest with 1.0.0 (maybe earlier)",
|
||||
ReplaceWith(
|
||||
"RootExpectOptions(assertionVerb, representationInsteadOfSubject, reporter)",
|
||||
"ch.tutteli.atrium.logic.creating.RootExpectOptions"
|
||||
)
|
||||
)
|
||||
data class ExpectOptions<T>(
|
||||
val assertionVerb: Translatable? = null,
|
||||
val representationInsteadOfSubject: ((T) -> Any)? = null,
|
||||
@@ -227,5 +265,9 @@ data class ExpectOptions<T>(
|
||||
}
|
||||
|
||||
@Suppress("FunctionName")
|
||||
@Deprecated(
|
||||
"Use RootExpectOptions instead; will be removed latest with 1.0.0 (maybe earlier)",
|
||||
ReplaceWith("RootExpectOptions(configuration)", "ch.tutteli.atrium.logic.creating.RootExpectOptions")
|
||||
)
|
||||
fun <T> ExpectOptions(configuration: ExpectBuilder.OptionsChooser<T>.() -> Unit): ExpectOptions<T> =
|
||||
ExpectBuilder.OptionsChooser.createAndBuild(configuration)
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
//TODO remove file with 1.0.0
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package ch.tutteli.atrium.domain.builders.reporting.impl.verb
|
||||
|
||||
import ch.tutteli.atrium.domain.builders.reporting.ExpectBuilder
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
//TODO remove file with 1.0.0
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package ch.tutteli.atrium.domain.builders.reporting.impl.verb
|
||||
|
||||
import ch.tutteli.atrium.core.ExperimentalNewExpectTypes
|
||||
|
||||
@@ -8,12 +8,13 @@ import ch.tutteli.atrium.assertions.Assertion
|
||||
import ch.tutteli.atrium.assertions.AssertionGroup
|
||||
import ch.tutteli.atrium.assertions.ExplanatoryAssertionGroupType
|
||||
import ch.tutteli.atrium.assertions.builders.assertionBuilder
|
||||
import ch.tutteli.atrium.core.ExperimentalNewExpectTypes
|
||||
import ch.tutteli.atrium.core.None
|
||||
import ch.tutteli.atrium.core.coreFactory
|
||||
import ch.tutteli.atrium.creating.CollectingExpect
|
||||
import ch.tutteli.atrium.creating.Expect
|
||||
import ch.tutteli.atrium.domain.builders.reporting.ExpectBuilder
|
||||
import ch.tutteli.atrium.domain.builders.reporting.ExpectOptions
|
||||
import ch.tutteli.atrium.logic.creating.RootExpectBuilder
|
||||
import ch.tutteli.atrium.logic.creating.RootExpectOptions
|
||||
import org.spekframework.spek2.Spek
|
||||
import org.spekframework.spek2.style.specification.describe
|
||||
|
||||
@@ -31,10 +32,13 @@ abstract class SubjectLessSpec<T>(
|
||||
|
||||
expandAssertionGroups(assertions)
|
||||
|
||||
val container = ExpectBuilder.forSubject(1.0)
|
||||
|
||||
@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
|
||||
@UseExperimental(ExperimentalNewExpectTypes::class)
|
||||
val container = RootExpectBuilder.forSubject(1.0)
|
||||
.withVerb("custom assertion verb")
|
||||
.withOptions(
|
||||
ExpectOptions(
|
||||
RootExpectOptions(
|
||||
reporter = coreFactory.newOnlyFailureReporter(
|
||||
coreFactory.newAssertionFormatterFacade(coreFactory.newAssertionFormatterController()),
|
||||
coreFactory.newNoOpAtriumErrorAdjuster()
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
package ch.tutteli.atrium.specs.verbs
|
||||
|
||||
import ch.tutteli.atrium.api.fluent.en_GB.*
|
||||
import ch.tutteli.atrium.core.ExperimentalNewExpectTypes
|
||||
import ch.tutteli.atrium.core.polyfills.fullName
|
||||
import ch.tutteli.atrium.creating.Expect
|
||||
import ch.tutteli.atrium.domain.builders.reporting.ExpectBuilder
|
||||
import ch.tutteli.atrium.domain.builders.reporting.ExpectOptions
|
||||
import ch.tutteli.atrium.domain.builders.reporting.ReporterBuilder
|
||||
import ch.tutteli.atrium.logic._logic
|
||||
import ch.tutteli.atrium.logic.changeSubject
|
||||
import ch.tutteli.atrium.logic.creating.RootExpectBuilder
|
||||
import ch.tutteli.atrium.logic.creating.RootExpectOptions
|
||||
import ch.tutteli.atrium.specs.AssertionVerb
|
||||
import ch.tutteli.atrium.specs.prefixedDescribeTemplate
|
||||
import ch.tutteli.atrium.specs.toBeDescr
|
||||
@@ -171,11 +172,14 @@ private fun Suite.testNonNullableSubject(assertionVerb: (Int) -> Expect<Int>) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
|
||||
@UseExperimental(ExperimentalNewExpectTypes::class)
|
||||
// does not make sense to test the verbs with the verbs themselves. Thus we create our own assertion verb here
|
||||
private fun <R> assert(act: () -> R): Expect<() -> R> =
|
||||
ExpectBuilder.forSubject(act)
|
||||
RootExpectBuilder.forSubject(act)
|
||||
.withVerb(AssertionVerb.EXPECT_THROWN)
|
||||
.withOptions(ExpectOptions(reporter = AtriumReporterSupplier.REPORTER))
|
||||
.withOptions(RootExpectOptions(reporter = AtriumReporterSupplier.REPORTER))
|
||||
.build()
|
||||
|
||||
private object AtriumReporterSupplier {
|
||||
|
||||
@@ -2,8 +2,9 @@ package ch.tutteli.atrium.specs.reporting.translating
|
||||
|
||||
import ch.tutteli.atrium.api.fluent.en_GB.*
|
||||
import ch.tutteli.atrium.api.verbs.internal.expect
|
||||
import ch.tutteli.atrium.domain.builders.reporting.ExpectBuilder
|
||||
import ch.tutteli.atrium.domain.builders.reporting.ExpectOptions
|
||||
import ch.tutteli.atrium.core.ExperimentalNewExpectTypes
|
||||
import ch.tutteli.atrium.logic.creating.RootExpectBuilder
|
||||
import ch.tutteli.atrium.logic.creating.RootExpectOptions
|
||||
import ch.tutteli.atrium.reporting.Reporter
|
||||
import ch.tutteli.atrium.reporting.translating.Locale
|
||||
import ch.tutteli.atrium.reporting.translating.StringBasedTranslatable
|
||||
@@ -104,17 +105,23 @@ abstract class TranslatorIntSpec(
|
||||
prefixedDescribeTemplate(describePrefix, description, body)
|
||||
|
||||
val reporterDeChFallbackFr = reporterFactory(Locale("de", "CH"), arrayOf(Locale("fr")))
|
||||
|
||||
@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
|
||||
@UseExperimental(ExperimentalNewExpectTypes::class)
|
||||
fun <T : Any> assertWithDeCh_Fr(subject: T) =
|
||||
ExpectBuilder.forSubject(subject)
|
||||
RootExpectBuilder.forSubject(subject)
|
||||
.withVerb(AssertionVerb.ASSERT)
|
||||
.withOptions(ExpectOptions(reporter = reporterDeChFallbackFr))
|
||||
.withOptions(RootExpectOptions(reporter = reporterDeChFallbackFr))
|
||||
.build()
|
||||
|
||||
val reporterDeChFallbackFrIt = reporterFactory(Locale("de", "CH"), arrayOf(Locale("fr", "CH"), Locale("it", "CH")))
|
||||
|
||||
@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
|
||||
@UseExperimental(ExperimentalNewExpectTypes::class)
|
||||
fun <T : Any> assertWithDeCh_Fr_It(subject: T) =
|
||||
ExpectBuilder.forSubject(subject)
|
||||
RootExpectBuilder.forSubject(subject)
|
||||
.withVerb(AssertionVerb.ASSERT)
|
||||
.withOptions(ExpectOptions(reporter = reporterDeChFallbackFrIt))
|
||||
.withOptions(RootExpectOptions(reporter = reporterDeChFallbackFrIt))
|
||||
.build()
|
||||
|
||||
val descriptionAnyAssertion = DescriptionAnyAssertion::class.simpleName
|
||||
@@ -272,9 +279,12 @@ abstract class TranslatorIntSpec(
|
||||
val locale = Locale("zh", country)
|
||||
val reporter = reporterFactory(locale, arrayOf())
|
||||
|
||||
val assert = ExpectBuilder.forSubject(1)
|
||||
|
||||
@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
|
||||
@UseExperimental(ExperimentalNewExpectTypes::class)
|
||||
val assert = RootExpectBuilder.forSubject(1)
|
||||
.withVerb(AssertionVerb.ASSERT)
|
||||
.withOptions(ExpectOptions(reporter = reporter))
|
||||
.withOptions(RootExpectOptions(reporter = reporter))
|
||||
.build()
|
||||
|
||||
prefixedDescribe("primary locale is 'zh_$country' and no fallback defined") {
|
||||
|
||||
@@ -2,8 +2,9 @@ description = 'Specifies the internally used assertion verbs as common module'
|
||||
|
||||
dependencies {
|
||||
api prefixedProject('core-api-common')
|
||||
api prefixedProject('domain-builders-common')
|
||||
api prefixedProject('logic-common')
|
||||
|
||||
//TODO remove with 0.16.0
|
||||
runtimeOnly prefixedProject('core-robstoll-common')
|
||||
|
||||
testImplementation prefixedProject('specs-common')
|
||||
|
||||
@@ -2,10 +2,11 @@ package ch.tutteli.atrium.api.verbs.internal
|
||||
|
||||
import ch.tutteli.atrium.api.verbs.internal.AssertionVerb.EXPECT
|
||||
import ch.tutteli.atrium.assertions.Assertion
|
||||
import ch.tutteli.atrium.core.ExperimentalNewExpectTypes
|
||||
import ch.tutteli.atrium.creating.Expect
|
||||
import ch.tutteli.atrium.creating.RootExpect
|
||||
import ch.tutteli.atrium.domain.builders.reporting.ExpectBuilder
|
||||
import ch.tutteli.atrium.domain.builders.reporting.ReporterBuilder
|
||||
import ch.tutteli.atrium.logic.creating.RootExpectBuilder
|
||||
import ch.tutteli.atrium.reporting.Reporter
|
||||
import ch.tutteli.atrium.reporting.ReporterFactory
|
||||
import ch.tutteli.atrium.reporting.translating.StringBasedTranslatable
|
||||
@@ -18,8 +19,10 @@ import ch.tutteli.atrium.reporting.translating.StringBasedTranslatable
|
||||
* @return The newly created assertion container.
|
||||
* @throws AssertionError in case an assertion does not hold.
|
||||
*/
|
||||
@Suppress("DEPRECATION" /* OptIn is only available since 1.3.70 which we cannot use if we want to support 1.2 */)
|
||||
@UseExperimental(ExperimentalNewExpectTypes::class)
|
||||
fun <T> expect(subject: T): RootExpect<T> =
|
||||
ExpectBuilder.forSubject(subject)
|
||||
RootExpectBuilder.forSubject(subject)
|
||||
.withVerb(EXPECT)
|
||||
.withoutOptions()
|
||||
.build()
|
||||
|
||||
@@ -2,7 +2,7 @@ description = 'Specifies the internally used assertion verbs for the JS platform
|
||||
|
||||
dependencies {
|
||||
api prefixedProject('core-api-js')
|
||||
api prefixedProject('domain-builders-js')
|
||||
api prefixedProject('logic-js')
|
||||
|
||||
runtimeOnly prefixedProject('core-robstoll-js')
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
description = 'Specifies the internally used assertion verbs'
|
||||
|
||||
dependencies {
|
||||
api prefixedProject('domain-builders-jvm')
|
||||
api prefixedProject('core-api-jvm')
|
||||
api prefixedProject('logic-jvm')
|
||||
|
||||
runtimeOnly prefixedProject('core-robstoll-jvm')
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ import ch.tutteli.atrium.assertions.Assertion
|
||||
import ch.tutteli.atrium.creating.Expect
|
||||
import ch.tutteli.atrium.creating.FeatureExpect
|
||||
import ch.tutteli.atrium.creating.RootExpect
|
||||
import ch.tutteli.atrium.domain.builders.reporting.ExpectBuilder
|
||||
import ch.tutteli.atrium.logic._logic
|
||||
import ch.tutteli.atrium.logic.creating.RootExpectBuilder
|
||||
import ch.tutteli.atrium.logic.manualFeature
|
||||
|
||||
/**
|
||||
@@ -18,7 +18,7 @@ import ch.tutteli.atrium.logic.manualFeature
|
||||
* @throws AssertionError in case an assertion does not hold.
|
||||
*/
|
||||
fun <T> assert(subject: T): RootExpect<T> =
|
||||
ExpectBuilder.forSubject(subject)
|
||||
RootExpectBuilder.forSubject(subject)
|
||||
.withVerb(ASSERT)
|
||||
.withoutOptions()
|
||||
.build()
|
||||
|
||||
@@ -5,8 +5,8 @@ import ch.tutteli.atrium.assertions.Assertion
|
||||
import ch.tutteli.atrium.creating.Expect
|
||||
import ch.tutteli.atrium.creating.FeatureExpect
|
||||
import ch.tutteli.atrium.creating.RootExpect
|
||||
import ch.tutteli.atrium.domain.builders.reporting.ExpectBuilder
|
||||
import ch.tutteli.atrium.logic._logic
|
||||
import ch.tutteli.atrium.logic.creating.RootExpectBuilder
|
||||
import ch.tutteli.atrium.logic.manualFeature
|
||||
|
||||
/**
|
||||
@@ -18,7 +18,7 @@ import ch.tutteli.atrium.logic.manualFeature
|
||||
* @throws AssertionError in case an assertion does not hold.
|
||||
*/
|
||||
fun <T> assertThat(subject: T): RootExpect<T> =
|
||||
ExpectBuilder.forSubject(subject)
|
||||
RootExpectBuilder.forSubject(subject)
|
||||
.withVerb(ASSERT_THAT)
|
||||
.withoutOptions()
|
||||
.build()
|
||||
|
||||
@@ -5,8 +5,8 @@ import ch.tutteli.atrium.assertions.Assertion
|
||||
import ch.tutteli.atrium.creating.Expect
|
||||
import ch.tutteli.atrium.creating.FeatureExpect
|
||||
import ch.tutteli.atrium.creating.RootExpect
|
||||
import ch.tutteli.atrium.domain.builders.reporting.ExpectBuilder
|
||||
import ch.tutteli.atrium.logic._logic
|
||||
import ch.tutteli.atrium.logic.creating.RootExpectBuilder
|
||||
import ch.tutteli.atrium.logic.manualFeature
|
||||
|
||||
/**
|
||||
@@ -18,7 +18,7 @@ import ch.tutteli.atrium.logic.manualFeature
|
||||
* @throws AssertionError in case an assertion does not hold.
|
||||
*/
|
||||
fun <T> expect(subject: T): RootExpect<T> =
|
||||
ExpectBuilder.forSubject(subject)
|
||||
RootExpectBuilder.forSubject(subject)
|
||||
.withVerb(EXPECT)
|
||||
.withoutOptions()
|
||||
.build()
|
||||
|
||||
@@ -7,9 +7,9 @@ import ch.tutteli.atrium.reporting.translating.StringBasedTranslatable
|
||||
* Contains the [DescriptiveAssertion.description]s of the assertion functions which are applicable to [Any].
|
||||
*/
|
||||
enum class DescriptionFunLikeAssertion(override val value: String) : StringBasedTranslatable {
|
||||
@Deprecated("Will be removed with 1.0.0")
|
||||
@Deprecated("Will be removed latest with 1.0.0 (maybe earlier)")
|
||||
IS_NOT_THROWING_1("wirft"),
|
||||
@Deprecated("Will be removed with 1.0.0")
|
||||
@Deprecated("Will be removed latest with 1.0.0 (maybe earlier)")
|
||||
IS_NOT_THROWING_2("keine Exception bei Aufruf"),
|
||||
NO_EXCEPTION_OCCURRED("❗❗ keine Exception wurde geworfen"),
|
||||
THROWN_EXCEPTION_WHEN_CALLED("geworfene Exception bei Aufruf"),
|
||||
|
||||
@@ -32,9 +32,9 @@ enum class DescriptionIterableAssertion(override val value: String) : StringBase
|
||||
INDEX_FROM_TO("Index %s..%s"),
|
||||
NUMBER_OF_OCCURRENCES("Anzahl Treffer"),
|
||||
SIZE_EXCEEDED("❗❗ hasNext() hat `false` zurückgegeben"),
|
||||
@Deprecated("Will be removed with 1.0.0")
|
||||
@Deprecated("Will be removed latest with 1.0.0 (maybe earlier)")
|
||||
CANNOT_EVALUATE_SUBJECT_EMPTY_ITERABLE("$COULD_NOT_EVALUATE_DEFINED_ASSERTIONS -- `Iterable` gibt keinen nächsten Eintrag zurück.\n$VISIT_COULD_NOT_EVALUATE_ASSERTIONS"),
|
||||
@Deprecated("Will be removed with 1.0.0")
|
||||
@Deprecated("Will be removed latest with 1.0.0 (maybe earlier)")
|
||||
CANNOT_EVALUATE_SUBJECT_ONLY_NULL("$COULD_NOT_EVALUATE_DEFINED_ASSERTIONS -- `Iterable` gibt nur `null` zurück.\n$VISIT_COULD_NOT_EVALUATE_ASSERTIONS"),
|
||||
WARNING_ADDITIONAL_ELEMENTS("zusätzliche Elemente entdeckt"),
|
||||
@Deprecated("Use WARNING_ADDITIONAL_ELEMENTS; will be removed latest with 1.0.0", ReplaceWith("WARNING_ADDITIONAL_ELEMENTS"))
|
||||
|
||||
@@ -7,7 +7,7 @@ import ch.tutteli.atrium.reporting.translating.StringBasedTranslatable
|
||||
* Contains the [DescriptiveAssertion.description]s of the assertion functions which are applicable to [Map].
|
||||
*/
|
||||
enum class DescriptionListAssertion(override val value: String) : StringBasedTranslatable {
|
||||
@Deprecated("Will be removed with 1.0.0")
|
||||
@Deprecated("Will be removed latest with 1.0.0 (maybe earlier)")
|
||||
CANNOT_EVALUATE_INDEX_OUT_OF_BOUNDS("$COULD_NOT_EVALUATE_DEFINED_ASSERTIONS -- Index ausserhalb der Grenzen (index out of bounds).\n$VISIT_COULD_NOT_EVALUATE_ASSERTIONS"),
|
||||
INDEX_OUT_OF_BOUNDS("❗❗ Index ausserhalb der Grenzen (index out of bounds)")
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import ch.tutteli.atrium.reporting.translating.StringBasedTranslatable
|
||||
*/
|
||||
@Deprecated("Will be removed with latest with 1.0.0")
|
||||
enum class DescriptionMapAssertion(override val value: String) : StringBasedTranslatable {
|
||||
@Deprecated("Will be removed with 1.0.0")
|
||||
@Deprecated("Will be removed latest with 1.0.0 (maybe earlier)")
|
||||
CANNOT_EVALUATE_KEY_DOES_NOT_EXIST("$COULD_NOT_EVALUATE_DEFINED_ASSERTIONS -- der gegebene Key existiert nicht.\n$VISIT_COULD_NOT_EVALUATE_ASSERTIONS"),
|
||||
|
||||
@Deprecated("Will be removed with latest with 1.0.0")
|
||||
|
||||
@@ -12,7 +12,7 @@ enum class DescriptionThrowableAssertion(override val value: String) : StringBas
|
||||
ReplaceWith("ch.tutteli.atrium.translations.DescriptionAnyAssertion.IS_A")
|
||||
)
|
||||
IS_A("ist eine"),
|
||||
@Deprecated("Will be removed with 1.0.0",
|
||||
@Deprecated("Will be removed latest with 1.0.0 (maybe earlier)",
|
||||
ReplaceWith("ch.tutteli.atrium.translations.DescriptionFunLikeAssertion.NO_EXCEPTION_OCCURRED")
|
||||
)
|
||||
NO_EXCEPTION_OCCURRED("keine Exception wurde geworfen"),
|
||||
@@ -23,8 +23,8 @@ enum class DescriptionThrowableAssertion(override val value: String) : StringBas
|
||||
OCCURRED_EXCEPTION_MESSAGE("message"),
|
||||
OCCURRED_EXCEPTION_STACKTRACE("stacktrace"),
|
||||
OCCURRED_EXCEPTION_SUPPRESSED("suppressed"),
|
||||
@Deprecated("Will be removed with 1.0.0")
|
||||
@Deprecated("Will be removed latest with 1.0.0 (maybe earlier)")
|
||||
IS_NOT_THROWN_1("wird"),
|
||||
@Deprecated("Will be removed with 1.0.0")
|
||||
@Deprecated("Will be removed latest with 1.0.0 (maybe earlier)")
|
||||
IS_NOT_THROWN_2("nicht geworfen"),
|
||||
}
|
||||
|
||||
@@ -37,6 +37,6 @@ enum class ErrorMessages(override val value: String) : StringBasedTranslatable {
|
||||
HINT_AT_LEAST_ONE_ASSERTION_DEFINED("Sometimes you can use an alternative to `{ }` For instance, instead of `toThrow<..> { }` you should use `toThrow<..>()`"),
|
||||
// HINT_AT_LEAST_ONE_ASSERTION_DEFINED("Manchmal kann man eine Alternative zu `{ }` verwenden. Zum Beispiel, anstelle von `wirft<..> { }` sollten Sie `wirft<..>()` verwenden."),
|
||||
|
||||
@Deprecated("Will be removed with 1.0.0")
|
||||
@Deprecated("Will be removed latest with 1.0.0 (maybe earlier)")
|
||||
SUBJECT_ACCESSED_TOO_EARLY("Konnte die zusätzlichen Aussagen (Assertions) nicht auswerten; das Subjekt (subject) wurde zu früh verwendet. Bitte erfassen Sie einen Bug-Report unter $BUG_REPORT_URL inklusive Stacktrace wenn möglich -- vielen Dank."),
|
||||
}
|
||||
|
||||
@@ -7,9 +7,9 @@ import ch.tutteli.atrium.reporting.translating.StringBasedTranslatable
|
||||
* Contains the [DescriptiveAssertion.description]s of the assertion functions which are applicable to [Any].
|
||||
*/
|
||||
enum class DescriptionFunLikeAssertion(override val value: String) : StringBasedTranslatable {
|
||||
@Deprecated("Will be removed with 1.0.0")
|
||||
@Deprecated("Will be removed latest with 1.0.0 (maybe earlier)")
|
||||
IS_NOT_THROWING_1("does not"),
|
||||
@Deprecated("Will be removed with 1.0.0")
|
||||
@Deprecated("Will be removed latest with 1.0.0 (maybe earlier)")
|
||||
IS_NOT_THROWING_2("throw when invoked"),
|
||||
NO_EXCEPTION_OCCURRED("❗❗ no exception occurred"),
|
||||
THROWN_EXCEPTION_WHEN_CALLED("thrown exception when called"),
|
||||
|
||||
@@ -32,9 +32,9 @@ enum class DescriptionIterableAssertion(override val value: String) : StringBase
|
||||
INDEX_FROM_TO("index %s..%s"),
|
||||
NUMBER_OF_OCCURRENCES("number of such entries"),
|
||||
SIZE_EXCEEDED("❗❗ hasNext() returned false"),
|
||||
@Deprecated("Will be removed with 1.0.0")
|
||||
@Deprecated("Will be removed latest with 1.0.0 (maybe earlier)")
|
||||
CANNOT_EVALUATE_SUBJECT_EMPTY_ITERABLE("$COULD_NOT_EVALUATE_DEFINED_ASSERTIONS -- `Iterable` has no next entry.\n$VISIT_COULD_NOT_EVALUATE_ASSERTIONS"),
|
||||
@Deprecated("Will be removed with 1.0.0")
|
||||
@Deprecated("Will be removed latest with 1.0.0 (maybe earlier)")
|
||||
CANNOT_EVALUATE_SUBJECT_ONLY_NULL("$COULD_NOT_EVALUATE_DEFINED_ASSERTIONS -- `Iterable` returns only `null` for `next()`.\n$VISIT_COULD_NOT_EVALUATE_ASSERTIONS"),
|
||||
WARNING_ADDITIONAL_ELEMENTS("additional elements detected"),
|
||||
@Deprecated("Use WARNING_ADDITIONAL_ELEMENTS; will be removed latest with 1.0.0", ReplaceWith("WARNING_ADDITIONAL_ELEMENTS"))
|
||||
|
||||
@@ -7,7 +7,7 @@ import ch.tutteli.atrium.reporting.translating.StringBasedTranslatable
|
||||
* Contains the [DescriptiveAssertion.description]s of the assertion functions which are applicable to [Map].
|
||||
*/
|
||||
enum class DescriptionListAssertion(override val value: String) : StringBasedTranslatable {
|
||||
@Deprecated("Will be removed with 1.0.0")
|
||||
@Deprecated("Will be removed latest with 1.0.0 (maybe earlier)")
|
||||
CANNOT_EVALUATE_INDEX_OUT_OF_BOUNDS("$COULD_NOT_EVALUATE_DEFINED_ASSERTIONS -- index out of bounds.\n$VISIT_COULD_NOT_EVALUATE_ASSERTIONS"),
|
||||
INDEX_OUT_OF_BOUNDS("❗❗ index out of bounds")
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ enum class DescriptionThrowableAssertion(override val value: String) : StringBas
|
||||
)
|
||||
IS_A("is a"),
|
||||
@Deprecated(
|
||||
"Will be removed with 1.0.0",
|
||||
"Will be removed latest with 1.0.0 (maybe earlier)",
|
||||
ReplaceWith("ch.tutteli.atrium.translations.DescriptionFunLikeAssertion.NO_EXCEPTION_OCCURRED")
|
||||
)
|
||||
NO_EXCEPTION_OCCURRED("no exception occurred"),
|
||||
@@ -24,8 +24,8 @@ enum class DescriptionThrowableAssertion(override val value: String) : StringBas
|
||||
OCCURRED_EXCEPTION_MESSAGE("message"),
|
||||
OCCURRED_EXCEPTION_STACKTRACE("stacktrace"),
|
||||
OCCURRED_EXCEPTION_SUPPRESSED("suppressed"),
|
||||
@Deprecated("Will be removed with 1.0.0")
|
||||
@Deprecated("Will be removed latest with 1.0.0 (maybe earlier)")
|
||||
IS_NOT_THROWN_1("is"),
|
||||
@Deprecated("Will be removed with 1.0.0")
|
||||
@Deprecated("Will be removed latest with 1.0.0 (maybe earlier)")
|
||||
IS_NOT_THROWN_2("not thrown at all"),
|
||||
}
|
||||
|
||||
@@ -35,6 +35,6 @@ enum class ErrorMessages(override val value: String) : StringBasedTranslatable {
|
||||
)
|
||||
HINT_AT_LEAST_ONE_ASSERTION_DEFINED("Sometimes you can use an alternative to `{ }` For instance, instead of `toThrow<..> { }` you should use `toThrow<..>()`"),
|
||||
|
||||
@Deprecated("Will be removed with 1.0.0")
|
||||
@Deprecated("Will be removed latest with 1.0.0 (maybe earlier)")
|
||||
SUBJECT_ACCESSED_TOO_EARLY("Could not evaluate sub-assertions; the subject was accessed too early. Please report a bug at $BUG_REPORT_URL including stacktrace if possible -- thank you"),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user