From 066fed15220ea21ac102359283ec0dafc53b69f1 Mon Sep 17 00:00:00 2001 From: Thomas Adamcik Date: Wed, 22 Jan 2014 00:10:30 +0100 Subject: [PATCH] mpd: Update tokenizer to use mopidy.mpd.exceptions --- mopidy/mpd/exceptions.py | 4 ++- mopidy/mpd/tokenize.py | 30 +++++++++++------- tests/mpd/test_tokenizer.py | 62 +++++++++++++++++++++---------------- 3 files changed, 56 insertions(+), 40 deletions(-) diff --git a/mopidy/mpd/exceptions.py b/mopidy/mpd/exceptions.py index ec874553..6738b4c9 100644 --- a/mopidy/mpd/exceptions.py +++ b/mopidy/mpd/exceptions.py @@ -54,9 +54,11 @@ class MpdPermissionError(MpdAckError): self.message = 'you don\'t have permission for "%s"' % self.command -class MpdUnknownCommand(MpdAckError): +class MpdUnknownError(MpdAckError): error_code = MpdAckError.ACK_ERROR_UNKNOWN + +class MpdUnknownCommand(MpdUnknownError): def __init__(self, *args, **kwargs): super(MpdUnknownCommand, self).__init__(*args, **kwargs) assert self.command is not None, 'command must be given explicitly' diff --git a/mopidy/mpd/tokenize.py b/mopidy/mpd/tokenize.py index 554df9e6..04799719 100644 --- a/mopidy/mpd/tokenize.py +++ b/mopidy/mpd/tokenize.py @@ -2,6 +2,8 @@ from __future__ import unicode_literals import re +from mopidy.mpd import exceptions + class Error(Exception): pass @@ -42,27 +44,31 @@ UNESCAPE_RE = re.compile(r'\\(.)') # Backslash escapes any following char. def split(line): if not line.strip(): - raise Error('No command given') # 5@0 + raise exceptions.MpdNoCommand('No command given') match = WORD_RE.match(line) if not match: - raise Error('Invalid word character') # 5@0 + raise exceptions.MpdUnknownError('Invalid word character') whitespace, command, remainder = match.groups() if whitespace: - raise Error('Letter expected') # 5@0 + raise exceptions.MpdUnknownError('Letter expected') result = [command] while remainder: match = PARAM_RE.match(remainder) if not match: - # Following checks are simply to match MPD error messages: - match = BAD_QUOTED_PARAM_RE.match(remainder) - if match: - if match.group(1): - raise Error('Space expected after closing \'"\'') # 2@0 - else: - raise Error('Missing closing \'"\'') # 2@0 - raise Error('Invalid unquoted character') # 2@0 + msg = _determine_error_message(remainder) + raise exceptions.MpdArgError(msg, command=command) unquoted, quoted, remainder = match.groups() result.append(unquoted or UNESCAPE_RE.sub(r'\g<1>', quoted)) - return result + + +def _determine_error_message(remainder): + # Following checks are simply to match MPD error messages: + match = BAD_QUOTED_PARAM_RE.match(remainder) + if match: + if match.group(1): + return 'Space expected after closing \'"\'' + else: + return 'Missing closing \'"\'' + return 'Invalid unquoted character' diff --git a/tests/mpd/test_tokenizer.py b/tests/mpd/test_tokenizer.py index 7c014c84..546df847 100644 --- a/tests/mpd/test_tokenizer.py +++ b/tests/mpd/test_tokenizer.py @@ -4,25 +4,24 @@ from __future__ import unicode_literals import unittest -from mopidy.mpd import tokenize +from mopidy.mpd import exceptions, tokenize class TestTokenizer(unittest.TestCase): def assertTokenizeEquals(self, expected, line): self.assertEqual(expected, tokenize.split(line)) - def assertTokenizeRaisesError(self, line, message=None): - with self.assertRaises(tokenize.Error) as cm: + def assertTokenizeRaises(self, exception, message, line): + with self.assertRaises(exception) as cm: tokenize.split(line) - if message: - self.assertEqual(cm.exception.message, message) + self.assertEqual(cm.exception.message, message) def test_empty_string(self): - self.assertTokenizeRaisesError('', 'No command given') - - def test_whitespace(self): - self.assertTokenizeRaisesError(' ', 'No command given') - self.assertTokenizeRaisesError('\t\t\t', 'No command given') + ex = exceptions.MpdNoCommand + msg = 'No command given' + self.assertTokenizeRaises(ex, msg, '') + self.assertTokenizeRaises(ex, msg, ' ') + self.assertTokenizeRaises(ex, msg, '\t\t\t') def test_command(self): self.assertTokenizeEquals(['test'], 'test') @@ -34,14 +33,18 @@ class TestTokenizer(unittest.TestCase): self.assertTokenizeEquals(['test'], 'test\t\t\t') def test_command_leading_whitespace(self): - self.assertTokenizeRaisesError(' test', 'Letter expected') - self.assertTokenizeRaisesError('\ttest', 'Letter expected') + ex = exceptions.MpdUnknownError + msg = 'Letter expected' + self.assertTokenizeRaises(ex, msg, ' test') + self.assertTokenizeRaises(ex, msg, '\ttest') def test_invalid_command(self): - self.assertTokenizeRaisesError('foo/bar', 'Invalid word character') - self.assertTokenizeRaisesError('æøå', 'Invalid word character') - self.assertTokenizeRaisesError('test?', 'Invalid word character') - self.assertTokenizeRaisesError('te"st', 'Invalid word character') + ex = exceptions.MpdUnknownError + msg = 'Invalid word character' + self.assertTokenizeRaises(ex, msg, 'foo/bar') + self.assertTokenizeRaises(ex, msg, 'æøå') + self.assertTokenizeRaises(ex, msg, 'test?') + self.assertTokenizeRaises(ex, msg, 'te"st') def test_unquoted_param(self): self.assertTokenizeEquals(['test', 'param'], 'test param') @@ -56,11 +59,12 @@ class TestTokenizer(unittest.TestCase): self.assertTokenizeEquals(['test', 'param'], 'test param\t\t') def test_unquoted_param_invalid_chars(self): + ex = exceptions.MpdArgError msg = 'Invalid unquoted character' - self.assertTokenizeRaisesError('test par"m', msg) - self.assertTokenizeRaisesError('test foo\bbar', msg) - self.assertTokenizeRaisesError('test foo"bar"baz', msg) - self.assertTokenizeRaisesError('test foo\'bar', msg) + self.assertTokenizeRaises(ex, msg, 'test par"m') + self.assertTokenizeRaises(ex, msg, 'test foo\bbar') + self.assertTokenizeRaises(ex, msg, 'test foo"bar"baz') + self.assertTokenizeRaises(ex, msg, 'test foo\'bar') def test_unquoted_param_numbers(self): self.assertTokenizeEquals(['test', '123'], 'test 123') @@ -90,11 +94,12 @@ class TestTokenizer(unittest.TestCase): self.assertTokenizeEquals(['test', 'param'], 'test "param"\t\t') def test_quoted_param_invalid_chars(self): + ex = exceptions.MpdArgError msg = 'Space expected after closing \'"\'' - self.assertTokenizeRaisesError('test "foo"bar"', msg) - self.assertTokenizeRaisesError('test "foo"bar" ', msg) - self.assertTokenizeRaisesError('test "foo"bar', msg) - self.assertTokenizeRaisesError('test "foo"bar ', msg) + self.assertTokenizeRaises(ex, msg, 'test "foo"bar"') + self.assertTokenizeRaises(ex, msg, 'test "foo"bar" ') + self.assertTokenizeRaises(ex, msg, 'test "foo"bar') + self.assertTokenizeRaises(ex, msg, 'test "foo"bar ') def test_quoted_param_numbers(self): self.assertTokenizeEquals(['test', '123'], 'test "123"') @@ -133,9 +138,12 @@ class TestTokenizer(unittest.TestCase): r'test "foo\"bar" baz 123') def test_unbalanced_quotes(self): + ex = exceptions.MpdArgError msg = 'Invalid unquoted character' - self.assertTokenizeRaisesError('test "foo bar" baz"', msg) + self.assertTokenizeRaises(ex, msg, 'test "foo bar" baz"') def test_missing_closing_quote(self): - self.assertTokenizeRaisesError('test "foo', 'Missing closing \'"\'') - self.assertTokenizeRaisesError('test "foo a ', 'Missing closing \'"\'') + ex = exceptions.MpdArgError + msg = 'Missing closing \'"\'' + self.assertTokenizeRaises(ex, msg, 'test "foo') + self.assertTokenizeRaises(ex, msg, 'test "foo a ')