/**Junit5 Test生命周期如下：
 * @BeforeAll
 *    @BeforeEach
 *       @Test,@RepeatedTest, @ParameterizedTest, @TestFactory, or @TestTemplate
 *    @AfterEach
 * @AfterAll
 */

import org.junit.jupiter.api.*
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.DynamicTest.dynamicTest
import org.junit.jupiter.api.Order

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.OrderAnnotation::class)
class StandardTests {
    lateinit var  calculator:Calculator
    //@BeforeAll和@AfterAll在修饰非静态方法时需添加@TestInstance(TestInstance.Lifecycle.PER_CLASS)
    //在所有测试方法运行前运行
    @BeforeAll
    fun initAll() {
        println("before all")
        calculator = Calculator()
   }
    //每个测试方法运行前运行
    @BeforeEach
    fun init() {
        println("before each")
    }

    @Test
    fun succeedingTest() {
        println("succeedingTest")
        assertEquals(5, calculator.add(2, 3), "error message:2+3*5")
    }

    @Test
    @DisplayName("Custom test name:failing test")
    fun failingTest() {
        println("failingTest")
        assertEquals(1.0, calculator.div(3, 2), "error message:3/2=1.5")
        println("failing......")
    }

    @Test
    @Disabled("for demonstration purposes")
    fun skippedTest() {
        // not executed
        println("skipped test")
    }

    @Test
    @Order(1)
    fun abortedTest() {
        println("aborted test1")
        Assumptions.assumeTrue("abc".contains("Z"))
        println("aborted test2")
        Assertions.fail<Any>("test should have been aborted")
    }

    //每个测试方法运行完毕后运行
    @AfterEach
    fun tearDown() {
        println("after each")
    }

    //@BeforeAll和@AfterAll在修饰非静态方法时需添加@TestInstance(TestInstance.Lifecycle.PER_CLASS)
    //在所有测试方法运行完毕后运行
    @AfterAll
    fun tearDownAll() {
        println("after all")
    }

    //@BeforeAll和@AfterAll可以直接修饰java静态方法
    companion object {
        @BeforeAll
        @JvmStatic
        fun beforeAll() {
            println("before all---companion object")
        }

        @AfterAll
        @JvmStatic
       fun afterAll() {
            println("after all---companion object")
        }
    }

    @Test
    @Order(1)
    fun nullValues() {
     // perform assertions against null values
        println("order 1")
    }

    @RepeatedTest(3)
    @Order(2)
    fun emptyValues() {
        println("order 2")
    }

    @Test
    @Order(3)
    fun validValues() {
        println("order 3")
        // fails if execution time exceeds 100 milliseconds
    }

    @TestFactory
    fun dynamicTestsFromCollection(): Collection<DynamicTest?>? {
        return listOf(
            dynamicTest("1st dynamic test") { assertTrue(calculator.add(3, 2) == 6) },
            dynamicTest("2nd dynamic test") { assertEquals(5, calculator.mul(2, 2)) }
        )
    }

    @TestFactory
    fun dynamicTestsFromArray(): Array<DynamicTest?>? {
        return arrayOf(
            dynamicTest("3rd dynamic test") { assertTrue(calculator.add(3, 2) == 6) },
            dynamicTest("4th dynamic test") { assertEquals(4, calculator.mul(2, 2)) }
        )
    }

    @TestFactory
    fun dynamicNodeSingleTest(): DynamicNode? {
        return dynamicTest("5th dynamic test") { assertTrue(calculator.add(3, 2) == 6) }
    }

    @Nested
    @DisplayName("when new")
    inner class WhenNew {
        lateinit var list: List<Int>
        @BeforeEach
        fun createNewList() {
            println("createNewList")
            list = listOf(1, 2, 3)
        }

        @Test
        @DisplayName("is empty")
        fun isEmpty() {
            println("newList is Empty")
            assertTrue(list.isEmpty());
        }
    }
}

