# mypy: allow-untyped-defs import builtins import io import logging import os import pickle import platform from unittest.mock import MagicMock, patch from typing import Generator, Tuple import pytest import localpaths # type: ignore from . import serve from .serve import ( ConfigBuilder, Test262WindowHandler, Test262WindowTestHandler, Test262WindowModuleHandler, Test262WindowModuleTestHandler, Test262StrictWindowHandler, Test262StrictWindowTestHandler, Test262StrictHandler, inject_script) logger = logging.getLogger() @pytest.mark.skipif(platform.uname()[0] == "Windows", reason="Expected contents are platform-dependent") def test_make_hosts_file_nix(): with ConfigBuilder(logger, ports={"http": [8000]}, browser_host="foo.bar", alternate_hosts={"alt": "foo2.bar"}, subdomains={"a", "b"}, not_subdomains={"x, y"}) as c: hosts = serve.make_hosts_file(c, "192.168.42.42") lines = hosts.split("\n") assert lines == [ "# Start web-platform-tests hosts", "192.168.42.42\tfoo.bar", "192.168.42.42\ta.foo.bar", "192.168.42.42\tb.foo.bar", "192.168.42.42\tfoo2.bar", "192.168.42.42\ta.foo2.bar", "192.168.42.42\tb.foo2.bar", "# End web-platform-tests hosts", "", ] @pytest.mark.skipif(platform.uname()[0] != "Windows", reason="Expected contents are platform-dependent") def test_make_hosts_file_windows(): with ConfigBuilder(logger, ports={"http": [8000]}, browser_host="foo.bar", alternate_hosts={"alt": "foo2.bar"}, subdomains={"a", "b"}, not_subdomains={"x", "y"}) as c: hosts = serve.make_hosts_file(c, "192.168.42.42") lines = hosts.split("\n") assert lines == [ "# Start web-platform-tests hosts", "192.168.42.42\tfoo.bar", "192.168.42.42\ta.foo.bar", "192.168.42.42\tb.foo.bar", "192.168.42.42\tfoo2.bar", "192.168.42.42\ta.foo2.bar", "192.168.42.42\tb.foo2.bar", "0.0.0.0\tx.foo.bar", "0.0.0.0\ty.foo.bar", "0.0.0.0\tx.foo2.bar", "0.0.0.0\ty.foo2.bar", "# End web-platform-tests hosts", "", ] def test_ws_doc_root_default(): with ConfigBuilder(logger) as c: assert c.doc_root == localpaths.repo_root assert c.ws_doc_root == os.path.join(localpaths.repo_root, "websockets", "handlers") assert c.paths["ws_doc_root"] == c.ws_doc_root def test_init_ws_doc_root(): with ConfigBuilder(logger, ws_doc_root="/") as c: assert c.doc_root == localpaths.repo_root # check this hasn't changed assert c.ws_doc_root == "/" assert c.paths["ws_doc_root"] == c.ws_doc_root def test_set_ws_doc_root(): cb = ConfigBuilder(logger) cb.ws_doc_root = "/" with cb as c: assert c.doc_root == localpaths.repo_root # check this hasn't changed assert c.ws_doc_root == "/" assert c.paths["ws_doc_root"] == c.ws_doc_root def test_pickle(): # Ensure that the config object can be pickled with ConfigBuilder(logger) as c: pickle.dumps(c) def test_alternate_host_unspecified(): ConfigBuilder(logger, browser_host="web-platform.test") @pytest.mark.parametrize("primary, alternate", [ ("web-platform.test", "web-platform.test"), ("a.web-platform.test", "web-platform.test"), ("web-platform.test", "a.web-platform.test"), ("a.web-platform.test", "a.web-platform.test"), ]) def test_alternate_host_invalid(primary, alternate): with pytest.raises(ValueError): ConfigBuilder(logger, browser_host=primary, alternate_hosts={"alt": alternate}) @pytest.mark.parametrize("primary, alternate", [ ("web-platform.test", "not-web-platform.test"), ("a.web-platform.test", "b.web-platform.test"), ("web-platform-tests.dev", "web-platform-tests.live"), ]) def test_alternate_host_valid(primary, alternate): ConfigBuilder(logger, browser_host=primary, alternate_hosts={"alt": alternate}) # A token marking the location of expected script injection. INJECT_SCRIPT_MARKER = b"" def test_inject_script_after_head(): html = b""" """ assert INJECT_SCRIPT_MARKER in html assert inject_script(html.replace(INJECT_SCRIPT_MARKER, b""), INJECT_SCRIPT_MARKER) == html def test_inject_script_no_html_head(): html = b"""
""" assert INJECT_SCRIPT_MARKER in html assert inject_script(html.replace(INJECT_SCRIPT_MARKER, b""), INJECT_SCRIPT_MARKER) == html def test_inject_script_no_doctype(): html = b"""
""" assert INJECT_SCRIPT_MARKER in html assert inject_script(html.replace(INJECT_SCRIPT_MARKER, b""), INJECT_SCRIPT_MARKER) == html def test_inject_script_parse_error(): html = b"""
""" assert INJECT_SCRIPT_MARKER in html # On a parse error, the script should not be injected and the original content should be # returned. assert INJECT_SCRIPT_MARKER not in inject_script(html.replace(INJECT_SCRIPT_MARKER, b""), INJECT_SCRIPT_MARKER) @pytest.fixture def handler_setup() -> Generator[Tuple[str, str], None, None]: """Provides a mocked filesystem environment for testing any handler class.""" tests_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "tests", "testdata")) url_base = "/" mock_file_contents = { os.path.normpath(os.path.join(tests_root, "test262", "basic.js")): """/*---\ndescription: A basic test includes: [assert.js, sta.js] ---*/ assert.sameValue(1, 1); """, os.path.normpath(os.path.join(tests_root, "test262", "negative.js")): """/*---\ndescription: A negative test negative: phase: runtime type: TypeError ---*/ throw new TypeError(); """, os.path.normpath(os.path.join(tests_root, "test262", "module.js")): """/*---\ndescription: A module test flags: [module] ---*/ import {} from 'some-module'; """, os.path.normpath(os.path.join(tests_root, "test262", "teststrict.js")): """/*---\ndescription: A strict mode test flags: [onlyStrict] includes: [propertyHelper.js] ---*/ console.log('hello'); """ } # Store original functions to be called if our mock doesn't handle the file original_open = builtins.open original_exists = os.path.exists original_isdir = os.path.isdir def custom_open(file, mode='r', *args, **kwargs): normalized_file = os.path.normpath(file) if normalized_file in mock_file_contents: if 'b' in mode: return io.BytesIO(mock_file_contents[normalized_file].encode('utf-8')) else: return io.StringIO(mock_file_contents[normalized_file]) return original_open(file, mode, *args, **kwargs) def custom_exists(path): normalized_path = os.path.normpath(path) return normalized_path in mock_file_contents or original_exists(path) def custom_isdir(path): normalized_path = os.path.normpath(path) expected_dir = os.path.normpath(os.path.join(tests_root, "test262")) return normalized_path == expected_dir or original_isdir(path) with patch('builtins.open', side_effect=custom_open), \ patch('os.path.exists', side_effect=custom_exists), \ patch('os.path.isdir', side_effect=custom_isdir): yield tests_root, url_base def _create_mock_request(path: str) -> MagicMock: mock_request = MagicMock() mock_request.url_parts.path = path mock_request.url_parts.query = "" return mock_request # Ensure pytest doesn't consider Test-prefixed classes to be testcases Test262WindowHandler.__test__ = False # type: ignore[attr-defined] Test262WindowTestHandler.__test__ = False # type: ignore[attr-defined] Test262WindowModuleHandler.__test__ = False # type: ignore[attr-defined] Test262WindowModuleTestHandler.__test__ = False # type: ignore[attr-defined] Test262StrictWindowHandler.__test__ = False # type: ignore[attr-defined] Test262StrictWindowTestHandler.__test__ = False # type: ignore[attr-defined] Test262StrictHandler.__test__ = False # type: ignore[attr-defined] @pytest.mark.parametrize("handler_cls, expected", [ (Test262WindowHandler, [(".test262.html", ".js", ".test262-test.html")]), (Test262WindowTestHandler, [(".test262-test.html", ".js")]), (Test262WindowModuleHandler, [(".test262-module.html", ".js", ".test262-module-test.html")]), (Test262WindowModuleTestHandler, [(".test262-module-test.html", ".js")]), (Test262StrictWindowHandler, [(".test262.strict.html", ".js", ".test262-test.strict.html")]), (Test262StrictWindowTestHandler, [(".test262-test.strict.html", ".js", ".test262.strict.js")]), ]) def test_path_replace(handler_setup, handler_cls, expected): """Verifies that handlers correctly map request paths to internal resources.""" root, url_base = handler_setup handler = handler_cls(base_path=root, url_base=url_base) assert handler.path_replace == expected @pytest.mark.parametrize("handler_cls, request_path, expected_metadata", [ ( Test262WindowTestHandler, "/test262/basic.test262-test.html", [('script', '/third_party/test262/harness/assert.js'), ('script', '/third_party/test262/harness/sta.js')] ), ( Test262WindowTestHandler, "/test262/negative.test262-test.html", [('negative', 'TypeError')] ), ( Test262StrictWindowTestHandler, "/test262/teststrict.test262-test.strict.html", [('script', '/third_party/test262/harness/propertyHelper.js')] ), ]) def test_get_metadata(handler_setup, handler_cls, request_path, expected_metadata): """Verifies metadata extraction logic for any handler.""" root, url_base = handler_setup handler = handler_cls(root, url_base) mock_request = _create_mock_request(request_path) metadata = list(handler._get_metadata(mock_request)) for item in expected_metadata: assert item in metadata assert len(expected_metadata) == len(metadata) @pytest.mark.parametrize("handler_cls, request_path, expected_substrings", [ # Test262WindowHandler: Should contain the iframe pointing to the test ( Test262WindowHandler, "/test262/basic.test262.html", [''] ), # Test262WindowTestHandler: Should contain script tags ( Test262WindowTestHandler, "/test262/basic.test262-test.html", ['', '', ''] ), # Test262WindowModuleTestHandler: Should contain module import ( Test262WindowModuleTestHandler, "/test262/module.test262-module-test.html", ['"] ), # Strict HTML Case: points to the .strict.js variant ( Test262StrictWindowTestHandler, "/test262/teststrict.test262-test.strict.html", ['src="/test262/teststrict.test262.strict.js"'] ), # Strict JS Case: The handler that serves the actual script ( Test262StrictHandler, "/test262/teststrict.test262.strict.js", ['"use strict";', "console.log('hello');"] ), ]) def test_wrapper_content(handler_setup, handler_cls, request_path, expected_substrings): """Verifies generated HTML/JS content for any handler.""" root, url_base = handler_setup handler = handler_cls(base_path=root, url_base=url_base) mock_request = _create_mock_request(request_path) mock_response = MagicMock() handler.handle_request(mock_request, mock_response) content = mock_response.content for item in expected_substrings: assert item in content