From 4389855953cd90d47b6b7b31bf5bc2c6f3f04c93 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Mon, 20 Nov 2023 10:42:08 +0800 Subject: [PATCH] Add test coverage of new core app classes. --- core/src/toga/app.py | 16 ++++++++++++-- core/tests/app/test_app.py | 9 ++++++++ core/tests/app/test_documentapp.py | 20 +++++++++++++++++ core/tests/app/test_simpleapp.py | 29 +++++++++++++++++++++++++ core/tests/app/test_windowlessapp.py | 29 +++++++++++++++++++++++++ dummy/src/toga_dummy/app.py | 32 ++++++++++++++++++++-------- dummy/src/toga_dummy/factory.py | 4 +++- 7 files changed, 127 insertions(+), 12 deletions(-) create mode 100644 core/tests/app/test_simpleapp.py create mode 100644 core/tests/app/test_windowlessapp.py diff --git a/core/src/toga/app.py b/core/src/toga/app.py index db7e00509f..ec369f1a5a 100644 --- a/core/src/toga/app.py +++ b/core/src/toga/app.py @@ -953,7 +953,7 @@ def _create_impl(self): self.factory.WindowlessApp(interface=self) -class DocumentApp(App): +class DocumentApp(AbstractBaseApp): def __init__( self, formal_name: str | None = None, @@ -978,6 +978,19 @@ def __init__( :param document_types: Initial :any:`document_types` mapping. """ + ###################################################################### + # 2023-10: Backwards compatibility + ###################################################################### + if id is not None: + warn( + "App.id is deprecated and will be ignored. Use app_id instead", + DeprecationWarning, + stacklevel=2, + ) + ###################################################################### + # End Backwards compatibility + ###################################################################### + if document_types is None: raise ValueError("A document must manage at least one document type.") @@ -995,7 +1008,6 @@ def __init__( description=description, startup=startup, on_exit=on_exit, - id=id, ) def _create_impl(self): diff --git a/core/tests/app/test_app.py b/core/tests/app/test_app.py index deac2063f5..9544084467 100644 --- a/core/tests/app/test_app.py +++ b/core/tests/app/test_app.py @@ -236,6 +236,9 @@ def test_create( metadata_mock.assert_called_once_with(expected_app_name) + # A normal app was created. + assert_action_performed(app, "create App") + @pytest.mark.parametrize( "kwargs, exc_type, message", @@ -289,6 +292,9 @@ def test_app_metadata(monkeypatch): assert app.home_page == "https://example.com/test-app" assert app.description == "A test app" + # A normal app was created. + assert_action_performed(app, "create App") + def test_explicit_app_metadata(monkeypatch): """App metadata can be provided explicitly, overriding module-level metadata""" @@ -327,6 +333,9 @@ def test_explicit_app_metadata(monkeypatch): assert app.on_exit._raw == on_exit_handler + # A normal app was created. + assert_action_performed(app, "create App") + @pytest.mark.parametrize("construct", [True, False]) def test_icon_construction(construct): diff --git a/core/tests/app/test_documentapp.py b/core/tests/app/test_documentapp.py index f4c53af086..25a4dfddcb 100644 --- a/core/tests/app/test_documentapp.py +++ b/core/tests/app/test_documentapp.py @@ -156,3 +156,23 @@ async def _do_close(): assert not asyncio.get_event_loop().run_until_complete(_do_close()) app.exit.assert_not_called() + + +def test_deprecated_args(monkeypatch): + """Deprecated arguments to the DocumentApp constructor raise warnings.""" + monkeypatch.setattr(sys, "argv", ["app-exe"]) + + # Range is deprecated + with pytest.warns( + DeprecationWarning, + match="App.id is deprecated and will be ignored. Use app_id instead", + ): + app = toga.DocumentApp( + "Test App", + "org.beeware.document-app", + id="my-app", + document_types={"foobar": ExampleDocument}, + ) + + assert app._impl.interface == app + assert_action_performed(app, "create DocumentApp") diff --git a/core/tests/app/test_simpleapp.py b/core/tests/app/test_simpleapp.py new file mode 100644 index 0000000000..aa67766a69 --- /dev/null +++ b/core/tests/app/test_simpleapp.py @@ -0,0 +1,29 @@ +from unittest.mock import Mock + +import toga +from toga_dummy.utils import assert_action_performed + + +def test_simple_app(): + """A SimpleApp could be created""" + on_exit_handler = Mock() + + app = toga.SimpleApp( + formal_name="Test App", + app_id="org.example.test-app", + author="Jane Developer", + version="1.2.3", + home_page="https://example.com/test-app", + description="A test app", + on_exit=on_exit_handler, + ) + + assert app.author == "Jane Developer" + assert app.version == "1.2.3" + assert app.home_page == "https://example.com/test-app" + assert app.description == "A test app" + + assert app.on_exit._raw == on_exit_handler + + # A simple app was created. + assert_action_performed(app, "create Simple App") diff --git a/core/tests/app/test_windowlessapp.py b/core/tests/app/test_windowlessapp.py new file mode 100644 index 0000000000..df559ac2d0 --- /dev/null +++ b/core/tests/app/test_windowlessapp.py @@ -0,0 +1,29 @@ +from unittest.mock import Mock + +import toga +from toga_dummy.utils import assert_action_performed + + +def test_windowless_app(): + """A WindowlessApp could be created""" + on_exit_handler = Mock() + + app = toga.WindowlessApp( + formal_name="Test App", + app_id="org.example.test-app", + author="Jane Developer", + version="1.2.3", + home_page="https://example.com/test-app", + description="A test app", + on_exit=on_exit_handler, + ) + + assert app.author == "Jane Developer" + assert app.version == "1.2.3" + assert app.home_page == "https://example.com/test-app" + assert app.description == "A test app" + + assert app.on_exit._raw == on_exit_handler + + # A windowless app was created. + assert_action_performed(app, "create Windowless App") diff --git a/dummy/src/toga_dummy/app.py b/dummy/src/toga_dummy/app.py index 0f752b5e7d..3b6e05bdbf 100644 --- a/dummy/src/toga_dummy/app.py +++ b/dummy/src/toga_dummy/app.py @@ -10,7 +10,7 @@ class MainWindow(Window): pass -class App(LoggedObject): +class BaseApp(LoggedObject): def __init__(self, interface): super().__init__() self.interface = interface @@ -19,10 +19,6 @@ def __init__(self, interface): self.loop = asyncio.get_event_loop() self.create() - def create(self): - self._action("create App") - self.interface._startup() - def create_menus(self): self._action("create App menus") @@ -30,9 +26,6 @@ def main_loop(self): print("Starting app using Dummy backend.") self._action("main loop") - def set_main_window(self, window): - self._action("set_main_window", window=window) - def show_about_dialog(self): self._action("show_about_dialog") @@ -68,7 +61,28 @@ def simulate_exit(self): self.interface.on_exit() -class DocumentApp(App): +class SimpleApp(BaseApp): + def create(self): + self._action("create Simple App") + self.interface._startup() + + def set_main_window(self, window): + self._action("set_main_window", window=window) + + +class App(SimpleApp): + def create(self): + self._action("create App") + self.interface._startup() + + +class WindowlessApp(BaseApp): + def create(self): + self._action("create Windowless App") + self.interface._startup() + + +class DocumentApp(BaseApp): def create(self): self._action("create DocumentApp") self.interface._startup() diff --git a/dummy/src/toga_dummy/factory.py b/dummy/src/toga_dummy/factory.py index 07a1d84113..9a8b8f0692 100644 --- a/dummy/src/toga_dummy/factory.py +++ b/dummy/src/toga_dummy/factory.py @@ -1,5 +1,5 @@ from . import dialogs -from .app import App, DocumentApp, MainWindow +from .app import App, DocumentApp, MainWindow, SimpleApp, WindowlessApp from .command import Command from .documents import Document from .fonts import Font @@ -42,6 +42,8 @@ def not_implemented(feature): "not_implemented", "App", "DocumentApp", + "SimpleApp", + "WindowlessApp", "MainWindow", "Command", "Document",