Skip to content

Commit b0073ac

Browse files
committed
test: migrate DocInfo tests to runtime
1 parent 754ee9b commit b0073ac

3 files changed

Lines changed: 185 additions & 57 deletions

File tree

tests/runtime/_testutils/errors.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,5 +90,5 @@
9090
# TypeError("expected ..., ... found")
9191
# TypeError("expected ..., got ...")
9292
raise_unexpected_type = pytest.raises(
93-
TypeError, match=r"expected \S+, (got \S+|\S+ found)"
93+
TypeError, match=r"expected [^,]+, (got \S+|\S+ found)"
9494
)

tests/runtime/elem/test_docinfo.py

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
from __future__ import annotations
2+
3+
import pathlib
4+
import sys
5+
from types import NoneType
6+
from typing import (
7+
Any,
8+
cast,
9+
no_type_check,
10+
)
11+
12+
import pook # pyright: ignore[reportMissingTypeStubs]
13+
import pytest
14+
from hypothesis import given, settings
15+
from lxml.etree import (
16+
DTD as DTD,
17+
DocInfo as DocInfo,
18+
_Element,
19+
fromstring,
20+
parse,
21+
)
22+
23+
from .._testutils import strategy as _st
24+
from .._testutils.errors import (
25+
raise_attr_not_writable,
26+
raise_invalid_filename_type,
27+
raise_invalid_utf8_type,
28+
raise_unexpected_type,
29+
)
30+
from ..conftest import http_pool
31+
32+
if sys.version_info >= (3, 11):
33+
from typing import reveal_type
34+
else:
35+
from typing_extensions import reveal_type
36+
37+
if sys.version_info >= (3, 12):
38+
from collections.abc import Buffer
39+
else:
40+
from typing_extensions import Buffer
41+
42+
43+
class TestSource:
44+
def test_from_local_str(self, xml2_bytes_with_dtd: bytes) -> None:
45+
root = fromstring(xml2_bytes_with_dtd)
46+
docinfo = root.getroottree().docinfo
47+
reveal_type(docinfo)
48+
reveal_type(docinfo.root_name)
49+
reveal_type(docinfo.xml_version)
50+
reveal_type(docinfo.encoding)
51+
reveal_type(docinfo.standalone)
52+
reveal_type(docinfo.doctype)
53+
reveal_type(docinfo.internalDTD)
54+
reveal_type(docinfo.externalDTD)
55+
reveal_type(docinfo.public_id)
56+
reveal_type(docinfo.system_url)
57+
reveal_type(docinfo.URL)
58+
59+
def test_from_local_file(self, xml2_filepath: pathlib.Path) -> None:
60+
tree = parse(source=xml2_filepath)
61+
docinfo = tree.docinfo
62+
reveal_type(docinfo)
63+
reveal_type(docinfo.root_name)
64+
reveal_type(docinfo.xml_version)
65+
reveal_type(docinfo.encoding)
66+
reveal_type(docinfo.standalone)
67+
reveal_type(docinfo.doctype)
68+
reveal_type(docinfo.internalDTD)
69+
reveal_type(docinfo.externalDTD)
70+
reveal_type(docinfo.public_id)
71+
reveal_type(docinfo.system_url)
72+
reveal_type(docinfo.URL)
73+
74+
def test_from_remote_url(self, xml2_bytes_with_dtd: bytes) -> None:
75+
with pook.get( # pyright: ignore[reportUnknownMemberType]
76+
"https://example.com/test.xml",
77+
reply=200,
78+
response_type="xml",
79+
response_body=xml2_bytes_with_dtd,
80+
):
81+
http_response = http_pool.request("GET", "https://example.com/test.xml")
82+
tree = parse(source=http_response)
83+
docinfo = tree.docinfo
84+
reveal_type(docinfo)
85+
reveal_type(docinfo.root_name)
86+
reveal_type(docinfo.xml_version)
87+
reveal_type(docinfo.encoding)
88+
reveal_type(docinfo.standalone)
89+
reveal_type(docinfo.doctype)
90+
reveal_type(docinfo.internalDTD)
91+
reveal_type(docinfo.externalDTD)
92+
reveal_type(docinfo.public_id)
93+
reveal_type(docinfo.system_url)
94+
reveal_type(docinfo.URL)
95+
96+
97+
class TestProperties:
98+
@no_type_check
99+
def test_ro_properties(self, xml2_bytes_with_dtd: bytes) -> None:
100+
root = fromstring(xml2_bytes_with_dtd)
101+
docinfo = root.getroottree().docinfo
102+
103+
with raise_attr_not_writable:
104+
docinfo.root_name = docinfo.root_name
105+
with raise_attr_not_writable:
106+
docinfo.xml_version = docinfo.xml_version
107+
with raise_attr_not_writable:
108+
docinfo.encoding = docinfo.encoding
109+
with raise_attr_not_writable:
110+
docinfo.standalone = docinfo.standalone
111+
with raise_attr_not_writable:
112+
docinfo.doctype = docinfo.doctype
113+
with raise_attr_not_writable:
114+
docinfo.internalDTD = docinfo.internalDTD
115+
with raise_attr_not_writable:
116+
docinfo.externalDTD = docinfo.externalDTD
117+
118+
def test_rw_properties_ok(self, xml2_bytes_with_dtd: bytes) -> None:
119+
root = fromstring(xml2_bytes_with_dtd)
120+
docinfo = root.getroottree().docinfo
121+
122+
old_public_id = docinfo.public_id or "PUBLIC_ID"
123+
docinfo.public_id = None
124+
docinfo.public_id = old_public_id
125+
reveal_type(docinfo.public_id)
126+
127+
old_system_url = docinfo.system_url or "SYSTEM_URL"
128+
docinfo.system_url = None
129+
docinfo.system_url = old_system_url
130+
docinfo.system_url = old_system_url.encode()
131+
docinfo.system_url = bytearray(old_system_url.encode())
132+
reveal_type(docinfo.system_url)
133+
134+
old_URL = docinfo.URL or "URL"
135+
docinfo.URL = None
136+
docinfo.URL = old_URL
137+
docinfo.URL = old_URL.encode()
138+
reveal_type(docinfo.URL)
139+
140+
@settings(max_examples=300)
141+
@given(thing=_st.all_instances_except_of_type(str, NoneType))
142+
def test_rw_properties_bad_public_id(
143+
self,
144+
disposable_element: _Element,
145+
thing: Any,
146+
) -> None:
147+
docinfo = disposable_element.getroottree().docinfo
148+
if isinstance(thing, (bytes, Buffer)):
149+
raise_cm = pytest.raises(
150+
TypeError, match=r"string pattern on a bytes-like object"
151+
)
152+
else:
153+
raise_cm = raise_unexpected_type
154+
with raise_cm:
155+
docinfo.public_id = cast(Any, thing)
156+
157+
@settings(max_examples=300)
158+
@given(thing=_st.all_instances_except_of_type(str, bytes, Buffer, NoneType))
159+
def test_rw_properties_bad_system_url(
160+
self,
161+
disposable_element: _Element,
162+
thing: Any,
163+
) -> None:
164+
docinfo = disposable_element.getroottree().docinfo
165+
with raise_invalid_utf8_type:
166+
docinfo.system_url = thing
167+
168+
@settings(max_examples=300)
169+
@given(thing=_st.all_instances_except_of_type(str, bytes, NoneType))
170+
def test_rw_properties_bad_URL(
171+
self,
172+
disposable_element: _Element,
173+
thing: Any,
174+
) -> None:
175+
docinfo = disposable_element.getroottree().docinfo
176+
with raise_invalid_filename_type:
177+
docinfo.URL = thing
178+
179+
180+
class TestMethods:
181+
def test_clear(self, xml2_bytes_with_dtd: bytes) -> None:
182+
root = fromstring(xml2_bytes_with_dtd)
183+
docinfo = root.getroottree().docinfo
184+
reveal_type(docinfo.clear())

tests/static/test-etree.yml

Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -57,62 +57,6 @@
5757
document = etree.XML("<doc></doc>", parser=etree.XMLParser(), base_url="http://example.com/")
5858
reveal_type(document) # NR: .+ "[\w\.]+\._Element"$
5959
60-
- case: docinfo_methods
61-
main: |
62-
from lxml.etree import DocInfo
63-
d: DocInfo
64-
d.clear()
65-
66-
- case: docinfo_properties_read
67-
parametrized:
68-
- prop: root_name
69-
rt: 'builtins\.str'
70-
optional: false
71-
- prop: xml_version
72-
rt: 'builtins\.str'
73-
optional: false
74-
- prop: encoding
75-
rt: 'builtins\.str'
76-
optional: false
77-
- prop: standalone
78-
rt: 'builtins\.bool'
79-
optional: true
80-
- prop: doctype
81-
rt: 'builtins\.str'
82-
optional: false
83-
- prop: internalDTD
84-
rt: '[\w\.]+\.DTD'
85-
optional: true
86-
- prop: externalDTD
87-
rt: '[\w\.]+\.DTD'
88-
optional: true
89-
- prop: public_id
90-
rt: 'builtins\.str'
91-
optional: true
92-
- prop: system_url
93-
rt: 'builtins\.str'
94-
optional: true
95-
- prop: URL
96-
rt: 'builtins\.str'
97-
optional: true
98-
main: |
99-
from lxml.etree import DocInfo
100-
d: DocInfo
101-
reveal_type(d.{{ prop }}) # NR: .+ "{%- if optional -%}{{rt}} \| None{%- else -%}{{rt}}{%- endif -%}"
102-
103-
- case: docinfo_properties_write
104-
parametrized:
105-
- prop: public_id
106-
- prop: system_url
107-
- prop: URL
108-
main: |
109-
from lxml.etree import DocInfo
110-
d: DocInfo
111-
s: str
112-
b: bytes
113-
d.{{ prop }} = s
114-
d.{{ prop }} = None
115-
11660
- case: smartstring_properties_type
11761
parametrized:
11862
- prop: is_attribute

0 commit comments

Comments
 (0)