|
| 1 | +from __future__ import absolute_import, division, unicode_literals |
| 2 | + |
| 3 | +from types import ModuleType |
| 4 | +import xml.etree.ElementTree as ElementTree |
| 5 | + |
| 6 | +import pytest |
| 7 | + |
| 8 | +from html5lib import HTMLParser, getTreeBuilder |
| 9 | +from html5lib._utils import moduleFactoryFactory |
| 10 | + |
| 11 | + |
| 12 | +def _module_factory(): |
| 13 | + def factory(backend, *args, **kwargs): |
| 14 | + return {"backend": backend, "arguments": args, "options": kwargs} |
| 15 | + |
| 16 | + return moduleFactoryFactory(factory) |
| 17 | + |
| 18 | + |
| 19 | +@pytest.mark.parametrize("args_a, options_a, args_b, options_b", [ |
| 20 | + (("first",), {}, ("second",), {}), |
| 21 | + ((), {"enabled": False}, (), {"enabled": True}), |
| 22 | + (("first",), {"enabled": False}, ("first",), {"enabled": True}), |
| 23 | + (("first",), {"enabled": False}, ("second",), {"enabled": False}), |
| 24 | +], ids=["positional", "keyword", "shared-arguments", "shared-options"]) |
| 25 | +def test_module_factory_reuses_each_configuration(args_a, options_a, args_b, options_b): |
| 26 | + backend = ModuleType(str("factory_backend")) |
| 27 | + build = _module_factory() |
| 28 | + |
| 29 | + first = build(backend, *args_a, **options_a) |
| 30 | + second = build(backend, *args_b, **options_b) |
| 31 | + first_again = build(backend, *args_a, **options_a) |
| 32 | + second_again = build(backend, *args_b, **options_b) |
| 33 | + |
| 34 | + assert first.backend is backend |
| 35 | + assert second.backend is backend |
| 36 | + assert first.arguments == args_a |
| 37 | + assert second.arguments == args_b |
| 38 | + assert first.options == options_a |
| 39 | + assert second.options == options_b |
| 40 | + assert first_again.arguments == args_a |
| 41 | + assert first_again.options == options_a |
| 42 | + assert second_again.arguments == args_b |
| 43 | + assert second_again.options == options_b |
| 44 | + assert first is not second |
| 45 | + assert first_again is first |
| 46 | + assert second_again is second |
| 47 | + |
| 48 | + |
| 49 | +def test_module_factory_keeps_distinct_backends_cached(): |
| 50 | + backend_a = ModuleType(str("factory_backend_a")) |
| 51 | + backend_b = ModuleType(str("factory_backend_b")) |
| 52 | + build = _module_factory() |
| 53 | + |
| 54 | + first = build(backend_a, enabled=True) |
| 55 | + second = build(backend_b, enabled=True) |
| 56 | + |
| 57 | + assert first.backend is backend_a |
| 58 | + assert second.backend is backend_b |
| 59 | + assert first is not second |
| 60 | + assert build(backend_a, enabled=True) is first |
| 61 | + assert build(backend_b, enabled=True) is second |
| 62 | + |
| 63 | + |
| 64 | +@pytest.mark.parametrize("full_tree", [False, True]) |
| 65 | +def test_etree_builder_identity_survives_alternating_options(full_tree): |
| 66 | + first = getTreeBuilder("etree", ElementTree, fullTree=full_tree) |
| 67 | + first_parser = HTMLParser(tree=first, namespaceHTMLElements=False) |
| 68 | + second = getTreeBuilder("etree", ElementTree, fullTree=not full_tree) |
| 69 | + second_parser = HTMLParser(tree=second, namespaceHTMLElements=False) |
| 70 | + first_again = getTreeBuilder("etree", ElementTree, fullTree=full_tree) |
| 71 | + second_again = getTreeBuilder("etree", ElementTree, fullTree=not full_tree) |
| 72 | + |
| 73 | + assert first.implementation is ElementTree |
| 74 | + assert second.implementation is ElementTree |
| 75 | + assert first is not second |
| 76 | + assert first_again is first |
| 77 | + assert second_again is second |
| 78 | + assert isinstance(first_parser.tree, first_again) |
| 79 | + assert isinstance(second_parser.tree, second_again) |
| 80 | + |
| 81 | + # Parsing is an existing-behavior control, not the cache regression itself. |
| 82 | + parsers = [(first_parser, full_tree), (second_parser, not full_tree)] |
| 83 | + for parser, includes_document in parsers: |
| 84 | + document = parser.parse("<p>content</p>") |
| 85 | + root = document.find("html") if includes_document else document |
| 86 | + assert root.tag == "html" |
| 87 | + assert root.find("body/p").text == "content" |
0 commit comments