diff --git a/fs_uae_wrapper/cd32.py b/fs_uae_wrapper/cd32.py index dcf6d89..fe5bc60 100644 --- a/fs_uae_wrapper/cd32.py +++ b/fs_uae_wrapper/cd32.py @@ -10,7 +10,6 @@ name. """ import os import shutil -import subprocess import sys import tempfile @@ -151,11 +150,7 @@ class CD32(object): """execute game in provided directory""" curdir = os.path.abspath('.') os.chdir(self.dir) - try: - subprocess.call(['fs-uae'] + fs_uae_options) - except subprocess.CalledProcessError: - sys.stderr.write('Warning: fs-uae returned non 0 exit code\n') - + utils.run_command(['fs-uae'] + fs_uae_options) os.chdir(curdir) return True @@ -170,11 +165,10 @@ class CD32(object): if os.path.exists(self.save_filename): os.unlink(self.save_filename) - try: - subprocess.call(['7z', 'a', self.save_filename, - os.path.join(self.dir, 'fs-uae-save')]) - except subprocess.CalledProcessError: - sys.stderr.write('Warning: archiving save state failed\n') + code = utils.run_command(['7z', 'a', self.save_filename, + os.path.join(self.dir, 'fs-uae-save')]) + if code != 0: + sys.stderr.write('Error: archiving save state failed\n') return False return True @@ -188,12 +182,7 @@ class CD32(object): curdir = os.path.abspath('.') os.chdir(self.dir) - try: - subprocess.call(['7z', 'x', self.save_filename]) - except subprocess.CalledProcessError: - sys.stderr.write('Warning: extracting archive with save state ' - 'failed\n') - + utils.run_command(['7z', 'x', self.save_filename]) os.chdir(curdir) return True diff --git a/fs_uae_wrapper/utils.py b/fs_uae_wrapper/utils.py index 7824f78..c3bb1fb 100644 --- a/fs_uae_wrapper/utils.py +++ b/fs_uae_wrapper/utils.py @@ -3,6 +3,7 @@ Misc utilities """ from distutils import spawn import os +import six import subprocess import sys try: @@ -105,6 +106,24 @@ def extract_archive(arch_name, show_gui_message, message_text): return True +def run_command(cmd): + """ + Run provided command. Return true if command execution returns zero exit + code, false otherwise. If cmd is a string, there would be an attempt to + split it up for subprocess call method. + """ + + if isinstance(six.text_type(cmd), six.string_types): + cmd = cmd.split() + + code = subprocess.call(cmd) + if code != 0: + sys.stderr.write('Command `{0}` returned non 0 exit ' + 'code\n'.format(cmd[0])) + return False + return True + + def merge_all_options(configuration, commandline): """ Merge dictionaries with wrapper options into one. Commandline options diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ffe2fce --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +six diff --git a/tests/test_cd32.py b/tests/test_cd32.py index 0a63e03..b456941 100644 --- a/tests/test_cd32.py +++ b/tests/test_cd32.py @@ -1,7 +1,6 @@ import os import sys import shutil -import subprocess from tempfile import mkstemp, mkdtemp from unittest import TestCase @@ -18,6 +17,7 @@ class TestCD32(TestCase): def setUp(self): fd, self.fname = mkstemp() self.dirname = mkdtemp() + self.confdir = mkdtemp() os.close(fd) self._argv = sys.argv[:] sys.argv = ['fs-uae-wrapper'] @@ -29,6 +29,10 @@ class TestCD32(TestCase): shutil.rmtree(self.dirname) except OSError: pass + try: + shutil.rmtree(self.confdir) + except OSError: + pass os.unlink(self.fname) sys.argv = self._argv[:] @@ -119,17 +123,62 @@ class TestCD32(TestCase): self.assertFalse(acd32._extract()) utils_extract.assert_called_once_with(self.fname, '1', 'arch.7z') - @mock.patch('subprocess.call') - def test_run_game(self, sub_call): + @mock.patch('fs_uae_wrapper.utils.run_command') + def test_run_game(self, run): acd32 = cd32.CD32() acd32.dir = self.dirname self.assertTrue(acd32._run_game([])) - sub_call.assert_called_once_with(['fs-uae']) + run.assert_called_once_with(['fs-uae']) # Errors from emulator are not fatal to wrappers - sub_call.reset_mock() - sub_call.side_effect = subprocess.CalledProcessError(2, 'fs-uae') + run.reset_mock() + run.return_value = False self.assertTrue(acd32._run_game([])) - sub_call.assert_called_once_with(['fs-uae']) + run.assert_called_once_with(['fs-uae']) + + @mock.patch('fs_uae_wrapper.utils.run_command') + def test_save_save(self, run): + + acd32 = cd32.CD32() + acd32.dir = self.dirname + acd32.save_filename = "foobar_save.7z" + run.return_value = 0 + + self.assertTrue(acd32._save_save()) + + os.chdir(self.confdir) + with open(acd32.save_filename, 'w') as fobj: + fobj.write('asd') + + self.assertTrue(acd32._save_save()) + + os.mkdir(os.path.join(self.dirname, 'fs-uae-save')) + self.assertTrue(acd32._save_save()) + + run.return_value = 1 + self.assertFalse(acd32._save_save()) + + @mock.patch('fs_uae_wrapper.utils.run_command') + def test_load_save(self, run): + + acd32 = cd32.CD32() + acd32.dir = self.dirname + acd32.save_filename = "foobar_save.7z" + run.return_value = 0 + + # fail to load save is not fatal + self.assertTrue(acd32._load_save()) + + os.chdir(self.confdir) + with open(acd32.save_filename, 'w') as fobj: + fobj.write('asd') + + self.assertTrue(acd32._load_save()) + run.assert_called_once_with(['7z', 'x', acd32.save_filename]) + + # failure in searching for archiver are also non fatal + run.reset_mock() + run.return_value = 1 + self.assertTrue(acd32._save_save()) diff --git a/tox.ini b/tox.ini index da7db51..a8bf4bf 100644 --- a/tox.ini +++ b/tox.ini @@ -7,7 +7,9 @@ usedevelop = True usedevelop=True setenv = COVERAGE_FILE = .coverage commands = py.test --cov=fs_uae_wrapper --cov-report=term-missing -deps = -r{toxinidir}/test-requirements.txt + +deps = -r{toxinidir}/requirements.txt + -r{toxinidir}/test-requirements.txt [testenv:py27] deps = {[testenv]deps}