package com.peachpasswords.vault import java.io.File import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertNull import org.junit.Assert.assertTrue import org.junit.Test class PinUnlockStoreTest { @Test fun pin_policy_requires_four_to_twelve_ascii_digits() { assertEquals("PIN must be 4–12 digits", pinValidationError("123")) assertEquals("PIN must contain digits only", pinValidationError("12a4")) assertNull(pinValidationError("1234")) assertNull(pinValidationError("123456789012")) } @Test fun pin_store_uses_hardware_envelope_and_limited_use_attempt_gates() { val relativePath = "app/src/main/java/com/peachpasswords/vault/PinUnlockStore.kt" val source = (File(relativePath).takeIf { it.exists() } ?: File("../$relativePath")).readText() assertTrue(source.contains("AndroidKeyStore")) assertTrue(source.contains("KeyProperties.KEY_ALGORITHM_HMAC_SHA256")) assertTrue(source.contains("setMaxUsageCount(1)")) assertTrue(source.contains("probeLimitedUseEnforcement()")) assertTrue(source.contains("const val FORMAT_VERSION = 3")) assertTrue(source.contains("setIsStrongBoxBacked(true)")) assertTrue(source.contains("StrongBoxUnavailableException")) assertTrue(source.contains("KeyInfo")) assertFalse(source.contains("VaultCrypto.encrypt(vaultKey, pinKey")) assertFalse(source.contains("wrap(vaultKey, pinKey)")) } }