package com.keyboardr.testing import com.google.common.truth.* import com.google.common.truth.Truth.assertWithMessage import com.google.common.truth.Truth.assert_ import java.math.BigDecimal import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract open class AssertionBuilder internal constructor(val scope: T) { inline infix fun that(block: T.() -> Unit) { scope.block() } infix fun that(actual: BigDecimal?): BigDecimalSubject = scope.startAssert().that(actual) infix fun that(actual: Any?): Subject = scope.startAssert().that(actual) infix fun that(actual: Class<*>?): ClassSubject = scope.startAssert().that(actual) infix fun that(actual: Throwable?): ThrowableSubject = scope.startAssert().that(actual) infix fun that(actual: Long?): LongSubject = scope.startAssert().that(actual) infix fun that(actual: Double?): DoubleSubject = scope.startAssert().that(actual) infix fun that(actual: Float?): FloatSubject = scope.startAssert().that(actual) infix fun that(actual: Int?): IntegerSubject = scope.startAssert().that(actual) infix fun that(actual: Boolean?): BooleanSubject = scope.startAssert().that(actual) infix fun that(actual: String?): StringSubject = scope.startAssert().that(actual) infix fun that(actual: Iterable<*>?): IterableSubject = scope.startAssert().that(actual) infix fun that(actual: Array?): ObjectArraySubject = scope.startAssert().that(actual) infix fun that(actual: Map<*, *>?): MapSubject = scope.startAssert().that(actual) } object Assert : AssertionBuilder(Assertions) { fun withMessage(message: String) = AssertionBuilder(MessageAssertionScope(message)) fun withExtension(extension: T) = AssertionBuilder(extension) } @OptIn(ExperimentalContracts::class) inline fun assertThat(block: AssertionScope.() -> Unit) { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } Assert that block } @OptIn(ExperimentalContracts::class) inline fun assertWithMessage(message: String, block: AssertionScope.() -> Unit) { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } Assert.withMessage(message) that block } @Suppress("unused", "NOTHING_TO_INLINE") @AssertionDsl abstract class AssertionScope { open fun startAssert(): StandardSubjectBuilder = assert_() inline infix fun Boolean?.shouldBe(expected: Boolean?) = when (expected) { null -> startAssert().that(this).isNull() true -> startAssert().that(this).isTrue() false -> startAssert().that(this).isFalse() } inline infix fun Int?.shouldEqual(expected: Int) = startAssert().that(this).isEqualTo(expected) inline infix fun Long?.shouldEqual(expected: Long) = startAssert().that(this).isEqualTo(expected) inline infix fun Float?.shouldEqual(expected: Float) = startAssert().that(this).isEqualTo(expected) inline infix fun Any?.shouldEqual(expected: Any?) = startAssert().that(this).isEqualTo(expected) inline infix fun Int?.shouldNotEqual(expected: Int) = startAssert().that(this).isNotEqualTo(expected) inline infix fun Long?.shouldNotEqual(expected: Long) = startAssert().that(this).isNotEqualTo(expected) inline infix fun Float?.shouldNotEqual(expected: Float) = startAssert().that(this).isNotEqualTo(expected) inline infix fun Any?.shouldNotEqual(expected: Any) = startAssert().that(this).isNotEqualTo(expected) inline infix fun Int?.shouldBeSameAs(expected: Int) = startAssert().that(this).isSameInstanceAs(expected) inline infix fun Long?.shouldBeSameAs(expected: Long) = startAssert().that(this).isSameInstanceAs(expected) inline infix fun Float?.shouldBeSameAs(expected: Float) = startAssert().that(this).isSameInstanceAs(expected) inline infix fun Any?.shouldBeSameAs(expected: Any?) = startAssert().that(this).isSameInstanceAs(expected) inline infix fun Int?.shouldBeAtLeast(expected: Int) = startAssert().that(this).isAtLeast(expected) inline infix fun Long?.shouldBeAtLeast(expected: Long) = startAssert().that(this).isAtLeast(expected) inline infix fun Float?.shouldBeAtLeast(expected: Float) = startAssert().that(this).isAtLeast(expected) // foo shouldBe null inline infix fun Any?.shouldBe(@Suppress("UNUSED_PARAMETER") nothing: Nothing?) = startAssert().that(this).isNull() // foo shouldBe !null inline infix fun Any?.shouldBe(@Suppress("UNUSED_PARAMETER") nonNull: NonNull) = startAssert().that(this).isNotNull() inline fun Iterable<*>?.shouldBeEmpty() = startAssert().that(this).isEmpty() inline fun Iterable<*>?.shouldNotBeEmpty() = startAssert().that(this).isNotEmpty() inline fun Iterable<*>?.shouldNotContainDuplicates() = startAssert().that(this).containsNoDuplicates() inline infix fun Iterable<*>?.shouldHaveSize(expectedSize: Int) = startAssert().that(this).hasSize(expectedSize) inline infix fun Iterable<*>?.shouldContain(element: Any?) = startAssert().that(this).contains(element) inline infix fun Iterable<*>?.shouldNotContain(element: Any?) = startAssert().that(this).doesNotContain(element) inline infix fun Iterable<*>?.shouldContainOnly(element: Any?): Ordered = startAssert().that(this).containsExactly(element) inline fun Iterable<*>?.shouldContainExactlyElements(vararg varargs: Any): Ordered = startAssert().that(this).containsExactly(*varargs) inline infix fun Iterable<*>?.shouldContainExactly(expected: Iterable<*>): Ordered = startAssert().that(this).containsExactlyElementsIn(expected) inline infix fun Iterable<*>?.shouldContainExactly(expected: Array<*>): Ordered = startAssert().that(this).containsExactlyElementsIn(expected) inline operator fun Nothing?.not() = NonNull object NonNull } object Assertions : AssertionScope() class MessageAssertionScope(private val message: String) : AssertionScope() { override fun startAssert(): StandardSubjectBuilder = assertWithMessage(message) } @DslMarker annotation class AssertionDsl