@file:Suppress("DEPRECATION" /* will be removed with 1.0.0 */)
package ch.tutteli.atrium.spec.creating

import ch.tutteli.atrium.api.cc.en_GB.toBe
import ch.tutteli.atrium.api.cc.en_GB.toThrow
import ch.tutteli.atrium.assertions.Assertion
import ch.tutteli.atrium.creating.CollectingAssertionPlant
import ch.tutteli.atrium.spec.AssertionVerbFactory
import ch.tutteli.atrium.spec.inCaseOf
import ch.tutteli.atrium.spec.prefixedDescribe
import org.jetbrains.spek.api.Spek
import org.jetbrains.spek.api.dsl.SpecBody
import org.jetbrains.spek.api.dsl.context
import org.jetbrains.spek.api.dsl.it

//TODO remove with 1.0.0 - no need to migrate to Spek2
@Deprecated("Switch from Assert to Expect and use Spec from atrium-specs-common; will be removed with 1.0.0")
abstract class CollectingAssertionPlantSpec(
    verbs: AssertionVerbFactory,
    testeeFactory: (() -> Int) -> CollectingAssertionPlant<Int>,
    describePrefix: String = "[Atrium] "
) : Spek({

    fun prefixedDescribe(description: String, body: SpecBody.() -> Unit)
        = prefixedDescribe(describePrefix, description, body)

    val testee = testeeFactory { 1 }

    prefixedDescribe("fun ${testee::getAssertions.name}") {

        context("no assertion has been added so far") {
            it("returns an empty list") {
                verbs.checkImmediately(testee.getAssertions()).toBe(listOf())
            }

            inCaseOf("an assertion is added") {
                val assertion: Assertion = object : Assertion {
                    override fun holds() = true
                }
                testee.addAssertion(assertion)
                it("returns the assertion") {
                    verbs.checkImmediately(testee.getAssertions()).toBe(listOf(assertion))
                }

                it("returns the assertion when calling ${testee::getAssertions.name} a second time") {
                    verbs.checkImmediately(testee.getAssertions()).toBe(listOf(assertion))
                }
            }
        }
    }

    @Suppress("DEPRECATION" /* TODO remove with 1.0.0 */)
    prefixedDescribe("accessing ${testee::subject.name}") {
        context("subject was provided") {
            it("does not throw an exception when accessing subject") {
                testee.subject
            }
        }

        context("provider throws an ${ch.tutteli.atrium.creating.PlantHasNoSubjectException::class.simpleName}") {
            val plantHasNoSubjectException = ch.tutteli.atrium.creating.PlantHasNoSubjectException()
            val testeeThrowing = testeeFactory { throw plantHasNoSubjectException }

            it("throws the exception when accessing subject") {
                verbs.checkException {
                    testeeThrowing.subject
                }.toThrow<ch.tutteli.atrium.creating.PlantHasNoSubjectException> { toBe(plantHasNoSubjectException) }
            }
        }
    }


})
