fix tests for new path formatting

Slowly expunging the terrible idea that was `pathmod`...
This commit is contained in:
Adrian Sampson 2013-12-25 00:28:26 -08:00
parent a9faa9bf74
commit d6ff4308f9
4 changed files with 93 additions and 52 deletions

View file

@ -193,13 +193,11 @@ def _orelse(exp1, exp2):
# Path element formatting for templating.
def format_for_path(value, key=None, pathmod=None):
def format_for_path(value, key=None):
"""Sanitize the value for inclusion in a path: replace separators
with _, etc. Doesn't guarantee that the whole path will be valid;
you should still call `util.sanitize_path` on the complete path.
"""
pathmod = pathmod or os.path
if isinstance(value, str):
value = value.decode('utf8', 'ignore')
elif key in ('track', 'tracktotal', 'disc', 'disctotal'):
@ -776,7 +774,7 @@ class Item(Model):
album = self.get_album()
if album:
for key in ALBUM_KEYS_ITEM:
mapping[key] = album._get_formatted(key)
mapping[key] = album._get_formatted(key, for_path)
# Use the album artist if the track artist is not set and
# vice-versa.
@ -825,7 +823,7 @@ class Item(Model):
subpath_tmpl = Template(path_format)
# Evaluate the selected template.
subpath = self.evaluate_template(subpath_tmpl, True, pathmod)
subpath = self.evaluate_template(subpath_tmpl, True)
# Prepare path for output: normalize Unicode characters.
if platform == 'darwin':
@ -979,7 +977,7 @@ class Album(Model):
item_dir = item_dir or self.item_dir()
filename_tmpl = Template(beets.config['art_filename'].get(unicode))
subpath = format_for_path(self.evaluate_template(filename_tmpl))
subpath = self.evaluate_template(filename_tmpl, True)
subpath = util.sanitize_path(subpath,
replacements=self._lib.replacements)
subpath = bytestring_path(subpath)
@ -1908,14 +1906,13 @@ class DefaultTemplateFunctions(object):
"""
_prefix = 'tmpl_'
def __init__(self, item=None, lib=None, pathmod=None):
def __init__(self, item=None, lib=None):
"""Paramaterize the functions. If `item` or `lib` is None, then
some functions (namely, ``aunique``) will always evaluate to the
empty string.
"""
self.item = item
self.lib = lib
self.pathmod = pathmod or os.path
def functions(self):
"""Returns a dictionary containing the functions defined in this
@ -2039,8 +2036,7 @@ class DefaultTemplateFunctions(object):
return res
# Flatten disambiguation value into a string.
disam_value = format_for_path(getattr(album, disambiguator),
disambiguator, self.pathmod)
disam_value = album._get_formatted(disambiguator, True)
res = u' [{0}]'.format(disam_value)
self.lib._memotable[memokey] = res
return res

View file

@ -19,6 +19,7 @@ import os
import logging
import tempfile
import shutil
from contextlib import contextmanager
# Use unittest2 on Python < 2.7.
try:
@ -243,3 +244,22 @@ class Bag(object):
def __getattr__(self, key):
return self.fields.get(key)
# Platform mocking.
@contextmanager
def platform_windows():
import ntpath
old_path = os.path
os.path = ntpath
yield
os.path = old_path
@contextmanager
def platform_posix():
import posixpath
old_path = os.path
os.path = posixpath
yield
os.path = old_path

View file

@ -16,8 +16,6 @@
"""
import os
import sqlite3
import ntpath
import posixpath
import shutil
import re
import unicodedata
@ -221,22 +219,26 @@ class DestinationTest(_common.TestCase):
def test_distination_windows_removes_both_separators(self):
self.i.title = 'one \\ two / three.mp3'
p = self.i.destination(pathmod=ntpath)
with _common.platform_windows():
p = self.i.destination()
self.assertFalse('one \\ two' in p)
self.assertFalse('one / two' in p)
self.assertFalse('two \\ three' in p)
self.assertFalse('two / three' in p)
def test_sanitize_unix_replaces_leading_dot(self):
p = util.sanitize_path(u'one/.two/three', posixpath)
with _common.platform_posix():
p = util.sanitize_path(u'one/.two/three')
self.assertFalse('.' in p)
def test_sanitize_windows_replaces_trailing_dot(self):
p = util.sanitize_path(u'one/two./three', ntpath)
with _common.platform_windows():
p = util.sanitize_path(u'one/two./three')
self.assertFalse('.' in p)
def test_sanitize_windows_replaces_illegal_chars(self):
p = util.sanitize_path(u':*?"<>|', ntpath)
with _common.platform_windows():
p = util.sanitize_path(u':*?"<>|')
self.assertFalse(':' in p)
self.assertFalse('*' in p)
self.assertFalse('?' in p)
@ -322,33 +324,39 @@ class DestinationTest(_common.TestCase):
self.assertEqual(self.i.destination(), np('one/three'))
def test_sanitize_windows_replaces_trailing_space(self):
p = util.sanitize_path(u'one/two /three', ntpath)
with _common.platform_windows():
p = util.sanitize_path(u'one/two /three')
self.assertFalse(' ' in p)
def test_component_sanitize_replaces_separators(self):
name = posixpath.join('a', 'b')
newname = beets.library.format_for_path(name, None, posixpath)
self.assertNotEqual(name, newname)
def test_component_sanitize_does_not_replace_separators(self):
with _common.platform_posix():
name = os.path.join('a', 'b')
newname = beets.library.format_for_path(name, None)
self.assertEqual(name, newname)
def test_component_sanitize_pads_with_zero(self):
name = beets.library.format_for_path(1, 'track', posixpath)
with _common.platform_posix():
name = beets.library.format_for_path(1, 'track')
self.assertTrue(name.startswith('0'))
def test_component_sanitize_uses_kbps_bitrate(self):
val = beets.library.format_for_path(12345, 'bitrate', posixpath)
with _common.platform_posix():
val = beets.library.format_for_path(12345, 'bitrate')
self.assertEqual(val, u'12kbps')
def test_component_sanitize_uses_khz_samplerate(self):
val = beets.library.format_for_path(12345, 'samplerate', posixpath)
with _common.platform_posix():
val = beets.library.format_for_path(12345, 'samplerate')
self.assertEqual(val, u'12kHz')
def test_component_sanitize_datetime(self):
val = beets.library.format_for_path(1368302461.210265, 'added',
posixpath)
with _common.platform_posix():
val = beets.library.format_for_path(1368302461.210265, 'added')
self.assertTrue(val.startswith('2013'))
def test_component_sanitize_none(self):
val = beets.library.format_for_path(None, 'foo', posixpath)
with _common.platform_posix():
val = beets.library.format_for_path(None, 'foo')
self.assertEqual(val, u'')
def test_artist_falls_back_to_albumartist(self):
@ -380,19 +388,22 @@ class DestinationTest(_common.TestCase):
self.assertEqual(p.rsplit(os.path.sep, 1)[1], 'something')
def test_sanitize_path_works_on_empty_string(self):
p = util.sanitize_path(u'', posixpath)
with _common.platform_posix():
p = util.sanitize_path(u'')
self.assertEqual(p, u'')
def test_sanitize_with_custom_replace_overrides_built_in_sub(self):
p = util.sanitize_path(u'a/.?/b', posixpath, [
(re.compile(ur'foo'), u'bar'),
])
with _common.platform_posix():
p = util.sanitize_path(u'a/.?/b', None, [
(re.compile(ur'foo'), u'bar'),
])
self.assertEqual(p, u'a/.?/b')
def test_sanitize_with_custom_replace_adds_replacements(self):
p = util.sanitize_path(u'foo/bar', posixpath, [
(re.compile(ur'foo'), u'bar'),
])
with _common.platform_posix():
p = util.sanitize_path(u'foo/bar', None, [
(re.compile(ur'foo'), u'bar'),
])
self.assertEqual(p, u'bar/bar')
def test_unicode_normalized_nfd_on_mac(self):
@ -434,7 +445,9 @@ class PathFormattingMixin(object):
def _assert_dest(self, dest, i=None):
if i is None:
i = self.i
self.assertEqual(i.destination(pathmod=posixpath), dest)
with _common.platform_posix():
actual = i.destination()
self.assertEqual(actual, dest)
class DestinationFunctionTest(_common.TestCase, PathFormattingMixin):
@ -552,21 +565,24 @@ class DisambiguationTest(_common.TestCase, PathFormattingMixin):
class PathConversionTest(_common.TestCase):
def test_syspath_windows_format(self):
path = ntpath.join('a', 'b', 'c')
outpath = util.syspath(path, pathmod=ntpath)
with _common.platform_windows():
path = os.path.join('a', 'b', 'c')
outpath = util.syspath(path)
self.assertTrue(isinstance(outpath, unicode))
self.assertTrue(outpath.startswith(u'\\\\?\\'))
def test_syspath_posix_unchanged(self):
path = posixpath.join('a', 'b', 'c')
outpath = util.syspath(path, pathmod=posixpath)
with _common.platform_posix():
path = os.path.join('a', 'b', 'c')
outpath = util.syspath(path)
self.assertEqual(path, outpath)
def _windows_bytestring_path(self, path):
old_gfse = sys.getfilesystemencoding
sys.getfilesystemencoding = lambda: 'mbcs'
try:
return util.bytestring_path(path, ntpath)
with _common.platform_windows():
return util.bytestring_path(path)
finally:
sys.getfilesystemencoding = old_gfse
@ -582,26 +598,32 @@ class PathConversionTest(_common.TestCase):
class PluginDestinationTest(_common.TestCase):
# Mock the plugins.template_values(item) function.
def _template_values(self, item):
return self._tv_map
def setUp(self):
super(PluginDestinationTest, self).setUp()
# Mock beets.plugins.item_field_getters.
self._tv_map = {}
self.old_template_values = plugins.template_values
plugins.template_values = self._template_values
def field_getters():
getters = {}
for key, value in self._tv_map.items():
getters[key] = lambda _: value
return getters
self.old_field_getters = plugins.item_field_getters
plugins.item_field_getters = field_getters
self.lib = beets.library.Library(':memory:')
self.lib.directory = '/base'
self.lib.path_formats = [('default', u'$artist $foo')]
self.i = item(self.lib)
def tearDown(self):
super(PluginDestinationTest, self).tearDown()
plugins.template_values = self.old_template_values
plugins.item_field_getters = self.old_field_getters
def _assert_dest(self, dest):
self.assertEqual(self.i.destination(pathmod=posixpath),
'/base/' + dest)
with _common.platform_posix():
the_dest = self.i.destination()
self.assertEqual(the_dest, '/base/' + dest)
def test_undefined_value_not_substituted(self):
self._assert_dest('the artist $foo')
@ -934,15 +956,18 @@ class PathStringTest(_common.TestCase):
class PathTruncationTest(_common.TestCase):
def test_truncate_bytestring(self):
p = util.truncate_path('abcde/fgh', posixpath, 4)
with _common.platform_posix():
p = util.truncate_path('abcde/fgh', None, 4)
self.assertEqual(p, 'abcd/fgh')
def test_truncate_unicode(self):
p = util.truncate_path(u'abcde/fgh', posixpath, 4)
with _common.platform_posix():
p = util.truncate_path(u'abcde/fgh', None, 4)
self.assertEqual(p, u'abcd/fgh')
def test_truncate_preserves_extension(self):
p = util.truncate_path(u'abcde/fgh.ext', posixpath, 5)
with _common.platform_posix():
p = util.truncate_path(u'abcde/fgh.ext', None, 5)
self.assertEqual(p, u'abcde/f.ext')

View file

@ -104,7 +104,7 @@ class ListTest(_common.TestCase):
self.assertTrue(u'1' in out)
self.assertTrue(u'the album' in out)
self.assertTrue(u'the artist' in out)
self.assertEqual(u'the artist - the album - 1', out.strip())
self.assertEqual(u'the artist - the album - 0001', out.strip())
def test_list_album_format(self):
self._run_list(album=True, fmt='$genre')