diff --git a/python/servo/devtools_tests.py b/python/servo/devtools_tests.py index 159bd21c3ba..d1281ead688 100644 --- a/python/servo/devtools_tests.py +++ b/python/servo/devtools_tests.py @@ -25,14 +25,16 @@ import socketserver import subprocess import time from threading import Thread -from typing import Any, Optional +from typing import Any, Iterable, Optional, TypeVar import unittest +from collections import Counter + # Set this to true to log requests in the internal web servers. LOG_REQUESTS = False -@dataclass(frozen=True) +@dataclass(frozen=True, order=True) class Source: introduction_type: str url: str @@ -113,6 +115,26 @@ class Devtools: self.exited = True +# TODO: Use new syntax in python 3.12 +# +# +T = TypeVar("T") +FrozenMultiset = tuple[tuple[T, int], ...] + + +def frozen_multiset(items: Iterable[T] = []) -> FrozenMultiset[T]: + """ + Simulate a frozen multiset using a tuple of tuples. + Python does not have one yet: + + + """ + # First make a mutable multiset + result = Counter(items) + # then convert it to a tuple with a stable order + return tuple(sorted(result.items())) + + class DevtoolsTests(unittest.IsolatedAsyncioTestCase): # /path/to/servo/python/servo script_path = None @@ -147,9 +169,9 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): def test_sources_list(self): self.run_servoshell(url=f"{self.base_urls[0]}/sources/test.html") self.assert_sources_list( - set( + Counter( [ - tuple( + frozen_multiset( [ Source("srcScript", f"{self.base_urls[0]}/sources/classic.js"), Source("inlineScript", f"{self.base_urls[0]}/sources/test.html"), @@ -158,51 +180,57 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): Source("importedModule", f"{self.base_urls[0]}/sources/module.js"), ] ), - tuple([Source("Worker", f"{self.base_urls[0]}/sources/classic_worker.js")]), + frozen_multiset([Source("Worker", f"{self.base_urls[0]}/sources/classic_worker.js")]), ] ), ) def test_sources_list_with_data_no_scripts(self): self.run_servoshell(url="data:text/html,") - self.assert_sources_list(set([tuple()])) + self.assert_sources_list(Counter([frozen_multiset()])) # Sources list for `introductionType` = `inlineScript` and `srcScript` def test_sources_list_with_data_empty_inline_classic_script(self): self.run_servoshell(url="data:text/html,") - self.assert_sources_list(set([tuple()])) + self.assert_sources_list(Counter([frozen_multiset()])) def test_sources_list_with_data_inline_classic_script(self): self.run_servoshell(url="data:text/html,") - self.assert_sources_list(set([tuple([Source("inlineScript", "data:text/html,")])])) + self.assert_sources_list( + Counter([frozen_multiset([Source("inlineScript", "data:text/html,")])]) + ) def test_sources_list_with_data_external_classic_script(self): self.run_servoshell(url=f'data:text/html,') - self.assert_sources_list(set([tuple([Source("srcScript", f"{self.base_urls[0]}/sources/classic.js")])])) + self.assert_sources_list( + Counter([frozen_multiset([Source("srcScript", f"{self.base_urls[0]}/sources/classic.js")])]) + ) def test_sources_list_with_data_empty_inline_module_script(self): self.run_servoshell(url="data:text/html,") - self.assert_sources_list(set([tuple()])) + self.assert_sources_list(Counter([frozen_multiset()])) def test_sources_list_with_data_inline_module_script(self): self.run_servoshell(url="data:text/html,") self.assert_sources_list( - set([tuple([Source("inlineScript", "data:text/html,")])]) + Counter([frozen_multiset([Source("inlineScript", "data:text/html,")])]) ) def test_sources_list_with_data_external_module_script(self): self.run_servoshell(url=f"{self.base_urls[0]}/sources/test_sources_list_with_data_external_module_script.html") - self.assert_sources_list(set([tuple([Source("srcScript", f"{self.base_urls[0]}/sources/module.js")])])) + self.assert_sources_list( + Counter([frozen_multiset([Source("srcScript", f"{self.base_urls[0]}/sources/module.js")])]) + ) # Sources list for `introductionType` = `importedModule` def test_sources_list_with_static_import_module(self): self.run_servoshell(url=f"{self.base_urls[0]}/sources/test_sources_list_with_static_import_module.html") self.assert_sources_list( - set( + Counter( [ - tuple( + frozen_multiset( [ Source( "inlineScript", @@ -218,9 +246,9 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): def test_sources_list_with_dynamic_import_module(self): self.run_servoshell(url=f"{self.base_urls[0]}/sources/test_sources_list_with_dynamic_import_module.html") self.assert_sources_list( - set( + Counter( [ - tuple( + frozen_multiset( [ Source( "inlineScript", @@ -238,9 +266,9 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): def test_sources_list_with_classic_worker(self): self.run_servoshell(url=f"{self.base_urls[0]}/sources/test_sources_list_with_classic_worker.html") self.assert_sources_list( - set( + Counter( [ - tuple( + frozen_multiset( [ Source( "inlineScript", @@ -248,7 +276,7 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): ), ] ), - tuple( + frozen_multiset( [ Source("Worker", f"{self.base_urls[0]}/sources/classic_worker.js"), ] @@ -260,16 +288,16 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): def test_sources_list_with_module_worker(self): self.run_servoshell(url=f"{self.base_urls[0]}/sources/test_sources_list_with_module_worker.html") self.assert_sources_list( - set( + Counter( [ - tuple( + frozen_multiset( [ Source( "inlineScript", f"{self.base_urls[0]}/sources/test_sources_list_with_module_worker.html" ), ] ), - tuple( + frozen_multiset( [ Source("Worker", f"{self.base_urls[0]}/sources/module_worker.js"), ] @@ -285,9 +313,9 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): url='data:text/html,' ) self.assert_sources_list( - set( + Counter( [ - tuple( + frozen_multiset( [ Source( "inlineScript", @@ -303,9 +331,9 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): def test_sources_list_with_injected_script_write_but_no_display_url(self): self.run_servoshell(url='data:text/html,') self.assert_sources_list( - set( + Counter( [ - tuple( + frozen_multiset( [ Source( "inlineScript", @@ -321,9 +349,9 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): script = 's=document.createElement("script");s.append("//%23 sourceURL=http://test");document.body.append(s)' self.run_servoshell(url=f"data:text/html,") self.assert_sources_list( - set( + Counter( [ - tuple( + frozen_multiset( [ Source( "inlineScript", @@ -340,9 +368,9 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): script = 's=document.createElement("script");s.append("1");document.body.append(s)' self.run_servoshell(url=f"data:text/html,") self.assert_sources_list( - set( + Counter( [ - tuple( + frozen_multiset( [ Source( "inlineScript", @@ -357,9 +385,9 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): def test_sources_list_with_eval_and_display_url(self): self.run_servoshell(url='data:text/html,') self.assert_sources_list( - set( + Counter( [ - tuple( + frozen_multiset( [ Source( "inlineScript", 'data:text/html,' @@ -373,7 +401,9 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): def test_sources_list_with_eval_but_no_display_url(self): self.run_servoshell(url='data:text/html,') - self.assert_sources_list(set([tuple([Source("inlineScript", 'data:text/html,')])])) + self.assert_sources_list( + Counter([frozen_multiset([Source("inlineScript", 'data:text/html,')])]) + ) def test_sources_list_with_debugger_eval_and_display_url(self): self.run_servoshell(url="data:text/html,") @@ -389,7 +419,9 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): ) console.evaluate_js_async("//# sourceURL=http://test") evaluation_result.result(1) - self.assert_sources_list(set([tuple([Source("debugger eval", "http://test/")])]), devtools=devtools) + self.assert_sources_list( + Counter([frozen_multiset([Source("debugger eval", "http://test/")])]), devtools=devtools + ) def test_sources_list_with_debugger_eval_but_no_display_url(self): self.run_servoshell(url="data:text/html,") @@ -405,14 +437,14 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): ) console.evaluate_js_async("1") evaluation_result.result(1) - self.assert_sources_list(set([tuple([])]), devtools=devtools) + self.assert_sources_list(Counter([frozen_multiset([])]), devtools=devtools) def test_sources_list_with_function_and_display_url(self): self.run_servoshell(url='data:text/html,') self.assert_sources_list( - set( + Counter( [ - tuple( + frozen_multiset( [ Source( "inlineScript", @@ -428,9 +460,9 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): def test_sources_list_with_function_but_no_display_url(self): self.run_servoshell(url='data:text/html,') self.assert_sources_list( - set( + Counter( [ - tuple( + frozen_multiset( [ Source("inlineScript", 'data:text/html,'), ] @@ -445,9 +477,9 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): url='data:text/html,' ) self.assert_sources_list( - set( + Counter( [ - tuple( + frozen_multiset( [ Source( "inlineScript", @@ -462,15 +494,15 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): def test_sources_list_with_javascript_url_but_no_display_url(self): self.run_servoshell(url='data:text/html,') - self.assert_sources_list(set([tuple([])])) + self.assert_sources_list(Counter([frozen_multiset([])])) @unittest.expectedFailure def test_sources_list_with_event_handler_and_display_url(self): self.run_servoshell(url='data:text/html,') self.assert_sources_list( - set( + Counter( [ - tuple( + frozen_multiset( [ Source("eventHandler", "http://test/"), ] @@ -481,15 +513,15 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): def test_sources_list_with_event_handler_but_no_display_url(self): self.run_servoshell(url='data:text/html,') - self.assert_sources_list(set([tuple([])])) + self.assert_sources_list(Counter([frozen_multiset([])])) @unittest.expectedFailure def test_sources_list_with_dom_timer_and_display_url(self): self.run_servoshell(url='data:text/html,') self.assert_sources_list( - set( + Counter( [ - tuple( + frozen_multiset( [ Source("domTimer", "http://test/"), ] @@ -501,16 +533,16 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): @unittest.expectedFailure def test_sources_list_with_dom_timer_but_no_display_url(self): self.run_servoshell(url='data:text/html,') - self.assert_sources_list(set([tuple([])])) + self.assert_sources_list(Counter([frozen_multiset([])])) # Sources list for scripts with `displayURL` (`//# sourceURL`), despite not being required by `introductionType` def test_sources_list_with_inline_script_and_display_url(self): self.run_servoshell(url="data:text/html,") self.assert_sources_list( - set( + Counter( [ - tuple( + frozen_multiset( [ Source("inlineScript", "http://test/"), ] @@ -523,9 +555,9 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): def test_sources_list_with_inline_script_but_invalid_display_url(self): self.run_servoshell(url="data:text/html,") self.assert_sources_list( - set( + Counter( [ - tuple( + frozen_multiset( [ Source("inlineScript", "data:text/html,"), ] @@ -537,9 +569,9 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): def test_sources_list_with_inline_script_but_no_display_url(self): self.run_servoshell(url="data:text/html,") self.assert_sources_list( - set( + Counter( [ - tuple( + frozen_multiset( [ Source("inlineScript", "data:text/html,"), ] @@ -554,9 +586,9 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): def test_sources_list_with_iframe_srcdoc_and_display_url(self): self.run_servoshell(url='data:text/html,