diff --git a/test/_common.py b/test/_common.py index b8963d87b..dbe40dbc8 100644 --- a/test/_common.py +++ b/test/_common.py @@ -126,6 +126,16 @@ class TestCase(unittest.TestCase): self.assertFalse(os.path.exists(path), 'file exists: %s' % path) +class LibTestCase(TestCase): + """A test case that includes an in-memory library object (`lib`) and + an item added to the library (`i`). + """ + def setUp(self): + super(LibTestCase, self).setUp() + self.lib = beets.library.Library(':memory:') + self.i = item(self.lib) + + # Mock timing. diff --git a/test/rsrc/test.blb b/test/rsrc/test.blb deleted file mode 100644 index 27dfa1190..000000000 Binary files a/test/rsrc/test.blb and /dev/null differ diff --git a/test/test_db.py b/test/test_db.py index c653bd5a6..798cab7f5 100644 --- a/test/test_db.py +++ b/test/test_db.py @@ -33,28 +33,11 @@ from beets import config TEMP_LIB = os.path.join(_common.RSRC, 'test_copy.blb') -def lib(): - shutil.copy(os.path.join(_common.RSRC, 'test.blb'), TEMP_LIB) - return beets.library.Library(TEMP_LIB) -def remove_lib(): - if os.path.exists(TEMP_LIB): - os.unlink(TEMP_LIB) -def boracay(l): - return beets.library.Item(l, - **l._connection().execute('select * from items where id=3').fetchone() - ) +# Shortcut to path normalization. np = util.normpath -class LoadTest(_common.TestCase): - def setUp(self): - super(LoadTest, self).setUp() - self.lib = lib() - self.i = boracay(self.lib) - def tearDown(self): - super(LoadTest, self).tearDown() - self.lib._connection().close() - remove_lib() +class LoadTest(_common.LibTestCase): def test_load_restores_data_from_db(self): original_title = self.i.title self.i.title = 'something' @@ -63,25 +46,18 @@ class LoadTest(_common.TestCase): def test_load_clears_dirty_flags(self): self.i.artist = 'something' + self.assertTrue('artist' in self.i._dirty) self.i.load() self.assertTrue('artist' not in self.i._dirty) -class StoreTest(_common.TestCase): - def setUp(self): - super(StoreTest, self).setUp() - self.lib = lib() - self.i = boracay(self.lib) - def tearDown(self): - super(StoreTest, self).tearDown() - self.lib._connection().close() - remove_lib() +class StoreTest(_common.LibTestCase): def test_store_changes_database_value(self): self.i.year = 1987 self.i.store() new_year = self.lib._connection().execute( 'select year from items where ' - 'title="Boracay"').fetchone()['year'] + 'title="the title"').fetchone()['year'] self.assertEqual(new_year, 1987) def test_store_only_writes_dirty_fields(self): @@ -90,7 +66,7 @@ class StoreTest(_common.TestCase): self.i.store() new_genre = self.lib._connection().execute( 'select genre from items where ' - 'title="Boracay"').fetchone()['genre'] + 'title="the title"').fetchone()['genre'] self.assertEqual(new_genre, original_genre) def test_store_clears_dirty_flags(self): @@ -98,14 +74,12 @@ class StoreTest(_common.TestCase): self.i.store() self.assertTrue('composer' not in self.i._dirty) + class AddTest(_common.TestCase): def setUp(self): super(AddTest, self).setUp() self.lib = beets.library.Library(':memory:') self.i = item() - def tearDown(self): - super(AddTest, self).tearDown() - self.lib._connection().close() def test_item_add_inserts_row(self): self.lib.add(self.i) @@ -122,21 +96,14 @@ class AddTest(_common.TestCase): 'where composer="the composer"').fetchone()['grouping'] self.assertEqual(new_grouping, self.i.grouping) -class RemoveTest(_common.TestCase): - def setUp(self): - super(RemoveTest, self).setUp() - self.lib = lib() - self.i = boracay(self.lib) - def tearDown(self): - super(RemoveTest, self).tearDown() - self.lib._connection().close() - remove_lib() +class RemoveTest(_common.LibTestCase): def test_remove_deletes_from_db(self): self.i.remove() - c = self.lib._connection().execute('select * from items where id=3') + c = self.lib._connection().execute('select * from items') self.assertEqual(c.fetchone(), None) + class GetSetTest(_common.TestCase): def setUp(self): super(GetSetTest, self).setUp() @@ -157,6 +124,7 @@ class GetSetTest(_common.TestCase): def test_invalid_field_raises_attributeerror(self): self.assertRaises(AttributeError, getattr, self.i, 'xyzzy') + class DestinationTest(_common.TestCase): def setUp(self): super(DestinationTest, self).setUp() @@ -458,6 +426,7 @@ class DestinationTest(_common.TestCase): dest = self.i.destination(platform='linux2', fragment=True) self.assertEqual(dest, u'foo.caf\xe9') + class PathFormattingMixin(object): """Utilities for testing path formatting.""" def _setf(self, fmt): @@ -467,6 +436,7 @@ class PathFormattingMixin(object): i = self.i self.assertEqual(i.destination(pathmod=posixpath), dest) + class DestinationFunctionTest(_common.TestCase, PathFormattingMixin): def setUp(self): super(DestinationFunctionTest, self).setUp() @@ -518,6 +488,7 @@ class DestinationFunctionTest(_common.TestCase, PathFormattingMixin): self._setf(u'%foo{bar}') self._assert_dest('/base/%foo{bar}') + class DisambiguationTest(_common.TestCase, PathFormattingMixin): def setUp(self): super(DisambiguationTest, self).setUp() @@ -578,6 +549,7 @@ class DisambiguationTest(_common.TestCase, PathFormattingMixin): self._setf(u'foo%aunique{albumartist album,albumtype}/$title') self._assert_dest('/base/foo [foo_bar]/the title', self.i1) + class PathConversionTest(_common.TestCase): def test_syspath_windows_format(self): path = ntpath.join('a', 'b', 'c') @@ -608,6 +580,7 @@ class PathConversionTest(_common.TestCase): outpath = self._windows_bytestring_path(path) self.assertEqual(outpath, u'C:\\caf\xe9'.encode('utf8')) + class PluginDestinationTest(_common.TestCase): # Mock the plugins.template_values(item) function. def _template_values(self, item): @@ -651,6 +624,7 @@ class PluginDestinationTest(_common.TestCase): } self._assert_dest('the artist bar_baz') + class MigrationTest(_common.TestCase): """Tests the ability to change the database schema between versions. @@ -758,6 +732,7 @@ class MigrationTest(_common.TestCase): album = c.fetchone() self.assertEqual(album['albumartist'], 'theartist') + class AlbumInfoTest(_common.TestCase): def setUp(self): super(AlbumInfoTest, self).setUp() @@ -845,6 +820,7 @@ class AlbumInfoTest(_common.TestCase): self.i.remove() self.assertEqual(len(self.lib.albums()), 0) + class ArtDestinationTest(_common.TestCase): def setUp(self): super(ArtDestinationTest, self).setUp() @@ -871,6 +847,7 @@ class ArtDestinationTest(_common.TestCase): art = self.ai.art_destination('something.jpg') self.assert_('artYimage' in art) + class PathStringTest(_common.TestCase): def setUp(self): super(PathStringTest, self).setUp() @@ -954,6 +931,7 @@ class PathStringTest(_common.TestCase): alb = self.lib.get_album(alb.id) self.assert_(isinstance(alb.artpath, str)) + class PathTruncationTest(_common.TestCase): def test_truncate_bytestring(self): p = util.truncate_path('abcde/fgh', posixpath, 4) @@ -967,6 +945,7 @@ class PathTruncationTest(_common.TestCase): p = util.truncate_path(u'abcde/fgh.ext', posixpath, 5) self.assertEqual(p, u'abcde/f.ext') + class MtimeTest(_common.TestCase): def setUp(self): super(MtimeTest, self).setUp() @@ -1001,6 +980,7 @@ class MtimeTest(_common.TestCase): self.i.read() self.assertGreaterEqual(self.i.mtime, self._mtime()) + class ImportTimeTest(_common.TestCase): def setUp(self): super(ImportTimeTest, self).setUp() @@ -1016,8 +996,10 @@ class ImportTimeTest(_common.TestCase): self.singleton = item(self.lib) self.assertGreater(self.singleton.added, 0) + def suite(): return unittest.TestLoader().loadTestsFromName(__name__) + if __name__ == '__main__': unittest.main(defaultTest='suite') diff --git a/test/test_query.py b/test/test_query.py index 0066b537b..fd04209f8 100644 --- a/test/test_query.py +++ b/test/test_query.py @@ -22,7 +22,6 @@ import beets.library pqp = beets.library.parse_query_part -some_item = _common.item() class QueryParseTest(unittest.TestCase): def test_one_basic_term(self): @@ -70,10 +69,11 @@ class QueryParseTest(unittest.TestCase): r = ('year', '1999..2010', beets.library.NumericQuery) self.assertEqual(pqp(q), r) + class AnyFieldQueryTest(unittest.TestCase): def setUp(self): self.lib = beets.library.Library(':memory:') - self.lib.add(some_item) + _common.item(self.lib) def test_no_restriction(self): q = beets.library.AnyFieldQuery('title', beets.library.ITEM_KEYS, @@ -90,25 +90,44 @@ class AnyFieldQueryTest(unittest.TestCase): beets.library.SubstringQuery) self.assertEqual(self.lib.items(q).get(), None) -# Convenient asserts for matching items. + class AssertsMixin(object): def assert_matched(self, results, titles): self.assertEqual([i.title for i in results], titles) + +# A test case class providing a library with some dummy data and some +# assertions involving that data. +class DummyDataTestCase(_common.TestCase, AssertsMixin): + def setUp(self): + super(DummyDataTestCase, self).setUp() + self.lib = beets.library.Library(':memory:') + items = [_common.item() for _ in range(3)] + items[0].title = 'foo bar' + items[0].artist = 'one' + items[0].album = 'baz' + items[0].year = 2001 + items[1].title = 'baz qux' + items[1].artist = 'two' + items[1].album = 'baz' + items[1].year = 2002 + items[2].title = 'beets 4 eva' + items[2].artist = 'three' + items[2].album = 'foo' + items[2].year = 2003 + for item in items: + self.lib.add(item) + self.lib.add_album(items[:2]) + def assert_matched_all(self, results): self.assert_matched(results, [ - 'Littlest Things', - 'Take Pills', - 'Lovers Who Uncover', - 'Boracay', + 'foo bar', + 'baz qux', + 'beets 4 eva', ]) -class GetTest(unittest.TestCase, AssertsMixin): - def setUp(self): - self.lib = beets.library.Library( - os.path.join(_common.RSRC, 'test.blb') - ) +class GetTest(DummyDataTestCase): def test_get_empty(self): q = '' results = self.lib.items(q) @@ -120,24 +139,24 @@ class GetTest(unittest.TestCase, AssertsMixin): self.assert_matched_all(results) def test_get_one_keyed_term(self): - q = 'artist:Lil' + q = 'title:qux' results = self.lib.items(q) - self.assert_matched(results, ['Littlest Things']) + self.assert_matched(results, ['baz qux']) def test_get_one_keyed_regexp(self): - q = r'artist::L.+y' + q = r'artist::t.+r' results = self.lib.items(q) - self.assert_matched(results, ['Littlest Things']) + self.assert_matched(results, ['beets 4 eva']) def test_get_one_unkeyed_term(self): - q = 'Terry' + q = 'three' results = self.lib.items(q) - self.assert_matched(results, ['Boracay']) + self.assert_matched(results, ['beets 4 eva']) def test_get_one_unkeyed_regexp(self): - q = r':y$' + q = r':x$' results = self.lib.items(q) - self.assert_matched(results, ['Boracay']) + self.assert_matched(results, ['baz qux']) def test_get_no_matches(self): q = 'popebear' @@ -152,101 +171,91 @@ class GetTest(unittest.TestCase, AssertsMixin): self.assert_matched(results, []) def test_term_case_insensitive(self): - q = 'UNCoVER' + q = 'oNE' results = self.lib.items(q) - self.assert_matched(results, ['Lovers Who Uncover']) + self.assert_matched(results, ['foo bar']) def test_regexp_case_sensitive(self): - q = r':UNCoVER' + q = r':oNE' results = self.lib.items(q) self.assert_matched(results, []) - q = r':Uncover' + q = r':one' results = self.lib.items(q) - self.assert_matched(results, ['Lovers Who Uncover']) + self.assert_matched(results, ['foo bar']) def test_term_case_insensitive_with_key(self): - q = 'album:stiLL' + q = 'artist:thrEE' results = self.lib.items(q) - self.assert_matched(results, ['Littlest Things']) + self.assert_matched(results, ['beets 4 eva']) def test_key_case_insensitive(self): - q = 'ArTiST:Allen' + q = 'ArTiST:three' results = self.lib.items(q) - self.assert_matched(results, ['Littlest Things']) + self.assert_matched(results, ['beets 4 eva']) def test_unkeyed_term_matches_multiple_columns(self): - q = 'little' + q = 'baz' results = self.lib.items(q) self.assert_matched(results, [ - 'Littlest Things', - 'Lovers Who Uncover', - 'Boracay', + 'foo bar', + 'baz qux', ]) def test_unkeyed_regexp_matches_multiple_columns(self): - q = r':^T' + q = r':z$' results = self.lib.items(q) self.assert_matched(results, [ - 'Take Pills', - 'Lovers Who Uncover', - 'Boracay', + 'foo bar', + 'baz qux', ]) def test_keyed_term_matches_only_one_column(self): - q = 'artist:little' + q = 'title:baz' results = self.lib.items(q) - self.assert_matched(results, [ - 'Lovers Who Uncover', - 'Boracay', - ]) + self.assert_matched(results, ['baz qux']) def test_keyed_regexp_matches_only_one_column(self): - q = r'album::\sS' + q = r'title::baz' results = self.lib.items(q) self.assert_matched(results, [ - 'Littlest Things', - 'Lovers Who Uncover', + 'baz qux', ]) def test_multiple_terms_narrow_search(self): - q = 'little ones' + q = 'qux baz' results = self.lib.items(q) self.assert_matched(results, [ - 'Lovers Who Uncover', - 'Boracay', + 'baz qux', ]) def test_multiple_regexps_narrow_search(self): - q = r':\sS :^T' + q = r':baz :qux' results = self.lib.items(q) - self.assert_matched(results, ['Lovers Who Uncover']) + self.assert_matched(results, ['baz qux']) def test_mixed_terms_regexps_narrow_search(self): - q = r':\sS lily' + q = r':baz qux' results = self.lib.items(q) - self.assert_matched(results, ['Littlest Things']) + self.assert_matched(results, ['baz qux']) def test_single_year(self): - q = 'year:2006' + q = 'year:2001' results = self.lib.items(q) - self.assert_matched(results, [ - 'Littlest Things', - 'Lovers Who Uncover', - ]) + self.assert_matched(results, ['foo bar']) def test_year_range(self): - q = 'year:2000..2010' + q = 'year:2000..2002' results = self.lib.items(q) self.assert_matched(results, [ - 'Littlest Things', - 'Take Pills', - 'Lovers Who Uncover', + 'foo bar', + 'baz qux', ]) def test_bad_year(self): q = 'year:delete from items' self.assertRaises(ValueError, self.lib.items, q) + class MemoryGetTest(unittest.TestCase, AssertsMixin): def setUp(self): self.album_item = _common.item() @@ -315,6 +324,7 @@ class MemoryGetTest(unittest.TestCase, AssertsMixin): results = self.lib.items(q) self.assertFalse(results) + class MatchTest(unittest.TestCase): def setUp(self): self.item = _common.item() @@ -359,6 +369,7 @@ class MatchTest(unittest.TestCase): q = beets.library.NumericQuery('bitrate', '200000..300000') self.assertFalse(q.match(self.item)) + class PathQueryTest(unittest.TestCase, AssertsMixin): def setUp(self): self.lib = beets.library.Library(':memory:') @@ -418,45 +429,25 @@ class PathQueryTest(unittest.TestCase, AssertsMixin): results = self.lib.items(q) self.assert_matched(results, ['path item']) -class BrowseTest(unittest.TestCase, AssertsMixin): - def setUp(self): - self.lib = beets.library.Library( - os.path.join(_common.RSRC, 'test.blb') - ) - - def test_album_list(self): - albums = list(self.lib.albums()) - album_names = [a.album for a in albums] - for aname in ['Alright, Still', 'Person Pitch', 'Sing Song', - 'Terry Tales & Fallen Gates EP']: - self.assert_(aname in album_names) - self.assertEqual(len(albums), 4) - - def test_item_list(self): - items = self.lib.items() - self.assert_matched(items, [ - 'Littlest Things', - 'Take Pills', - 'Lovers Who Uncover', - 'Boracay', - ]) +class DefaultSearchFieldsTest(DummyDataTestCase): def test_albums_matches_album(self): - albums = list(self.lib.albums('person')) + albums = list(self.lib.albums('baz')) self.assertEqual(len(albums), 1) def test_albums_matches_albumartist(self): - albums = list(self.lib.albums('panda')) + albums = list(self.lib.albums(['album artist'])) self.assertEqual(len(albums), 1) def test_items_matches_title(self): - items = self.lib.items('boracay') - self.assert_matched(items, ['Boracay']) + items = self.lib.items('beets') + self.assert_matched(items, ['beets 4 eva']) def test_items_does_not_match_year(self): - items = self.lib.items('2007') + items = self.lib.items('2001') self.assert_matched(items, []) + class StringParseTest(unittest.TestCase): def test_single_field_query(self): q = beets.library.AndQuery.from_string(u'albumtype:soundtrack') @@ -466,8 +457,10 @@ class StringParseTest(unittest.TestCase): self.assertEqual(subq.field, 'albumtype') self.assertEqual(subq.pattern, 'soundtrack') + def suite(): return unittest.TestLoader().loadTestsFromName(__name__) + if __name__ == '__main__': unittest.main(defaultTest='suite')