File: test_splash.py

package info (click to toggle)
pyinstaller 6.18.0%2Bds-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 11,824 kB
  • sloc: python: 41,828; ansic: 12,123; makefile: 171; sh: 131; xml: 19
file content (146 lines) | stat: -rw-r--r-- 5,561 bytes parent folder | download | duplicates (3)
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
#-----------------------------------------------------------------------------
# Copyright (c) 2005-2023, PyInstaller Development Team.
#
# Distributed under the terms of the GNU General Public License (version 2
# or later) with exception for distributing the bootloader.
#
# The full license is in the file COPYING.txt, distributed with this software.
#
# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception)
#-----------------------------------------------------------------------------
"""
Tests for splash screen.

NOTE: splash screen is not supported on macOS due to incompatible design.
"""

import pytest

from PyInstaller.compat import is_darwin, is_musl
from PyInstaller.utils.tests import importorskip

pytestmark = [
    importorskip('tkinter'),
    pytest.mark.skipif(is_darwin, reason="Splash screen is not supported on macOS."),
    pytest.mark.xfail(is_musl, reason="musl + tkinter is known to cause mysterious segfaults."),
]


# Test that splash screen is successfully started. This is an "interactive"
# test (see test_interactive.py), where we expect the program to run for
# specified amount of time, before we terminate it.
@pytest.mark.parametrize("build_mode", ['onedir', 'onefile'])
@pytest.mark.parametrize("with_tkinter", [False, True], ids=['notkinter', 'tkinter'])
def test_splash_screen_running(pyi_builder_spec, capfd, monkeypatch, build_mode, with_tkinter):
    if build_mode == 'onefile':
        monkeypatch.setenv('_TEST_SPLASH_BUILD_MODE', 'onefile')
    if with_tkinter:
        monkeypatch.setenv('_TEST_SPLASH_WITH_TKINTER', '1')

    pyi_builder_spec.test_spec(
        'spec_with_splash.spec',
        runtime=10,  # Interactive test - terminate test program after 10 seconds.
    )

    out, err = capfd.readouterr()
    assert 'SPLASH: splash screen started' in err, \
        f"Cannot find log entry indicating start of splash screen in:\n{err}"


# Check that splash-enabled program properly exits (e.g., there are no crashes in bootloader during shutdown).
# This is not coveved by the `test_splash_screen_running`, because that one terminates the program.
# There are three variants of this test:
# - splash screen is kept running until the end
# - user imports pyi_splash, which calls pyi_splash.close() via atexit()
# - user imports pyi_splash and calls pyi_splash.close()
def test_splash_screen_shutdown_auto(pyi_builder, script_dir):
    splash_image = script_dir.parent / 'data' / 'splash' / 'image.png'
    pyi_builder.test_source(
        """
        print("Done!")
        """,
        pyi_args=["--splash", str(splash_image)],
    )


def test_splash_screen_shutdown_atexit(pyi_builder, script_dir):
    splash_image = script_dir.parent / 'data' / 'splash' / 'image.png'
    pyi_builder.test_source(
        """
        # Importing pyi_splash registers pyi_splash.close() call via atexit().
        print("Importing pyi_splash...")
        import pyi_splash

        print("Done!")
        """,
        pyi_args=["--splash", str(splash_image)],
    )


def test_splash_screen_shutdown_manual(pyi_builder, script_dir):
    splash_image = script_dir.parent / 'data' / 'splash' / 'image.png'
    pyi_builder.test_source(
        """
        print("Importing pyi_splash...")
        import pyi_splash

        print("Closing splash screen from program...")
        pyi_splash.close()

        print("Done!")
        """,
        pyi_args=["--splash", str(splash_image)],
    )


# Check that splash screen is gracefully disabled in subprocesses spawned via sys.executable
def test_pyi_splash_in_subprocess(pyi_builder, script_dir):
    splash_image = script_dir.parent / 'data' / 'splash' / 'image.png'
    pyi_builder.test_script(
        "pyi_splash_in_subprocess.py",
        pyi_args=["--splash", str(splash_image)],
    )


# Check that splash screen is gracefully disabled via PYINSTALLER_SUPPRESS_SPLASH_SCREEN environment variable.
# The test procedure is adapted from pyi_splash_in_subprocess.py script of `test_pyi_splash_in_subprocess`.
def test_pyi_splash_suppress(pyi_builder, script_dir, monkeypatch):
    monkeypatch.setenv("PYINSTALLER_SUPPRESS_SPLASH_SCREEN", "1")
    splash_image = script_dir.parent / 'data' / 'splash' / 'image.png'
    pyi_builder.test_source(
        """
        import time

        # The pyi_splash module must be importable
        print("Importing pyi_splash...")
        import pyi_splash

        # Check module's guts to validate its state. Not for public use...

        # Module must be marked as initialized, regardless of whether splash screen is active or suppressed.
        assert pyi_splash._initialized, "Module is not marked as initialized!"

        # IPC port must be zero
        assert pyi_splash._ipc_port == 0, f"Unexpected IPC port value: {pyi_splash._ipc_port}"

        # Connection must be left closed
        assert pyi_splash._ipc_socket_closed, \
            "Unexpected splash screen socket state - expected it to be closed, but it is open!"

        # Test of public API

        # is_alive() should return false
        assert not pyi_splash.is_alive(), "Unexpected splash screen status!"

        # update_text() should be a no-op. Most importantly, it should not raise an error.
        pyi_splash.update_text("Updated text")
        time.sleep(1)

        # Same goes for close().
        pyi_splash.close()

        # After close, splash screen should be (still) inactive
        assert not pyi_splash.is_alive(), "Splash screen is not inactive!"
        """,
        pyi_args=["--splash", str(splash_image)],
    )