def test_password_metrics(self):
        metrics = passwordmetrics.metrics('correcthorseb!wdbatterystaplerWd3t')
        self.assertEqual(metrics['words'], {'et', 'stapler', 'i', 'correct', 'battery', 'horse'})
        self.assertEqual(metrics['used_groups'], {'uppercase', 'lowercase', 'punctuation', 'digits'})
        self.assertEqual(metrics['unused_groups'], {'non-printable', 'whitespace', 'other'})
        self.assertEqual(metrics['length'], 34)
        self.assertAlmostEqual(metrics['entropy'], 101.57032841892621)
        self.assertAlmostEqual(metrics['word_entropy'], 62.24279530886037)
        self.assertAlmostEqual(metrics['character_entropy'], 39.32753311006583)

        metrics = passwordmetrics.metrics('b4naNAf!ddler')
        self.assertEqual(metrics['words'], {'banana', 'fiddler'})
        self.assertEqual(metrics['used_groups'], {'uppercase', 'lowercase', 'punctuation', 'digits'})
        self.assertEqual(metrics['unused_groups'], {'non-printable', 'whitespace', 'other'})
        self.assertEqual(metrics['length'], 13)
        self.assertAlmostEqual(metrics['entropy'], 40.37060138599877)
        self.assertAlmostEqual(metrics['word_entropy'], 29.585966540441248)
        self.assertAlmostEqual(metrics['character_entropy'], 10.784634845557521)

        # Repeated words do not increase entropy
        # (Although they probably should add 1)
        self.assertEqual(passwordmetrics.metrics('battery')['entropy'],
                         passwordmetrics.metrics('batterybattery')['entropy'])

        # Repeated substitutions do not increase entropy:
        self.assertEqual(passwordmetrics.metrics('b4tterybattery')['entropy'],
                         passwordmetrics.metrics('b4tteryb4ttery')['entropy'])

        # Differenty substitutions *do' not increase entropy:
        self.assertNotEqual(passwordmetrics.metrics('b4tteryb4ttery')['entropy'],
                            passwordmetrics.metrics('b4ttery84ttery')['entropy'])
    def test_substitutions(self):
        # This long password gets a reasonable score on characters alone
        self.assertAlmostEqual(passwordmetrics._character_entropy('Tr0ub4dor&3')[0], 65.54588851677637)
        # But much worse when considering it uses a word, even though it's misspelled and only
        # appears once in the whole corpus (because I put it there).
        self.assertAlmostEqual(passwordmetrics.metrics('Tr0ub4dor&3')['entropy'], 42.11714046349914)
        # Although still better than if there was no substitutions in the word
        self.assertAlmostEqual(passwordmetrics.metrics('Troubador&3')['entropy'], 31.332505617941614)

        words, rest = passwordmetrics._find_words('batterybattery', self.words)
        self.assertEquals(rest, '')

        words, rest = passwordmetrics._find_words('b4tteryb4ttery', self.words)
        self.assertEquals(rest, '4')

        words, rest = passwordmetrics._find_words('b4ttery8attery', self.words)
        self.assertEquals(rest, '48')
    def test_custom_wordlist(self):
        # You might want to include non-english words in the word list.
        words = {}
        # Open a toy wordlist
        with open('docs/ordlista_sv.txt', 'rt', encoding='latin-1') as wordlist:
            for line in wordlist.readlines():
                word, entropy = line.strip().split(' ')
                words[word] = float(entropy)

        passwordmetrics.configure(words=words)

        # It won't find English words
        res = passwordmetrics.metrics('correcthorsebatterystapler')
        self.assertEqual(res['words'], set())

        # It will find some Swedish words
        res = passwordmetrics.metrics('korrekthästbatterihäftapparat')
        self.assertEqual(res['words'], set([u'batteri', u'korrekt', u'h\xe4ftapparat', u'h\xe4st']))
 def test_password_entropy(self):
     self.assertAlmostEqual(passwordmetrics.metrics('abcdefgh')['entropy'], 36.7646671442273)
     self.assertAlmostEqual(passwordmetrics.metrics('xyFg98%!')['entropy'], 55.49709479680921)
     self.assertAlmostEqual(passwordmetrics.metrics('correcthorsebatterystaple')['entropy'], 45.58216824444706)