File: test_app.py

package info (click to toggle)
app-model 0.5.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 700 kB
  • sloc: python: 5,484; makefile: 4
file content (134 lines) | stat: -rw-r--r-- 4,646 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
from __future__ import annotations

import os
import sys
from typing import TYPE_CHECKING

import pytest

from app_model import Application
from app_model.expressions import Context
from app_model.types import Action
from app_model.types._menu_rule import MenuRule

if TYPE_CHECKING:
    from conftest import FullApp


def test_app_create() -> None:
    assert Application.get_app("my_app") is None
    app = Application("my_app")
    assert Application.get_app("my_app") is app

    # NOTE: for some strange reason, this test fails if I move this line
    # below the error assertion below... I don't know why.
    assert Application.get_or_create("my_app") is app

    with pytest.raises(ValueError, match="Application 'my_app' already exists"):
        Application("my_app")

    assert repr(app) == "Application('my_app')"
    Application.destroy("my_app")


def test_app(full_app: FullApp) -> None:
    app = full_app

    app.commands.execute_command(app.Commands.OPEN)
    app.mocks.open.assert_called_once()
    app.commands.execute_command(app.Commands.COPY)
    app.mocks.copy.assert_called_once()
    app.commands.execute_command(app.Commands.PASTE)
    app.mocks.paste.assert_called_once()


def test_sorting(full_app: FullApp) -> None:
    groups = list(full_app.menus.iter_menu_groups(full_app.Menus.EDIT))
    assert len(groups) == 3
    [_g0, g1, g2] = groups
    assert all(i.group == "1_undo_redo" for i in g1)
    assert all(i.group == "2_copy_paste" for i in g2)

    assert [i.command.title for i in g1] == ["Undo", "Redo"]
    assert [i.command.title for i in g2] == ["Copy", "Paste"]


def test_action_import_by_string(full_app: FullApp) -> None:
    """the REDO command is declared as a string in the conftest.py file

    This tests that it can be lazily imported at callback runtime and executed
    """
    assert "fake_module" not in sys.modules
    assert full_app.commands.execute_command(full_app.Commands.REDO).result()
    assert "fake_module" in sys.modules
    full_app.mocks.redo.assert_called_once()

    # tests what happens when the module cannot be found
    with pytest.raises(
        ModuleNotFoundError, match="Command 'unimportable' was not importable"
    ):
        full_app.commands.execute_command(full_app.Commands.UNIMPORTABLE)
    # the second time we try within a session, nothing should happen
    full_app.commands.execute_command(full_app.Commands.UNIMPORTABLE)

    # tests what happens when the object is not callable cannot be found
    with pytest.raises(
        TypeError,
        match=r"Command 'not\.callable' did not resolve to a callble object",
    ):
        full_app.commands.execute_command(full_app.Commands.NOT_CALLABLE)
    # the second time we try within a session, nothing should happen
    full_app.commands.execute_command(full_app.Commands.NOT_CALLABLE)


def test_action_raises_exception(full_app: FullApp) -> None:
    result = full_app.commands.execute_command(full_app.Commands.RAISES)
    with pytest.raises(ValueError):
        result.result()

    # the function that raised the exception is `_raise_an_error` in conftest.py
    assert str(result.exception()) == "This is an error"

    assert not full_app.raise_synchronous_exceptions
    full_app.raise_synchronous_exceptions = True
    assert full_app.raise_synchronous_exceptions

    with pytest.raises(ValueError):
        full_app.commands.execute_command(full_app.Commands.RAISES)


def test_app_context() -> None:
    app = Application("app1")
    assert isinstance(app.context, Context)
    Application.destroy("app1")
    assert app.context["is_windows"] == (os.name == "nt")
    assert "is_mac" in app.context
    assert "is_linux" in app.context

    app = Application("app2", context={"a": 1})
    assert isinstance(app.context, Context)
    assert app.context["a"] == 1
    Application.destroy("app2")

    app = Application("app3", context=Context({"a": 1}))
    assert isinstance(app.context, Context)
    assert app.context["a"] == 1
    Application.destroy("app3")

    with pytest.raises(TypeError, match="context must be a Context or MutableMapping"):
        Application("app4", context=1)  # type: ignore[arg-type]


def test_register_actions() -> None:
    app = Application("app5")
    actions = app.registered_actions
    assert not actions
    dispose = app.register_action(
        "my_action", title="My Action", callback=lambda: None, menus=["Window"]
    )
    assert "my_action" in actions
    assert isinstance(action := actions["my_action"], Action)
    assert action.menus == [MenuRule(id="Window")]
    dispose()
    assert "my_action" not in actions
    assert not actions