diff --git a/pubs/pubs_cmd.py b/pubs/pubs_cmd.py index da8a43e..2edfd65 100644 --- a/pubs/pubs_cmd.py +++ b/pubs/pubs_cmd.py @@ -69,7 +69,6 @@ def execute(raw_args=sys.argv): prog="pubs", add_help=True) parser.add_argument('--version', action='version', version=__version__) subparsers = parser.add_subparsers(title="valid commands", dest="command") - subparsers.required = True # Populate the parser with core commands for cmd_name, cmd_mod in CORE_CMDS.items(): @@ -83,8 +82,15 @@ def execute(raw_args=sys.argv): # Eventually autocomplete autocomplete(parser) + # Parse and run appropriate command - args = parser.parse_args(remaining_args) + # if no command, print help and exit peacefully (as '--help' does) + args = parser.parse_args(remaining_args) + if not args.command: + ui.error("Too few arguments!\n") + parser.print_help(file=sys.stderr) + sys.exit(2) + args.prog = "pubs" # FIXME? args.func(conf, args) diff --git a/readme.md b/readme.md index 1a060e2..21767db 100644 --- a/readme.md +++ b/readme.md @@ -125,3 +125,4 @@ You can access the self-documented configuration by using `pubs conf`, and all t - [Olivier Mangin](http://olivier.mangin.com) - Jonathan Grizou - Arnold Sykosch +- [Bill Flynn](https://github.com/wflynny) diff --git a/tests/fake_env.py b/tests/fake_env.py index 00ad0da..f239018 100644 --- a/tests/fake_env.py +++ b/tests/fake_env.py @@ -90,7 +90,7 @@ class FakeInput(): class TestFakeFs(fake_filesystem_unittest.TestCase): def setUp(self): - self.rootpath = os.path.dirname(__file__) + self.rootpath = os.path.abspath(os.path.dirname(__file__)) self.setUpPyfakefs() self.fs.CreateDirectory(self.rootpath) os.chdir(self.rootpath) diff --git a/tests/test_usecase.py b/tests/test_usecase.py index 506ed03..41b652a 100644 --- a/tests/test_usecase.py +++ b/tests/test_usecase.py @@ -35,8 +35,15 @@ class FakeSystemExit(Exception): function, so they can be catched by ExpectedFailure tests in Python 2.x. If a code is expected to raise SystemExit, catch FakeSystemExit instead. + + Added explicit __init__ so SystemExit.code functionality could be emulated. + Taking form from https://stackoverflow.com/a/26938914/1634191 """ - pass + def __init__(self, message, code=None, *args): + self.message = message + self.code = code + + super(FakeSystemExit, self).__init__(message, *args) # code for fake fs @@ -131,9 +138,9 @@ class CommandTestCase(fake_env.TestFakeFs): exc_class, exc, tb = sys.exc_info() if sys.version_info.major == 2: # using six to avoid a SyntaxError in Python 3.x - six.reraise(FakeSystemExit, exc, tb) + six.reraise(FakeSystemExit, FakeSystemExit(*exc.args), tb) else: - raise FakeSystemExit(exc).with_traceback(tb) + raise FakeSystemExit(*exc.args).with_traceback(tb) def tearDown(self): pass @@ -190,8 +197,27 @@ class URLContentTestCase(DataCommandTestCase): class TestAlone(CommandTestCase): def test_alone_misses_command(self): - with self.assertRaises(FakeSystemExit): + with self.assertRaises(FakeSystemExit) as cm: self.execute_cmds(['pubs']) + self.assertEqual(cm.exception.code, 2) + + + @unittest.skipIf(sys.version_info.major == 2, "not supported for Python2") + def test_alone_prints_help(self): + # capturing the output of `pubs --help` is difficult because argparse + # raises as SystemExit(0) after calling `print_help`, and this gets + # caught so no output is captured. so comparing outputs of `pubs` and + # `pubs --help` isn't too easy unless substantially reorganization of + # the parser and testing context is made. instead, the exit codes of + # the two usecases are compared. + + with self.assertRaises(FakeSystemExit) as cm1: + self.execute_cmds(['pubs']) + + with self.assertRaises(FakeSystemExit) as cm2: + self.execute_cmds(['pubs', '--help']) + + self.assertEqual(cm1.exception.code, cm2.exception.code, 2) class TestInit(CommandTestCase):