package wang.yaojia.webterm.clienttls

import org.junit.jupiter.api.Assertions.assertArrayEquals
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertNull
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test

/**
 * Truth table for the pure client X509KeyManager alias selection (iOS `MutualTLSChallengeResponder`
 * analogue): present iff an identity is installed AND its key type is acceptable.
 */
class ClientKeyManagerLogicTest {
    private val alias = "device"
    private val installed = ClientKeyManagerLogic(KeyManagerIdentity(alias = alias, keyAlgorithm = "RSA"))
    private val empty = ClientKeyManagerLogic(identity = null)

    @Test
    fun presentsAliasWhenServerAcceptsOurKeyType() {
        assertEquals(alias, installed.chooseClientAlias(arrayOf("RSA")))
        assertEquals(alias, installed.chooseClientAlias(arrayOf("EC", "RSA")))
        assertEquals(alias, installed.chooseClientAlias(arrayOf("rsa")), "match is case-insensitive")
    }

    @Test
    fun failsOpenWhenServerExpressesNoKeyTypeConstraint() {
        assertEquals(alias, installed.chooseClientAlias(null))
        assertEquals(alias, installed.chooseClientAlias(emptyArray()))
    }

    @Test
    fun presentsNothingOnKeyTypeMismatch() {
        assertNull(installed.chooseClientAlias(arrayOf("EC")))
        assertNull(installed.chooseClientAlias(arrayOf("DSA", "EC")))
    }

    @Test
    fun presentsNothingWhenNoIdentityInstalled() {
        assertNull(empty.chooseClientAlias(arrayOf("RSA")))
        assertNull(empty.chooseClientAlias(null))
        assertNull(empty.clientAliases("RSA"))
        assertFalse(empty.ownsAlias(alias))
    }

    @Test
    fun clientAliasesReturnsSingletonWhenEligible() {
        assertArrayEquals(arrayOf(alias), installed.clientAliases("RSA"))
        assertArrayEquals(arrayOf(alias), installed.clientAliases(null))
        assertNull(installed.clientAliases("EC"))
    }

    @Test
    fun ownsAliasGatesKeyMaterialToThePinnedAlias() {
        assertTrue(installed.ownsAlias(alias))
        assertFalse(installed.ownsAlias("someone-else"))
        assertFalse(installed.ownsAlias(null))
    }
}
