diff --git a/pyutil/scripts/passphrase.py b/pyutil/scripts/passphrase.py index b69ee7c..1f4fff1 100644 --- a/pyutil/scripts/passphrase.py +++ b/pyutil/scripts/passphrase.py @@ -4,7 +4,7 @@ # This file is part of pyutil; see README.rst for licensing terms. -import argparse, math, random +import argparse, math, random, sys from pyutil.mathutil import div_ceil @@ -71,4 +71,7 @@ def main(): passphrase, bits = gen_passphrase(args.bits, allwords) - print u"Your new password is: '%s'. It is worth about %.0d bits." % (passphrase, bits) + sys.stdout.write(passphrase) + sys.stdout.write('\n') + + sys.stderr.write(u"This passphrase encodes about {:.0f} bits.\n".format(bits)) diff --git a/pyutil/test/current/test_passphrase.py b/pyutil/test/current/test_passphrase.py new file mode 100644 index 0000000..4ee818e --- /dev/null +++ b/pyutil/test/current/test_passphrase.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8-with-signature-unix; fill-column: 77 -*- +# -*- indent-tabs-mode: nil -*- + +# This file is part of pyutil; see README.rst for licensing terms. + +import unittest +from cStringIO import StringIO + +from mock import patch, call, ANY + +from pyutil.scripts import passphrase + + +class Passphrase(unittest.TestCase): + + @patch('argparse.ArgumentParser') + @patch('pyutil.scripts.passphrase.gen_passphrase') + @patch('sys.stdout') + @patch('sys.stderr') + def test_main(self, m_stderr, m_stdout, + m_gen_passphrase, m_ArgumentParser): + + m_args = m_ArgumentParser.return_value.parse_args.return_value + m_args.dictionary = StringIO('alpha\nbeta\n') + m_args.bits = 42 + + m_gen_passphrase.return_value = ('wombat', 43) + + passphrase.main() + + self.assertEqual( + m_ArgumentParser.mock_calls, + [call( + prog='passphrase', + description=('Create a random passphrase by ' + + 'picking a few random words.')), + call().add_argument( + '-d', + '--dictionary', + help=('what file to read a list of words from ' + + "(or omit this option to use passphrase's " + + 'bundled dictionary)'), + type=ANY, + metavar="DICT"), + call().add_argument( + 'bits', + help="how many bits of entropy minimum", + type=float, + metavar="BITS"), + call().parse_args()]) + + self.assertEqual( + m_gen_passphrase.mock_calls, + [call(42, {u'alpha', u'beta'})]) + + self.assertEqual( + m_stdout.mock_calls, + [call.write(u"wombat"), + call.write('\n')]) + + self.assertEqual( + m_stderr.mock_calls, + [call.write(u"This passphrase encodes about 43 bits.\n")]) diff --git a/setup.py b/setup.py index 26651a3..5181808 100644 --- a/setup.py +++ b/setup.py @@ -47,7 +47,10 @@ (os.path.join(u'pyutil', u'data'), [os.path.join(u'pyutil', u'data', u'wordlist.txt')]) ] -install_requires=[u'zbase32 >= 1.0'] +install_requires = [ + u'zbase32 >= 1.0', + u'simplejson >= 2.1.0', +] readmetext_bytes = open(u'README.rst').read() readmetext_unicode = readmetext_bytes.decode('utf-8') @@ -68,6 +71,10 @@ data_files=data_files, extras_require={u'jsonutil': [u'simplejson >= 2.1.0',]}, install_requires=install_requires, + tests_require=[ + u'twisted >= 15.5.0', # for trial (eg user: test_observer) + u'mock >= 1.3.0', + ], classifiers=trove_classifiers, entry_points = { u'console_scripts': [