81 lines
2.8 KiB
Python
81 lines
2.8 KiB
Python
import os
|
|
import sys
|
|
from unittest.mock import MagicMock
|
|
|
|
import pytest
|
|
|
|
import matplotlib.backends.backend_webagg_core
|
|
from matplotlib.backends.backend_webagg_core import (
|
|
FigureCanvasWebAggCore, NavigationToolbar2WebAgg,
|
|
)
|
|
from matplotlib.testing import subprocess_run_for_testing
|
|
|
|
|
|
@pytest.mark.parametrize("backend", ["webagg", "nbagg"])
|
|
def test_webagg_fallback(backend):
|
|
pytest.importorskip("tornado")
|
|
if backend == "nbagg":
|
|
pytest.importorskip("IPython")
|
|
env = dict(os.environ)
|
|
if sys.platform != "win32":
|
|
env["DISPLAY"] = ""
|
|
|
|
env["MPLBACKEND"] = backend
|
|
|
|
test_code = (
|
|
"import os;"
|
|
+ f"assert os.environ['MPLBACKEND'] == '{backend}';"
|
|
+ "import matplotlib.pyplot as plt; "
|
|
+ "print(plt.get_backend());"
|
|
f"assert '{backend}' == plt.get_backend().lower();"
|
|
)
|
|
subprocess_run_for_testing([sys.executable, "-c", test_code], env=env, check=True)
|
|
|
|
|
|
def test_webagg_core_no_toolbar():
|
|
fm = matplotlib.backends.backend_webagg_core.FigureManagerWebAgg
|
|
assert fm._toolbar2_class is None
|
|
|
|
|
|
def test_toolbar_button_dispatch_allowlist():
|
|
"""Only declared toolbar items should be dispatched."""
|
|
fig = MagicMock()
|
|
canvas = FigureCanvasWebAggCore(fig)
|
|
canvas.toolbar = MagicMock(spec=NavigationToolbar2WebAgg)
|
|
canvas.toolbar.toolitems = NavigationToolbar2WebAgg.toolitems
|
|
|
|
# Valid toolbar action should be dispatched.
|
|
canvas.handle_toolbar_button({'name': 'home'})
|
|
canvas.toolbar.home.assert_called_once()
|
|
|
|
# Invalid names should be silently ignored.
|
|
canvas.toolbar.reset_mock()
|
|
canvas.handle_toolbar_button({'name': '__init__'})
|
|
canvas.handle_toolbar_button({'name': 'not_a_real_button'})
|
|
# No methods should have been called.
|
|
assert canvas.toolbar.method_calls == []
|
|
|
|
|
|
@pytest.mark.parametrize("host, origin, allowed", [
|
|
("localhost:8988", "http://localhost:8988", True),
|
|
("localhost:8988", "http://evil.com", False),
|
|
("localhost:8988", "http://127.0.0.1:8988", False),
|
|
("localhost:8988", "http://[::1]:8988", False),
|
|
("127.0.0.1:8988", "http://127.0.0.1:8988", True),
|
|
("127.0.0.1:8988", "http://localhost:8988", False),
|
|
("127.0.0.1:8988", "http://[::1]:8988", False),
|
|
("[::1]:8988", "http://[::1]:8988", True),
|
|
("[::1]:8988", "http://[::2]:8988", False),
|
|
("[::1]:8988", "http://localhost:8988", False),
|
|
("[::1]:8988", "http://evil.com", False),
|
|
])
|
|
def test_websocket_rejects_cross_origin(host, origin, allowed):
|
|
"""Verify Tornado's default check_origin rejects cross-origin requests."""
|
|
pytest.importorskip("tornado")
|
|
from matplotlib.backends.backend_webagg import WebAggApplication
|
|
|
|
ws = WebAggApplication.WebSocket.__new__(WebAggApplication.WebSocket)
|
|
ws.request = MagicMock()
|
|
ws.request.headers = {"Host": host}
|
|
assert ws.check_origin(origin) is allowed
|