def setUp(self): self.data = { 'path/to/somefile': '1366207797;1024;6cf9224c0ced0affde6832a101676ff656a7cd6f', 'path/to/anotherfile': '1366207797;1024;040f06fd774092478d450774f5ba30c5da78acc8' } def data_delitem(key): del self.data[key] def data_getitem(key): return self.data[key] def data_setitem(key, value): self.data[key] = value def data_nextkey(key): key_iter = iter(self.data) while key_iter.next() != key: pass return key_iter.next() self.dbmock = MagicMock() self.dbmock.__delitem__.side_effect = data_delitem self.dbmock.__getitem__.side_effect = data_getitem self.dbmock.__setitem__.side_effect = data_setitem self.dbmock.__len__.side_effect = lambda: len(self.data) self.dbmock.firstkey.side_effect = lambda: self.data.iterkeys().next() self.dbmock.nextkey.side_effect = data_nextkey self.gdbm_mock = MagicMock(spec_set=gdbm) self.gdbm_mock.open.return_value = self.dbmock self.hashdb = HashDb('<filename>', self.gdbm_mock)
def test_does_not_update_hash_if_modification_and_size_unchanged(self): with FilesMock() as files: files.add_file('./path/to/somefile', 1366207797, 1024) self.hashdb.update_path('.', 'path/to/somefile') expected = HashDb.Entry(1366207797, 1024, '6cf9224c0ced0affde6832a101676ff656a7cd6f') self.assertEqual(self.hashdb['path/to/somefile'], expected)
def test_update_uses_relative_path(self): with FilesMock() as files: files.add_file('path/to/somefile', 1366207797, 42) self.hashdb.update_path('path', 'to/somefile') expected = HashDb.Entry( 1366207797, 42, hashlib.sha1(FilesMock.File.content).hexdigest()) self.assertEqual(self.hashdb['to/somefile'], expected)
def test_updates_hash_if_size_changed(self): with FilesMock() as files: files.add_file('./path/to/somefile', 1366207797, 42) self.hashdb.update_path('.', 'path/to/somefile') expected = HashDb.Entry( 1366207797, 42, hashlib.sha1(FilesMock.File.content).hexdigest()) self.assertEqual(self.hashdb['path/to/somefile'], expected)
def test_updates_hash_if_modification_time_changed(self): with FilesMock() as files: files.add_file('./path/to/somefile', 123, 1024) self.hashdb.update_path('.', 'path/to/somefile') expected = HashDb.Entry( 123, 1024, hashlib.sha1(FilesMock.File.content).hexdigest()) self.assertEqual(self.hashdb['path/to/somefile'], expected)
def test_inserts_hash_for_new_file(self): with FilesMock() as files: files.add_file('./newfile', 123, 42) self.hashdb.update_path('.', 'newfile') expected = HashDb.Entry( 123, 42, hashlib.sha1(FilesMock.File.content).hexdigest()) self.assertEqual(self.hashdb['newfile'], expected)
def test_provides_dictionary_interface(self): entry = self.hashdb['path/to/somefile'] self.assertEqual(entry.modification, 1366207797) self.assertEqual(entry.size, 1024) self.assertEqual(entry.sha1, '6cf9224c0ced0affde6832a101676ff656a7cd6f') with self.assertRaises(KeyError): entry = self.hashdb['newpath'] self.hashdb['newpath'] = HashDb.Entry( 12345, 256, '07d307d64e062a0ba2ed725571aecd89f2214232') self.assertEqual(self.data['newpath'], '12345;256;07d307d64e062a0ba2ed725571aecd89f2214232')
def test_reads_complete_file(self): with FilesMock() as files: with patch('__builtin__.open', mock_open()) as open_patch: chunks = ['con', 'tent', ''] def read_chunk(size): return chunks.pop(0) file_mock = MagicMock() file_mock.__enter__.return_value = file_mock file_mock.read.side_effect = read_chunk open_patch.return_value = file_mock files.add_file('./newfile', 123, 42) self.hashdb.update_path('.', 'newfile') expected = HashDb.Entry(123, 42, hashlib.sha1('content').hexdigest()) self.assertEqual(self.hashdb['newfile'], expected)
class HashDbTest(unittest.TestCase): def setUp(self): self.data = { 'path/to/somefile': '1366207797;1024;6cf9224c0ced0affde6832a101676ff656a7cd6f', 'path/to/anotherfile': '1366207797;1024;040f06fd774092478d450774f5ba30c5da78acc8' } def data_delitem(key): del self.data[key] def data_getitem(key): return self.data[key] def data_setitem(key, value): self.data[key] = value def data_nextkey(key): key_iter = iter(self.data) while key_iter.next() != key: pass return key_iter.next() self.dbmock = MagicMock() self.dbmock.__delitem__.side_effect = data_delitem self.dbmock.__getitem__.side_effect = data_getitem self.dbmock.__setitem__.side_effect = data_setitem self.dbmock.__len__.side_effect = lambda: len(self.data) self.dbmock.firstkey.side_effect = lambda: self.data.iterkeys().next() self.dbmock.nextkey.side_effect = data_nextkey self.gdbm_mock = MagicMock(spec_set=gdbm) self.gdbm_mock.open.return_value = self.dbmock self.hashdb = HashDb('<filename>', self.gdbm_mock) def test_can_be_used_in_with(self): with FilesMock() as files: files.add_file('./path/to/somefile', 1366207797, 1024) with HashDb('<filename>', self.gdbm_mock) as db: db.update_path('.', 'path/to/somefile') def test_allows_iteration(self): keys = ['0', '1', '2', None] self.dbmock.firstkey.side_effect = lambda: keys[0] self.dbmock.nextkey.side_effect = lambda key: keys[keys.index(key) + 1] for key in self.hashdb: self.assertTrue(key in keys, 'key = %s' % key) def test_has_length(self): self.assertEqual(len(self.hashdb), len(self.data)) def test_provides_dictionary_interface(self): entry = self.hashdb['path/to/somefile'] self.assertEqual(entry.modification, 1366207797) self.assertEqual(entry.size, 1024) self.assertEqual(entry.sha1, '6cf9224c0ced0affde6832a101676ff656a7cd6f') with self.assertRaises(KeyError): entry = self.hashdb['newpath'] self.hashdb['newpath'] = HashDb.Entry( 12345, 256, '07d307d64e062a0ba2ed725571aecd89f2214232') self.assertEqual(self.data['newpath'], '12345;256;07d307d64e062a0ba2ed725571aecd89f2214232') def test_allows_deletion_of_entries(self): del self.hashdb['path/to/somefile'] self.assertFalse('path/to/somefile' in self.hashdb) def test_inserts_hash_for_new_file(self): with FilesMock() as files: files.add_file('./newfile', 123, 42) self.hashdb.update_path('.', 'newfile') expected = HashDb.Entry( 123, 42, hashlib.sha1(FilesMock.File.content).hexdigest()) self.assertEqual(self.hashdb['newfile'], expected) def test_reads_complete_file(self): with FilesMock() as files: with patch('__builtin__.open', mock_open()) as open_patch: chunks = ['con', 'tent', ''] def read_chunk(size): return chunks.pop(0) file_mock = MagicMock() file_mock.__enter__.return_value = file_mock file_mock.read.side_effect = read_chunk open_patch.return_value = file_mock files.add_file('./newfile', 123, 42) self.hashdb.update_path('.', 'newfile') expected = HashDb.Entry(123, 42, hashlib.sha1('content').hexdigest()) self.assertEqual(self.hashdb['newfile'], expected) def test_updates_hash_if_modification_time_changed(self): with FilesMock() as files: files.add_file('./path/to/somefile', 123, 1024) self.hashdb.update_path('.', 'path/to/somefile') expected = HashDb.Entry( 123, 1024, hashlib.sha1(FilesMock.File.content).hexdigest()) self.assertEqual(self.hashdb['path/to/somefile'], expected) def test_updates_hash_if_size_changed(self): with FilesMock() as files: files.add_file('./path/to/somefile', 1366207797, 42) self.hashdb.update_path('.', 'path/to/somefile') expected = HashDb.Entry( 1366207797, 42, hashlib.sha1(FilesMock.File.content).hexdigest()) self.assertEqual(self.hashdb['path/to/somefile'], expected) def test_update_uses_relative_path(self): with FilesMock() as files: files.add_file('path/to/somefile', 1366207797, 42) self.hashdb.update_path('path', 'to/somefile') expected = HashDb.Entry( 1366207797, 42, hashlib.sha1(FilesMock.File.content).hexdigest()) self.assertEqual(self.hashdb['to/somefile'], expected) def test_does_not_update_hash_if_modification_and_size_unchanged(self): with FilesMock() as files: files.add_file('./path/to/somefile', 1366207797, 1024) self.hashdb.update_path('.', 'path/to/somefile') expected = HashDb.Entry(1366207797, 1024, '6cf9224c0ced0affde6832a101676ff656a7cd6f') self.assertEqual(self.hashdb['path/to/somefile'], expected) def test_update_path_throws_exception_for_non_existing_files(self): with FilesMock() as files: files.add_file('./existent', 1, 1) with self.assertRaises(OSError) as cm: self.hashdb.update_path('.', 'nonexistent') self.assertEqual(cm.exception.errno, errno.ENOENT) def test_can_update_all_paths_in_tree(self): with patch('os.walk') as walk: dirpath = 'dir' walk.return_value = [(dirpath, ['a', 'b'], ['file0', 'file1']), (os.path.join(dirpath, 'a'), [], ['file2']), (os.path.join(dirpath, 'b'), [], ['file3', 'file4'])] with patch.object(self.hashdb, 'update_path') as update_path: self.hashdb.update_tree(dirpath) expected = [ call(dirpath, f) for f in [ 'file0', 'file1', os.path.join('a', 'file2'), os.path.join('b', 'file3'), os.path.join('b', 'file4') ] ] self.assertEqual(len(update_path.call_args_list), len(expected)) for c in update_path.call_args_list: self.assertIn(c, expected) def test_can_exclude_patterns_in_update_tree(self): with patch('os.walk') as walk: dirpath = 'dir' walk.return_value = [(dirpath, ['a', 'b'], ['file0', 'exclude1']), (os.path.join(dirpath, 'a'), [], ['exclude2']), (os.path.join(dirpath, 'b'), [], ['file3', 'file4'])] with patch.object(self.hashdb, 'update_path') as update_path: self.hashdb.update_tree(dirpath, exclude=r'exclude\d') expected = [ call(dirpath, f) for f in [ 'file0', os.path.join('b', 'file3'), os.path.join('b', 'file4') ] ] self.assertEqual(len(update_path.call_args_list), len(expected)) for c in update_path.call_args_list: self.assertIn(c, expected) def test_update_all_prints_walk_errors_and_continues(self): with patch('os.walk') as walk: dirpath = 'dir' def test_error_handler(path, onerror): with patch('sys.stderr') as stderr: buffer = StringIO() stderr.write = buffer.write onerror( OSError(errno.EPERM, 'Permission denied.', 'somedir')) self.assertEqual( buffer.getvalue(), sys.argv[0] + ": somedir: Permission denied.\n") return [(dirpath, [], [])] walk.side_effect = test_error_handler self.hashdb.update_tree(dirpath) def test_update_all_prints_update_path_errors_and_continues(self): with patch('os.walk') as walk: dirpath = 'dir' walk.return_value = [(dirpath, [], ['file'])] with patch('sys.stderr') as stderr: buffer = StringIO() stderr.write = buffer.write with patch.object(self.hashdb, 'update_path') as update_path: update_path.side_effect = OSError(errno.EPERM, 'Permission denied.', 'file') self.hashdb.update_tree(dirpath) self.assertEqual(buffer.getvalue(), sys.argv[0] + ": file: Permission denied.\n") def test_strip_deletes_hashes_for_nonexistent_files(self): with FilesMock() as files: files.add_file('path/to/somefile', 123, 1024) self.hashdb.strip() self.assertIn('path/to/somefile', self.hashdb) self.assertNotIn('path/to/anotherfile', self.hashdb) def test_verify_tree(self): self.data['path/to/missingOnDisk'] = \ '1366207797;1024;040f06fd774092478d450774f5ba30c5da78acc8' with patch('os.walk') as walk: dirpath = 'dir' walk.return_value = [ (dirpath, ['path'], []), (os.path.join(dirpath, 'path'), ['to'], ['missingInDb']), (os.path.join(dirpath, 'path', 'to'), [], ['somefile']), (os.path.join(dirpath, 'path', 'to'), [], ['anotherfile']) ] with FilesMock() as files: files.add_file('dir/path/to/somefile', 1, 1) files.add_file('dir/path/to/anotherfile', 1, 1) changed, missing_in_db, missing_on_disk = \ self.hashdb.verify_tree(dirpath) self.assertEqual(changed, ['path/to/somefile']) self.assertEqual(missing_in_db, ['path/missingInDb']) self.assertEqual(missing_on_disk, ['path/to/missingOnDisk']) def test_verify_tree_can_exclude_patterns(self): self.data['path/to/exclude3'] = \ '1366207797;1024;040f06fd774092478d450774f5ba30c5da78acc8' with patch('os.walk') as walk: dirpath = 'dir' walk.return_value = [(dirpath, ['path'], []), (os.path.join(dirpath, 'path'), ['to'], ['exclude1']), (os.path.join(dirpath, 'path', 'to'), [], ['exclude2']), (os.path.join(dirpath, 'path', 'to'), [], ['anotherfile'])] with FilesMock() as files: files.add_file('dir/path/to/exclude2', 1, 1) files.add_file('dir/path/to/anotherfile', 1, 1) changed, missing_in_db, missing_on_disk = \ self.hashdb.verify_tree( dirpath, exclude=r'exclude\d|somefile') self.assertEqual(changed, []) self.assertEqual(missing_in_db, []) self.assertEqual(missing_on_disk, []) def test_verify_tree_prints_walk_errors_and_continues(self): with patch('os.walk') as walk: dirpath = 'dir' def test_error_handler(path, onerror): with patch('sys.stderr') as stderr: buffer = StringIO() stderr.write = buffer.write onerror( OSError(errno.EPERM, 'Permission denied.', 'somedir')) self.assertEqual( buffer.getvalue(), sys.argv[0] + ": somedir: Permission denied.\n") return [(dirpath, [], [])] walk.side_effect = test_error_handler self.hashdb.verify_tree(dirpath) def test_verify_tree_prints_raised_errors_and_continues(self): with patch('os.walk') as walk: dirpath = 'dir' walk.return_value = [(dirpath, [], ['file'])] with patch('sys.stderr') as stderr: buffer = StringIO() stderr.write = buffer.write with patch('os.path.join') as path_join: path_join.side_effect = OSError(errno.EPERM, 'Permission denied.', 'file') self.hashdb.verify_tree(dirpath) self.assertTrue(buffer.getvalue().startswith( sys.argv[0] + ": file: Permission denied.\n"))
def test_entries_differing_in_sha1_are_unequal(self): a = HashDb.Entry(123, 456, '6cf9224c0ced0affde6832a101676ff656a7cd6f') b = HashDb.Entry(123, 456, '07d307d64e062a0ba2ed725571aecd89f2214232') self.assertNotEqual(a, b)
def test_entries_differing_in_size_are_unequal(self): a = HashDb.Entry(123, 456, '6cf9224c0ced0affde6832a101676ff656a7cd6f') b = HashDb.Entry(123, 23, '6cf9224c0ced0affde6832a101676ff656a7cd6f') self.assertNotEqual(a, b)
def test_equal_entries_considered_equal(self): a = HashDb.Entry(123, 456, '6cf9224c0ced0affde6832a101676ff656a7cd6f') b = HashDb.Entry(123, 456, '6cf9224c0ced0affde6832a101676ff656a7cd6f') self.assertEqual(a, b)
def test_can_be_used_in_with(self): with FilesMock() as files: files.add_file('./path/to/somefile', 1366207797, 1024) with HashDb('<filename>', self.gdbm_mock) as db: db.update_path('.', 'path/to/somefile')
class HashDbTest(unittest.TestCase): def setUp(self): self.data = { 'path/to/somefile': '1366207797;1024;6cf9224c0ced0affde6832a101676ff656a7cd6f', 'path/to/anotherfile': '1366207797;1024;040f06fd774092478d450774f5ba30c5da78acc8' } def data_delitem(key): del self.data[key] def data_getitem(key): return self.data[key] def data_setitem(key, value): self.data[key] = value def data_nextkey(key): key_iter = iter(self.data) while key_iter.next() != key: pass return key_iter.next() self.dbmock = MagicMock() self.dbmock.__delitem__.side_effect = data_delitem self.dbmock.__getitem__.side_effect = data_getitem self.dbmock.__setitem__.side_effect = data_setitem self.dbmock.__len__.side_effect = lambda: len(self.data) self.dbmock.firstkey.side_effect = lambda: self.data.iterkeys().next() self.dbmock.nextkey.side_effect = data_nextkey self.gdbm_mock = MagicMock(spec_set=gdbm) self.gdbm_mock.open.return_value = self.dbmock self.hashdb = HashDb('<filename>', self.gdbm_mock) def test_can_be_used_in_with(self): with FilesMock() as files: files.add_file('./path/to/somefile', 1366207797, 1024) with HashDb('<filename>', self.gdbm_mock) as db: db.update_path('.', 'path/to/somefile') def test_allows_iteration(self): keys = ['0', '1', '2', None] self.dbmock.firstkey.side_effect = lambda: keys[0] self.dbmock.nextkey.side_effect = lambda key: keys[keys.index(key) + 1] for key in self.hashdb: self.assertTrue(key in keys, 'key = %s' % key) def test_has_length(self): self.assertEqual(len(self.hashdb), len(self.data)) def test_provides_dictionary_interface(self): entry = self.hashdb['path/to/somefile'] self.assertEqual(entry.modification, 1366207797) self.assertEqual(entry.size, 1024) self.assertEqual( entry.sha1, '6cf9224c0ced0affde6832a101676ff656a7cd6f') with self.assertRaises(KeyError): entry = self.hashdb['newpath'] self.hashdb['newpath'] = HashDb.Entry( 12345, 256, '07d307d64e062a0ba2ed725571aecd89f2214232') self.assertEqual( self.data['newpath'], '12345;256;07d307d64e062a0ba2ed725571aecd89f2214232') def test_allows_deletion_of_entries(self): del self.hashdb['path/to/somefile'] self.assertFalse('path/to/somefile' in self.hashdb) def test_inserts_hash_for_new_file(self): with FilesMock() as files: files.add_file('./newfile', 123, 42) self.hashdb.update_path('.', 'newfile') expected = HashDb.Entry( 123, 42, hashlib.sha1(FilesMock.File.content).hexdigest()) self.assertEqual(self.hashdb['newfile'], expected) def test_reads_complete_file(self): with FilesMock() as files: with patch('__builtin__.open', mock_open()) as open_patch: chunks = ['con', 'tent', ''] def read_chunk(size): return chunks.pop(0) file_mock = MagicMock() file_mock.__enter__.return_value = file_mock file_mock.read.side_effect = read_chunk open_patch.return_value = file_mock files.add_file('./newfile', 123, 42) self.hashdb.update_path('.', 'newfile') expected = HashDb.Entry( 123, 42, hashlib.sha1('content').hexdigest()) self.assertEqual(self.hashdb['newfile'], expected) def test_updates_hash_if_modification_time_changed(self): with FilesMock() as files: files.add_file('./path/to/somefile', 123, 1024) self.hashdb.update_path('.', 'path/to/somefile') expected = HashDb.Entry( 123, 1024, hashlib.sha1(FilesMock.File.content).hexdigest()) self.assertEqual(self.hashdb['path/to/somefile'], expected) def test_updates_hash_if_size_changed(self): with FilesMock() as files: files.add_file('./path/to/somefile', 1366207797, 42) self.hashdb.update_path('.', 'path/to/somefile') expected = HashDb.Entry( 1366207797, 42, hashlib.sha1(FilesMock.File.content).hexdigest()) self.assertEqual(self.hashdb['path/to/somefile'], expected) def test_update_uses_relative_path(self): with FilesMock() as files: files.add_file('path/to/somefile', 1366207797, 42) self.hashdb.update_path('path', 'to/somefile') expected = HashDb.Entry( 1366207797, 42, hashlib.sha1(FilesMock.File.content).hexdigest()) self.assertEqual(self.hashdb['to/somefile'], expected) def test_does_not_update_hash_if_modification_and_size_unchanged(self): with FilesMock() as files: files.add_file('./path/to/somefile', 1366207797, 1024) self.hashdb.update_path('.', 'path/to/somefile') expected = HashDb.Entry( 1366207797, 1024, '6cf9224c0ced0affde6832a101676ff656a7cd6f') self.assertEqual(self.hashdb['path/to/somefile'], expected) def test_update_path_throws_exception_for_non_existing_files(self): with FilesMock() as files: files.add_file('./existent', 1, 1) with self.assertRaises(OSError) as cm: self.hashdb.update_path('.', 'nonexistent') self.assertEqual(cm.exception.errno, errno.ENOENT) def test_can_update_all_paths_in_tree(self): with patch('os.walk') as walk: dirpath = 'dir' walk.return_value = [ (dirpath, ['a', 'b'], ['file0', 'file1']), (os.path.join(dirpath, 'a'), [], ['file2']), (os.path.join(dirpath, 'b'), [], ['file3', 'file4'])] with patch.object(self.hashdb, 'update_path') as update_path: self.hashdb.update_tree(dirpath) expected = [call(dirpath, f) for f in [ 'file0', 'file1', os.path.join('a', 'file2'), os.path.join('b', 'file3'), os.path.join('b', 'file4')]] self.assertEqual( len(update_path.call_args_list), len(expected)) for c in update_path.call_args_list: self.assertIn(c, expected) def test_can_exclude_patterns_in_update_tree(self): with patch('os.walk') as walk: dirpath = 'dir' walk.return_value = [ (dirpath, ['a', 'b'], ['file0', 'exclude1']), (os.path.join(dirpath, 'a'), [], ['exclude2']), (os.path.join(dirpath, 'b'), [], ['file3', 'file4'])] with patch.object(self.hashdb, 'update_path') as update_path: self.hashdb.update_tree(dirpath, exclude=r'exclude\d') expected = [call(dirpath, f) for f in [ 'file0', os.path.join('b', 'file3'), os.path.join('b', 'file4')]] self.assertEqual( len(update_path.call_args_list), len(expected)) for c in update_path.call_args_list: self.assertIn(c, expected) def test_update_all_prints_walk_errors_and_continues(self): with patch('os.walk') as walk: dirpath = 'dir' def test_error_handler(path, onerror): with patch('sys.stderr') as stderr: buffer = StringIO() stderr.write = buffer.write onerror(OSError( errno.EPERM, 'Permission denied.', 'somedir')) self.assertEqual( buffer.getvalue(), sys.argv[0] + ": somedir: Permission denied.\n") return [(dirpath, [], [])] walk.side_effect = test_error_handler self.hashdb.update_tree(dirpath) def test_update_all_prints_update_path_errors_and_continues(self): with patch('os.walk') as walk: dirpath = 'dir' walk.return_value = [(dirpath, [], ['file'])] with patch('sys.stderr') as stderr: buffer = StringIO() stderr.write = buffer.write with patch.object(self.hashdb, 'update_path') as update_path: update_path.side_effect = OSError( errno.EPERM, 'Permission denied.', 'file') self.hashdb.update_tree(dirpath) self.assertEqual( buffer.getvalue(), sys.argv[0] + ": file: Permission denied.\n") def test_strip_deletes_hashes_for_nonexistent_files(self): with FilesMock() as files: files.add_file('path/to/somefile', 123, 1024) self.hashdb.strip() self.assertIn('path/to/somefile', self.hashdb) self.assertNotIn('path/to/anotherfile', self.hashdb) def test_verify_tree(self): self.data['path/to/missingOnDisk'] = \ '1366207797;1024;040f06fd774092478d450774f5ba30c5da78acc8' with patch('os.walk') as walk: dirpath = 'dir' walk.return_value = [ (dirpath, ['path'], []), (os.path.join(dirpath, 'path'), ['to'], ['missingInDb']), (os.path.join(dirpath, 'path', 'to'), [], ['somefile']), (os.path.join(dirpath, 'path', 'to'), [], ['anotherfile'])] with FilesMock() as files: files.add_file('dir/path/to/somefile', 1, 1) files.add_file('dir/path/to/anotherfile', 1, 1) changed, missing_in_db, missing_on_disk = \ self.hashdb.verify_tree(dirpath) self.assertEqual(changed, ['path/to/somefile']) self.assertEqual(missing_in_db, ['path/missingInDb']) self.assertEqual(missing_on_disk, ['path/to/missingOnDisk']) def test_verify_tree_can_exclude_patterns(self): self.data['path/to/exclude3'] = \ '1366207797;1024;040f06fd774092478d450774f5ba30c5da78acc8' with patch('os.walk') as walk: dirpath = 'dir' walk.return_value = [ (dirpath, ['path'], []), (os.path.join(dirpath, 'path'), ['to'], ['exclude1']), (os.path.join(dirpath, 'path', 'to'), [], ['exclude2']), (os.path.join(dirpath, 'path', 'to'), [], ['anotherfile'])] with FilesMock() as files: files.add_file('dir/path/to/exclude2', 1, 1) files.add_file('dir/path/to/anotherfile', 1, 1) changed, missing_in_db, missing_on_disk = \ self.hashdb.verify_tree( dirpath, exclude=r'exclude\d|somefile') self.assertEqual(changed, []) self.assertEqual(missing_in_db, []) self.assertEqual(missing_on_disk, []) def test_verify_tree_prints_walk_errors_and_continues(self): with patch('os.walk') as walk: dirpath = 'dir' def test_error_handler(path, onerror): with patch('sys.stderr') as stderr: buffer = StringIO() stderr.write = buffer.write onerror(OSError( errno.EPERM, 'Permission denied.', 'somedir')) self.assertEqual( buffer.getvalue(), sys.argv[0] + ": somedir: Permission denied.\n") return [(dirpath, [], [])] walk.side_effect = test_error_handler self.hashdb.verify_tree(dirpath) def test_verify_tree_prints_raised_errors_and_continues(self): with patch('os.walk') as walk: dirpath = 'dir' walk.return_value = [(dirpath, [], ['file'])] with patch('sys.stderr') as stderr: buffer = StringIO() stderr.write = buffer.write with patch('os.path.join') as path_join: path_join.side_effect = OSError( errno.EPERM, 'Permission denied.', 'file') self.hashdb.verify_tree(dirpath) self.assertTrue(buffer.getvalue().startswith( sys.argv[0] + ": file: Permission denied.\n"))