No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 
 

206 líneas
7.0 KiB

  1. """passlib.tests -- tests for passlib.pwd"""
  2. #=============================================================================
  3. # imports
  4. #=============================================================================
  5. # core
  6. import itertools
  7. import logging; log = logging.getLogger(__name__)
  8. # site
  9. # pkg
  10. from passlib.tests.utils import TestCase
  11. # local
  12. __all__ = [
  13. "UtilsTest",
  14. "GenerateTest",
  15. "StrengthTest",
  16. ]
  17. #=============================================================================
  18. #
  19. #=============================================================================
  20. class UtilsTest(TestCase):
  21. """test internal utilities"""
  22. descriptionPrefix = "passlib.pwd"
  23. def test_self_info_rate(self):
  24. """_self_info_rate()"""
  25. from passlib.pwd import _self_info_rate
  26. self.assertEqual(_self_info_rate(""), 0)
  27. self.assertEqual(_self_info_rate("a" * 8), 0)
  28. self.assertEqual(_self_info_rate("ab"), 1)
  29. self.assertEqual(_self_info_rate("ab" * 8), 1)
  30. self.assertEqual(_self_info_rate("abcd"), 2)
  31. self.assertEqual(_self_info_rate("abcd" * 8), 2)
  32. self.assertAlmostEqual(_self_info_rate("abcdaaaa"), 1.5488, places=4)
  33. # def test_total_self_info(self):
  34. # """_total_self_info()"""
  35. # from passlib.pwd import _total_self_info
  36. #
  37. # self.assertEqual(_total_self_info(""), 0)
  38. #
  39. # self.assertEqual(_total_self_info("a" * 8), 0)
  40. #
  41. # self.assertEqual(_total_self_info("ab"), 2)
  42. # self.assertEqual(_total_self_info("ab" * 8), 16)
  43. #
  44. # self.assertEqual(_total_self_info("abcd"), 8)
  45. # self.assertEqual(_total_self_info("abcd" * 8), 64)
  46. # self.assertAlmostEqual(_total_self_info("abcdaaaa"), 12.3904, places=4)
  47. #=============================================================================
  48. # word generation
  49. #=============================================================================
  50. # import subject
  51. from passlib.pwd import genword, default_charsets
  52. ascii_62 = default_charsets['ascii_62']
  53. hex = default_charsets['hex']
  54. class WordGeneratorTest(TestCase):
  55. """test generation routines"""
  56. descriptionPrefix = "passlib.pwd.genword()"
  57. def setUp(self):
  58. super(WordGeneratorTest, self).setUp()
  59. # patch some RNG references so they're reproducible.
  60. from passlib.pwd import SequenceGenerator
  61. self.patchAttr(SequenceGenerator, "rng",
  62. self.getRandom("pwd generator"))
  63. def assertResultContents(self, results, count, chars, unique=True):
  64. """check result list matches expected count & charset"""
  65. self.assertEqual(len(results), count)
  66. if unique:
  67. if unique is True:
  68. unique = count
  69. self.assertEqual(len(set(results)), unique)
  70. self.assertEqual(set("".join(results)), set(chars))
  71. def test_general(self):
  72. """general behavior"""
  73. # basic usage
  74. result = genword()
  75. self.assertEqual(len(result), 9)
  76. # malformed keyword should have useful error.
  77. self.assertRaisesRegex(TypeError, "(?i)unexpected keyword.*badkwd", genword, badkwd=True)
  78. def test_returns(self):
  79. """'returns' keyword"""
  80. # returns=int option
  81. results = genword(returns=5000)
  82. self.assertResultContents(results, 5000, ascii_62)
  83. # returns=iter option
  84. gen = genword(returns=iter)
  85. results = [next(gen) for _ in range(5000)]
  86. self.assertResultContents(results, 5000, ascii_62)
  87. # invalid returns option
  88. self.assertRaises(TypeError, genword, returns='invalid-type')
  89. def test_charset(self):
  90. """'charset' & 'chars' options"""
  91. # charset option
  92. results = genword(charset="hex", returns=5000)
  93. self.assertResultContents(results, 5000, hex)
  94. # chars option
  95. # there are 3**3=27 possible combinations
  96. results = genword(length=3, chars="abc", returns=5000)
  97. self.assertResultContents(results, 5000, "abc", unique=27)
  98. # chars + charset
  99. self.assertRaises(TypeError, genword, chars='abc', charset='hex')
  100. # TODO: test rng option
  101. #=============================================================================
  102. # phrase generation
  103. #=============================================================================
  104. # import subject
  105. from passlib.pwd import genphrase
  106. simple_words = ["alpha", "beta", "gamma"]
  107. class PhraseGeneratorTest(TestCase):
  108. """test generation routines"""
  109. descriptionPrefix = "passlib.pwd.genphrase()"
  110. def assertResultContents(self, results, count, words, unique=True, sep=" "):
  111. """check result list matches expected count & charset"""
  112. self.assertEqual(len(results), count)
  113. if unique:
  114. if unique is True:
  115. unique = count
  116. self.assertEqual(len(set(results)), unique)
  117. out = set(itertools.chain.from_iterable(elem.split(sep) for elem in results))
  118. self.assertEqual(out, set(words))
  119. def test_general(self):
  120. """general behavior"""
  121. # basic usage
  122. result = genphrase()
  123. self.assertEqual(len(result.split(" ")), 4) # 48 / log(7776, 2) ~= 3.7 -> 4
  124. # malformed keyword should have useful error.
  125. self.assertRaisesRegex(TypeError, "(?i)unexpected keyword.*badkwd", genphrase, badkwd=True)
  126. def test_entropy(self):
  127. """'length' & 'entropy' keywords"""
  128. # custom entropy
  129. result = genphrase(entropy=70)
  130. self.assertEqual(len(result.split(" ")), 6) # 70 / log(7776, 2) ~= 5.4 -> 6
  131. # custom length
  132. result = genphrase(length=3)
  133. self.assertEqual(len(result.split(" ")), 3)
  134. # custom length < entropy
  135. result = genphrase(length=3, entropy=48)
  136. self.assertEqual(len(result.split(" ")), 4)
  137. # custom length > entropy
  138. result = genphrase(length=4, entropy=12)
  139. self.assertEqual(len(result.split(" ")), 4)
  140. def test_returns(self):
  141. """'returns' keyword"""
  142. # returns=int option
  143. results = genphrase(returns=1000, words=simple_words)
  144. self.assertResultContents(results, 1000, simple_words)
  145. # returns=iter option
  146. gen = genphrase(returns=iter, words=simple_words)
  147. results = [next(gen) for _ in range(1000)]
  148. self.assertResultContents(results, 1000, simple_words)
  149. # invalid returns option
  150. self.assertRaises(TypeError, genphrase, returns='invalid-type')
  151. def test_wordset(self):
  152. """'wordset' & 'words' options"""
  153. # wordset option
  154. results = genphrase(words=simple_words, returns=5000)
  155. self.assertResultContents(results, 5000, simple_words)
  156. # words option
  157. results = genphrase(length=3, words=simple_words, returns=5000)
  158. self.assertResultContents(results, 5000, simple_words, unique=3**3)
  159. # words + wordset
  160. self.assertRaises(TypeError, genphrase, words=simple_words, wordset='bip39')
  161. #=============================================================================
  162. # eof
  163. #=============================================================================