File: test_app.py

package info (click to toggle)
mu-editor 1.0.2%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 9,048 kB
  • sloc: python: 16,322; makefile: 129; xml: 29; sh: 11
file content (159 lines) | stat: -rw-r--r-- 5,541 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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# -*- coding: utf-8 -*-
"""
Tests for the app script.
"""
import sys
import os.path
from unittest import mock
from mu.app import excepthook, run, setup_logging, debug, setup_modes
from mu.logic import LOG_FILE, LOG_DIR, DEBUGGER_PORT, ENCODING
from mu.interface.themes import NIGHT_STYLE, DAY_STYLE, CONTRAST_STYLE


def test_setup_logging():
    """
    Ensure that logging is set up in some way.
    """
    with mock.patch('mu.app.TimedRotatingFileHandler') as log_conf, \
            mock.patch('mu.app.os.path.exists', return_value=False),\
            mock.patch('mu.app.logging') as logging, \
            mock.patch('mu.app.os.makedirs', return_value=None) as mkdir:
        setup_logging()
        mkdir.assert_called_once_with(LOG_DIR)
        log_conf.assert_called_once_with(LOG_FILE, when='midnight',
                                         backupCount=5, delay=0,
                                         encoding=ENCODING)
        logging.getLogger.assert_called_once_with()
        assert sys.excepthook == excepthook


def test_setup_modes_with_pgzero():
    """
    If pgzero is installed, allow Pygame Zero mode.
    """
    with mock.patch('mu.app.pkgutil.iter_modules', return_value=['pgzero', ]):
        mock_editor = mock.MagicMock()
        mock_view = mock.MagicMock()
        modes = setup_modes(mock_editor, mock_view)
        assert 'pygamezero' in modes


def test_setup_modes_without_pgzero():
    """
    If pgzero is NOT installed, do not add Pygame Zero mode to the list of
    available modes.
    """
    with mock.patch('mu.app.pkgutil.iter_modules', return_value=['foo', ]):
        mock_editor = mock.MagicMock()
        mock_view = mock.MagicMock()
        modes = setup_modes(mock_editor, mock_view)
        assert 'pygamezero' not in modes


def test_run():
    """
    Ensure the run function sets things up in the expected way.

    Why check this?

    We need to know if something fundamental has inadvertently changed and
    these tests highlight such a case.

    Testing the call_count and mock_calls allows us to measure the expected
    number of instantiations and method calls.
    """
    class DumSig:
        def __init__(self):
            @self.connect
            def default(*args):
                raise Exception('No signal handler connected')

        def connect(self, func):
            self.func = func
            return func

        def emit(self, *args):
            self.func(*args)

    class Win(mock.MagicMock):
        load_theme = DumSig()
        icon = 'icon'

    window = Win()

    with mock.patch('mu.app.setup_logging') as set_log, \
            mock.patch('mu.app.QApplication') as qa, \
            mock.patch('mu.app.QSplashScreen') as qsp, \
            mock.patch('mu.app.Editor') as ed, \
            mock.patch('mu.app.load_pixmap'), \
            mock.patch('mu.app.Window', window) as win, \
            mock.patch('mu.app.QTimer') as timer, \
            mock.patch('sys.argv', ['mu']), \
            mock.patch('sys.exit') as ex:
        run()
        assert set_log.call_count == 1
        # foo.call_count is instantiating the class
        assert qa.call_count == 1
        # foo.mock_calls are method calls on the object
        assert len(qa.mock_calls) == 8
        assert qsp.call_count == 1
        assert len(qsp.mock_calls) == 2
        assert timer.call_count == 1
        assert len(timer.mock_calls) == 4
        assert ed.call_count == 1
        assert len(ed.mock_calls) == 3
        assert win.call_count == 1
        assert len(win.mock_calls) == 6
        assert ex.call_count == 1
        window.load_theme.emit('day')
        qa.assert_has_calls([mock.call().setStyleSheet(DAY_STYLE)])
        window.load_theme.emit('night')
        qa.assert_has_calls([mock.call().setStyleSheet(NIGHT_STYLE)])
        window.load_theme.emit('contrast')
        qa.assert_has_calls([mock.call().setStyleSheet(CONTRAST_STYLE)])


def test_excepthook():
    """
    Test that custom excepthook logs error and calls sys.exit.
    """
    ex = Exception('BANG')
    exc_args = (type(ex), ex, ex.__traceback__)

    with mock.patch('mu.app.logging.error') as error, \
            mock.patch('mu.app.sys.exit') as exit:
        excepthook(*exc_args)
        error.assert_called_once_with('Unrecoverable error', exc_info=exc_args)
        exit.assert_called_once_with(1)


def test_debug():
    """
    Ensure the debugger is run with the expected arguments given the filename
    and other arguments passed in via sys.argv.
    """
    mock_sys = mock.MagicMock()
    mock_sys.argv = [None, 'foo.py', 'foo', 'bar', 'baz']
    mock_runner = mock.MagicMock()
    with mock.patch('mu.app.sys', mock_sys), \
            mock.patch('mu.app.run_debugger', mock_runner):
        debug()
    expected_filename = os.path.normcase(os.path.abspath('foo.py'))
    mock_runner.assert_called_once_with('localhost', DEBUGGER_PORT,
                                        expected_filename,
                                        ['foo', 'bar', 'baz', ])


def test_debug_no_args():
    """
    If the debugger is accidentally started with no filename and/or associated
    args, then emit a friendly message to indicate the problem.
    """
    mock_sys = mock.MagicMock()
    mock_sys.argv = [None, ]
    mock_print = mock.MagicMock()
    with mock.patch('mu.app.sys', mock_sys), \
            mock.patch('builtins.print', mock_print):
        debug()
    msg = "Debugger requires a Python script filename to run."
    mock_print.assert_called_once_with(msg)