diff --git a/beets/library.py b/beets/library.py index 0c1acba22..b6d8f4c07 100644 --- a/beets/library.py +++ b/beets/library.py @@ -45,7 +45,8 @@ log = logging.getLogger('beets') class PathQuery(dbcore.FieldQuery): """A query that matches all items under a given path. - On Windows paths are case-insensitive, contratly to UNIX platforms. + On Windows paths are case-insensitive by default, contrarly to UNIX + platforms. """ escape_re = re.compile(r'[\\_%]') @@ -53,11 +54,16 @@ class PathQuery(dbcore.FieldQuery): _is_windows = platform.system() == 'Windows' - def __init__(self, field, pattern, fast=True): + def __init__(self, field, pattern, fast=True, case_sensitive=None): super(PathQuery, self).__init__(field, pattern, fast) - if self._is_windows: + if case_sensitive is None: + # setting this value as the default one would make it un-patchable + # and therefore un-testable + case_sensitive = not self._is_windows + if not case_sensitive: pattern = pattern.lower() + self.case_sensitive = case_sensitive # Match the path as a single file. self.file_path = util.bytestring_path(util.normpath(pattern)) @@ -65,13 +71,13 @@ class PathQuery(dbcore.FieldQuery): self.dir_path = util.bytestring_path(os.path.join(self.file_path, b'')) def match(self, item): - path = item.path.lower() if self._is_windows else item.path + path = item.path if self.case_sensitive else item.path.lower() return (path == self.file_path) or path.startswith(self.dir_path) def col_clause(self): file_blob = buffer(self.file_path) - if not self._is_windows: + if self.case_sensitive: dir_blob = buffer(self.dir_path) return '({0} = ?) || (substr({0}, 1, ?) = ?)'.format(self.field), \ (file_blob, len(dir_blob), dir_blob) diff --git a/test/test_query.py b/test/test_query.py index 2511aa841..ee0f3d0ba 100644 --- a/test/test_query.py +++ b/test/test_query.py @@ -17,6 +17,7 @@ from __future__ import (division, absolute_import, print_function, unicode_literals) +from functools import partial from mock import patch from test import _common @@ -465,14 +466,23 @@ class PathQueryTest(_common.LibTestCase, TestHelper, AssertsMixin): def test_case_sensitivity(self): self.add_album(path='/A/B/C2.mp3', title='caps path') - q = 'path:/A/B' + + makeq = partial(beets.library.PathQuery, 'path', '/A/B') + + results = self.lib.items(makeq(case_sensitive=True)) + self.assert_items_matched(results, ['caps path']) + + results = self.lib.items(makeq(case_sensitive=False)) + self.assert_items_matched(results, ['path item', 'caps path']) + + # test platform-aware default sensitivity with patch('beets.library.PathQuery._is_windows', False): - results = self.lib.items(q) - self.assert_items_matched(results, ['caps path']) + q = makeq() + self.assertEqual(q.case_sensitive, True) with patch('beets.library.PathQuery._is_windows', True): - results = self.lib.items(q) - self.assert_items_matched(results, ['path item', 'caps path']) + q = makeq() + self.assertEqual(q.case_sensitive, False) class IntQueryTest(unittest.TestCase, TestHelper):