blob: 0051aa1591dbe177908032d076c6f124c9a02654 [file] [log] [blame]
Sybren A. Stüvel3d5c0982016-03-17 13:27:41 +01001"""
2Unit tests for CLI entry points.
3"""
4
5import unittest
6import sys
7import functools
8from contextlib import contextmanager
9
10import os
11from io import StringIO, BytesIO
12
13import rsa
14import rsa.cli
15
16if sys.version_info[0] < 3:
17 IOClass = BytesIO
18else:
19 IOClass = StringIO
20
21
22@contextmanager
23def captured_output():
24 """Captures output to stdout and stderr"""
25
26 new_out, new_err = IOClass(), IOClass()
27 old_out, old_err = sys.stdout, sys.stderr
28 try:
29 sys.stdout, sys.stderr = new_out, new_err
30 yield sys.stdout, sys.stderr
31 finally:
32 sys.stdout, sys.stderr = old_out, old_err
33
34
35@contextmanager
36def cli_args(*new_argv):
37 """Updates sys.argv[1:] for a single test."""
38
39 old_args = sys.argv[:]
40 sys.argv[1:] = [str(arg) for arg in new_argv]
41
42 try:
43 yield
44 finally:
45 sys.argv[1:] = old_args
46
47
48def cleanup_files(*filenames):
49 """Makes sure the files don't exist when the test runs, and deletes them afterward."""
50
51 def remove():
52 for fname in filenames:
53 if os.path.exists(fname):
54 os.unlink(fname)
55
56 def decorator(func):
57 @functools.wraps(func)
58 def wrapper(*args, **kwargs):
59 remove()
60 try:
61 return func(*args, **kwargs)
62 finally:
63 remove()
64
65 return wrapper
66
67 return decorator
68
69
70class AbstractCliTest(unittest.TestCase):
71 def assertExits(self, status_code, func, *args, **kwargs):
72 try:
73 func(*args, **kwargs)
74 except SystemExit as ex:
75 if status_code == ex.code:
76 return
77 self.fail('SystemExit() raised by %r, but exited with code %i, expected %i' % (
78 func, ex.code, status_code))
79 else:
80 self.fail('SystemExit() not raised by %r' % func)
81
82
83class KeygenTest(AbstractCliTest):
84 def test_keygen_no_args(self):
85 with cli_args():
86 self.assertExits(1, rsa.cli.keygen)
87
88 def test_keygen_priv_stdout(self):
89 with captured_output() as (out, err):
90 with cli_args(128):
91 rsa.cli.keygen()
92
93 lines = out.getvalue().splitlines()
94 self.assertEqual('-----BEGIN RSA PRIVATE KEY-----', lines[0])
95 self.assertEqual('-----END RSA PRIVATE KEY-----', lines[-1])
96
97 # The key size should be shown on stderr
98 self.assertTrue('128-bit key' in err.getvalue())
99
100 @cleanup_files('test_cli_privkey_out.pem')
101 def test_keygen_priv_out_pem(self):
102 with captured_output() as (out, err):
103 with cli_args('--out=test_cli_privkey_out.pem', '--form=PEM', 128):
104 rsa.cli.keygen()
105
106 # The key size should be shown on stderr
107 self.assertTrue('128-bit key' in err.getvalue())
108
109 # The output file should be shown on stderr
110 self.assertTrue('test_cli_privkey_out.pem' in err.getvalue())
111
112 # If we can load the file as PEM, it's good enough.
113 with open('test_cli_privkey_out.pem', 'rb') as pemfile:
114 rsa.PrivateKey.load_pkcs1(pemfile.read())
115
116 @cleanup_files('test_cli_privkey_out.der')
117 def test_keygen_priv_out_der(self):
118 with captured_output() as (out, err):
119 with cli_args('--out=test_cli_privkey_out.der', '--form=DER', 128):
120 rsa.cli.keygen()
121
122 # The key size should be shown on stderr
123 self.assertTrue('128-bit key' in err.getvalue())
124
125 # The output file should be shown on stderr
126 self.assertTrue('test_cli_privkey_out.der' in err.getvalue())
127
128 # If we can load the file as der, it's good enough.
129 with open('test_cli_privkey_out.der', 'rb') as derfile:
130 rsa.PrivateKey.load_pkcs1(derfile.read(), format='DER')
131
132 @cleanup_files('test_cli_privkey_out.pem', 'test_cli_pubkey_out.pem')
133 def test_keygen_pub_out_pem(self):
134 with captured_output() as (out, err):
135 with cli_args('--out=test_cli_privkey_out.pem',
136 '--pubout=test_cli_pubkey_out.pem',
137 '--form=PEM', 256):
138 rsa.cli.keygen()
139
140 # The key size should be shown on stderr
141 self.assertTrue('256-bit key' in err.getvalue())
142
143 # The output files should be shown on stderr
144 self.assertTrue('test_cli_privkey_out.pem' in err.getvalue())
145 self.assertTrue('test_cli_pubkey_out.pem' in err.getvalue())
146
147 # If we can load the file as PEM, it's good enough.
148 with open('test_cli_pubkey_out.pem', 'rb') as pemfile:
149 rsa.PublicKey.load_pkcs1(pemfile.read())