From 4d0db3fcb437187242eadb2c897f9b8640918dce Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Mon, 23 Sep 2013 10:57:17 -0700 Subject: [PATCH] tests: obviate on-disk test library --- test/_common.py | 10 +++ test/rsrc/test.blb | Bin 14336 -> 0 bytes test/test_db.py | 68 +++++++----------- test/test_query.py | 169 ++++++++++++++++++++++----------------------- 4 files changed, 116 insertions(+), 131 deletions(-) delete mode 100644 test/rsrc/test.blb 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 27dfa11907e5a1a5486a21bbbc7065cbac88fdc2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14336 zcmeHM&2JM&6rWiqSqKHBB5DDxm>#mtK0|&CGtsNf4lxhF!_tnKy4{-u&jh@%xQ8 zZm*i0k$bLZQ%)Ap7{VBRLI^_0fX^}bgwID%(83D5aiY9i(Ll4mqj6}}3V#co!-aoT zLF*KYMf~`EPMa133v6G0Y1MV3Qa4Dwvb1UtDIyomHZdK}I?N+I&$OvGAYC??Aw9~s zNYiqgGlW{rzTHrYGlZMmVuZ5?99leX`aG-%wPZQf+F_0tc5AtI&-GzOHA=^G`#sa? z1l0kfp0H_#*scRc$YPrgRDpZ6)lC$+%c&LUn0_lRB^s=OXSV!cc$nN~4iBr%o~`-_ zqe#KrK2F%Wizo3zu#&rvq#97=?M7CQJhkB3BrA ziJH)&O=g9YbJGrVT3gg{nB}V;KDB!mi${Rr+N>8MCTCXGG0QFq^Tq}KE{(e&b}Q~1#t>1J{|Uws!+j;3V0dm7l7b+(k}$o_$4 zNiTX1KS}sN8=NCiP4BjxB3gd9+xu;0Vvpni0oV|U;|2H{!$-A6i22jw_%S+-o@##- z{t{s-p5X=UEE*oi^QE&TsA^a~5cVqW;Z@#*0P)LIY_jh<pz1<6UvlfwE%`r z;WMS>(zzEfw9Y&@QR>uUKDj_{PzwTpEQ8bg#Hb15ms|*FIuI6*1?7x6dk&G&tyr9S z4&~;3rauL913-tDFsx!4m!_ttPQ1V>R!wU_D#G@1#q!L~7936++_bFn+|>Y4I0oxm zuq(b;305davbcY`dn~WHJpucnBY_7P^ezHy7Zxul&Eo@M_0tD)W=`@wPyNg>583jif*9^>@JqULxahY|oU#)b&1s-Nb^c^D zeSC5x&y(;J(J`9GqQ~@!s7HKwrw{euC_jQ_{9{BABHFJZs&Q_P(AQsJU1aLtp2{XNX0ePM>x{4&t{wvlk`wg0%RY@_xvOY}PhukZ;SZIYIas1NrbDep#4;mEf`Ue}n0T0ynzbRF6$RkK?KW$Zus$t* z|26akp(omJxEG!PFZJF&UC@iA5`Nf?j*JH7+%ubf$f*UVPgEyTJS=Q{^r<3l-vD!l z`vHkYPTYK+;>01%eVO3dH9Yo>h8+Qv-!0k{88UHldJW8k~w;v^aI04rZvs~gM4 zI;pL%+^nqMC7&60XGZG6wT{UL;vOUDGFlDpw@BT%Qy<-WpIUvkNBid5%I!_#Vl>x` zxG$R~x7JAY*4mBLm1>==8@1I+)sXQI7XbN_BakET1|l#i)~w=x0!relK0gfvCi#;i z@CG1|i2pZWwfPcr1abtD2nhbKqbmsgh!5k(+7H^F1y@w}e1>mN>cz?|9#&1K%^oOr z7gPL3bI?%SBinK;VEZd;*Nr>DpZ25rjigRMU$WzonBz=;JT_6hUBXD3uo7FP2MqSeE*-75;CIjLWDWN-boE_HOoPMoF5#{oaILoSnrF z?fA+go?cykBA`k z;%tw%QhTggllmhe-p5IY#}4boMR2pl*v%pz^W(tDILgtKDVfH&*KQVNIwajr#DAXg z?|ItgjX44b7J)qfKd@VyFDyr3Uj*{_-xs1>AxGfAB9O=bf!*4CVL1Z(B9O=bz7XXK JIRXb3foFr{K>Gjy 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')