All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.serenitybdd.screenplay.ensure.Expectation.kt Maven / Gradle / Ivy

package net.serenitybdd.screenplay.ensure

import net.serenitybdd.screenplay.Actor
import net.thucydides.core.steps.ExecutedStepDescription
import net.thucydides.core.steps.StepEventBus
import java.time.LocalDate

typealias BooleanPredicate = (actor: Actor?, actual: A) -> Boolean
typealias SingleValuePredicate = (actor: Actor?, actual: A, expected: E) -> Boolean
typealias DoubleValuePredicate = (actor: Actor?, actual: A, startRange: E, endRange: E) -> Boolean

fun  expectThatActualIs(message: String, predicate: SingleValuePredicate) = Expectation("is $message", "is not $message", predicate)
fun  expectThatActualIs(message: String, negatedMessage: String, predicate: SingleValuePredicate) = Expectation(message, negatedMessage, predicate)
fun  expectThatActualIs(message: String, predicate: DoubleValuePredicate) = DoubleValueExpectation(message, predicate)
fun  expectThatActualIs(message: String, predicate: BooleanPredicate) = PredicateExpectation("is $message", "is not $message", predicate)
fun  expectThatActualIs(message: String, negatedMessage: String, predicate: BooleanPredicate) = PredicateExpectation(message, negatedMessage, predicate)
fun  expectThatActualIs(message: String, predicate: SingleValuePredicate, predicateDescription: String) = Expectation("is $message", "is not $message", predicate, predicateDescription)
fun  expectThatActualIs(message: String, negatedMessage: String, predicate: SingleValuePredicate, predicateDescription: String) = Expectation(message, negatedMessage, predicate, predicateDescription)
fun  expectThatActualContainsElementsThat(message: String,
                                             predicate: BooleanPredicate,
                                             predicateDescription: String,
                                             qualifier: ElementQualifier,
                                             predicateNumber: GrammaticalNumber) =
        CollectionPredicateExpectation(message,
                predicateDescription,
                qualifier,
                predicate,
                predicateNumber)

/**
 * Models a single value predicate with a description
 */
class Expectation(private val expectation: String,
                        private val negatedExpectation: String,
                        val predicate: SingleValuePredicate,
                        private val readableExpectedValue: String? = null) {

    fun describe(expected: E?, isNegated: Boolean = false, expectedDescription: String?) =
            expectationDescription(expectation,
                    negatedExpectation,
                    expected,
                    isNegated,
                    if (expectedDescription != null) expectedDescription else readableExpectedValue)

    fun compareActualWithExpected(actual: A?, expected: E, isNegated: Boolean = false, expectedDescription: String?) =
            compareExpectedWithActual(expectation,
                    negatedExpectation,
                    actual as Any?,
                    expected as Any?,
                    isNegated,
                    if (expectedDescription != null) expectedDescription else readableExpectedValue)

    fun apply(actual: A, expected: E, actor: Actor?) = predicate(actor, actual, expected)
}

/**
 * Models a value predicate with a description that takes no parameters
 */
open class PredicateExpectation(val expectation: String,
                                   private val negatedExpression: String,
                                   val predicate: BooleanPredicate,
                                   private val isNegated: Boolean = false) {
    open fun compareActualWithExpected(actual: A?, isNegated: Boolean = false, expectedDescription: String? = "a value") =
            compareExpectedWithActual(expectation, negatedExpression, actual as Any?, isNegated, expectedDescription)

    fun describe(isNegated: Boolean = false, expectedDescription: String?) =
            predicateDescription(expectation,
                    negatedExpression,
                    isNegated,
                    expectedDescription
            )

    fun apply(actual: A, actor: Actor?) = if (isNegated) !predicate(actor, actual) else predicate(actor, actual)
}

class CollectionPredicateExpectation(expectation: String,
                                        private val predicateDescription: String,
                                        private val qualifier: ElementQualifier,
                                        predicate: BooleanPredicate,
                                        private val number: GrammaticalNumber) : PredicateExpectation(expectation, "not $expectation", predicate) {
    override fun compareActualWithExpected(actual: A?, isNegated: Boolean, expectedDescription: String?) = collectionPredicateDescription(
            expectation,
            qualifier,
            predicateDescription,
            number,
            actual as Any?,
            isNegated)
}

/**
 * Models a value predicate with a description that takes two parameters
 */
class DoubleValueExpectation(val expectation: String, val predicate: DoubleValuePredicate) {
    fun compareActualWithExpected(actual: A,
                                  startRange: E?,
                                  endRange: E?,
                                  isNegated: Boolean,
                                  expectedDescription: String?) = rangeDescription(expectation,
            actual,
            startRange as Any?,
            endRange as Any?,
            isNegated,
            expectedDescription)

    fun describeRange(startRange: E?,
                 endRange: E?,
                 isNegated: Boolean,
                 expectedDescription: String?) = rangeDescription(expectation,
            startRange as Any?,
            endRange as Any?,
            isNegated,
            expectedDescription)

    fun apply(actual: A, startRange: E?, endRange: E?, actor: Actor?) = predicate(actor, actual, startRange!!, endRange!!)
}


private fun compareExpectedWithActual(expectation: String,
                                  negatedExpectation: String,
                                  actual: Any?,
                                  expected: Any?,
                                  isNegated: Boolean,
                                  readableExpectedValue: String?): String {
    val expectedAsText = specifiedDesciptionOrDescriptionFromType(expected, readableExpectedValue)
    val actualAsText = if (BlackBox.hasLastEntry()) BlackBox.lastEntry().actual else actual.toString()// else specifiedDesciptionOrDescriptionFromType(actualValue(actual), readableActualDescription)
    val expressionAsText = if (isNegated) negatedExpectation else expectation
    val expectedDescription = "Expecting $expectedAsText that $expressionAsText"
    val butGot = "But got".padEnd(expectedDescription.length, '.')
    val expectedValue = if (BlackBox.hasLastEntry()) BlackBox.lastEntry().expected else expectedValue(expected)

    return """
$expectedDescription: <$expectedValue>
$butGot: <$actualAsText>"""
}

private fun expectationDescription(expectation: String,
                                  negatedExpectation: String,
                                  expected: Any?,
                                  isNegated: Boolean,
                                  readableExpectedValue: String?): String {
    val expectedAsText = specifiedDesciptionOrDescriptionFromType(expected, readableExpectedValue)
    val expressionAsText = if (isNegated) negatedExpectation else expectation
    val expectedDescription = "$expectedAsText that $expressionAsText"
    val expectedValue = expectedValue(expected)

    return """$expectedDescription: <$expectedValue>"""
}

private fun specifiedDesciptionOrDescriptionFromType(actual: Any?, readableActualDescription: String?): String {
    if (readableActualDescription != null) return readableActualDescription else return expectedType(actual)
}

private fun rangeDescription(expectation: String,
                             actual: Any?,
                             startRange: Any?,
                             endRange: Any?,
                             isNegated: Boolean,
                             expectedDescription: String?): String {
    val expecedType = if (expectedDescription == null) expectedType(actual) else expectedDescription
    val expectedAsText = "Expecting $expecedType ${thatIsOrIsnt(isNegated)}$expectation ${expectedValue(startRange)} and ${expectedValue(endRange)}"
    val actualAsText = if (BlackBox.hasLastEntry()) BlackBox.lastEntry().actual else actualValue(actual)

    return """
$expectedAsText
But got: $actualAsText"""
}

private fun rangeDescription(expectation: String,
                             startRange: Any?,
                             endRange: Any?,
                             isNegated: Boolean,
                             expectedDescription: String?): String {
    val expecedType = if (expectedDescription == null) "a value" else expectedDescription
    return "$expecedType ${thatIsOrIsnt(isNegated)}$expectation ${expectedValue(startRange)} and ${expectedValue(endRange)}"
}

private fun compareExpectedWithActual(expectation: String, negatedExpectation: String, actual: Any?, isNegated: Boolean, expectedDescription: String? = "value"): String {
    val expectedExpression = if (!isNegated) expectation else negatedExpectation
    val expectedType = if (expectedDescription == null) expectedType(actual) else expectedDescription
    val expectedAsString = "Expecting $expectedType that $expectedExpression"
    val actualAsText = if (BlackBox.hasLastEntry()) BlackBox.lastEntry().actual else actualValue(actual)// else specifiedDesciptionOrDescriptionFromType(actualValue(actual), readableActualDescription)

    return """
$expectedAsString
But got: $actualAsText"""
}

private fun predicateDescription(expectation: String, negatedExpectation: String, isNegated: Boolean, expectedDescription: String? = "value"): String {
    val expectedExpression = if (!isNegated) expectation else negatedExpectation
    val expectedType = if (expectedDescription == null) "a value" else expectedDescription
    return "$expectedType that $expectedExpression"
}

private fun collectionPredicateDescription(expectation: String,
                                           qualifier: ElementQualifier,
                                           predicateDescription: String,
                                           number: GrammaticalNumber,
                                           actual: Any?,
                                           isNegated: Boolean): String {
    // Expecting a collection that [matches|does not match]: [all elements|no element] [have size|has size] [greater than 4]
    val resolvedQualifier = qualifier.resolve(number)
    val matchesOrDoesNotMatch = matchesOrDoesNotMatch(isNegated)
    val expected = "Expecting a collection that $matchesOrDoesNotMatch: $expectation $resolvedQualifier $predicateDescription"
    val actualAsText = if (BlackBox.hasLastEntry()) BlackBox.lastEntry().actual else actualValue(actual)

    return """
$expected
But got: ${actualAsText}"""
}

fun expectedType(expected: Any?) = if (expected is Collection<*>) "a collection" else "a value"
fun thatIsOrIsnt(isNegated: Boolean) = if (isNegated) "that is not " else "that is "
fun matchesOrDoesNotMatch(isNegated: Boolean) = if (isNegated) "does not match" else "matches"
fun expectedValue(expected: Any?) = if (expected is String) "\"$expected\"" else expected
fun actualValue(actual: Any?) = if (actual is String) "\"$actual\"" else actual




© 2015 - 2025 Weber Informatics LLC | Privacy Policy