/*
 * Copyright 2015-2023 the original author or authors.
 *
 * All rights reserved. This program and the accompanying materials are
 * made available under the terms of the Eclipse Public License v2.0 which
 * accompanies this distribution and is available at
 *
 * https://www.eclipse.org/legal/epl-v20.html
 */
package org.junit.jupiter.api

import org.junit.jupiter.api.AssertEquals.assertEquals
import org.junit.jupiter.api.AssertionTestUtils.assertEmptyMessage
import org.junit.jupiter.api.AssertionTestUtils.assertMessageContains
import org.junit.jupiter.api.AssertionTestUtils.assertMessageEquals
import org.opentest4j.AssertionFailedError
import java.util.stream.Stream

class KotlinFailAssertionsTests {

    @Test
    fun `fail with string`() {
        val message = "test"
        val ex = assertThrows<AssertionFailedError> {
            fail(message)
        }
        assertMessageEquals(ex, message)
    }

    @Test
    fun `fail with message supplier`() {
        val message = "test"
        val ex = assertThrows<AssertionFailedError> {
            fail { message }
        }
        assertMessageEquals(ex, message)
    }

    @Test
    fun `fail with null string`() {
        val ex = assertThrows<AssertionFailedError> {
            fail(null as String?)
        }
        assertEmptyMessage(ex)
    }

    @Test
    fun `fail with null message supplier`() {
        val ex = assertThrows<AssertionFailedError> {
            fail(null as (() -> String)?)
        }
        assertEmptyMessage(ex)
    }

    @Test
    fun `fail with string and throwable`() {
        val message = "message"
        val throwableCause = "cause"
        val ex = assertThrows<AssertionFailedError> {
            fail(message, Throwable(throwableCause))
        }
        assertMessageEquals(ex, message)
        val cause = ex.cause
        assertMessageContains(cause, throwableCause)
    }

    @Test
    fun `fail with throwable`() {
        val throwableCause = "cause"
        val ex = assertThrows<AssertionFailedError> {
            fail(Throwable(throwableCause))
        }
        assertEmptyMessage(ex)
        val cause = ex.cause
        assertMessageContains(cause, throwableCause)
    }

    @Test
    fun `fail with string and null throwable`() {
        val message = "message"
        val ex = assertThrows<AssertionFailedError> {
            fail(message, null)
        }
        assertMessageEquals(ex, message)
        if (ex.cause != null) {
            throw AssertionError("Cause should have been null")
        }
    }

    @Test
    fun `fail with null string and throwable`() {
        val throwableCause = "cause"
        val ex = assertThrows<AssertionFailedError> {
            fail(null, Throwable(throwableCause))
        }
        assertEmptyMessage(ex)
        val cause = ex.cause
        assertMessageContains(cause, throwableCause)
    }

    @Test
    fun `fail usable as a stream expression`() {
        val count = Stream.empty<Any>()
            .peek { _ -> fail("peek should never be called") }
            .filter { _ -> fail("filter should never be called", Throwable("cause")) }
            .map { _ -> fail(Throwable("map should never be called")) }
            .sorted { _, _ -> fail { "sorted should never be called" } }
            .count()
        assertEquals(0L, count)
    }

    @Test
    fun `fail usable as a sequence expression`() {
        val count = emptyList<Any>()
            .asSequence()
            .onEach { _ -> fail("peek should never be called") }
            .filter { _ -> fail("filter should never be called", Throwable("cause")) }
            .map { _ -> fail(Throwable("map should never be called")) }
            .count()
        assertEquals(0, count)
    }
}
