new tests for DB and file operations

Also, new organization for tests and automatic loader. Fixed bugs uncovered by new tests.

--HG--
extra : convert_revision : svn%3A41726ec3-264d-0410-9c23-a9f1637257cc/trunk%4069
This commit is contained in:
adrian.sampson 2008-07-07 05:23:17 +00:00
parent 9090ef25b5
commit cd124d2dad
7 changed files with 316 additions and 7 deletions

View file

@ -61,9 +61,10 @@ def _ancestry(path):
"""Return a list consisting of path's parent directory, its grandparent,
and so on. For instance, _ancestry('/a/b/c') == ['/', '/a', '/a/b']."""
out = []
while path != '/':
while path and path != '/':
path = os.path.dirname(path)
out.insert(0, path)
if path: # don't yield ''
out.insert(0, path)
return out
def _walk_files(path):
@ -143,6 +144,7 @@ class Item(object):
c = self.library.conn.execute(
'select * from items where id=?', (load_id,) )
self._fill_record(c.fetchone())
self._clear_dirty()
c.close()
def store(self, store_id=None, store_all=False):

View file

@ -1,12 +1,15 @@
#!/usr/bin/env python
import unittest
test_modules = ['test_mediafile', 'test_library']
import os
import re
def suite():
s = unittest.TestSuite()
for mod in map(__import__, test_modules):
s.addTest(mod.suite())
# get the suite() of every module in this directory begining with test_
for fname in os.listdir('.'):
match = re.match(r'(test_\S+)\.py', fname)
if match:
s.addTest(__import__(match.group(1)).suite())
return s
if __name__ == '__main__':

162
test/test_db.py Executable file
View file

@ -0,0 +1,162 @@
#!/usr/bin/env python
"""
Tests for non-query database functions of Item.
"""
import unittest, sys, os
sys.path.append('..')
import beets.library
def lib(): return beets.library.Library('rsrc' + os.sep + 'test.blb')
def boracay(l): return beets.library.Item(l.conn.execute('select * from items '
'where id=3').fetchone(), l)
def item(lib=None): return beets.library.Item({
'title': u'the title',
'artist': u'the artist',
'album': u'the album',
'genre': u'the genre',
'composer': u'the composer',
'grouping': u'the grouping',
'year': 1,
'track': 2,
'tracktotal': 3,
'disc': 4,
'disctotal': 5,
'lyrics': u'the lyrics',
'comments': u'the comments',
'bpm': 6,
'comp': True,
'path': 'somepath',
}, lib)
class LoadTest(unittest.TestCase):
def setUp(self):
self.lib = lib()
self.i = boracay(self.lib)
def tearDown(self):
self.lib.conn.close()
def test_load_restores_data_from_db(self):
original_title = self.i.title
self.i.title = 'something'
self.i.load()
self.assertEqual(original_title, self.i.title)
def test_load_clears_dirty_flags(self):
self.i.artist = 'something'
self.i.load()
self.assertTrue(not self.i.dirty['artist'])
class StoreTest(unittest.TestCase):
def setUp(self):
self.lib = lib()
self.i = boracay(self.lib)
def tearDown(self):
self.lib.conn.close()
def test_store_changes_database_value(self):
self.i.year = 1987
self.i.store()
new_year = self.lib.conn.execute('select year from items where '
'title="Boracay"').fetchone()['year']
self.assertEqual(new_year, 1987)
def test_store_only_writes_dirty_fields(self):
original_genre = self.i.genre
self.i.record['genre'] = 'beatboxing' # change value w/o dirtying
self.i.store()
new_genre = self.lib.conn.execute('select genre from items where '
'title="Boracay"').fetchone()['genre']
self.assertEqual(new_genre, original_genre)
def test_store_clears_dirty_flags(self):
self.i.composer = 'tvp'
self.i.store()
self.assertTrue(not self.i.dirty['composer'])
class AddTest(unittest.TestCase):
def setUp(self):
self.lib = lib()
self.i = item(self.lib)
def tearDown(self):
self.lib.conn.close()
def test_add_inserts_row(self):
self.i.add()
new_grouping = self.lib.conn.execute('select grouping from items '
'where composer="the composer"').fetchone()['grouping']
self.assertEqual(new_grouping, self.i.grouping)
class RemoveTest(unittest.TestCase):
def setUp(self):
self.lib = lib()
self.i = boracay(self.lib)
def tearDown(self):
self.lib.conn.close()
def test_remove_deletes_from_db(self):
self.i.remove()
c = self.lib.conn.execute('select * from items where id=3')
self.assertEqual(c.fetchone(), None)
class GetSetTest(unittest.TestCase):
def setUp(self):
self.i = item()
def test_set_changes_value(self):
self.i.bpm = 4915
self.assertEqual(self.i.bpm, 4915)
def test_set_sets_dirty_flag(self):
self.i.comp = True
self.assertTrue(self.i.dirty['comp'])
class DestinationTest(unittest.TestCase):
def setUp(self):
self.lib = beets.library.Library(':memory:')
self.i = item(self.lib)
def tearDown(self):
self.lib.conn.close()
def test_directory_works_with_trailing_slash(self):
self.lib.options['directory'] = 'one/'
self.lib.options['path_format'] = 'two'
self.assertEqual(self.i.destination(), 'one/two')
def test_directory_works_without_trailing_slash(self):
self.lib.options['directory'] = 'one'
self.lib.options['path_format'] = 'two'
self.assertEqual(self.i.destination(), 'one/two')
def test_destination_substitues_metadata_values(self):
self.lib.options['directory'] = 'base'
self.lib.options['path_format'] = '$album/$artist $title'
self.i.title = 'three'
self.i.artist = 'two'
self.i.album = 'one'
self.assertEqual(self.i.destination(), 'base/one/two three')
def test_destination_substitutes_extension(self):
self.lib.options['directory'] = 'base'
self.lib.options['path_format'] = '$extension'
self.i.path = 'hey.audioFormat'
self.assertEqual(self.i.destination(), 'base/audioFormat')
def test_destination_pads_some_indices(self):
self.lib.options['directory'] = 'base'
self.lib.options['path_format'] = '$track $tracktotal ' \
'$disc $disctotal $bpm $year'
self.i.track = 1
self.i.tracktotal = 2
self.i.disc = 3
self.i.disctotal = 4
self.i.bpm = 5
self.i.year = 6
self.assertEqual(self.i.destination(), 'base/01 02 03 04 5 6')
def suite():
return unittest.TestLoader().loadTestsFromName(__name__)
if __name__ == '__main__':
unittest.main(defaultTest='suite')

131
test/test_files.py Executable file
View file

@ -0,0 +1,131 @@
#!/usr/bin/env python
"""
Test file manipulation functionality of Item.
"""
import unittest, shutil, sys, os
sys.path.append('..')
import beets.library
from os.path import join
def mkfile(path):
open(path, 'w').close()
class MoveTest(unittest.TestCase):
def setUp(self):
# make a temporary file
self.path = join('rsrc', 'temp.mp3')
shutil.copy(join('rsrc', 'full.mp3'), self.path)
# add it to a temporary library
self.lib = beets.library.Library(':memory:')
self.i = beets.library.Item.from_path(self.path)
self.i.add(self.lib)
# set up the destination
self.libdir = join('rsrc', 'testlibdir')
self.lib.options['directory'] = self.libdir
self.lib.options['path_format'] = join('$artist',
'$album', '$title')
self.i.artist = 'one'
self.i.album = 'two'
self.i.title = 'three'
self.dest = join(self.libdir, 'one', 'two', 'three')
def tearDown(self):
if os.path.exists(self.path):
os.remove(self.path)
if os.path.exists(self.libdir):
shutil.rmtree(self.libdir)
def test_move_arrives(self):
self.i.move()
self.assertTrue(os.path.exists(self.dest))
def test_move_departs(self):
self.i.move()
self.assertTrue(not os.path.exists(self.path))
def test_copy_arrives(self):
self.i.move(copy=True)
self.assertTrue(os.path.exists(self.dest))
def test_copy_does_not_depart(self):
self.i.move(copy=True)
self.assertTrue(os.path.exists(self.path))
def test_move_changes_path(self):
self.i.move()
self.assertEqual(self.i.path,self.dest)
class DeleteTest(unittest.TestCase):
def setUp(self):
# make a temporary file
self.path = join('rsrc', 'temp.mp3')
shutil.copy(join('rsrc', 'full.mp3'), self.path)
# add it to a temporary library
self.lib = beets.library.Library(':memory:')
self.i = beets.library.Item.from_path(self.path)
self.i.add(self.lib)
def tearDown(self):
# make sure the temp file is gone
if os.path.exists(self.path):
os.remove(self.path)
def test_delete_deletes_file(self):
self.i.delete()
self.assertTrue(not os.path.exists(self.path))
def test_delete_removes_from_db(self):
self.i.delete()
c = self.lib.conn.execute('select * from items where 1')
self.assertEqual(c.fetchone(), None)
class WalkTest(unittest.TestCase):
def setUp(self):
# create a directory structure for testing
self.base = join('rsrc', 'temp_walk')
os.mkdir(self.base)
mkfile(join(self.base, 'file'))
os.mkdir(join(self.base, 'dir1'))
mkfile(join(self.base, 'dir1', 'dir1f1'))
mkfile(join(self.base, 'dir1', 'dir1f2'))
os.mkdir(join(self.base, 'dir2'))
mkfile(join(self.base, 'dir2', 'dir2f'))
os.mkdir(join(self.base, 'dir2', 'dir2dir'))
mkfile(join(self.base, 'dir2', 'dir2dir', 'dir2dirf'))
def tearDown(self):
shutil.rmtree(self.base)
def test_walk_single_file(self):
path = join(self.base, 'file')
s = set(beets.library._walk_files(path))
self.assertTrue(path in s)
s.remove(path)
self.assertTrue(not s) # s is empty (i.e., contains nothing else)
def test_walk_flat_directory(self):
path = join(self.base, 'dir1')
s = set(beets.library._walk_files(path))
for f in (join(path, 'dir1f1'),
join(path, 'dir1f2')):
self.assertTrue(f in s)
s.remove(f)
self.assertTrue(not s)
def test_walk_hierarchy(self):
path = join(self.base, 'dir2')
s = set(beets.library._walk_files(path))
for f in (join(path, 'dir2f'),
join(path, 'dir2dir', 'dir2dirf')):
self.assertTrue(f in s)
s.remove(f)
self.assertTrue(not s)
def suite():
return unittest.TestLoader().loadTestsFromName(__name__)
if __name__ == '__main__':
unittest.main(defaultTest='suite')

View file

@ -1,8 +1,14 @@
#!/usr/bin/env python
"""
Test the MediaFile metadata layer.
"""
import unittest, sys, os, shutil
sys.path.append('..')
import beets.mediafile
def MakeReadingTest(path, correct_dict, field):
class ReadingTest(unittest.TestCase):
def setUp(self):

View file

@ -1,4 +1,9 @@
#!/usr/bin/env python
"""
Various tests for querying the library database.
"""
import unittest, sys, os
sys.path.append('..')
import beets.library
@ -43,7 +48,7 @@ class QueryParseTest(unittest.TestCase):
class GetTest(unittest.TestCase):
def setUp(self):
self.lib = beets.library.Library('rsrc' + os.sep + 'get.blb')
self.lib = beets.library.Library('rsrc' + os.sep + 'test.blb')
def assert_matched(self, result_iterator, title):
self.assertEqual(result_iterator.next().title, title)