root / kamaki / cli / argument / test.py @ b7ff6e0c
History | View | Annotate | Download (11.3 kB)
1 |
# Copyright 2013 GRNET S.A. All rights reserved.
|
---|---|
2 |
#
|
3 |
# Redistribution and use in source and binary forms, with or
|
4 |
# without modification, are permitted provided that the following
|
5 |
# conditions are met:
|
6 |
#
|
7 |
# 1. Redistributions of source code must retain the above
|
8 |
# copyright notice, this list of conditions and the following
|
9 |
# disclaimer.
|
10 |
#
|
11 |
# 2. Redistributions in binary form must reproduce the above
|
12 |
# copyright notice, this list of conditions and the following
|
13 |
# disclaimer in the documentation and/or other materials
|
14 |
# provided with the distribution.
|
15 |
#
|
16 |
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
|
17 |
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18 |
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
19 |
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
|
20 |
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
21 |
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
22 |
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
23 |
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
24 |
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
25 |
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
26 |
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
27 |
# POSSIBILITY OF SUCH DAMAGE.
|
28 |
#
|
29 |
# The views and conclusions contained in the software and
|
30 |
# documentation are those of the authors and should not be
|
31 |
# interpreted as representing official policies, either expressed
|
32 |
# or implied, of GRNET S.A.
|
33 |
|
34 |
from mock import patch, call, MagicMock |
35 |
from unittest import TestCase |
36 |
from StringIO import StringIO |
37 |
from datetime import datetime |
38 |
#from itertools import product
|
39 |
|
40 |
from kamaki.cli import argument, errors |
41 |
from kamaki.cli.config import Config |
42 |
|
43 |
|
44 |
cnf_path = 'kamaki.cli.config.Config'
|
45 |
|
46 |
|
47 |
class Argument(TestCase): |
48 |
|
49 |
def test___init__(self): |
50 |
self.assertRaises(ValueError, argument.Argument, 'non-integer') |
51 |
self.assertRaises(AssertionError, argument.Argument, 1) |
52 |
self.assertRaises(AssertionError, argument.Argument, 0, 'noname') |
53 |
self.assertRaises(AssertionError, argument.Argument, 0, '--no name') |
54 |
self.assertRaises(AssertionError, argument.Argument, 0, ['-n', 'n m']) |
55 |
for arity, help, parsed_name, default in ( |
56 |
(0, 'help 0', '--zero', None), |
57 |
(1, 'help 1', ['--one', '-o'], 'lala'), |
58 |
(-1, 'help -1', ['--help', '--or', '--more'], 0), |
59 |
(0, 'help 0 again', ['--again', ], True)): |
60 |
a = argument.Argument(arity, help, parsed_name, default) |
61 |
if arity:
|
62 |
self.assertEqual(arity, a.arity)
|
63 |
self.assertEqual(help, a.help)
|
64 |
|
65 |
exp_name = parsed_name if (
|
66 |
isinstance(parsed_name, list)) else [parsed_name, ] |
67 |
self.assertEqual(exp_name, a.parsed_name)
|
68 |
|
69 |
exp_default = default or (None if arity else False) |
70 |
self.assertEqual(exp_default, a.default)
|
71 |
|
72 |
def test_value(self): |
73 |
a = argument.Argument(1, parsed_name='--value') |
74 |
for value in (None, '', 0, 0.1, -12, [1, 'a', 2.8], (3, 'lala'), 'pi'): |
75 |
a.value = value |
76 |
self.assertEqual(value, a.value)
|
77 |
|
78 |
def test_update_parser(self): |
79 |
for i, arity in enumerate((-1, 0, 1)): |
80 |
arp = argument.ArgumentParser() |
81 |
pname, aname = '--pname%s' % i, 'a_name_%s' % i |
82 |
a = argument.Argument(arity, 'args', pname, 42) |
83 |
a.update_parser(arp, aname) |
84 |
|
85 |
f = StringIO() |
86 |
arp.print_usage(file=f), f.seek(0)
|
87 |
usage, exp = f.readline(), '[%s%s]\n' % (
|
88 |
pname, (' %s' % aname.upper()) if arity else '') |
89 |
self.assertEqual(usage[-len(exp):], exp) |
90 |
del arp
|
91 |
|
92 |
|
93 |
class ConfigArgument(TestCase): |
94 |
|
95 |
def setUp(self): |
96 |
argument._config_arg = argument.ConfigArgument('Recovered Path')
|
97 |
|
98 |
def test_value(self): |
99 |
c = argument._config_arg |
100 |
self.assertEqual(c.value, None) |
101 |
exp = '/some/random/path'
|
102 |
c.value = exp |
103 |
self.assertTrue(isinstance(c.value, Config)) |
104 |
self.assertEqual(c.file_path, exp)
|
105 |
self.assertEqual(c.value.path, exp)
|
106 |
|
107 |
def test_get(self): |
108 |
c = argument._config_arg |
109 |
c.value = None
|
110 |
with patch('%s.get' % cnf_path, return_value='config') as get: |
111 |
self.assertEqual(c.value.get('global', 'config_cli'), 'config') |
112 |
self.assertEqual(get.mock_calls[-1], call('global', 'config_cli')) |
113 |
|
114 |
@patch('%s.keys' % cnf_path, return_value=( |
115 |
'image_cli', 'config_cli', 'history_cli', 'file')) |
116 |
def test_groups(self, keys): |
117 |
c = argument._config_arg |
118 |
c.value = None
|
119 |
cset = set(c.groups)
|
120 |
self.assertTrue(cset.issuperset(['image', 'config', 'history'])) |
121 |
self.assertEqual(keys.mock_calls[-1], call('global')) |
122 |
self.assertFalse('file' in cset) |
123 |
self.assertEqual(keys.mock_calls[-1], call('global')) |
124 |
|
125 |
@patch('%s.items' % cnf_path, return_value=( |
126 |
('image_cli', 'image'), ('file', 'pithos'), |
127 |
('config_cli', 'config'), ('history_cli', 'history'))) |
128 |
def test_cli_specs(self, items): |
129 |
c = argument._config_arg |
130 |
c.value = None
|
131 |
cset = set(c.cli_specs)
|
132 |
self.assertTrue(cset.issuperset([
|
133 |
('image', 'image'), ('config', 'config'), ('history', 'history')])) |
134 |
self.assertEqual(items.mock_calls[-1], call('global')) |
135 |
self.assertFalse(cset.issuperset([('file', 'pithos'), ])) |
136 |
self.assertEqual(items.mock_calls[-1], call('global')) |
137 |
|
138 |
def test_get_global(self): |
139 |
c = argument._config_arg |
140 |
c.value = None
|
141 |
for k, v in ( |
142 |
('config_cli', 'config'), |
143 |
('image_cli', 'image'), |
144 |
('history_cli', 'history')): |
145 |
with patch('%s.get_global' % cnf_path, return_value=v) as gg: |
146 |
self.assertEqual(c.get_global(k), v)
|
147 |
self.assertEqual(gg.mock_calls[-1], call(k)) |
148 |
|
149 |
def test_get_cloud(self): |
150 |
c = argument._config_arg |
151 |
c.value = None
|
152 |
with patch(
|
153 |
'%s.get_cloud' % cnf_path,
|
154 |
return_value='http://cloud') as get_cloud: |
155 |
self.assertTrue(len(c.get_cloud('mycloud', 'url')) > 0) |
156 |
self.assertEqual(get_cloud.mock_calls[-1], call('mycloud', 'url')) |
157 |
with patch(
|
158 |
'%s.get_cloud' % cnf_path,
|
159 |
side_effect=KeyError('no token')) as get_cloud: |
160 |
self.assertRaises(KeyError, c.get_cloud, 'mycloud', 'token') |
161 |
invalidcloud = 'PLEASE_DO_NOT_EVER_NAME_YOUR_CLOUD_LIKE_THIS111'
|
162 |
self.assertRaises(KeyError, c.get_cloud, invalidcloud, 'url') |
163 |
|
164 |
|
165 |
class RuntimeConfigArgument(TestCase): |
166 |
|
167 |
def setUp(self): |
168 |
argument._config_arg = argument.ConfigArgument('Recovered Path')
|
169 |
|
170 |
@patch('kamaki.cli.argument.Argument.__init__') |
171 |
def test___init__(self, arg): |
172 |
config, help, pname, default = 'config', 'help', 'pname', 'default' |
173 |
rca = argument.RuntimeConfigArgument(config, help, pname, default) |
174 |
self.assertTrue(isinstance(rca, argument.RuntimeConfigArgument)) |
175 |
self.assertEqual(rca._config_arg, config)
|
176 |
self.assertEqual(arg.mock_calls[-1], call(1, help, pname, default)) |
177 |
|
178 |
@patch('%s.override' % cnf_path) |
179 |
def test_value(self, override): |
180 |
config, help, pname, default = argument._config_arg, 'help', '-n', 'df' |
181 |
config.value = None
|
182 |
rca = argument.RuntimeConfigArgument(config, help, pname, default) |
183 |
self.assertEqual(rca.value, default)
|
184 |
|
185 |
for options in ('grp', 'grp.opt', 'k v', '=nokey', 2.8, None, 42, ''): |
186 |
self.assertRaises(TypeError, rca.value, options) |
187 |
|
188 |
for options in ('key=val', 'grp.key=val', 'dotted.opt.key=val'): |
189 |
rca.value = options |
190 |
option, sep, val = options.partition('=')
|
191 |
grp, sep, key = option.partition('.')
|
192 |
grp, key = (grp, key) if key else ('global', grp) |
193 |
self.assertEqual(override.mock_calls[-1], call(grp, key, val)) |
194 |
|
195 |
|
196 |
class FlagArgument(TestCase): |
197 |
|
198 |
@patch('kamaki.cli.argument.Argument.__init__') |
199 |
def test___init__(self, arg): |
200 |
help, pname, default = 'help', 'pname', 'default' |
201 |
fa = argument.FlagArgument(help, pname, default) |
202 |
self.assertTrue(isinstance(fa, argument.FlagArgument)) |
203 |
arg.assert_called_once(0, help, pname, default)
|
204 |
|
205 |
|
206 |
class ValueArgument(TestCase): |
207 |
|
208 |
@patch('kamaki.cli.argument.Argument.__init__') |
209 |
def test___init__(self, arg): |
210 |
help, pname, default = 'help', 'pname', 'default' |
211 |
fa = argument.ValueArgument(help, pname, default) |
212 |
self.assertTrue(isinstance(fa, argument.ValueArgument)) |
213 |
arg.assert_called_once(1, help, pname, default)
|
214 |
|
215 |
|
216 |
class IntArgument(TestCase): |
217 |
|
218 |
def test_value(self): |
219 |
ia = argument.IntArgument(parsed_name='--ia')
|
220 |
self.assertEqual(ia.value, None) |
221 |
for v in (1, 0, -1, 923455555555555555555555555555555): |
222 |
ia.value = v |
223 |
self.assertEqual(ia.value, v)
|
224 |
for v in ('1', '-1', 2.8): |
225 |
ia.value = v |
226 |
self.assertEqual(ia.value, int(v)) |
227 |
for v, err in ( |
228 |
('invalid', errors.CLIError),
|
229 |
(None, TypeError), (False, TypeError), ([1, 2, 3], TypeError)): |
230 |
try:
|
231 |
ia.value = v |
232 |
except Exception as e: |
233 |
self.assertTrue(isinstance(e, err)) |
234 |
|
235 |
|
236 |
class DateArgument(TestCase): |
237 |
|
238 |
def test_timestamp(self): |
239 |
da = argument.DateArgument(parsed_name='--date')
|
240 |
self.assertEqual(da.timestamp, None) |
241 |
date, format, exp = '24-10-1917', '%d-%m-%Y', -1646964000.0 |
242 |
da._value = argument.dtm.strptime(date, format) |
243 |
self.assertEqual(da.timestamp, exp)
|
244 |
|
245 |
def test_formated(self): |
246 |
da = argument.DateArgument(parsed_name='--date')
|
247 |
self.assertEqual(da.formated, None) |
248 |
date, format, exp = ( |
249 |
'24-10-1917', '%d-%m-%Y', 'Wed Oct 24 00:00:00 1917') |
250 |
da._value = argument.dtm.strptime(date, format) |
251 |
self.assertEqual(da.formated, exp)
|
252 |
|
253 |
@patch('kamaki.cli.argument.DateArgument.timestamp') |
254 |
@patch('kamaki.cli.argument.DateArgument.format_date') |
255 |
def test_value(self, format_date, timestamp): |
256 |
da = argument.DateArgument(parsed_name='--date')
|
257 |
self.assertTrue(isinstance(da.value, MagicMock)) |
258 |
da.value = 'Something'
|
259 |
format_date.assert_called_once(call('Something'))
|
260 |
|
261 |
def test_format_date(self): |
262 |
da = argument.DateArgument(parsed_name='--date')
|
263 |
for datestr, exp in ( |
264 |
('Wed Oct 24 01:02:03 1917', datetime(1917, 10, 24, 1, 2, 3)), |
265 |
('24-10-1917', datetime(1917, 10, 24)), |
266 |
('01:02:03 24-10-1917', datetime(1917, 10, 24, 1, 2, 3))): |
267 |
self.assertEqual(da.format_date(datestr), exp)
|
268 |
for datestr, err in ( |
269 |
('32-40-20134', errors.CLIError),
|
270 |
('Wednesday, 24 Oct 2017', errors.CLIError),
|
271 |
(None, TypeError), (0.8, TypeError)): |
272 |
self.assertRaises(err, da.format_date, datestr)
|
273 |
|
274 |
|
275 |
if __name__ == '__main__': |
276 |
from sys import argv |
277 |
from kamaki.cli.test import runTestCase |
278 |
runTestCase(Argument, 'Argument', argv[1:]) |
279 |
runTestCase(ConfigArgument, 'ConfigArgument', argv[1:]) |
280 |
runTestCase(RuntimeConfigArgument, 'RuntimeConfigArgument', argv[1:]) |
281 |
runTestCase(FlagArgument, 'FlagArgument', argv[1:]) |
282 |
runTestCase(FlagArgument, 'ValueArgument', argv[1:]) |
283 |
runTestCase(IntArgument, 'IntArgument', argv[1:]) |
284 |
runTestCase(DateArgument, 'DateArgument', argv[1:]) |