Skip to content

Commit d2e30da

Browse files
author
Gauvain Pocentek
committed
Add some unit tests for CLI
Reorganize the cli.py code to ease the testing.
1 parent 8aa8d8c commit d2e30da

File tree

3 files changed

+172
-72
lines changed

3 files changed

+172
-72
lines changed

gitlab/cli.py

+77-68
Original file line numberDiff line numberDiff line change
@@ -63,69 +63,6 @@ def _cls_to_what(cls):
6363
return camel_re.sub(r'\1-\2', cls.__name__).lower()
6464

6565

66-
def _populate_sub_parser_by_class(cls, sub_parser):
67-
for action_name in ['list', 'get', 'create', 'update', 'delete']:
68-
attr = 'can' + action_name.capitalize()
69-
if not getattr(cls, attr):
70-
continue
71-
sub_parser_action = sub_parser.add_parser(action_name)
72-
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
73-
required=True)
74-
for x in cls.requiredUrlAttrs]
75-
sub_parser_action.add_argument("--sudo", required=False)
76-
77-
if action_name == "list":
78-
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
79-
required=True)
80-
for x in cls.requiredListAttrs]
81-
sub_parser_action.add_argument("--page", required=False)
82-
sub_parser_action.add_argument("--per-page", required=False)
83-
84-
elif action_name in ["get", "delete"]:
85-
if cls not in [gitlab.CurrentUser]:
86-
if cls.getRequiresId:
87-
id_attr = cls.idAttr.replace('_', '-')
88-
sub_parser_action.add_argument("--%s" % id_attr,
89-
required=True)
90-
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
91-
required=True)
92-
for x in cls.requiredGetAttrs if x != cls.idAttr]
93-
94-
elif action_name == "create":
95-
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
96-
required=True)
97-
for x in cls.requiredCreateAttrs]
98-
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
99-
required=False)
100-
for x in cls.optionalCreateAttrs]
101-
102-
elif action_name == "update":
103-
id_attr = cls.idAttr.replace('_', '-')
104-
sub_parser_action.add_argument("--%s" % id_attr,
105-
required=True)
106-
107-
attrs = (cls.requiredUpdateAttrs
108-
if (cls.requiredUpdateAttrs or cls.optionalUpdateAttrs)
109-
else cls.requiredCreateAttrs)
110-
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
111-
required=True)
112-
for x in attrs if x != cls.idAttr]
113-
114-
attrs = (cls.optionalUpdateAttrs
115-
if (cls.requiredUpdateAttrs or cls.optionalUpdateAttrs)
116-
else cls.optionalCreateAttrs)
117-
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
118-
required=False)
119-
for x in attrs]
120-
121-
if cls in EXTRA_ACTIONS:
122-
for action_name in sorted(EXTRA_ACTIONS[cls]):
123-
sub_parser_action = sub_parser.add_parser(action_name)
124-
d = EXTRA_ACTIONS[cls][action_name]
125-
[sub_parser_action.add_argument("--%s" % arg, required=True)
126-
for arg in d.get('required', [])]
127-
128-
12966
def do_auth(gitlab_id, config_files):
13067
try:
13168
gl = gitlab.Gitlab.from_config(gitlab_id, config_files)
@@ -286,11 +223,70 @@ def do_project_milestone_issues(self, cls, gl, what, args):
286223
_die("Impossible to get milestone issues (%s)" % str(e))
287224

288225

289-
def main():
290-
if "--version" in sys.argv:
291-
print(gitlab.__version__)
292-
exit(0)
226+
def _populate_sub_parser_by_class(cls, sub_parser):
227+
for action_name in ['list', 'get', 'create', 'update', 'delete']:
228+
attr = 'can' + action_name.capitalize()
229+
if not getattr(cls, attr):
230+
continue
231+
sub_parser_action = sub_parser.add_parser(action_name)
232+
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
233+
required=True)
234+
for x in cls.requiredUrlAttrs]
235+
sub_parser_action.add_argument("--sudo", required=False)
236+
237+
if action_name == "list":
238+
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
239+
required=True)
240+
for x in cls.requiredListAttrs]
241+
sub_parser_action.add_argument("--page", required=False)
242+
sub_parser_action.add_argument("--per-page", required=False)
293243

244+
elif action_name in ["get", "delete"]:
245+
if cls not in [gitlab.CurrentUser]:
246+
if cls.getRequiresId:
247+
id_attr = cls.idAttr.replace('_', '-')
248+
sub_parser_action.add_argument("--%s" % id_attr,
249+
required=True)
250+
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
251+
required=True)
252+
for x in cls.requiredGetAttrs if x != cls.idAttr]
253+
254+
elif action_name == "create":
255+
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
256+
required=True)
257+
for x in cls.requiredCreateAttrs]
258+
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
259+
required=False)
260+
for x in cls.optionalCreateAttrs]
261+
262+
elif action_name == "update":
263+
id_attr = cls.idAttr.replace('_', '-')
264+
sub_parser_action.add_argument("--%s" % id_attr,
265+
required=True)
266+
267+
attrs = (cls.requiredUpdateAttrs
268+
if (cls.requiredUpdateAttrs or cls.optionalUpdateAttrs)
269+
else cls.requiredCreateAttrs)
270+
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
271+
required=True)
272+
for x in attrs if x != cls.idAttr]
273+
274+
attrs = (cls.optionalUpdateAttrs
275+
if (cls.requiredUpdateAttrs or cls.optionalUpdateAttrs)
276+
else cls.optionalCreateAttrs)
277+
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
278+
required=False)
279+
for x in attrs]
280+
281+
if cls in EXTRA_ACTIONS:
282+
for action_name in sorted(EXTRA_ACTIONS[cls]):
283+
sub_parser_action = sub_parser.add_parser(action_name)
284+
d = EXTRA_ACTIONS[cls][action_name]
285+
[sub_parser_action.add_argument("--%s" % arg, required=True)
286+
for arg in d.get('required', [])]
287+
288+
289+
def _build_parser(args=sys.argv[1:]):
294290
parser = argparse.ArgumentParser(
295291
description="GitLab API Command Line Interface")
296292
parser.add_argument("--version", help="Display the version.",
@@ -330,7 +326,20 @@ def main():
330326
_populate_sub_parser_by_class(cls, object_subparsers)
331327
object_subparsers.required = True
332328

333-
arg = parser.parse_args()
329+
return parser
330+
331+
332+
def _parse_args(args=sys.argv[1:]):
333+
parser = _build_parser()
334+
return parser.parse_args(args)
335+
336+
337+
def main():
338+
if "--version" in sys.argv:
339+
print(gitlab.__version__)
340+
exit(0)
341+
342+
arg = _parse_args()
334343
args = arg.__dict__
335344

336345
config_files = arg.config_file

gitlab/tests/test_cli.py

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
#
4+
# Copyright (C) 2016 Gauvain Pocentek <gauvain@pocentek.net>
5+
#
6+
# This program is free software: you can redistribute it and/or modify
7+
# it under the terms of the GNU Lesser General Public License as published by
8+
# the Free Software Foundation, either version 3 of the License, or
9+
# (at your option) any later version.
10+
#
11+
# This program is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU Lesser General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU Lesser General Public License
17+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
19+
from __future__ import print_function
20+
from __future__ import absolute_import
21+
22+
import argparse
23+
24+
import six
25+
try:
26+
import unittest
27+
except ImportError:
28+
import unittest2 as unittest
29+
30+
from gitlab import cli
31+
32+
33+
class TestCLI(unittest.TestCase):
34+
def test_what_to_cls(self):
35+
self.assertEqual("Foo", cli._what_to_cls("foo"))
36+
self.assertEqual("FooBar", cli._what_to_cls("foo-bar"))
37+
38+
def test_cls_to_what(self):
39+
class Class(object):
40+
pass
41+
42+
class TestClass(object):
43+
pass
44+
45+
self.assertEqual("test-class", cli._cls_to_what(TestClass))
46+
self.assertEqual("class", cli._cls_to_what(Class))
47+
48+
def test_die(self):
49+
with self.assertRaises(SystemExit) as test:
50+
cli._die("foobar")
51+
52+
self.assertEqual(test.exception.code, 1)
53+
54+
def test_extra_actions(self):
55+
for cls, data in six.iteritems(cli.EXTRA_ACTIONS):
56+
for key in data:
57+
self.assertIsInstance(data[key], dict)
58+
59+
def test_parsing(self):
60+
args = cli._parse_args(['-v', '-g', 'gl_id',
61+
'-c', 'foo.cfg', '-c', 'bar.cfg',
62+
'project', 'list'])
63+
self.assertTrue(args.verbose)
64+
self.assertEqual(args.gitlab, 'gl_id')
65+
self.assertEqual(args.config_file, ['foo.cfg', 'bar.cfg'])
66+
self.assertEqual(args.what, 'project')
67+
self.assertEqual(args.action, 'list')
68+
69+
def test_parser(self):
70+
parser = cli._build_parser()
71+
subparsers = None
72+
for action in parser._actions:
73+
if type(action) == argparse._SubParsersAction:
74+
subparsers = action
75+
break
76+
self.assertIsNotNone(subparsers)
77+
self.assertIn('user', subparsers.choices)
78+
79+
user_subparsers = None
80+
for action in subparsers.choices['user']._actions:
81+
if type(action) == argparse._SubParsersAction:
82+
user_subparsers = action
83+
break
84+
self.assertIsNotNone(user_subparsers)
85+
self.assertIn('list', user_subparsers.choices)
86+
self.assertIn('get', user_subparsers.choices)
87+
self.assertIn('delete', user_subparsers.choices)
88+
self.assertIn('update', user_subparsers.choices)
89+
self.assertIn('create', user_subparsers.choices)
90+
self.assertIn('block', user_subparsers.choices)
91+
self.assertIn('unblock', user_subparsers.choices)
92+
93+
actions = user_subparsers.choices['create']._option_string_actions
94+
self.assertFalse(actions['--twitter'].required)
95+
self.assertTrue(actions['--username'].required)

gitlab/tests/test_gitlabobject.py

-4
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,3 @@ def test_content(self):
492492
def test_blob_fail(self):
493493
with HTTMock(self.resp_content_fail):
494494
self.assertRaises(GitlabGetError, self.obj.Content)
495-
496-
497-
if __name__ == "__main__":
498-
main()

0 commit comments

Comments
 (0)