Skip to content

Commit

Permalink
test: lxml.ElementInclude added to existing XInclude tests
Browse files Browse the repository at this point in the history
  • Loading branch information
abelcheung committed Apr 2, 2024
1 parent 7c435a1 commit 64ca3ba
Showing 1 changed file with 109 additions and 4 deletions.
113 changes: 109 additions & 4 deletions test-rt/test_xinclude.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
from __future__ import annotations

import copy
from inspect import Parameter, _ParameterKind, signature
from io import StringIO
from typing import Any, cast
from pathlib import Path
from typing import Any, Literal, cast, overload

import _testutils
import lxml.ElementInclude as EI
import pytest

# import pytest
from lxml.etree import (
XInclude,
_Element as _Element,
_Element,
_ElementTree as _ElementTree,
_ListErrorLog as _ListErrorLog,
fromstring,
parse,
)

reveal_type = getattr(_testutils, "reveal_type_wrapper")
Expand Down Expand Up @@ -55,3 +58,105 @@ def test_xinclude_as_func(self, xinc_sample_data: str) -> None:
result = xinc(elem)
reveal_type(elem)
reveal_type(result)


@overload
def good_loader(
href: str, mode: Literal["xml"], encoding: str | None = None
) -> _Element: ...
@overload
def good_loader(
href: str, mode: Literal["text"], encoding: str | None = None
) -> str: ...
def good_loader(href: str, mode: str, encoding: str | None = None) -> Any:
# Over simplified version of _lxml_default_loader without network
if mode == "xml":
return parse(href).getroot()
else:
return Path(href).read_text()


def bad_loader_1(href: str, mode: str, encoding: str | None = None) -> str:
return href


def bad_loader_2(href: str) -> str:
return href


def bad_loader_3(href: str, mode: str, _) -> _Element:
return parse(href).getroot()


class TestElementInclude:
# fmt: off
param_data = [
('elem' , _ParameterKind.POSITIONAL_OR_KEYWORD, Parameter.empty),
('loader' , _ParameterKind.POSITIONAL_OR_KEYWORD, None ),
('base_url' , _ParameterKind.POSITIONAL_OR_KEYWORD, None ),
('max_depth', _ParameterKind.POSITIONAL_OR_KEYWORD, 6 ),
]
# fmt: on

def test_func_sig(self, xinc_sample_data: str) -> None:
sig = signature(EI.include)
param = list(sig.parameters.values())
for i in range(len(param)):
assert (
param[i].name,
param[i].kind,
param[i].default,
) == self.param_data[i]

elem = fromstring(xinc_sample_data)
result = EI.include(elem)
reveal_type(result)

def test_input_type(self, xinc_sample_data: str) -> None:
elem = fromstring(xinc_sample_data)
EI.include(elem)
del elem

sio = StringIO(xinc_sample_data)
tree = parse(sio)
EI.include(tree)
del tree

with pytest.raises(AttributeError, match="no attribute 'getroottree'"):
EI.include(cast(Any, xinc_sample_data))

with pytest.raises(AttributeError, match="no attribute 'getroottree'"):
EI.include(cast(Any, sio))

sio.close()

def test_loader(self, xinc_sample_data: str) -> None:
elem = fromstring(xinc_sample_data)

temp_el = copy.copy(elem)
EI.include(temp_el, good_loader)
del temp_el

# It's actually ok to ignore 3rd param in XML mode
temp_el = copy.copy(elem)
EI.include(temp_el, cast(Any, bad_loader_3))
del temp_el

temp_el = copy.copy(elem)
with pytest.raises(AttributeError, match="no attribute 'getroottree'"):
EI.include(temp_el, cast(Any, bad_loader_1))
del temp_el

temp_el = copy.copy(elem)
with pytest.raises(
TypeError, match="takes 1 positional argument but 3 were given"
):
EI.include(temp_el, cast(Any, bad_loader_2))
del temp_el

temp_el = copy.copy(elem)
# Coerce loader into text mode, this is REALLY artificial though
temp_el[1].attrib['parse'] = 'text'
with pytest.raises(TypeError, match="can only concatenate str"):
EI.include(temp_el, cast(Any, bad_loader_3))
del temp_el

0 comments on commit 64ca3ba

Please sign in to comment.