Created
April 27, 2018 04:17
-
-
Save jrheard/552d5280186d60c0870c0c2132f3c6a0 to your computer and use it in GitHub Desktop.
how to use hypothesis to generate "valid" passwords
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import random | |
import string | |
from hypothesis import given | |
from hypothesis import settings | |
from hypothesis import strategies as st | |
import password_checker | |
def is_password_good(password): | |
return password_checker.is_password_good('jrheard', '12345', password) | |
def test_too_short_rejected(): | |
assert is_password_good('z$6') == False | |
def test_containing_student_info_is_bad(): | |
assert is_password_good('carlsJrHeard!') == False | |
assert is_password_good('Hi there! 12345') == False | |
def test_exactly_eight_characters(): | |
assert is_password_good('abc123!@') == True | |
def test_two_categories_not_enough(): | |
assert is_password_good('1234abcd') == False | |
assert is_password_good('ABCDabcd') == False | |
assert is_password_good('!!!!aaaa') == False | |
assert is_password_good('!!!AAA!A') == False | |
def test_three_categories_is_good(): | |
assert is_password_good('abc123!@') == True | |
assert is_password_good('abcABC123') == True | |
assert is_password_good('!@#ABCabc') == True | |
VALID_PASSWORD_CHARACTERS = ( | |
string.ascii_lowercase | |
+ string.ascii_uppercase | |
+ string.digits | |
+ string.punctuation | |
) | |
short_password_strategy = st.text(alphabet=VALID_PASSWORD_CHARACTERS, max_size=7) | |
@given(short_password=short_password_strategy) | |
def test_too_short_rejected_via_hypothesis(short_password): | |
assert is_password_good(short_password) == False | |
@st.composite | |
def valid_password_composite(draw): | |
"""Generates valid passwords to be given to the student's password checker. | |
See https://hypothesis.readthedocs.io/en/latest/data.html#composite-strategies. | |
""" | |
# Valid passwords can contain 3 or 4 categories of character. | |
num_categories_present = random.randint(3, 4) | |
booleans = [True] * num_categories_present | |
if num_categories_present == 3: | |
booleans.append(False) | |
random.shuffle(booleans) | |
contains_lowercase, contains_uppercase, contains_digits, contains_symbols = booleans | |
strategies = [] | |
if contains_lowercase: | |
strategies.append(draw(st.text(alphabet=string.ascii_lowercase, min_size=1))) | |
if contains_uppercase: | |
strategies.append(draw(st.text(alphabet=string.ascii_uppercase, min_size=1))) | |
if contains_digits: | |
strategies.append(draw(st.text(alphabet=string.digits, min_size=1))) | |
if contains_symbols: | |
strategies.append(draw(st.text(alphabet=string.punctuation, min_size=1))) | |
password = list(''.join(strategies)) | |
random.shuffle(password) | |
return ''.join(password) | |
valid_passwords = valid_password_composite().filter(lambda s: len(s) >= 8) | |
def doesnt_contain_student_info(password): | |
return '12345' not in password and 'jrheard' not in password | |
passwords_without_student_info = valid_passwords.filter(doesnt_contain_student_info) | |
@settings(max_examples=2000) | |
@given(password=passwords_without_student_info) | |
def test_long_enough_passwords_are_good(password): | |
assert is_password_good(password) == True |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment