1
0
mirror of https://github.com/gryf/fs-uae-wrapper.git synced 2026-02-03 06:45:49 +01:00

6 Commits
0.3 ... 0.4

Author SHA1 Message Date
db7b8e347a Version bump 2017-01-02 20:19:30 +01:00
994768806c Parametrize extract and create methods for Archive base class 2017-01-02 20:17:13 +01:00
19acb789b6 Added wrapper_archiver option
To give user a possibility to choose what archiver he can use another
options was introduced for cd32 and archive wrapper modules. This option
will indicate what archiver should be used for compressing the save
state directories.
2017-01-02 20:08:50 +01:00
5f98e9b794 Moved save state out of _make_archive method
Now _save_save method will be called from run() method.
2017-01-02 19:30:09 +01:00
3906e4c80b Moved which function to another module 2017-01-02 19:27:49 +01:00
38a2322e98 Fix for file_archive tests 2017-01-02 16:05:18 +01:00
13 changed files with 195 additions and 96 deletions

View File

@@ -126,6 +126,7 @@ Options used:
* ``wrapper`` (required) with ``cd32`` as an value * ``wrapper`` (required) with ``cd32`` as an value
* ``wrapper_archive`` (required) path to the archive with CD32 iso/cue/wav * ``wrapper_archive`` (required) path to the archive with CD32 iso/cue/wav
* ``wrapper_archiver`` (required) archiver to use for storage save state
* ``wrapper_gui_msg`` (optional) if set to "1", will display a graphical * ``wrapper_gui_msg`` (optional) if set to "1", will display a graphical
message during extracting files message during extracting files
@@ -181,7 +182,8 @@ Options used:
* ``wrapper`` (required) with ``cd32`` as an value * ``wrapper`` (required) with ``cd32`` as an value
* ``wrapper_archive`` (required) path to the archive with assets (usually means * ``wrapper_archive`` (required) path to the archive with assets (usually means
whole system directories, floppies or hd images) * ``wrapper_archiver`` (required) archiver to use for storage save state
whole system directories, floppies or hard disk images)
* ``wrapper_gui_msg`` (optional) if set to "1", will display a graphical * ``wrapper_gui_msg`` (optional) if set to "1", will display a graphical
message during extracting files message during extracting files
* ``wrapper_persist_data`` (optional) if set to "1", will compress (possibly * ``wrapper_persist_data`` (optional) if set to "1", will compress (possibly

View File

@@ -56,6 +56,10 @@ class Archive(base.Base):
if not self._run_emulator(self.fsuae_options.list()): if not self._run_emulator(self.fsuae_options.list()):
return False return False
if self._get_saves_dir():
if not self._save_save():
return False
return self._make_archive() return self._make_archive()
def _validate_options(self): def _validate_options(self):
@@ -79,14 +83,10 @@ class Archive(base.Base):
if self.all_options.get('wrapper_persist_data', '0') != '1': if self.all_options.get('wrapper_persist_data', '0') != '1':
return True return True
saves = self._get_saves_dir()
if saves:
if not self._save_save():
return False
curdir = os.path.abspath('.') curdir = os.path.abspath('.')
os.chdir(self.dir) os.chdir(self.dir)
saves = self._get_saves_dir()
if saves: if saves:
shutil.rmtree(saves) shutil.rmtree(saves)
os.unlink('Config.fs-uae') os.unlink('Config.fs-uae')

View File

@@ -7,6 +7,7 @@ import shutil
import tempfile import tempfile
from fs_uae_wrapper import utils from fs_uae_wrapper import utils
from fs_uae_wrapper import path
class Base(object): class Base(object):
@@ -96,7 +97,9 @@ class Base(object):
else: else:
self.arch_filepath = os.path.join(conf_abs_dir, arch) self.arch_filepath = os.path.join(conf_abs_dir, arch)
# set optional save_state # set optional save_state
self.save_filename = os.path.join(conf_abs_dir, conf_base + '_save.7z') arch_ext = utils.get_arch_ext(self.all_options['wrapper_archiver'])
self.save_filename = os.path.join(conf_abs_dir, conf_base + '_save' +
arch_ext)
def _copy_conf(self): def _copy_conf(self):
"""copy provided configuration as Config.fs-uae""" """copy provided configuration as Config.fs-uae"""
@@ -140,6 +143,7 @@ class Base(object):
""" """
Get the saves from emulator and store it where configuration is placed Get the saves from emulator and store it where configuration is placed
""" """
os.chdir(self.dir)
save_path = self._get_saves_dir() save_path = self._get_saves_dir()
if not save_path: if not save_path:
return True return True
@@ -147,10 +151,14 @@ class Base(object):
if os.path.exists(self.save_filename): if os.path.exists(self.save_filename):
os.unlink(self.save_filename) os.unlink(self.save_filename)
if not utils.run_command(['7z', 'a', self.save_filename, save_path]): curdir = os.path.abspath('.')
if not utils.create_archive(self.save_filename, '', [save_path]):
sys.stderr.write('Error: archiving save state failed\n') sys.stderr.write('Error: archiving save state failed\n')
os.chdir(curdir)
return False return False
os.chdir(curdir)
return True return True
def _load_save(self): def _load_save(self):
@@ -162,17 +170,18 @@ class Base(object):
curdir = os.path.abspath('.') curdir = os.path.abspath('.')
os.chdir(self.dir) os.chdir(self.dir)
utils.run_command(['7z', 'x', self.save_filename]) utils.extract_archive(self.save_filename)
os.chdir(curdir) os.chdir(curdir)
return True return True
def _get_saves_dir(self): def _get_saves_dir(self):
""" """
Return full path to save state directory or None in cases: Return path to save state directory or None in cases:
- there is no save state dir set relative to config file - there is no save state dir set relative to config file
- save state dir is set globally - save state dir is set globally
- save state dir is set relative to the config file - save state dir is set relative to the config file
- save state dir doesn't exists - save state dir doesn't exists
Note, that returned path is relative not absolute
""" """
if not self.all_options.get('save_states_dir'): if not self.all_options.get('save_states_dir'):
return None return None
@@ -187,7 +196,10 @@ class Base(object):
if not os.path.exists(save_path) or not os.path.isdir(save_path): if not os.path.exists(save_path) or not os.path.isdir(save_path):
return None return None
return save_path if save.endswith('/'):
save = save[:-1]
return save
def _validate_options(self): def _validate_options(self):
"""Validate mandatory options""" """Validate mandatory options"""
@@ -195,4 +207,15 @@ class Base(object):
sys.stderr.write("Configuration lacks of required " sys.stderr.write("Configuration lacks of required "
"`wrapper' option.\n") "`wrapper' option.\n")
return False return False
if 'wrapper_archiver' not in self.all_options:
sys.stderr.write("Configuration lacks of required "
"`wrapper_archiver' option.\n")
return False
if not path.which(self.all_options['wrapper_archiver']):
sys.stderr.write("Cannot find archiver `%s'." %
self.all_options['wrapper_archiver'])
return False
return True return True

View File

@@ -6,23 +6,7 @@ import subprocess
import sys import sys
import re import re
from fs_uae_wrapper import path
def which(archivers):
"""
Check if there selected archiver is available in the system and place it
to the archiver attribute
"""
if not isinstance(archivers, list):
archivers = [archivers]
for fname in archivers:
for path in os.environ["PATH"].split(os.pathsep):
path = os.path.join(path.strip('"'), fname)
if os.path.isfile(path) and os.access(path, os.X_OK):
return fname
return None
class Archive(object): class Archive(object):
@@ -32,15 +16,17 @@ class Archive(object):
ARCH = 'false' ARCH = 'false'
def __init__(self): def __init__(self):
self.archiver = which(self.ARCH) self.archiver = path.which(self.ARCH)
self._compess = self.archiver self._compess = self.archiver
self._decompess = self.archiver self._decompess = self.archiver
def create(self, arch_name): def create(self, arch_name, files=None):
""" """
Create archive. Return True on success, False otherwise. Create archive. Return True on success, False otherwise.
""" """
result = subprocess.call([self._compess] + self.ADD + [arch_name, '.']) files = files if files else ['.']
result = subprocess.call([self._compess] + self.ADD + [arch_name]
+ files)
if result != 0: if result != 0:
sys.stderr.write("Unable to create archive `%s'\n" % arch_name) sys.stderr.write("Unable to create archive `%s'\n" % arch_name)
return False return False
@@ -91,7 +77,7 @@ class ZipArchive(Archive):
def __init__(self): def __init__(self):
super(ZipArchive, self).__init__() super(ZipArchive, self).__init__()
if self.archiver == 'zip': if self.archiver == 'zip':
self._decompess = which('unzip') self._decompess = path.which('unzip')
ZipArchive.ADD = ['-r'] ZipArchive.ADD = ['-r']
ZipArchive.EXTRACT = [] ZipArchive.EXTRACT = []
@@ -105,7 +91,7 @@ class LzxArchive(Archive):
ARCH = 'unlzx' ARCH = 'unlzx'
@classmethod @classmethod
def create(self, arch_name): def create(self, arch_name, files=None):
sys.stderr.write('Cannot create LZX archive. Only extracting is' sys.stderr.write('Cannot create LZX archive. Only extracting is'
'supported\n') 'supported\n')
return False return False
@@ -114,20 +100,56 @@ class LzxArchive(Archive):
class RarArchive(Archive): class RarArchive(Archive):
ARCH = ['rar', 'unrar'] ARCH = ['rar', 'unrar']
def create(self, arch_name): def create(self, arch_name, files=None):
files = files if files else sorted(os.listdir('.'))
if self.archiver == 'unrar': if self.archiver == 'unrar':
sys.stderr.write('Cannot create RAR archive. Only extracting is' sys.stderr.write('Cannot create RAR archive. Only extracting is'
'supported by unrar.\n') 'supported by unrar.\n')
return False return False
result = subprocess.call([self._compess] + self.ADD + [arch_name] + result = subprocess.call([self._compess] + self.ADD + [arch_name] +
sorted(os.listdir('.'))) files)
if result != 0: if result != 0:
sys.stderr.write("Unable to create archive `%s'\n" % arch_name) sys.stderr.write("Unable to create archive `%s'\n" % arch_name)
return False return False
return True return True
class Archivers(object):
"""Archivers class"""
archivers = [{'arch': TarArchive, 'name': 'tar', 'ext': ['tar']},
{'arch': TarGzipArchive, 'name': 'tgz',
'ext': ['tar.gz', 'tgz']},
{'arch': TarBzip2Archive, 'name': 'tar.bz2',
'ext': ['tar.bz2']},
{'arch': TarXzArchive, 'name': 'tar.xz', 'ext': ['tar.xz']},
{'arch': RarArchive, 'name': 'rar', 'ext': ['rar']},
{'arch': SevenZArchive, 'name': '7z', 'ext': ['7z']},
{'arch': ZipArchive, 'name': 'zip', 'ext': ['zip']},
{'arch': LhaArchive, 'name': 'lha', 'ext': ['lha', 'lzh']},
{'arch': LzxArchive, 'name': 'lzx', 'ext': ['lzx']}]
@classmethod
def get(cls, extension):
"""
Get the archive class or None
"""
for arch in cls.archivers:
if extension in arch['ext']:
return arch['arch']
return None
@classmethod
def get_extension_by_name(cls, name):
"""
Get the first defined extension for the archive format
"""
for arch in cls.archivers:
if name == arch['name']:
return '.' + arch['ext'][0]
return None
def get_archiver(arch_name): def get_archiver(arch_name):
"""Return right class for provided archive file name""" """Return right class for provided archive file name"""
@@ -138,18 +160,10 @@ def get_archiver(arch_name):
if result: if result:
ext = result.groups()[0] ext = result.groups()[0]
archivers = {'.tar': TarArchive, if ext:
'.tgz': TarGzipArchive, ext = ext[1:]
'.tar.gz': TarGzipArchive,
'.tar.bz2': TarBzip2Archive,
'.tar.xz': TarXzArchive,
'.rar': RarArchive,
'.7z': SevenZArchive,
'.zip': ZipArchive,
'.lha': LhaArchive,
'.lzx': LzxArchive}
archiver = archivers.get(ext) archiver = Archivers.get(ext)
if not archiver: if not archiver:
sys.stderr.write("Unable find archive type for `%s'\n" % arch_name) sys.stderr.write("Unable find archive type for `%s'\n" % arch_name)
return None return None

22
fs_uae_wrapper/path.py Normal file
View File

@@ -0,0 +1,22 @@
"""
Misc utilities
"""
import os
def which(executables):
"""
Check if there selected archiver is available in the system and place it
to the archiver attribute
"""
if not isinstance(executables, list):
executables = [executables]
for fname in executables:
for path in os.environ["PATH"].split(os.pathsep):
path = os.path.join(path.strip('"'), fname)
if os.path.isfile(path) and os.access(path, os.X_OK):
return fname
return None

View File

@@ -57,7 +57,7 @@ def get_config_options(conf):
for key, val in parser.items(section)} for key, val in parser.items(section)}
def operate_archive(arch_name, operation, text): def operate_archive(arch_name, operation, text, params):
""" """
Create archive from contents of current directory Create archive from contents of current directory
""" """
@@ -77,31 +77,31 @@ def operate_archive(arch_name, operation, text):
res = archiver.extract(arch_name) res = archiver.extract(arch_name)
if operation == 'create': if operation == 'create':
res = archiver.create(arch_name) res = archiver.create(arch_name, params)
msg.close() msg.close()
return res return res
def create_archive(arch_name, title=''): def create_archive(arch_name, title='', params=None):
""" """
Create archive from contents of current directory Create archive from contents of current directory
""" """
msg = '' msg = ''
if title: if title:
msg = "Creating archive for `%s'. Please be patient" % title msg = "Creating archive for `%s'. Please be patient" % title
return operate_archive(arch_name, 'create', msg) return operate_archive(arch_name, 'create', msg, params)
def extract_archive(arch_name, title=''): def extract_archive(arch_name, title='', params=None):
""" """
Extract provided archive to current directory Extract provided archive to current directory
""" """
msg = '' msg = ''
if title: if title:
msg = "Extracting files for `%s'. Please be patient" % title msg = "Extracting files for `%s'. Please be patient" % title
return operate_archive(arch_name, 'extract', msg) return operate_archive(arch_name, 'extract', msg, params)
def run_command(cmd): def run_command(cmd):
@@ -217,3 +217,8 @@ def get_config(conf_file):
config['_base_dir'] = conf_dir config['_base_dir'] = conf_dir
return config return config
def get_arch_ext(archiver_name):
"""Return extension for the archiver"""
return file_archive.Archivers.get_extension_by_name(archiver_name)

View File

@@ -7,7 +7,7 @@ from distutils.core import setup
setup(name='fs-uae-wrapper', setup(name='fs-uae-wrapper',
packages=['fs_uae_wrapper'], packages=['fs_uae_wrapper'],
version='0.3', version='0.4',
description='Automate archives and state for fs-uae', description='Automate archives and state for fs-uae',
author='Roman Dobosz', author='Roman Dobosz',
author_email='gryf73@gmail.com', author_email='gryf73@gmail.com',

View File

@@ -35,6 +35,9 @@ class TestArchive(TestCase):
self.assertFalse(arch._validate_options()) self.assertFalse(arch._validate_options())
arch.all_options['wrapper_archive'] = 'fake.tgz' arch.all_options['wrapper_archive'] = 'fake.tgz'
self.assertFalse(arch._validate_options())
arch.all_options['wrapper_archiver'] = 'rar'
self.assertTrue(arch._validate_options()) self.assertTrue(arch._validate_options())
@mock.patch('tempfile.mkdtemp') @mock.patch('tempfile.mkdtemp')
@@ -57,7 +60,8 @@ class TestArchive(TestCase):
self.assertFalse(arch.run()) self.assertFalse(arch.run())
arch.all_options = {'wrapper': 'archive', arch.all_options = {'wrapper': 'archive',
'wrapper_archive': 'fake.tgz'} 'wrapper_archive': 'fake.tgz',
'wrapper_archiver': 'rar'}
self.assertFalse(arch.run()) self.assertFalse(arch.run())
@@ -85,12 +89,10 @@ class TestArchive(TestCase):
@mock.patch('shutil.rmtree') @mock.patch('shutil.rmtree')
@mock.patch('fs_uae_wrapper.utils.create_archive') @mock.patch('fs_uae_wrapper.utils.create_archive')
@mock.patch('fs_uae_wrapper.base.Base._get_title') @mock.patch('fs_uae_wrapper.base.Base._get_title')
@mock.patch('fs_uae_wrapper.base.Base._save_save')
@mock.patch('fs_uae_wrapper.base.Base._get_saves_dir') @mock.patch('fs_uae_wrapper.base.Base._get_saves_dir')
def test_make_archive(self, sdir, save, title, carch, rmt, unlink, rename): def test_make_archive(self, sdir, title, carch, rmt, unlink, rename):
sdir.return_value = None sdir.return_value = None
save.return_value = False
title.return_value = '' title.return_value = ''
carch.return_value = False carch.return_value = False
@@ -107,7 +109,4 @@ class TestArchive(TestCase):
self.assertTrue(arch._make_archive()) self.assertTrue(arch._make_archive())
sdir.return_value = '/some/path' sdir.return_value = '/some/path'
self.assertFalse(arch._make_archive())
save.return_value = True
self.assertTrue(arch._make_archive()) self.assertTrue(arch._make_archive())

View File

@@ -75,13 +75,15 @@ class TestBase(TestCase):
bobj = base.Base('Config.fs-uae', utils.CmdOption(), {}) bobj = base.Base('Config.fs-uae', utils.CmdOption(), {})
os.chdir(self.dirname) os.chdir(self.dirname)
bobj.conf_file = 'Config.fs-uae' bobj.conf_file = 'Config.fs-uae'
bobj.all_options = {'wrapper_archive': 'foo.7z'} bobj.all_options = {'wrapper_archive': 'foo.7z',
'wrapper_archiver': '7z'}
bobj._set_assets_paths() bobj._set_assets_paths()
full_path = os.path.join(self.dirname, 'Config_save.7z') full_path = os.path.join(self.dirname, 'Config_save.7z')
self.assertEqual(bobj.save_filename, full_path) self.assertEqual(bobj.save_filename, full_path)
bobj.all_options = {'wrapper_archive': '/home/user/foo.7z'} bobj.all_options = {'wrapper_archive': '/home/user/foo.7z',
'wrapper_archiver': '7z'}
bobj._set_assets_paths() bobj._set_assets_paths()
full_path = os.path.join(self.dirname, 'Config_save.7z') full_path = os.path.join(self.dirname, 'Config_save.7z')
@@ -141,14 +143,14 @@ class TestBase(TestCase):
run.assert_called_once_with(['fs-uae']) run.assert_called_once_with(['fs-uae'])
@mock.patch('fs_uae_wrapper.base.Base._get_saves_dir') @mock.patch('fs_uae_wrapper.base.Base._get_saves_dir')
@mock.patch('fs_uae_wrapper.utils.run_command') @mock.patch('fs_uae_wrapper.utils.create_archive')
def test_save_save(self, run, saves_dir): def test_save_save(self, carch, saves_dir):
bobj = base.Base('Config.fs-uae', utils.CmdOption(), {}) bobj = base.Base('Config.fs-uae', utils.CmdOption(), {})
bobj.dir = self.dirname bobj.dir = self.dirname
bobj.save_filename = 'foobar_save.7z' bobj.save_filename = 'foobar_save.7z'
saves_dir.bobj.save_filenamereturn_value = None saves_dir.bobj.save_filenamereturn_value = None
run.return_value = True carch.return_value = True
self.assertTrue(bobj._save_save()) self.assertTrue(bobj._save_save())
@@ -162,16 +164,16 @@ class TestBase(TestCase):
os.mkdir(os.path.join(self.dirname, 'fs-uae-save')) os.mkdir(os.path.join(self.dirname, 'fs-uae-save'))
self.assertTrue(bobj._save_save()) self.assertTrue(bobj._save_save())
run.return_value = False carch.return_value = False
self.assertFalse(bobj._save_save()) self.assertFalse(bobj._save_save())
@mock.patch('fs_uae_wrapper.utils.run_command') @mock.patch('fs_uae_wrapper.utils.extract_archive')
def test_load_save(self, run): def test_load_save(self, earch):
bobj = base.Base('Config.fs-uae', utils.CmdOption(), {}) bobj = base.Base('Config.fs-uae', utils.CmdOption(), {})
bobj.dir = self.dirname bobj.dir = self.dirname
bobj.save_filename = "foobar_save.7z" bobj.save_filename = "foobar_save.7z"
run.return_value = 0 earch.return_value = 0
# fail to load save is not fatal # fail to load save is not fatal
self.assertTrue(bobj._load_save()) self.assertTrue(bobj._load_save())
@@ -181,11 +183,11 @@ class TestBase(TestCase):
fobj.write('asd') fobj.write('asd')
self.assertTrue(bobj._load_save()) self.assertTrue(bobj._load_save())
run.assert_called_once_with(['7z', 'x', bobj.save_filename]) earch.assert_called_once_with(bobj.save_filename)
# failure in searching for archiver are also non fatal # failure in searching for archiver are also non fatal
run.reset_mock() earch.reset_mock()
run.return_value = 1 earch.return_value = 1
self.assertTrue(bobj._save_save()) self.assertTrue(bobj._save_save())
def test_get_saves_dir(self): def test_get_saves_dir(self):
@@ -214,9 +216,12 @@ class TestBase(TestCase):
os.unlink(path) os.unlink(path)
os.mkdir(path) os.mkdir(path)
self.assertEqual(bobj._get_saves_dir(), path) self.assertEqual(bobj._get_saves_dir(), 'saves')
def test_validate_options(self): @mock.patch('fs_uae_wrapper.path.which')
def test_validate_options(self, which):
which.return_value = None
bobj = base.Base('Config.fs-uae', utils.CmdOption(), {}) bobj = base.Base('Config.fs-uae', utils.CmdOption(), {})
bobj.all_options = {} bobj.all_options = {}
@@ -224,6 +229,15 @@ class TestBase(TestCase):
self.assertFalse(bobj._validate_options()) self.assertFalse(bobj._validate_options())
bobj.all_options = {'wrapper': 'dummy'} bobj.all_options = {'wrapper': 'dummy'}
self.assertFalse(bobj._validate_options())
bobj.all_options = {'wrapper': 'dummy',
'wrapper_archiver': 'myarchiver'}
self.assertFalse(bobj._validate_options())
which.return_value = '7z'
bobj.all_options = {'wrapper': 'dummy',
'wrapper_archiver': '7z'}
self.assertTrue(bobj._validate_options()) self.assertTrue(bobj._validate_options())
def test_run_clean(self): def test_run_clean(self):
@@ -233,7 +247,8 @@ class TestBase(TestCase):
self.assertFalse(bobj.run()) self.assertFalse(bobj.run())
bobj.all_options = {'wrapper': 'dummy'} bobj.all_options = {'wrapper': 'dummy',
'wrapper_archiver': 'rar'}
try: try:
self.assertTrue(bobj.run()) self.assertTrue(bobj.run())
self.assertTrue(os.path.exists(bobj.dir)) self.assertTrue(os.path.exists(bobj.dir))

View File

@@ -20,6 +20,9 @@ class TestCD32(TestCase):
self.assertFalse(acd32._validate_options()) self.assertFalse(acd32._validate_options())
acd32.all_options['wrapper_archive'] = 'fake.tgz' acd32.all_options['wrapper_archive'] = 'fake.tgz'
self.assertFalse(acd32._validate_options())
acd32.all_options['wrapper_archiver'] = 'rar'
self.assertTrue(acd32._validate_options()) self.assertTrue(acd32._validate_options())
@mock.patch('tempfile.mkdtemp') @mock.patch('tempfile.mkdtemp')
@@ -42,7 +45,8 @@ class TestCD32(TestCase):
self.assertFalse(acd32.run()) self.assertFalse(acd32.run())
acd32.all_options = {'wrapper': 'cd32', acd32.all_options = {'wrapper': 'cd32',
'wrapper_archive': 'fake.tgz'} 'wrapper_archive': 'fake.tgz',
'wrapper_archiver': 'rar'}
self.assertFalse(acd32.run()) self.assertFalse(acd32.run())

View File

@@ -60,13 +60,7 @@ class TestArchive(TestCase):
self.assertFalse(arch.extract('foo')) self.assertFalse(arch.extract('foo'))
call.assert_called_once_with(['false', 'x', 'foo']) call.assert_called_once_with(['false', 'x', 'foo'])
def test_archive_which(self): @mock.patch('fs_uae_wrapper.path.which')
self.assertEqual(file_archive.which('sh'), 'sh')
self.assertIsNone(file_archive.which('blahblahexec'))
self.assertEqual(file_archive.which(['blahblahexec', 'pip', 'sh']),
'pip')
@mock.patch('fs_uae_wrapper.file_archive.which')
@mock.patch('subprocess.call') @mock.patch('subprocess.call')
def test_tar(self, call, which): def test_tar(self, call, which):
with open('foo', 'w') as fobj: with open('foo', 'w') as fobj:
@@ -122,7 +116,7 @@ class TestArchive(TestCase):
self.assertFalse(arch.extract('foo')) self.assertFalse(arch.extract('foo'))
call.assert_called_once_with(['tar', 'xf', 'foo']) call.assert_called_once_with(['tar', 'xf', 'foo'])
@mock.patch('fs_uae_wrapper.file_archive.which') @mock.patch('fs_uae_wrapper.path.which')
@mock.patch('subprocess.call') @mock.patch('subprocess.call')
def test_lha(self, call, which): def test_lha(self, call, which):
with open('foo', 'w') as fobj: with open('foo', 'w') as fobj:
@@ -142,7 +136,7 @@ class TestArchive(TestCase):
self.assertFalse(arch.extract('foo')) self.assertFalse(arch.extract('foo'))
call.assert_called_once_with(['lha', 'x', 'foo']) call.assert_called_once_with(['lha', 'x', 'foo'])
@mock.patch('fs_uae_wrapper.file_archive.which') @mock.patch('fs_uae_wrapper.path.which')
@mock.patch('subprocess.call') @mock.patch('subprocess.call')
def test_lzx(self, call, which): def test_lzx(self, call, which):
with open('foo', 'w') as fobj: with open('foo', 'w') as fobj:
@@ -162,7 +156,7 @@ class TestArchive(TestCase):
self.assertFalse(arch.extract('foo')) self.assertFalse(arch.extract('foo'))
call.assert_called_once_with(['unlzx', '-x', 'foo']) call.assert_called_once_with(['unlzx', '-x', 'foo'])
@mock.patch('fs_uae_wrapper.file_archive.which') @mock.patch('fs_uae_wrapper.path.which')
@mock.patch('subprocess.call') @mock.patch('subprocess.call')
def test_7zip(self, call, which): def test_7zip(self, call, which):
with open('foo', 'w') as fobj: with open('foo', 'w') as fobj:
@@ -182,7 +176,7 @@ class TestArchive(TestCase):
self.assertFalse(arch.extract('foo')) self.assertFalse(arch.extract('foo'))
call.assert_called_once_with(['7z', 'x', 'foo']) call.assert_called_once_with(['7z', 'x', 'foo'])
@mock.patch('fs_uae_wrapper.file_archive.which') @mock.patch('fs_uae_wrapper.path.which')
@mock.patch('subprocess.call') @mock.patch('subprocess.call')
def test_zip(self, call, which): def test_zip(self, call, which):
with open('foo', 'w') as fobj: with open('foo', 'w') as fobj:
@@ -202,7 +196,7 @@ class TestArchive(TestCase):
self.assertFalse(arch.extract('foo')) self.assertFalse(arch.extract('foo'))
call.assert_called_once_with(['7z', 'x', 'foo']) call.assert_called_once_with(['7z', 'x', 'foo'])
@mock.patch('fs_uae_wrapper.file_archive.which') @mock.patch('fs_uae_wrapper.path.which')
@mock.patch('subprocess.call') @mock.patch('subprocess.call')
def test_rar(self, call, which): def test_rar(self, call, which):

12
tests/test_path.py Normal file
View File

@@ -0,0 +1,12 @@
from unittest import TestCase
from fs_uae_wrapper import path
class TestPath(TestCase):
def test_which(self):
self.assertEqual(path.which('sh'), 'sh')
self.assertIsNone(path.which('blahblahexec'))
self.assertEqual(path.which(['blahblahexec', 'pip', 'sh']),
'pip')

View File

@@ -72,41 +72,45 @@ class TestUtils(TestCase):
conf = utils.get_config_options(self.fname) conf = utils.get_config_options(self.fname)
self.assertDictEqual(conf, {'wrapper': ''}) self.assertDictEqual(conf, {'wrapper': ''})
@mock.patch('fs_uae_wrapper.path.which')
@mock.patch('fs_uae_wrapper.file_archive.Archive.extract') @mock.patch('fs_uae_wrapper.file_archive.Archive.extract')
@mock.patch('fs_uae_wrapper.file_archive.Archive.create') @mock.patch('fs_uae_wrapper.file_archive.Archive.create')
@mock.patch('fs_uae_wrapper.message.Message.close') @mock.patch('fs_uae_wrapper.message.Message.close')
@mock.patch('fs_uae_wrapper.message.Message.show') @mock.patch('fs_uae_wrapper.message.Message.show')
def test_operate_archive(self, show, close, create, extract): def test_operate_archive(self, show, close, create, extract, which):
os.chdir(self.dirname) os.chdir(self.dirname)
which.return_value = None
# No config # No config
self.assertFalse(utils.operate_archive('non-existend.7z', 'foo', '')) self.assertFalse(utils.operate_archive('non-existend.7z', 'foo', '',
None))
# Archive type not known # Archive type not known
with open('unsupported-archive.ace', 'w') as fobj: with open('unsupported-archive.ace', 'w') as fobj:
fobj.write("\n") fobj.write("\n")
self.assertFalse(utils.operate_archive('unsupported-archive.ace', self.assertFalse(utils.operate_archive('unsupported-archive.ace',
'foo', '')) 'foo', '', None))
# archive is known, but extraction will fail - we have an empty # archive is known, but extraction will fail - we have an empty
# archive and there is no guarantee, that 7z exists on system where # archive and there is no guarantee, that 7z exists on system where
# test will run # test will run
which.return_value = '7z'
extract.return_value = True extract.return_value = True
with open('supported-archive.7z', 'w') as fobj: with open('supported-archive.7z', 'w') as fobj:
fobj.write("\n") fobj.write("\n")
self.assertTrue(utils.operate_archive('supported-archive.7z', self.assertTrue(utils.operate_archive('supported-archive.7z',
'extract', '')) 'extract', '', None))
extract.assert_called_once() extract.assert_called_once()
extract.reset_mock() extract.reset_mock()
self.assertTrue(utils.operate_archive('supported-archive.7z', self.assertTrue(utils.operate_archive('supported-archive.7z',
'extract', '')) 'extract', '', None))
extract.assert_called_once() extract.assert_called_once()
os.unlink('supported-archive.7z') os.unlink('supported-archive.7z')
self.assertTrue(utils.operate_archive('supported-archive.7z', self.assertTrue(utils.operate_archive('supported-archive.7z',
'create', 'test')) 'create', 'test', ['foo']))
create.assert_called_once() create.assert_called_once()
show.assert_called_once() show.assert_called_once()
@@ -129,7 +133,9 @@ class TestUtils(TestCase):
fobj.write("\n") fobj.write("\n")
self.assertFalse(utils.extract_archive('supported-archive.7z')) self.assertFalse(utils.extract_archive('supported-archive.7z'))
def test_create_archive(self): @mock.patch('fs_uae_wrapper.file_archive.Archive.create')
def test_create_archive(self, arch_create):
arch_create.return_value = True
os.chdir(self.dirname) os.chdir(self.dirname)
@@ -148,8 +154,11 @@ class TestUtils(TestCase):
fobj.write("\n") fobj.write("\n")
self.assertFalse(utils.extract_archive('supported-archive.7z')) self.assertFalse(utils.extract_archive('supported-archive.7z'))
@mock.patch('fs_uae_wrapper.path.which')
@mock.patch('fs_uae_wrapper.file_archive.Archive.extract') @mock.patch('fs_uae_wrapper.file_archive.Archive.extract')
def test_extract_archive_positive(self, arch_extract): def test_extract_archive_positive(self, arch_extract, which):
arch_extract.return_value = True
which.return_value = '7z'
os.chdir(self.dirname) os.chdir(self.dirname)
# archive is known, and extraction should succeed # archive is known, and extraction should succeed