Skip to content

Commit

Permalink
Add some unit tests for CLI
Browse files Browse the repository at this point in the history
Reorganize the cli.py code to ease the testing.
  • Loading branch information
Gauvain Pocentek committed Feb 5, 2016
1 parent 8aa8d8c commit d2e30da
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 72 deletions.
145 changes: 77 additions & 68 deletions gitlab/cli.py
Expand Up @@ -63,69 +63,6 @@ def _cls_to_what(cls):
return camel_re.sub(r'\1-\2', cls.__name__).lower()


def _populate_sub_parser_by_class(cls, sub_parser):
for action_name in ['list', 'get', 'create', 'update', 'delete']:
attr = 'can' + action_name.capitalize()
if not getattr(cls, attr):
continue
sub_parser_action = sub_parser.add_parser(action_name)
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
required=True)
for x in cls.requiredUrlAttrs]
sub_parser_action.add_argument("--sudo", required=False)

if action_name == "list":
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
required=True)
for x in cls.requiredListAttrs]
sub_parser_action.add_argument("--page", required=False)
sub_parser_action.add_argument("--per-page", required=False)

elif action_name in ["get", "delete"]:
if cls not in [gitlab.CurrentUser]:
if cls.getRequiresId:
id_attr = cls.idAttr.replace('_', '-')
sub_parser_action.add_argument("--%s" % id_attr,
required=True)
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
required=True)
for x in cls.requiredGetAttrs if x != cls.idAttr]

elif action_name == "create":
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
required=True)
for x in cls.requiredCreateAttrs]
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
required=False)
for x in cls.optionalCreateAttrs]

elif action_name == "update":
id_attr = cls.idAttr.replace('_', '-')
sub_parser_action.add_argument("--%s" % id_attr,
required=True)

attrs = (cls.requiredUpdateAttrs
if (cls.requiredUpdateAttrs or cls.optionalUpdateAttrs)
else cls.requiredCreateAttrs)
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
required=True)
for x in attrs if x != cls.idAttr]

attrs = (cls.optionalUpdateAttrs
if (cls.requiredUpdateAttrs or cls.optionalUpdateAttrs)
else cls.optionalCreateAttrs)
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
required=False)
for x in attrs]

if cls in EXTRA_ACTIONS:
for action_name in sorted(EXTRA_ACTIONS[cls]):
sub_parser_action = sub_parser.add_parser(action_name)
d = EXTRA_ACTIONS[cls][action_name]
[sub_parser_action.add_argument("--%s" % arg, required=True)
for arg in d.get('required', [])]


def do_auth(gitlab_id, config_files):
try:
gl = gitlab.Gitlab.from_config(gitlab_id, config_files)
Expand Down Expand Up @@ -286,11 +223,70 @@ def do_project_milestone_issues(self, cls, gl, what, args):
_die("Impossible to get milestone issues (%s)" % str(e))


def main():
if "--version" in sys.argv:
print(gitlab.__version__)
exit(0)
def _populate_sub_parser_by_class(cls, sub_parser):
for action_name in ['list', 'get', 'create', 'update', 'delete']:
attr = 'can' + action_name.capitalize()
if not getattr(cls, attr):
continue
sub_parser_action = sub_parser.add_parser(action_name)
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
required=True)
for x in cls.requiredUrlAttrs]
sub_parser_action.add_argument("--sudo", required=False)

if action_name == "list":
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
required=True)
for x in cls.requiredListAttrs]
sub_parser_action.add_argument("--page", required=False)
sub_parser_action.add_argument("--per-page", required=False)

elif action_name in ["get", "delete"]:
if cls not in [gitlab.CurrentUser]:
if cls.getRequiresId:
id_attr = cls.idAttr.replace('_', '-')
sub_parser_action.add_argument("--%s" % id_attr,
required=True)
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
required=True)
for x in cls.requiredGetAttrs if x != cls.idAttr]

elif action_name == "create":
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
required=True)
for x in cls.requiredCreateAttrs]
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
required=False)
for x in cls.optionalCreateAttrs]

elif action_name == "update":
id_attr = cls.idAttr.replace('_', '-')
sub_parser_action.add_argument("--%s" % id_attr,
required=True)

attrs = (cls.requiredUpdateAttrs
if (cls.requiredUpdateAttrs or cls.optionalUpdateAttrs)
else cls.requiredCreateAttrs)
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
required=True)
for x in attrs if x != cls.idAttr]

attrs = (cls.optionalUpdateAttrs
if (cls.requiredUpdateAttrs or cls.optionalUpdateAttrs)
else cls.optionalCreateAttrs)
[sub_parser_action.add_argument("--%s" % x.replace('_', '-'),
required=False)
for x in attrs]

if cls in EXTRA_ACTIONS:
for action_name in sorted(EXTRA_ACTIONS[cls]):
sub_parser_action = sub_parser.add_parser(action_name)
d = EXTRA_ACTIONS[cls][action_name]
[sub_parser_action.add_argument("--%s" % arg, required=True)
for arg in d.get('required', [])]


def _build_parser(args=sys.argv[1:]):
parser = argparse.ArgumentParser(
description="GitLab API Command Line Interface")
parser.add_argument("--version", help="Display the version.",
Expand Down Expand Up @@ -330,7 +326,20 @@ def main():
_populate_sub_parser_by_class(cls, object_subparsers)
object_subparsers.required = True

arg = parser.parse_args()
return parser


def _parse_args(args=sys.argv[1:]):
parser = _build_parser()
return parser.parse_args(args)


def main():
if "--version" in sys.argv:
print(gitlab.__version__)
exit(0)

arg = _parse_args()
args = arg.__dict__

config_files = arg.config_file
Expand Down
95 changes: 95 additions & 0 deletions gitlab/tests/test_cli.py
@@ -0,0 +1,95 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2016 Gauvain Pocentek <gauvain@pocentek.net>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

from __future__ import print_function
from __future__ import absolute_import

import argparse

import six
try:
import unittest
except ImportError:
import unittest2 as unittest

from gitlab import cli


class TestCLI(unittest.TestCase):
def test_what_to_cls(self):
self.assertEqual("Foo", cli._what_to_cls("foo"))
self.assertEqual("FooBar", cli._what_to_cls("foo-bar"))

def test_cls_to_what(self):
class Class(object):
pass

class TestClass(object):
pass

self.assertEqual("test-class", cli._cls_to_what(TestClass))
self.assertEqual("class", cli._cls_to_what(Class))

def test_die(self):
with self.assertRaises(SystemExit) as test:
cli._die("foobar")

self.assertEqual(test.exception.code, 1)

def test_extra_actions(self):
for cls, data in six.iteritems(cli.EXTRA_ACTIONS):
for key in data:
self.assertIsInstance(data[key], dict)

def test_parsing(self):
args = cli._parse_args(['-v', '-g', 'gl_id',
'-c', 'foo.cfg', '-c', 'bar.cfg',
'project', 'list'])
self.assertTrue(args.verbose)
self.assertEqual(args.gitlab, 'gl_id')
self.assertEqual(args.config_file, ['foo.cfg', 'bar.cfg'])
self.assertEqual(args.what, 'project')
self.assertEqual(args.action, 'list')

def test_parser(self):
parser = cli._build_parser()
subparsers = None
for action in parser._actions:
if type(action) == argparse._SubParsersAction:
subparsers = action
break
self.assertIsNotNone(subparsers)
self.assertIn('user', subparsers.choices)

user_subparsers = None
for action in subparsers.choices['user']._actions:
if type(action) == argparse._SubParsersAction:
user_subparsers = action
break
self.assertIsNotNone(user_subparsers)
self.assertIn('list', user_subparsers.choices)
self.assertIn('get', user_subparsers.choices)
self.assertIn('delete', user_subparsers.choices)
self.assertIn('update', user_subparsers.choices)
self.assertIn('create', user_subparsers.choices)
self.assertIn('block', user_subparsers.choices)
self.assertIn('unblock', user_subparsers.choices)

actions = user_subparsers.choices['create']._option_string_actions
self.assertFalse(actions['--twitter'].required)
self.assertTrue(actions['--username'].required)
4 changes: 0 additions & 4 deletions gitlab/tests/test_gitlabobject.py
Expand Up @@ -492,7 +492,3 @@ def test_content(self):
def test_blob_fail(self):
with HTTMock(self.resp_content_fail):
self.assertRaises(GitlabGetError, self.obj.Content)


if __name__ == "__main__":
main()

0 comments on commit d2e30da

Please sign in to comment.