1
0
mirror of https://github.com/gryf/fs-uae-wrapper.git synced 2026-02-02 22:25:47 +01:00

11 Commits
0.8 ... 0.9.1

Author SHA1 Message Date
148d28dac2 Make archive name and archiver for savestate optional. 2024-09-11 21:23:49 +02:00
60139d1728 Move to pyproject. 2024-09-11 19:53:52 +02:00
68b1f2a787 Correct homepage in setup.cfg 2022-10-02 14:57:38 +02:00
75d2cff96c Drop Python2 support. 2022-09-02 19:01:56 +02:00
114984cbee Go with setup.cfg instead of setup.py. 2022-09-02 18:47:17 +02:00
b015e443eb Fix tests for file path calculations 2021-05-02 09:36:14 +02:00
874213aef9 Prevent from nonexistent paths in config.
In case of defining paths in config, which wrapper is trying to
normalize, sometimes it may happen, that paths can be either local or
remote - depending on the intention, i.e. one can add:

cdrom_drive_0: foo.iso

where foo can be either an unpacked file or just some companion image,
which exists within config file.

In this patch calculated path is checked against file existence, and if
it doesn't exists, original value is preserved.
2021-03-20 13:12:58 +01:00
1559591417 Changed python3 interpreter to default.
Currently, as a python3 interpreter, specific version has been chosen.
As fs-uae-wrapper doesn't use any special features from latest version
of the python3, it doesn't make sense to have fixed version of it. Just
let operating system pick right python 3 interpreter.
2019-10-06 18:09:32 +02:00
193e487bb9 Fix download link and typo in readme 2017-06-19 19:55:02 +02:00
eb9012f3fa Readme update 2017-01-12 21:09:12 +01:00
efbb5f6f05 Readme update 2017-01-09 06:41:16 +01:00
14 changed files with 191 additions and 136 deletions

View File

@@ -2,7 +2,10 @@ language: python
env: env:
- TOXENV=py27 - TOXENV=py27
- TOXENV=py27-flake8 - TOXENV=py27-flake8
- TOXENV=py34 - TOXENV=py3
- TOXENV=py34-flake8 - TOXENV=py3-flake8
install: pip install tox install: pip install tox
script: tox script: tox
before_install:
- sudo apt-get update
- sudo apt-get install -y python-tk python3-tk

View File

@@ -12,7 +12,7 @@ This little utility is a wrapper on great FS-UAE_ emulator, to perform some
actions, like uncompressing archived files (CD ROMs images, filesystems), actions, like uncompressing archived files (CD ROMs images, filesystems),
launch the emulator and archive emulator save state. launch the emulator and archive emulator save state.
As an example, if there is a collection of CD³² game files and one want to As an example, if there is a collection of CD³² game files and you want to
provide configuration for each game, but want to keep ISO images with provide configuration for each game, but want to keep ISO images with
corresponding files in archive (due to size of those images) than FS-UAE corresponding files in archive (due to size of those images) than FS-UAE
Wrapper is a way to achieve this. Wrapper is a way to achieve this.
@@ -25,11 +25,10 @@ preferably in a archive file vs a bunch of files.
Requirements Requirements
============ ============
- Python (2 or 3) - Python 3
- `fs-uae`_ (obviously :) - `fs-uae`_ (obviously :)
Also, there should be archivers programs available for compress/decompress Fs-uae-wrapper supports several types of archives:
archives. Fs-uae-wrapper supports several types of archives:
- `7z`_ - `7z`_
- `lha`_ - `lha`_
@@ -43,25 +42,35 @@ archives. Fs-uae-wrapper supports several types of archives:
- `zip`_ - `zip`_
There are several archive types which are supported, ranging from tar All of those formats should have corresponding software available in the
(compressed with gzip, bzip2 and xz), 7z, rar, zip. lha and lzx. All of those system, otherwise archive extraction/compression will fail.
formats should have corresponding decompressors available in the system,
otherwise archive extraction will fail.
Installation Installation
============ ============
Just perform (preferably in ``virtualenv``) a command: FS-UAE Wrapper is available on `CheeseShop`_ (or python package index if you
will). To install it, you can simply invoke (preferably in ``virtualenv``) a
command:
.. code:: shell-session .. code:: shell-session
$ pip install fs-uae-wrapper $ pip install fs-uae-wrapper
Note, that if ``virtualenv`` was used, there is no need for activating it every
time, since if invoke wrapper like this:
.. code:: shell-session
$ /path/to/virtualenv/bin/fs-uae-wrapper
you should be able run the wrapper properly. *Tested only on Linux :)*.
Usage Usage
===== =====
After installation you should be able to access new command After installation you should be able to access new command ``fs-uae-wrapper``
``fs-uae-wrapper``, and its invocation is identical like ``fs-uae`` binary: (or use the full path to the ``virtualenv`` like on the section above), and it's
invocation is identical like ``fs-uae`` binary:
.. code:: shell-session .. code:: shell-session
@@ -73,9 +82,9 @@ directly in fs-uae configuration or passed as an option:
.. code:: ini .. code:: ini
[config] [config]
... # ...
wrapper = cd32 wrapper = cd32
... # ...
or or
@@ -89,15 +98,19 @@ specific module will be loaded and depending on the module, there would be
performed specific tasks before ``fs-uae`` is launched and after it. performed specific tasks before ``fs-uae`` is launched and after it.
Assumption is, that configuration file are written in portable way, so the are Assumption is, that configuration file are written in portable way, so the are
saved as `relative configuration file`_ (hence the name ``Config.fs-uae``, even saved as `relative configuration file`_ (hence the name ``Config.fs-uae``),
if the are named differently. If certain wrapper is specified, it will create even if the are named differently. If certain wrapper is specified, it will
temporary directory and place the configuration file there as create temporary directory and place the configuration file there as
``Config.fs-uae``. ``Config.fs-uae``.
If no ``wrapper`` option would be passed either as an config option or If no ``wrapper`` option would be passed either as an config option or
command line argument, all command line options will be passed to the fs-uae command line argument, all command line options will be passed to the fs-uae
executable as-is. executable as-is.
Note, that you can also pass all *wrapper* options via commandline in the very
same way as you can pass config options to `fs-uae`, so you don't have to
modify original configuration if you don't want to.
There is also new config variable introduced: ``$WRAPPER`` which have the same There is also new config variable introduced: ``$WRAPPER`` which have the same
role as ``$CONFIG``, but apply for copied config. For instance - in module role as ``$CONFIG``, but apply for copied config. For instance - in module
archive there are filesystem extracted to new location - to access this archive there are filesystem extracted to new location - to access this
@@ -108,7 +121,7 @@ a config option:
[config] [config]
wrapper = archive wrapper = archive
... # ...
hard_drive_0 = $WRAPPER/my_hardrive hard_drive_0 = $WRAPPER/my_hardrive
@@ -118,7 +131,7 @@ directory, where configuration will be copied.
Modules Modules
======= =======
Currently, three wrapper modules are available: Currently, couple of wrapper modules are available:
- plain - plain
- cd32 - cd32
@@ -144,12 +157,12 @@ 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`` (conditionally required) archiver to use for storage * ``wrapper_archiver`` (optional) archiver to use for storage save state -
save state default ``7z``.
* ``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_save_state`` (optional) if set to "1", will load/archive save state * ``wrapper_save_state`` (optional) if set to "1", will load/archive save state
directory, defined as ``$CONFIG/[save-state-dir-name]`` using provided directory, defined as ``$WRAPPER/[save-state-dir-name]`` using provided
``wrapper_archiver`` archiver. If this option is enabled, ``wrapper_archiver`` archiver. If this option is enabled,
``wrapper_archiver`` will be required. ``wrapper_archiver`` will be required.
@@ -162,7 +175,7 @@ fragment of configuration file is saved as ``ChaosEngine.fs-uae``:
[config] [config]
wrapper = cd32 wrapper = cd32
wrapper_archive = ChaosEngine.7z wrapper_archive = ChaosEngine.7z
wrapper_archiver = 7z wrapper_archiver = zip
wrapper_gui_msg = 1 wrapper_gui_msg = 1
amiga_model = CD32 amiga_model = CD32
@@ -170,11 +183,11 @@ fragment of configuration file is saved as ``ChaosEngine.fs-uae``:
cdrom_drive_0 = Chaos Engine, The (1994)(Renegade)(M4)[!][CDD3445].cue cdrom_drive_0 = Chaos Engine, The (1994)(Renegade)(M4)[!][CDD3445].cue
save_states_dir = $CONFIG/fs-uae-save/ save_states_dir = $WRAPPER/fs-uae-save/
joystick_port_1_mode = cd32 gamepad joystick_port_1_mode = cd32 gamepad
platform = cd32 platform = cd32
... # ...
Command line invocation of the wrapper would be as follows: Command line invocation of the wrapper would be as follows:
@@ -186,7 +199,7 @@ Now, there several thing will happen:
- Config file will be read, and wrapper module will be found - Config file will be read, and wrapper module will be found
- New temporary directory will be created - New temporary directory will be created
- Archive with game assists will be extracted in that directory - Archive with game assets will be extracted in that directory
- Configuration file will be copied into that directory, and renamed to - Configuration file will be copied into that directory, and renamed to
``Config.fs-uae`` ``Config.fs-uae``
- If ``wrapper_save_state`` is set, and there is saved state archive, it also - If ``wrapper_save_state`` is set, and there is saved state archive, it also
@@ -206,16 +219,18 @@ archive
Options used: Options used:
* ``wrapper`` (required) with ``archive`` as an value * ``wrapper`` (required) with ``archive`` as an value
* ``wrapper_archive`` (required) path to the archive with assets (usually means * ``wrapper_archive`` (optional) path to the archive with assets (usually means
whole system directories, floppies or hard disk images) whole system directories, floppies or hard disk images), defaults to same
* ``wrapper_archiver`` (conditionally required) archiver to use for storage name as configuration file with some detected archive extension. Note, that
save state name is case sensitive
* ``wrapper_archiver`` (optional) archiver to use for storage save state -
default ``7z``.
* ``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
changed) data, replacing original archive changed) data, replacing original archive
* ``wrapper_save_state`` (optional) if set to "1", will archive save state * ``wrapper_save_state`` (optional) if set to "1", will archive save state
directory, defined as ``$CONFIG/[save-state-dir-name]`` using provided directory, defined as ``$WRAPPER/[save-state-dir-name]`` using provided
``wrapper_archiver`` archiver. If this option is enabled, ``wrapper_archiver`` archiver. If this option is enabled,
``wrapper_archiver`` will be required. ``wrapper_archiver`` will be required.
@@ -237,7 +252,7 @@ Example configuration:
wrapper_gui_msg = 1 wrapper_gui_msg = 1
wrapper_persist_data = 1 wrapper_persist_data = 1
wrapper_save_state = 1 wrapper_save_state = 1
... # ...
And execution is as usual: And execution is as usual:
@@ -264,7 +279,8 @@ savestate
Options used: Options used:
* ``wrapper`` (required) with ``archive`` as an value * ``wrapper`` (required) with ``archive`` as an value
* ``wrapper_archiver`` (required) archiver to use for storage save state * ``wrapper_archiver`` (optional) archiver to use for storage save state -
default ``7z``.
This module is primarily used to run emulator with read only media attached This module is primarily used to run emulator with read only media attached
(like images of floppies or uncompressed CD-ROMs) and its purpose is to (like images of floppies or uncompressed CD-ROMs) and its purpose is to
@@ -276,12 +292,11 @@ set to value ``1`` in this module.
Example configuration: Example configuration:
.. code:: ini .. code:: ini
:number-lines:
[config] [config]
wrapper = savestate wrapper = savestate
wrapper_archiver = 7z wrapper_archiver = 7z
... # ...
And execution is as usual: And execution is as usual:
@@ -312,3 +327,4 @@ This work is licensed on 3-clause BSD license. See LICENSE file for details.
.. _lzx: http://aminet.net/package/misc/unix/unlzx.c.readme .. _lzx: http://aminet.net/package/misc/unix/unlzx.c.readme
.. _tar: https://www.gnu.org/software/tar/ .. _tar: https://www.gnu.org/software/tar/
.. _zip: http://www.info-zip.org .. _zip: http://www.info-zip.org
.. _CheeseShop: https://pypi.python.org/pypi/fs-/fs-uae-wrapperuae-wrapper

View File

@@ -219,7 +219,11 @@ class Base(object):
changed_options[key] = abspath changed_options[key] = abspath
continue continue
changed_options[key] = os.path.abspath(val) _val = os.path.abspath(val)
if os.path.exists(_val):
changed_options[key] = _val
else:
changed_options[key] = val
self.fsuae_options.update(changed_options) self.fsuae_options.update(changed_options)
@@ -233,9 +237,9 @@ class Base(object):
return True return True
if 'wrapper_archiver' not in self.all_options: if 'wrapper_archiver' not in self.all_options:
logging.error("Configuration lacks of required " logging.warning("Configuration lacks of optional "
"`wrapper_archiver' option.") "`wrapper_archiver' option, fall back to 7z")
return False self.all_options['wrapper_archiver'] = "7z"
if not path.which(self.all_options['wrapper_archiver']): if not path.which(self.all_options['wrapper_archiver']):
logging.error("Cannot find archiver `%s'.", logging.error("Cannot find archiver `%s'.",
@@ -291,8 +295,30 @@ class ArchiveBase(Base):
validation_result = super(ArchiveBase, self)._validate_options() validation_result = super(ArchiveBase, self)._validate_options()
if 'wrapper_archive' not in self.all_options: if 'wrapper_archive' not in self.all_options:
sys.stderr.write("Configuration lacks of required " logging.warning("Configuration lacks of optional `wrapper_archive'"
"`wrapper_archive' option.\n") " option.\n")
validation_result = False wrapper_archive = self._get_wrapper_archive_name()
if wrapper_archive is None:
logging.error("Configuration lacks of optional "
"`wrapper_archive', cannot deduct the name by "
"configuration file name.\n")
validation_result = False
self.all_options['wrapper_archive'] = wrapper_archive
return validation_result return validation_result
def _get_wrapper_archive_name(self):
"""
Return full path to the archive name using configuration file
basename and appending one of the expected archive extensions.
"""
basename = os.path.splitext(self.conf_file)[0]
file_list = os.listdir('.')
for fname in file_list:
for ext in ('.7z', '.lha', '.lzx', '.zip', '.rar', '.tar', '.tgz',
'.tar.gz', '.tar.bz2', '.tar.xz'):
if ((basename + ext).lower() == fname.lower() and
basename == os.path.splitext(fname)[0]):
return fname
return None

View File

@@ -1,5 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
""" """
Simple class for executing fs-uae with specified parameters. This is a Simple class for executing fs-uae with specified parameters. This is a
failsafe class for running fs-uae. failsafe class for running fs-uae.

View File

@@ -1,14 +1,12 @@
""" """
Misc utilities Misc utilities
""" """
from distutils import spawn import configparser
import logging import logging
import os import os
import pathlib
import shutil
import subprocess import subprocess
try:
import configparser
except ImportError:
import ConfigParser as configparser
from fs_uae_wrapper import message from fs_uae_wrapper import message
from fs_uae_wrapper import file_archive from fs_uae_wrapper import file_archive
@@ -22,8 +20,8 @@ class CmdOption(dict):
def add(self, option): def add(self, option):
"""parse and add option to the dictionary""" """parse and add option to the dictionary"""
if not option.startswith('--'): if not option.startswith('--'):
raise AttributeError("Cannot add option `%s' to the dictionary" % raise AttributeError(f"Cannot add option {option} to the "
option) f"dictionary")
if '=' in option: if '=' in option:
key, val = option.split('=', 1) key, val = option.split('=', 1)
key = key[2:].strip() key = key[2:].strip()
@@ -38,15 +36,15 @@ class CmdOption(dict):
ret_list = [] ret_list = []
for key, val in self.items(): for key, val in self.items():
if val != '1': if val != '1':
ret_list.append('--%(k)s=%(v)s' % {'k': key, 'v': val}) ret_list.append(f'--{key}={val}')
else: else:
ret_list.append('--%(k)s' % {'k': key}) ret_list.append(f'--{key}')
return ret_list return ret_list
def get_config_options(conf): def get_config_options(conf):
"""Read config file and return options as a dict""" """Read config file and return options as a dict"""
parser = configparser.SafeConfigParser() parser = configparser.ConfigParser()
try: try:
parser.read(conf) parser.read(conf)
except configparser.ParsingError: except configparser.ParsingError:
@@ -90,7 +88,7 @@ def create_archive(arch_name, title='', params=None):
""" """
msg = '' msg = ''
if title: if title:
msg = "Creating archive for `%s'. Please be patient" % title msg = f"Creating archive for `{title}'. Please be patient"
return operate_archive(arch_name, 'create', msg, params) return operate_archive(arch_name, 'create', msg, params)
@@ -100,7 +98,7 @@ def extract_archive(arch_name, title='', params=None):
""" """
msg = '' msg = ''
if title: if title:
msg = "Extracting files for `%s'. Please be patient" % title msg = f"Extracting files for `{title}'. Please be patient"
return operate_archive(arch_name, 'extract', msg, params) return operate_archive(arch_name, 'extract', msg, params)
@@ -144,18 +142,20 @@ def interpolate_variables(string, config_path, base=None):
- $BASE - $BASE
""" """
_string = string
if '$CONFIG' in string: if '$CONFIG' in string:
conf_path = os.path.dirname(os.path.abspath(config_path)) conf_path = pathlib.Path(config_path).resolve().parent
string = os.path.abspath(string.replace('$CONFIG', conf_path)) string = str(pathlib.Path(string.replace('$CONFIG', str(conf_path)))
.resolve())
if '$HOME' in string: if '$HOME' in string:
string = string.replace('$HOME', os.path.expandvars('$HOME')) string = string.replace('$HOME', os.path.expandvars('$HOME'))
if '$EXE' in string: if '$EXE' in string:
string = string.replace('$EXE', spawn.find_executable('fs-uae')) string = string.replace('$EXE', shutil.which('fs-uae'))
if '$APP' in string: if '$APP' in string:
string = string.replace('$APP', spawn.find_executable('fs-uae')) string = string.replace('$APP', shutil.which('fs-uae'))
if '$DOCUMENTS' in string: if '$DOCUMENTS' in string:
xdg_docs = os.getenv('XDG_DOCUMENTS_DIR', xdg_docs = os.getenv('XDG_DOCUMENTS_DIR',
@@ -166,7 +166,9 @@ def interpolate_variables(string, config_path, base=None):
if '$BASE' in string: if '$BASE' in string:
string = string.replace('$BASE', base) string = string.replace('$BASE', base)
return string if os.path.exists(string):
return string
return _string
def get_config(conf_file): def get_config(conf_file):

View File

@@ -1,4 +1,3 @@
#!/usr/bin/env python
""" """
Wrapper for FS-UAE to perform some actions before and or after running the Wrapper for FS-UAE to perform some actions before and or after running the
emulator, if appropriate option is enabled. emulator, if appropriate option is enabled.
@@ -119,7 +118,3 @@ def run():
if not exit_code: if not exit_code:
sys.exit(4) sys.exit(4)
if __name__ == "__main__":
run()

40
pyproject.toml Normal file
View File

@@ -0,0 +1,40 @@
[build-system]
requires = ["setuptools >= 61.0"]
build-backend = "setuptools.build_meta"
[project]
name = "fs-uae-wrapper"
authors = [{name = "Roman Dobosz", email = "gryf73@gmail.com"}]
license = {text = "BSD"}
description = "Automate archives support and state saves for fs-uae"
readme = "README.rst"
requires-python = ">=3.8"
keywords = ["uae", "fs-uae", "amiga", "emulator", "wrapper"]
version = "0.9.1"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Environment :: Console",
"Intended Audience :: End Users/Desktop",
"License :: OSI Approved :: BSD License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: System :: Emulators",
"Topic :: Games/Entertainment"
]
[project.urls]
Homepage = "https://github.com/gryf/fs-uae-wrapper"
[project.scripts]
fs-uae-wrapper = "fs_uae_wrapper.wrapper:run"
[tool.setuptools]
py-modules = ["fs_uae_wrapper"]
[tool.distutils.bdist_wheel]
universal = true

View File

@@ -1,16 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Run CD32 games using fsuae
"""
from fs_uae_wrapper import wrapper
def main():
"""run wrapper"""
wrapper.run()
if __name__ == "__main__":
main()

View File

@@ -1,31 +0,0 @@
#!/usr/bin/env python
"""
Setup for the fs-uae-wrapper
"""
from setuptools import setup
setup(name='fs-uae-wrapper',
packages=['fs_uae_wrapper'],
version='0.8',
description='Automate archives and state for fs-uae',
author='Roman Dobosz',
author_email='gryf73@gmail.com',
url='https://github.com/gryf/fs-uea-wrapper',
download_url='https://github.com/gryf/pygtktalog.git',
keywords=['uae', 'fs-uae', 'amiga', 'emulator', 'wrapper'],
scripts=['script/fs-uae-wrapper'],
classifiers=['Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Development Status :: 4 - Beta',
'Environment :: Console',
'Intended Audience :: End Users/Desktop',
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Topic :: System :: Emulators',
'Topic :: Games/Entertainment'],
long_description=open('README.rst').read(),
options={'test': {'verbose': False,
'coverage': False}})

View File

@@ -47,9 +47,11 @@ class TestBase(TestCase):
bobj.clean() bobj.clean()
self.assertFalse(os.path.exists(self.dirname)) self.assertFalse(os.path.exists(self.dirname))
@mock.patch('os.path.exists')
@mock.patch('fs_uae_wrapper.utils.get_config') @mock.patch('fs_uae_wrapper.utils.get_config')
def test_normalize_options(self, get_config): def test_normalize_options(self, get_config, os_exists):
os_exists.return_value = True
bobj = base.Base('Config.fs-uae', utils.CmdOption(), {}) bobj = base.Base('Config.fs-uae', utils.CmdOption(), {})
get_config.return_value = {'kickstarts_dir': '/some/path'} get_config.return_value = {'kickstarts_dir': '/some/path'}
@@ -92,6 +94,28 @@ class TestBase(TestCase):
bobj._normalize_options() bobj._normalize_options()
self.assertDictEqual(bobj.fsuae_options, {}) self.assertDictEqual(bobj.fsuae_options, {})
@mock.patch('os.path.exists')
@mock.patch('fs_uae_wrapper.utils.get_config')
def test_normalize_options_path_not_exists(self, get_config, os_exists):
os_exists.return_value = False
bobj = base.Base('Config.fs-uae', utils.CmdOption(), {})
get_config.return_value = {'kickstarts_dir': '/some/path'}
bobj._normalize_options()
self.assertDictEqual(bobj.fsuae_options, {})
os.chdir(self.dirname)
get_config.return_value = {'fmv_rom': 'bar'}
bobj._normalize_options()
self.assertDictEqual(bobj.fsuae_options, {'fmv_rom': 'bar'})
get_config.return_value = {'floppies_dir': '../some/path'}
bobj.fsuae_options = utils.CmdOption()
bobj._normalize_options()
self.assertDictEqual(bobj.fsuae_options,
{'floppies_dir': '../some/path'})
def test_set_assets_paths(self): def test_set_assets_paths(self):
bobj = base.Base('Config.fs-uae', utils.CmdOption(), {}) bobj = base.Base('Config.fs-uae', utils.CmdOption(), {})
@@ -262,7 +286,7 @@ class TestBase(TestCase):
which.return_value = '7z' which.return_value = '7z'
bobj.all_options = {'wrapper': 'dummy', bobj.all_options = {'wrapper': 'dummy',
'wrapper_save_state': '1'} 'wrapper_save_state': '1'}
self.assertFalse(bobj._validate_options()) self.assertTrue(bobj._validate_options())
bobj.all_options = {'wrapper': 'dummy', bobj.all_options = {'wrapper': 'dummy',
'wrapper_save_state': '1', 'wrapper_save_state': '1',

View File

@@ -73,7 +73,7 @@ class TestSaveState(TestCase):
self.assertFalse(arch._validate_options()) self.assertFalse(arch._validate_options())
arch.all_options['wrapper'] = 'savestate' arch.all_options['wrapper'] = 'savestate'
self.assertFalse(arch._validate_options()) self.assertTrue(arch._validate_options())
arch.all_options['wrapper_archiver'] = 'rar' arch.all_options['wrapper_archiver'] = 'rar'
self.assertTrue(arch._validate_options()) self.assertTrue(arch._validate_options())

View File

@@ -234,11 +234,13 @@ class TestCmdOptions(TestCase):
self.assertListEqual(sorted(cmd.list()), self.assertListEqual(sorted(cmd.list()),
['--fast_memory=4096', '--fullscreen']) ['--fast_memory=4096', '--fullscreen'])
@mock.patch('os.path.exists')
@mock.patch('os.getenv') @mock.patch('os.getenv')
@mock.patch('os.path.expandvars') @mock.patch('os.path.expandvars')
@mock.patch('distutils.spawn.find_executable') @mock.patch('shutil.which')
def test_interpolate_variables(self, find_exe, expandv, getenv): def test_interpolate_variables(self, which, expandv, getenv, os_exists):
os_exists.return_value = True
itrpl = utils.interpolate_variables itrpl = utils.interpolate_variables
string = '$CONFIG/../path/to/smth' string = '$CONFIG/../path/to/smth'
@@ -250,7 +252,7 @@ class TestCmdOptions(TestCase):
'/home/user') '/home/user')
string = '$APP/$EXE' string = '$APP/$EXE'
find_exe.return_value = '/usr/bin/fs-uae' which.return_value = '/usr/bin/fs-uae'
self.assertEqual(itrpl(string, '/home/user/Config.fs-uae'), self.assertEqual(itrpl(string, '/home/user/Config.fs-uae'),
'/usr/bin/fs-uae//usr/bin/fs-uae') '/usr/bin/fs-uae//usr/bin/fs-uae')
@@ -264,3 +266,11 @@ class TestCmdOptions(TestCase):
'$BASE') '$BASE')
self.assertEqual(itrpl(string, '/home/user/Config.fs-uae', 'base'), self.assertEqual(itrpl(string, '/home/user/Config.fs-uae', 'base'),
'base') 'base')
@mock.patch('os.getenv')
@mock.patch('os.path.expandvars')
def test_interpolate_variables_path_not_exists(self, expandv, getenv):
itrpl = utils.interpolate_variables
string = '$CONFIG/../path/to/smth'
self.assertEqual(itrpl(string, '/home/user/Config.fs-uae'), string)

View File

@@ -47,10 +47,7 @@ class TestWrapper(TestCase):
fobj.write('\n') fobj.write('\n')
wrapper.run() wrapper.run()
mock_plain_run.called_once_with('Config.fs-uae', mock_plain_run.assert_called_once()
['--fullscreen',
'--fade_out_duration=0'],
[])
# This will obviously fail for nonexistent module # This will obviously fail for nonexistent module
sys.argv.append('--wrapper=dummy_wrapper') sys.argv.append('--wrapper=dummy_wrapper')

15
tox.ini
View File

@@ -1,5 +1,5 @@
[tox] [tox]
envlist = py27,py34,py27-flake8,py34-flake8 envlist = py3,py3-flake8
usedevelop = True usedevelop = True
@@ -10,16 +10,7 @@ commands = py.test --cov=fs_uae_wrapper --cov-report=term-missing
deps = -r{toxinidir}/test-requirements.txt deps = -r{toxinidir}/test-requirements.txt
[testenv:py27] [testenv:py3-flake8]
deps = {[testenv]deps} basepython = python3
mock
[testenv:py34-flake8]
basepython = python3.4
deps = flake8
commands = flake8 {posargs}
[testenv:py27-flake8]
basepython = python2.7
deps = flake8 deps = flake8
commands = flake8 {posargs} commands = flake8 {posargs}