package com.peachpasswords.autofill import org.junit.Assert.assertEquals import org.junit.Assert.assertNull import org.junit.Assert.assertTrue import org.junit.Test class PasswordPolicyTest { @Test fun reads_minlength_and_maxlength_attributes() { val p = PasswordPolicy.fromHtmlAttributes(mapOf("minlength" to "8", "maxlength" to "64")) assertEquals(8, p.minLength) assertEquals(64, p.maxLength) } @Test fun ignores_non_positive_lengths() { val p = PasswordPolicy.fromHtmlAttributes(mapOf("minlength" to "0", "maxlength" to "-1")) assertNull(p.minLength) assertNull(p.maxLength) } @Test fun pattern_range_fills_both_bounds() { val p = PasswordPolicy.fromHtmlAttributes(mapOf("pattern" to ".{8,20}")) assertEquals(8, p.minLength) assertEquals(20, p.maxLength) } @Test fun pattern_min_only() { val p = PasswordPolicy.fromHtmlAttributes(mapOf("pattern" to ".{12,}")) assertEquals(12, p.minLength) assertNull(p.maxLength) } @Test fun pattern_exact_sets_both() { val p = PasswordPolicy.fromHtmlAttributes(mapOf("pattern" to "[a-z]{10}")) assertEquals(10, p.minLength) assertEquals(10, p.maxLength) } @Test fun attributes_win_over_pattern() { val p = PasswordPolicy.fromHtmlAttributes( mapOf("minlength" to "6", "maxlength" to "30", "pattern" to ".{8,20}"), ) assertEquals(6, p.minLength) assertEquals(30, p.maxLength) } @Test fun no_constraints_yields_empty_policy() { val p = PasswordPolicy.fromHtmlAttributes(mapOf("autocomplete" to "new-password")) assertNull(p.minLength) assertNull(p.maxLength) } @Test fun generation_prefers_max_length() { // Strongest the site accepts. assertEquals(64, PasswordPolicy(minLength = 8, maxLength = 64).generationLength()) } @Test fun generation_caps_at_hard_max() { assertEquals(256, PasswordPolicy(maxLength = 500).generationLength()) } @Test fun generation_snaps_up_to_min() { // default 20 < min 25 -> snap up. assertEquals(25, PasswordPolicy(minLength = 25).generationLength()) } @Test fun generation_default_when_unconstrained() { assertEquals(PasswordPolicy.DEFAULT_LENGTH, PasswordPolicy().generationLength()) } @Test fun generation_never_below_the_floor() { // A page cannot talk the generator below the minimum under a // "strong password" label (PB-26-136). assertEquals(PasswordPolicy.MIN_GENERATION_LENGTH, PasswordPolicy(maxLength = 0).generationLength()) assertEquals(PasswordPolicy.MIN_GENERATION_LENGTH, PasswordPolicy(maxLength = 1).generationLength()) assertTrue(PasswordPolicy(maxLength = 1).isWeaklyConstrained) } @Test fun constraint_note_max() { val p = PasswordPolicy(maxLength = 20) assertEquals("This site allows max 20 characters", p.constraintNote(20)) } @Test fun constraint_note_min() { val p = PasswordPolicy(minLength = 12) assertEquals("This site requires at least 12 characters", p.constraintNote(12)) } @Test fun constraint_note_empty_when_interior() { val p = PasswordPolicy(minLength = 8, maxLength = 64) assertEquals("", p.constraintNote(30)) } }