diff --git a/beetsplug/bpd/__init__.py b/beetsplug/bpd/__init__.py index 99221bb9e..64fe49969 100644 --- a/beetsplug/bpd/__init__.py +++ b/beetsplug/bpd/__init__.py @@ -657,9 +657,19 @@ class Command(object): """ command_match = self.command_re.match(s) self.name = command_match.group(1) + + self.args = [] arg_matches = self.arg_re.findall(s[command_match.end():]) - self.args = [m[0] or m[1] for m in arg_matches] - self.args = [s.decode('utf8') for s in self.args] + for match in arg_matches: + if match[0]: + # Quoted argument. + arg = match[0] + arg = arg.replace('\\"', '"').replace('\\\\', '\\') + else: + # Unquoted argument. + arg = match[1] + arg = arg.decode('utf8') + self.args.append(arg) def run(self, conn): """Executes the command on the given connection. diff --git a/test/test_player.py b/test/test_player.py index 7c8adfd45..4bd95bb78 100644 --- a/test/test_player.py +++ b/test/test_player.py @@ -85,6 +85,47 @@ class FauxPathTest(unittest.TestCase): # Note that the path encodes doesn't currently try to distinguish # between the placeholder and strings identical to the placeholder. # This might be a nice feature but is not currently essential. + +class CommandParseTest(unittest.TestCase): + def test_no_args(self): + s = ur'command' + c = bpd.Command(s) + self.assertEqual(c.name, u'command') + self.assertEqual(c.args, []) + + def test_one_unquoted_arg(self): + s = ur'command hello' + c = bpd.Command(s) + self.assertEqual(c.name, u'command') + self.assertEqual(c.args, [u'hello']) + + def test_two_unquoted_args(self): + s = ur'command hello there' + c = bpd.Command(s) + self.assertEqual(c.name, u'command') + self.assertEqual(c.args, [u'hello', u'there']) + + def test_one_quoted_arg(self): + s = ur'command "hello there"' + c = bpd.Command(s) + self.assertEqual(c.name, u'command') + self.assertEqual(c.args, [u'hello there']) + + def test_heterogenous_args(self): + s = ur'command "hello there" sir' + c = bpd.Command(s) + self.assertEqual(c.name, u'command') + self.assertEqual(c.args, [u'hello there', u'sir']) + + def test_quote_in_arg(self): + s = ur'command "hello \" there"' + c = bpd.Command(s) + self.assertEqual(c.args, [u'hello " there']) + + def test_backslash_in_arg(self): + s = ur'command "hello \\ there"' + c = bpd.Command(s) + self.assertEqual(c.args, [u'hello \ there']) def suite(): return unittest.TestLoader().loadTestsFromName(__name__)