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

14 Commits

Author SHA1 Message Date
7b0ef15eae Added dummy message class for systems with python without tk 2026-01-10 18:48:41 +01:00
59bd1b6029 Make tempfile prefixed with fs-uae-wrapper string.
Also, included test requirements into tox file, and fixed docs.
2025-09-25 18:50:28 +02:00
f5e6471555 Removed license classifier in favor of SPDX entry. 2025-04-18 16:05:37 +02:00
4c61c3d7ea Fix user provided whdload options 2024-09-14 17:00:28 +02:00
7e3d68624f Fixed packages find in pyproject 2024-09-14 15:59:25 +02:00
f311605019 Take version from git tag. 2024-09-14 11:49:44 +02:00
418e480fb5 Fixes for readme 2024-09-14 11:34:33 +02:00
118d758ec7 Trailing space 2024-09-14 10:57:50 +02:00
3b597e34ee Fix some lint errors and warnings 2024-09-14 10:53:58 +02:00
7b40974779 Fixed imports order 2024-09-14 09:22:41 +02:00
b4ab8ac4f5 Change GH action icon location 2024-09-13 21:29:54 +02:00
8d8d38d5c0 Move from travis to gh actions 2024-09-13 21:27:40 +02:00
bd0aa3dee4 Changed name for the tests workflow 2024-09-13 21:25:00 +02:00
d2a9f39fd9 Create python-app.yml 2024-09-13 21:02:58 +02:00
25 changed files with 301 additions and 134 deletions

33
.github/workflows/test.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
name: Test
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest tox coverage pytest-cov pytest-pep8
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Test with pytest
run: |
tox

View File

@@ -1,11 +0,0 @@
language: python
env:
- TOXENV=py27
- TOXENV=py27-flake8
- TOXENV=py3
- TOXENV=py3-flake8
install: pip install tox
script: tox
before_install:
- sudo apt-get update
- sudo apt-get install -y python-tk python3-tk

View File

@@ -2,8 +2,8 @@
FS-UAE Wrapper
==============
.. image:: https://travis-ci.org/gryf/fs-uae-wrapper.svg?branch=master
:target: https://travis-ci.org/gryf/fs-uae-wrapper
.. image:: https://github.com/gryf/fs-uae-wrapper/workflows/Test/badge.svg
:target: https://github.com/gryf/fs-uae-wrapper/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster
.. image:: https://img.shields.io/pypi/v/fs-uae-wrapper.svg
:target: https://pypi.python.org/pypi/fs-uae-wrapper
@@ -137,6 +137,7 @@ Currently, couple of wrapper modules are available:
- cd32
- archive
- savestate
- whdload
plain
-----
@@ -323,11 +324,13 @@ Options used:
* ``wrapper_whdload_base`` (required) path to the whdload base system. Usually
it's minimal system containing at least whdload executables in C, and config
in S. Read on below for further details.
* ``wrapper_whdload_options`` (optional) this option will replace the line in
``s:whdload-startup`` with specific ``whdload`` options for certain slave.
For reference look at WHDLoad documentation and/or on ``s:WHDLoad.prefs``.
Note, that ``Slave=`` option must not be used.
* ``wrapper_archive`` (optional) path to the whdload archive, defaults to same
name as configuration file with some detected archive extension. Note, that
name is case sensitive
* ``wrapper_archiver`` (optional) archiver to use for storage save state -
default ``7z``.
This module is solely used with whdload distributed games (not just whdload
slave files, but whole games, which can be found on several places on the
@@ -336,22 +339,74 @@ internet).
Base image
~~~~~~~~~~
To make it work, first the minimal system archive need to be prepared. There
are few dependences to be included in such small system:
To make it work, first the absolute minimal image need to contain following
structure:
.. code::
.
├── C
│   ├── DIC
│   ├── Execute
│   ├── Patcher
│   ├── RawDIC
│   ├── SetPatch
│   ├── WHDLoad
│   └── WHDLoadCD32
└── S
├── startup-sequence
└── WHDLoad.prefs
where the minimum dependences are:
- ``Excecute`` from your copy of Workbench
- `WHDLoad`_ 18.9
- `uaequit`_
- `SetPatch`_ 43.6
- ``Excecute``, ``Assign`` and whatever commands you'll be use in scripts from
your copy of Workbench
and the ``S/startup-sequence`` should at least contain:
.. code::
setpatch QUIET
IF EXISTS S:whdload-startup
Execute S:whdload-startup
EndIF
To leverage more pleasant UX, additionally those bits should be installed (or -
copied into base image filesystem):
- ``Assign`` and whatever commands you'll be use in scripts from your copy of
Workbench
- `uaequit`_ - this will allow to quit emulator, after quiting game
- `kgiconload`_ - tool for reading icon and executing *default tool* with
optionally defined tool types as parameters (in this case: WHDLoad)
- `SKick`_ optionally - for kickstart relocations. Also images of corresponding
kickstart ROM images will be needed.
and then ``s/startup-sequence`` might looks a follows:
.. code::
Assign >NIL: ENV: RAM:
Assign >NIL: T: RAM:
setpatch QUIET
IF EXISTS S:whdload-startup
Execute S:whdload-startup
EndIF
C:UAEquit
Creating base image archive
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now, the tree for the minimal image could look like that:
.. code::
.
├── C
│   ├── Assign
@@ -369,9 +424,12 @@ Now, the tree for the minimal image could look like that:
└── WHDLoad.prefs
to use relocation tables you'll need to place ``Kickstarts`` drawer into Devs
drawer, so it'll looks like this:
drawer. Also keep in mind, that corresponding kickstart rom images need to be
placed there as well, otherwise it may or may not work. Structure looks like
this:
.. code::
.
├── C
│   ├── Assign
@@ -421,7 +479,7 @@ tar with different compressions: ``tar Jcf /tmp/base.tar.xz .``, ``tar zcf
/tmp/base.tgz .``, ``tar jcf /tmp/base.tar.bz2 .``. It should work with all
mentioned at the beginning of this document archivers.
Starting point is in ``S/startup-sequence`` file, where eventually
Starting point is in ``S/startup-sequence`` file, where eventually
``S/whdload-startup`` is executed, which will be created by fs-uae-warpper
before execution by fs-uae.
@@ -449,7 +507,7 @@ And execution is as usual:
Now, similar to the archive module, it will create temporary directory, unpack
base image there, unpack WHDLoad game archive, search for slave file, and
preapre ``s:whdload-startup``, and finally pass all the configuration to
prepare ``s:whdload-startup``, and finally pass all the configuration to
fs-uae.

View File

@@ -7,8 +7,7 @@ the temporary one.
import os
import shutil
from fs_uae_wrapper import base
from fs_uae_wrapper import utils
from fs_uae_wrapper import base, utils
class Wrapper(base.ArchiveBase):

View File

@@ -4,11 +4,9 @@ Base class for all wrapper modules
import logging
import os
import shutil
import sys
import tempfile
from fs_uae_wrapper import utils
from fs_uae_wrapper import path
from fs_uae_wrapper import path, utils
class Base(object):
@@ -46,7 +44,7 @@ class Base(object):
if not self._validate_options():
return False
self.dir = tempfile.mkdtemp()
self.dir = tempfile.mkdtemp(prefix='fs-uae-wrapper-')
self._normalize_options()
self._set_assets_paths()
@@ -84,7 +82,7 @@ class Base(object):
"""execute fs-uae"""
curdir = os.path.abspath('.')
os.chdir(self.dir)
utils.run_command(['fs-uae'] + self.fsuae_options.list())
utils.run_command(['fs-uae', *self.fsuae_options.list()])
os.chdir(curdir)
return True
@@ -325,6 +323,6 @@ class ArchiveBase(Base):
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]):
basename == os.path.splitext(fname)[0]):
return fname
return None

View File

@@ -1,18 +1,18 @@
"""
File archive classes
"""
import os
import subprocess
import re
import logging
import os
import re
import subprocess
from fs_uae_wrapper import path
class Archive(object):
"""Base class for archive support"""
ADD = ['a']
EXTRACT = ['x']
ADD = ('a',)
EXTRACT = ('x',)
ARCH = 'false'
def __init__(self):
@@ -27,8 +27,8 @@ class Archive(object):
files = files if files else ['.']
logging.debug("Calling `%s %s %s %s'.", self._compress,
" ".join(self.ADD), arch_name, " ".join(files))
result = subprocess.call([self._compress] + self.ADD + [arch_name]
+ files)
result = subprocess.call([self._compress, *self.ADD, arch_name,
*files])
if result != 0:
logging.error("Unable to create archive `%s'.", arch_name)
return False
@@ -44,8 +44,7 @@ class Archive(object):
logging.debug("Calling `%s %s %s'.", self._compress,
" ".join(self.ADD), arch_name)
result = subprocess.call([self._decompress] + self.EXTRACT +
[arch_name])
result = subprocess.call([self._decompress, *self.EXTRACT, arch_name])
if result != 0:
logging.error("Unable to extract archive `%s'.", arch_name)
return False
@@ -53,16 +52,16 @@ class Archive(object):
class TarArchive(Archive):
ADD = ['cf']
EXTRACT = ['xf']
ADD = ('cf',)
EXTRACT = ('xf',)
ARCH = 'tar'
def create(self, arch_name, files=None):
files = files if files else sorted(os.listdir('.'))
logging.debug("Calling `%s %s %s %s'.", self._compress,
" ".join(self.ADD), arch_name, " ".join(files))
result = subprocess.call([self._compress] + self.ADD + [arch_name] +
files)
result = subprocess.call([self._compress, *self.ADD, arch_name,
*files])
if result != 0:
logging.error("Unable to create archive `%s'.", arch_name)
return False
@@ -70,15 +69,15 @@ class TarArchive(Archive):
class TarGzipArchive(TarArchive):
ADD = ['zcf']
ADD = ('zcf',)
class TarBzip2Archive(TarArchive):
ADD = ['jcf']
ADD = ('jcf',)
class TarXzArchive(TarArchive):
ADD = ['Jcf']
ADD = ('Jcf',)
class LhaArchive(Archive):
@@ -86,8 +85,8 @@ class LhaArchive(Archive):
class ZipArchive(Archive):
ADD = ['a', '-tzip']
ARCH = ['7z', 'zip']
ADD = ('a', '-tzip')
ARCH = ('7z', 'zip')
def __init__(self):
super(ZipArchive, self).__init__()
@@ -102,7 +101,7 @@ class SevenZArchive(Archive):
class LzxArchive(Archive):
EXTRACT = ['-x']
EXTRACT = ('-x',)
ARCH = 'unlzx'
@classmethod
@@ -113,7 +112,7 @@ class LzxArchive(Archive):
class RarArchive(Archive):
ARCH = ['rar', 'unrar']
ARCH = ('rar', 'unrar')
def create(self, arch_name, files=None):
files = files if files else sorted(os.listdir('.'))
@@ -124,8 +123,8 @@ class RarArchive(Archive):
logging.debug("Calling `%s %s %s %s'.", self._compress,
" ".join(self.ADD), arch_name, " ".join(files))
result = subprocess.call([self._compress] + self.ADD + [arch_name] +
files)
result = subprocess.call([self._compress, *self.ADD, arch_name,
*files])
if result != 0:
logging.error("Unable to create archive `%s'.", arch_name)
return False
@@ -134,7 +133,7 @@ class RarArchive(Archive):
class Archivers(object):
"""Archivers class"""
archivers = [{'arch': TarArchive, 'name': 'tar', 'ext': ['tar']},
archivers = ({'arch': TarArchive, 'name': 'tar', 'ext': ['tar']},
{'arch': TarGzipArchive, 'name': 'tgz',
'ext': ['tar.gz', 'tgz']},
{'arch': TarBzip2Archive, 'name': 'tar.bz2',
@@ -144,7 +143,7 @@ class Archivers(object):
{'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']}]
{'arch': LzxArchive, 'name': 'lzx', 'ext': ['lzx']})
@classmethod
def get(cls, extension):

View File

@@ -20,7 +20,7 @@ class MessageGui(tkinter.Tk):
# Display window without decorations
self.wm_attributes('-type', 'splash')
self.frame = ttk.Frame(self, padding=5, borderwidth=0)
self.frame = tkinter.ttk.Frame(self, padding=5, borderwidth=0)
self.frame.grid()
tkinter.ttk.Label(self.frame, text=msg, relief="ridge",
padding=10).grid()

View File

@@ -0,0 +1,18 @@
"""
Display message as simple text on console
"""
import sys
class Message:
"""Just a fake message window for systems without TK"""
def __init__(self, msg):
self.msg = msg
self._process = None
def show(self):
sys.stdout.write(self.msg + "\n")
def close(self):
return None

View File

@@ -2,8 +2,7 @@
Simple class for executing fs-uae with specified parameters. This is a
failsafe class for running fs-uae.
"""
from fs_uae_wrapper import base
from fs_uae_wrapper import utils
from fs_uae_wrapper import base, utils
class Wrapper(base.Base):
@@ -17,8 +16,8 @@ class Wrapper(base.Base):
def _run_emulator(self):
"""execute fs-uae"""
utils.run_command(['fs-uae'] + [self.conf_file] +
self.fsuae_options.list())
utils.run_command(['fs-uae', self.conf_file,
*self.fsuae_options.list()])
def clean(self):
"""Do the cleanup. Here - just do nothing"""

View File

@@ -8,8 +8,11 @@ import pathlib
import shutil
import subprocess
from fs_uae_wrapper import message
from fs_uae_wrapper import file_archive
try:
from fs_uae_wrapper.message import Message
except ModuleNotFoundError:
from fs_uae_wrapper.nogui_message import Message
class CmdOption(dict):
@@ -65,7 +68,7 @@ def operate_archive(arch_name, operation, text, params):
if archiver is None:
return False
msg = message.Message(text)
msg = Message(text)
if text:
msg.show()

View File

@@ -5,10 +5,8 @@ It will use compressed base image and compressed directories.
"""
import logging
import os
import shutil
from fs_uae_wrapper import base
from fs_uae_wrapper import utils
from fs_uae_wrapper import base, utils
class Wrapper(base.ArchiveBase):
@@ -62,7 +60,6 @@ class Wrapper(base.ArchiveBase):
"location.", base_image)
return False
title = self._get_title()
curdir = os.path.abspath('.')
os.chdir(self.dir)
result = utils.extract_archive(base_image)
@@ -83,12 +80,20 @@ class Wrapper(base.ArchiveBase):
# find slave name
slave_fname = None
slave_path = None
case_insensitvie_map = {}
# build case insensitive map of paths and find the slave file
for root, dirnames, fnames in os.walk('.'):
for dirname in dirnames:
full_path = os.path.normpath(os.path.join(root, dirname))
case_insensitvie_map[full_path.lower()] = full_path
for root, dirs, fnames in os.walk('.'):
for fname in fnames:
if fname.lower().endswith('.slave'):
full_path = os.path.normpath(os.path.join(root, fname))
case_insensitvie_map[full_path.lower()] = full_path
if not slave_fname and fname.lower().endswith('.slave'):
slave_path, slave_fname = os.path.normpath(root), fname
break
if slave_fname is None:
logging.error("Cannot find .slave file in archive.")
return False
@@ -97,8 +102,8 @@ class Wrapper(base.ArchiveBase):
icon_fname = None
for fname in os.listdir(slave_path):
if (fname.lower().endswith('.info') and
os.path.splitext(slave_fname)[0].lower() ==
os.path.splitext(fname)[0].lower()):
os.path.splitext(slave_fname)[0].lower() ==
os.path.splitext(fname)[0].lower()):
icon_fname = fname
break
if icon_fname is None:
@@ -106,10 +111,26 @@ class Wrapper(base.ArchiveBase):
"archive.", slave_fname)
return False
# Write startup file
with open("S/whdload-startup", "w") as fobj:
fobj.write(f"cd {slave_path}\n")
fobj.write(f"C:kgiconload {icon_fname}\n")
# find proper way to handle slave
# 1. check if there are user provided params
contents = f"cd {slave_path}\n"
if self.all_options.get('wrapper_whdload_options'):
contents = (f"{contents}"
f"C:whdload "
f"{self.all_options['wrapper_whdload_options']} "
f"Slave={slave_fname}\n")
else:
# no params, find if kgiconload is available
if case_insensitvie_map.get('c/kgiconload'):
contents = f"{contents}C:kgiconload {icon_fname}\n"
else:
# if not, just add common defaults
contents = (f"{contents}C:whdload Preload "
f"Slave={slave_fname}\n")
fname = os.path.join(case_insensitvie_map.get('s'), 'whdload-startup')
with open(fname, "w") as fobj:
fobj.write(contents)
os.chdir(curdir)
return True

View File

@@ -7,8 +7,7 @@ import logging
import os
import sys
from fs_uae_wrapper import utils
from fs_uae_wrapper import WRAPPER_KEY
from fs_uae_wrapper import WRAPPER_KEY, utils
def setup_logger(options):

View File

@@ -1,21 +1,20 @@
[build-system]
requires = ["setuptools >= 61.0"]
requires = ["setuptools >= 77.0", "wheel", "setuptools-git-versioning"]
build-backend = "setuptools.build_meta"
[project]
name = "fs-uae-wrapper"
authors = [{name = "Roman Dobosz", email = "gryf73@gmail.com"}]
license = {text = "BSD"}
license = "BSD-3-Clause"
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.10.0"
dynamic = ["version"]
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",
@@ -34,7 +33,18 @@ Homepage = "https://github.com/gryf/fs-uae-wrapper"
fs-uae-wrapper = "fs_uae_wrapper.wrapper:run"
[tool.setuptools]
py-modules = ["fs_uae_wrapper"]
packages = ["fs_uae_wrapper"]
[tool.distutils.bdist_wheel]
universal = true
[tool.setuptools-git-versioning]
enabled = true
[tool.ruff.lint]
select = [
"F", # pyflakes
"E", # pycodestyle
"I", # isort
"RUF", # ruff-specific rules
]

View File

@@ -1,5 +0,0 @@
pytest
pytest-cov
pytest-pep8
coverage
flake8

View File

@@ -1,11 +1,9 @@
import os
import shutil
from tempfile import mkdtemp
from unittest import TestCase
from unittest import mock
from unittest import TestCase, mock
from fs_uae_wrapper import archive
from fs_uae_wrapper import utils
from fs_uae_wrapper import archive, utils
class TestArchive(TestCase):

View File

@@ -1,12 +1,10 @@
import os
import sys
import shutil
from tempfile import mkstemp, mkdtemp
from unittest import TestCase
from unittest import mock
import sys
from tempfile import mkdtemp, mkstemp
from unittest import TestCase, mock
from fs_uae_wrapper import base
from fs_uae_wrapper import utils
from fs_uae_wrapper import base, utils
class TestBase(TestCase):

View File

@@ -1,8 +1,6 @@
from unittest import TestCase
from unittest import mock
from unittest import TestCase, mock
from fs_uae_wrapper import cd32
from fs_uae_wrapper import utils
from fs_uae_wrapper import cd32, utils
class TestCD32(TestCase):

View File

@@ -1,8 +1,7 @@
import os
import shutil
from tempfile import mkdtemp
from unittest import TestCase
from unittest import mock
from unittest import TestCase, mock
from fs_uae_wrapper import file_archive

View File

@@ -1,8 +1,8 @@
from unittest import TestCase
import os
from unittest import mock
from unittest import TestCase, mock
from fs_uae_wrapper import message
from fs_uae_wrapper import nogui_message
if os.environ.get('DISPLAY'):
import tkinter as tk
@@ -39,6 +39,19 @@ class TestMessage(TestCase):
msg._process.join.assert_called_once()
class TestNOPMessage(TestCase):
@mock.patch('sys.stdout.write')
def test_show(self, stdout_write):
msg = nogui_message.Message('display that')
msg.show()
stdout_write.assert_called_once()
def test_close(self):
msg = nogui_message.Message('display that')
self.assertIsNone(msg.close())
if os.environ.get('DISPLAY'):
# Tkinter needs graphic environment for the widgets
class TestSpawn(TestCase):

View File

@@ -1,8 +1,6 @@
from unittest import TestCase
from unittest import mock
from unittest import TestCase, mock
from fs_uae_wrapper import plain
from fs_uae_wrapper import utils
from fs_uae_wrapper import plain, utils
class TestPlainModule(TestCase):

View File

@@ -1,11 +1,9 @@
import os
import shutil
from tempfile import mkdtemp
from unittest import TestCase
from unittest import mock
from unittest import TestCase, mock
from fs_uae_wrapper import savestate
from fs_uae_wrapper import utils
from fs_uae_wrapper import savestate, utils
class TestSaveState(TestCase):

View File

@@ -1,9 +1,8 @@
import os
import sys
from tempfile import mkstemp, mkdtemp
from unittest import TestCase
import shutil
from unittest import mock
import sys
from tempfile import mkdtemp, mkstemp
from unittest import TestCase, mock
from fs_uae_wrapper import utils

View File

@@ -1,11 +1,9 @@
import os
import shutil
from tempfile import mkdtemp
from unittest import TestCase
from unittest import mock
from unittest import TestCase, mock
from fs_uae_wrapper import whdload
from fs_uae_wrapper import utils
from fs_uae_wrapper import utils, whdload
class TestWHDLoad(TestCase):
@@ -163,7 +161,7 @@ class TestWHDLoad(TestCase):
@mock.patch('os.chdir')
def test_find_slave_no_slave_file(self, chdir, walk):
walk.return_value = [(".", ('game'), ()),
('./game', (), ('foo', 'bar', 'baz'))]
('./game', (), ('foo', 'bar', 'baz'))]
wrapper = whdload.Wrapper('Config.fs-uae', utils.CmdOption(), {})
self.assertFalse(wrapper._find_slave())
@@ -173,20 +171,63 @@ class TestWHDLoad(TestCase):
def test_find_slave_no_corresponding_icon(self, chdir, walk, listdir):
contents = ('foo', 'bar', 'baz.slave')
walk.return_value = [(".", ('game'), ()),
('./game', (), contents)]
('./game', (), contents)]
listdir.return_value = contents
wrapper = whdload.Wrapper('Config.fs-uae', utils.CmdOption(), {})
self.assertFalse(wrapper._find_slave())
@mock.patch('builtins.open')
@mock.patch('os.listdir')
@mock.patch('os.walk')
@mock.patch('os.chdir')
def test_find_slave_success(self, chdir, walk, listdir, bopen):
def test_find_slave_success(self, chdir, walk, listdir):
contents = ('foo', 'bar', 'baz.slave', 'baz.info')
walk.return_value = [(".", ('game'), ()),
('./game', (), contents)]
_open = mock.mock_open()
walk.return_value = [(".", ('C', 'S', 'game'), ()),
('./C', (), ('Assign', 'kgiconload')),
('./S', (), ()),
('./game', (), contents)]
listdir.return_value = contents
wrapper = whdload.Wrapper('Config.fs-uae', utils.CmdOption(), {})
self.assertTrue(wrapper._find_slave())
bopen.assert_called_once()
with mock.patch('builtins.open', _open):
self.assertTrue(wrapper._find_slave())
handle = _open()
handle.write.assert_called_once_with('cd game\n'
'C:kgiconload baz.info\n')
@mock.patch('os.listdir')
@mock.patch('os.walk')
@mock.patch('os.chdir')
def test_find_slave_minial(self, chdir, walk, listdir):
contents = ('foo', 'bar', 'baz.slave', 'baz.info')
_open = mock.mock_open()
walk.return_value = [(".", ('C', 'S', 'game'), ()),
('./C', (), ('Assign', 'WHDLoad')),
('./S', (), ()),
('./game', (), contents)]
listdir.return_value = contents
wrapper = whdload.Wrapper('Config.fs-uae', utils.CmdOption(), {})
with mock.patch('builtins.open', _open):
self.assertTrue(wrapper._find_slave())
handle = _open()
handle.write.assert_called_once_with('cd game\nC:whdload Preload '
'Slave=baz.slave\n')
@mock.patch('os.listdir')
@mock.patch('os.walk')
@mock.patch('os.chdir')
def test_find_custom_options(self, chdir, walk, listdir):
contents = ('foo', 'bar', 'baz.slave', 'baz.info')
_open = mock.mock_open()
walk.return_value = [(".", ('C', 'S', 'game'), ()),
('./C', (), ('Assign', 'WHDLoad')),
('./S', (), ()),
('./game', (), contents)]
listdir.return_value = contents
wrapper = whdload.Wrapper('Config.fs-uae', utils.CmdOption(), {})
whdl_opts = 'Preload SplashDelay=0 MMU PAL'
wrapper.all_options['wrapper_whdload_options'] = whdl_opts
with mock.patch('builtins.open', _open):
self.assertTrue(wrapper._find_slave())
handle = _open()
handle.write.assert_called_once_with(f'cd game\nC:whdload {whdl_opts} '
'Slave=baz.slave\n')

View File

@@ -1,9 +1,8 @@
import os
import sys
from tempfile import mkstemp, mkdtemp
from unittest import TestCase
import shutil
from unittest import mock
import sys
from tempfile import mkdtemp, mkstemp
from unittest import TestCase, mock
from fs_uae_wrapper import wrapper

View File

@@ -8,7 +8,12 @@ usedevelop=True
setenv = COVERAGE_FILE = .coverage
commands = py.test --cov=fs_uae_wrapper --cov-report=term-missing
deps = -r{toxinidir}/test-requirements.txt
deps =
pytest
pytest-cov
pytest-pep8
coverage
flake8
[testenv:py3-flake8]
basepython = python3