diff --git a/filehash/filehash.py b/filehash/filehash.py index cddfbd5..b2868ad 100644 --- a/filehash/filehash.py +++ b/filehash/filehash.py @@ -1,5 +1,6 @@ import abc import collections +from contextlib import contextmanager import glob import hashlib import os @@ -261,7 +262,8 @@ def verify_checksums(self, checksum_filename): there was a checksum mismatch (False). """ result = [] - with open(checksum_filename, mode="r") as checksum_list: + checksum_dir = os.path.dirname(os.path.realpath(checksum_filename)) + with open(checksum_filename, mode="r") as checksum_list, _chdir(checksum_dir): for line in checksum_list: expected_hash, filename = line.strip().split(" ", 1) filename = filename.strip() @@ -296,7 +298,8 @@ def verify_sfv(self, sfv_filename): if self.hash_algorithm.lower() != 'crc32': raise TypeError("SFV verification only supported with the 'crc32' algorithm.") result = [] - with open(sfv_filename, mode="r") as checksum_list: + checksum_dir = os.path.dirname(os.path.realpath(sfv_filename)) + with open(sfv_filename, mode="r") as checksum_list, _chdir(checksum_dir): for line in checksum_list: if line.startswith(";"): continue @@ -305,6 +308,16 @@ def verify_sfv(self, sfv_filename): result.append(VerifyHashResult(filename, expected_crc32 == actual_crc32)) return result +@contextmanager +def _chdir(dir_path): + _original = os.getcwd() + os.chdir(dir_path) + try: + yield + except: + raise Exception('unable to change to hash directory') + finally: + os.chdir(_original) _ALGORITHM_MAP = { 'adler32': Adler32, diff --git a/test_filehash.py b/test_filehash.py index 280e2f0..7248078 100644 --- a/test_filehash.py +++ b/test_filehash.py @@ -1,5 +1,7 @@ import inspect +import logging import os.path +import sys import unittest import filehash.filehash @@ -7,6 +9,10 @@ from filehash.filehash_cli import create_parser +logging.basicConfig(stream=sys.stderr) +logging.getLogger().setLevel(logging.DEBUG) + +logger = logging.getLogger(__file__) class TestFileHash(unittest.TestCase): """Test the FileHash class.""" @@ -64,7 +70,8 @@ def setUp(self): } } self.current_dir = os.getcwd() - os.chdir(os.path.join(os.path.abspath(os.path.dirname(__file__)), "testdata")) + self.testdata_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), "testdata") + os.chdir(self.testdata_dir) def tearDown(self): os.chdir(self.current_dir) @@ -186,6 +193,16 @@ def test_verify_checksums(self): results = [result.hashes_match for result in hasher.verify_checksums("hashes." + algo)] self.assertTrue(all(results)) + def test_verify_checksums_from_outside_dir(self): + """Test the verify_checksums() method from outside the hash directory.""" + os.chdir('/') # Change out of the "testdata" directory + logger.debug('Current directory: %s', os.path.realpath(os.curdir)) + for algo in SUPPORTED_ALGORITHMS: + checksum_file = os.path.join(self.testdata_dir, "hashes." + algo) + hasher = FileHash(algo) + results = [result.hashes_match for result in hasher.verify_checksums(checksum_file)] + self.assertTrue(all(results)) + def test_verify_sfv(self): """Test the verify_sfv() method.""" hasher = FileHash('crc32') @@ -197,6 +214,14 @@ def test_verify_sfv_neg(self): hasher = FileHash('sha1') self.assertRaises(TypeError, hasher.verify_sfv, "lorem_ipsum.sfv") + def test_verify_sfv_outside_dir(self): + """Test the verify_sfv() method.""" + os.chdir('/') # Change out of the "testdata" directory + checksum_file = os.path.join(self.testdata_dir, "lorem_ipsum.sfv") + hasher = FileHash('crc32') + results = [result.hashes_match for result in hasher.verify_sfv(checksum_file)] + self.assertTrue(all(results)) + class TestZlibHasherSubclasses(unittest.TestCase): """Test the subclasses of ZlibHasherBase i.e. Adler32, CRC32."""