Skip to content

Commit

Permalink
Improve test coverage
Browse files Browse the repository at this point in the history
Also switches hooks in pyproject.toml to the
new implementation.
  • Loading branch information
ronaldoussoren committed Dec 9, 2022
1 parent 94283b6 commit b66e4e6
Show file tree
Hide file tree
Showing 7 changed files with 722 additions and 259 deletions.
12 changes: 12 additions & 0 deletions doc/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,18 @@ the code might not work on older versions due to using newish APIs.

- Unsupported extra keys in a target definition are now an error.

As a side effect of this it is now possible to specify a target without
an enclosing list, e.g.:

.. source-code:: python

setup(
app="script.py",
...
)



py2app 0.28.4
-------------

Expand Down
277 changes: 275 additions & 2 deletions py2app_tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import plistlib
import sys
import sysconfig
import textwrap
from unittest import TestCase, mock

from py2app import _config
Expand Down Expand Up @@ -42,7 +43,7 @@ class Holder:
value._global = bag
value._local = {}

with self.assertRaisesRegex(AttributeError, "first_value"):
with self.assertRaisesRegex(AttributeError, "first-value"):
value.first

with self.assertRaisesRegex(AttributeError, "second"):
Expand All @@ -69,6 +70,11 @@ def test_from_single(self):
self.assertEqual(value.destination, pathlib.Path("."))
self.assertEqual(value.sources, [root / "value"])

self.assertEqual(
repr(value),
"<Resource destination=PosixPath('.') sources=[PosixPath('etc/value')]>",
)

def test_from_item(self):
root = pathlib.Path("etc")
value = _config.Resource.from_config(
Expand Down Expand Up @@ -105,6 +111,199 @@ def test_from_invalid_value(self):
):
_config.Resource.from_config(42, root, "my_location")

def test_comparison(self):
root = pathlib.Path("etc")
v1 = _config.Resource.from_config(
["dir", ["file1", "file2"]], root, "my_location"
)
v2 = _config.Resource.from_config(
["dir", ["file1", "file2"]], root, "other_location"
)
v3 = _config.Resource.from_config(
["dir", ["file1", "file3"]], root, "other_location"
)
v4 = _config.Resource.from_config(
["dir2", ["file1", "file2"]], root, "other_location"
)

self.assertTrue(v1 == v2)
self.assertFalse(v1 != v2)
self.assertFalse(v1 == 1)
self.assertTrue(v1 != 1)

self.assertTrue(v1 != v3)
self.assertFalse(v1 == v3)

self.assertTrue(v1 != v4)
self.assertFalse(v1 == v4)


class TestBundleOptions(TestCase):
def test_repr(self):
option = _config.BundleOptions(
_config.Py2appConfiguration([], {}, _config.RecipeOptions({})),
{"script": pathlib.Path("foo"), "extension": ".app", "chdir": False},
)
self.maxDiff = None
self.assertEqual(
repr(option),
textwrap.dedent(
"""\
<BundleOptions
build_type = BuildType.STANDALONE
name = 'foo'
script = PosixPath('foo')
plugin = False
extension = '.app'
iconfile = None
resources = ()
plist = {}
extra_scripts = ()
py_include = ()
py_exclude = ()
py_full_package = ()
macho_include = ()
macho_exclude = ()
chdir = False
argv_emulator = False
argv_inject = ()
emulate_shell_environment = False
redirect_to_asl = False
macho_strip = True
macho_arch = <BuildArch.UNIVERSAL2: 'universal2'>
deployment_target = '10.9'
python_optimize = 0
python_verbose = False
python_use_pythonpath = False
python_use_sitepackages = False
python_use_faulthandler = False
>"""
),
)


class TestRecipeOptions(TestCase):
def test_repr(self):
value = _config.RecipeOptions({})
self.assertEqual(
repr(value),
textwrap.dedent(
"""\
<RecipeOptions
zip_unsafe = ()
qt_plugins = None
matplotlib_backends = None
>"""
),
)


class TestPy2appConfiguration(TestCase):
def test_repr(self):
recipes = _config.RecipeOptions({})
bundles = []
value = _config.Py2appConfiguration(bundles, {}, recipes)
bundles.append(
_config.BundleOptions(
value,
{"script": pathlib.Path("foo"), "extension": ".app", "chdir": False},
)
)
bundles.append(
_config.BundleOptions(
value,
{"script": pathlib.Path("bar"), "extension": ".app", "chdir": True},
)
)

self.assertEqual(
repr(value),
textwrap.dedent(
"""\
<Py2appConfiguration
deployment_target = '10.9'
macho_strip = True
macho_arch = <BuildArch.UNIVERSAL2: 'universal2'>
python_optimize = 0
python_verbose = False
python_use_pythonpath = False
python_use_sitepackages = False
python_use_faulthandler = False
build_type = BuildType.STANDALONE
recipes = <RecipeOptions
zip_unsafe = ()
qt_plugins = None
matplotlib_backends = None
>
bundles = [
<BundleOptions
build_type = BuildType.STANDALONE
name = 'foo'
script = PosixPath('foo')
plugin = False
extension = '.app'
iconfile = None
resources = ()
plist = {}
extra_scripts = ()
py_include = ()
py_exclude = ()
py_full_package = ()
macho_include = ()
macho_exclude = ()
chdir = False
argv_emulator = False
argv_inject = ()
emulate_shell_environment = False
redirect_to_asl = False
macho_strip = True
macho_arch = <BuildArch.UNIVERSAL2: 'universal2'>
deployment_target = '10.9'
python_optimize = 0
python_verbose = False
python_use_pythonpath = False
python_use_sitepackages = False
python_use_faulthandler = False
>,
<BundleOptions
build_type = BuildType.STANDALONE
name = 'bar'
script = PosixPath('bar')
plugin = False
extension = '.app'
iconfile = None
resources = ()
plist = {}
extra_scripts = ()
py_include = ()
py_exclude = ()
py_full_package = ()
macho_include = ()
macho_exclude = ()
chdir = True
argv_emulator = False
argv_inject = ()
emulate_shell_environment = False
redirect_to_asl = False
macho_strip = True
macho_arch = <BuildArch.UNIVERSAL2: 'universal2'>
deployment_target = '10.9'
python_optimize = 0
python_verbose = False
python_use_pythonpath = False
python_use_sitepackages = False
python_use_faulthandler = False
>,
]
>"""
),
)


class TestParsing(TestCase):
# XXX: This indirectly also tests the various option
Expand Down Expand Up @@ -595,6 +794,29 @@ def test_global_options(self):
pathlib.Path("."),
)

with self.subTest("invalid python subkey"):
with self.assertRaisesRegex(
_config.ConfigurationError,
"invalid key 'tool.py2app.python.invalid'",
):
_config.parse_pyproject(
{
"tool": {
"py2app": {
"python": {
"invalid": "off",
},
"bundle": {
"main": {
"script": "main.py",
}
},
}
}
},
pathlib.Path("."),
)

for subkey, attribute in [
("verbose", "python_verbose"),
("use-pythonpath", "python_use_pythonpath"),
Expand Down Expand Up @@ -1182,6 +1404,34 @@ def test_bundle_options(self):
self.assertEqual(config.bundles[0].plist, {"key": "value"})
mock_open.assert_called_once_with(pathlib.Path("./data/Info.plist"), "rb")

with self.subTest("plist (invalid, path to existing file)"):
data = b"this is not valid"
stream = io.BytesIO(data)

with self.assertRaisesRegex(
_config.ConfigurationError,
"'tool.py2app.bundle.test.plist' invalid plist file",
):
with mock.patch(
"py2app._config.open", return_value=stream
) as mock_open:
_config.parse_pyproject(
{
"tool": {
"py2app": {
"bundle": {
"test": {
"script": "scriptmod.py",
"plist": "data/Info.plist",
}
},
}
}
},
pathlib.Path("."),
)
mock_open.assert_called_once_with(pathlib.Path("./data/Info.plist"), "rb")

with self.subTest("plist (invalid value type)"):
with self.assertRaisesRegex(
_config.ConfigurationError,
Expand Down Expand Up @@ -1405,7 +1655,7 @@ def test_bundle_options_inherited(self):

self.assertEqual(config.bundles[0].deployment_target, osrelease)
self.assertEqual(config.bundles[0].macho_strip, True)
self.assertEqual(config.bundles[0].macho_arch, config._BuildArch(cpuarch))
self.assertEqual(config.bundles[0].macho_arch, _config.BuildArch(cpuarch))
self.assertEqual(config.bundles[0].python_optimize, sys.flags.optimize)
self.assertEqual(config.bundles[0].python_verbose, bool(sys.flags.verbose))
self.assertEqual(config.bundles[0].python_use_pythonpath, False)
Expand Down Expand Up @@ -1792,6 +2042,29 @@ def test_bundle_options_inherited(self):
pathlib.Path("."),
)

with self.subTest("unknown python key"):
with self.assertRaisesRegex(
_config.ConfigurationError,
"invalid key: 'tool.py2app.bundle.main.python.unknown'",
):
_config.parse_pyproject(
{
"tool": {
"py2app": {
"bundle": {
"main": {
"script": "main.py",
"python": {
"unknown": "off",
},
}
},
}
}
},
pathlib.Path("."),
)

with self.subTest("invalid key"):
with self.assertRaisesRegex(
_config.ConfigurationError, "invalid key 'tool.py2app.bundle.main.foo'"
Expand Down
Loading

0 comments on commit b66e4e6

Please sign in to comment.