Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from sys import stderr
from typing import Optional, Any

_VALID_PACKAGE_NAME = re.compile(r"^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*$")
_VALID_PACKAGE_NAME = re.compile(r"^[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*$", re.ASCII)


class PackageManager:
Expand Down
8 changes: 4 additions & 4 deletions je_load_density/utils/project/template/template_keyword.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"user_count": 50, "spawn_rate": 10, "test_time": 5,
**{
"tasks": {
"get": {"request_url": "http://httpbin.org/get"},
"post": {"request_url": "http://httpbin.org/post"}
"get": {"request_url": "https://httpbin.org/get"},
"post": {"request_url": "https://httpbin.org/post"}
}
}
}]
Expand All @@ -21,8 +21,8 @@
"user_count": 50, "spawn_rate": 10, "test_time": 5,
**{
"tasks": {
"get": {"request_url": "http://httpbin.org/get"},
"post": {"request_url": "http://httpbin.org/post"}
"get": {"request_url": "https://httpbin.org/get"},
"post": {"request_url": "https://httpbin.org/post"}
}
}
}]
Expand Down
114 changes: 66 additions & 48 deletions je_load_density/utils/xml/change_xml_structure/change_xml_structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,27 @@
from xml.etree import ElementTree as _ElementTreeBuilder # nosec B405 - construction only, no parsing # nosemgrep: python.lang.security.use-defused-xml.use-defused-xml


def _collapse_singleton_lists(grouped: Dict[str, list]) -> Dict[str, Any]:
return {key: value[0] if len(value) == 1 else value for key, value in grouped.items()}


def _children_to_dict(children: list) -> Dict[str, Any]:
grouped: Dict[str, list] = defaultdict(list)
for child_dict in map(elements_tree_to_dict, children):
for key, value in child_dict.items():
grouped[key].append(value)
return _collapse_singleton_lists(grouped)


def _attach_text(elements_dict: Dict[str, Any], tag: str, text: str, has_children_or_attrs: bool) -> None:
if not text:
return
if has_children_or_attrs:
elements_dict[tag]["#text"] = text
else:
elements_dict[tag] = text


def elements_tree_to_dict(elements_tree: _ElementTreeBuilder.Element) -> Dict[str, Any]:
"""
將 XML ElementTree 轉換為字典
Expand All @@ -11,38 +32,57 @@ def elements_tree_to_dict(elements_tree: _ElementTreeBuilder.Element) -> Dict[st
:param elements_tree: XML ElementTree 元素 (XML ElementTree element)
:return: 對應的字典結構 (Dictionary representation)
"""
elements_dict: Dict[str, Any] = {elements_tree.tag: {} if elements_tree.attrib else None}
tag = elements_tree.tag
has_attrs = bool(elements_tree.attrib)
elements_dict: Dict[str, Any] = {tag: {} if has_attrs else None}
children = list(elements_tree)

# 遞迴處理子節點 (Recursively process children)
if children:
default_dict = defaultdict(list)
for dc in map(elements_tree_to_dict, children):
for key, value in dc.items():
default_dict[key].append(value)
elements_dict[elements_tree.tag] = {
key: value[0] if len(value) == 1 else value
for key, value in default_dict.items()
}

# 加入屬性 (Add attributes)
if elements_tree.attrib:
elements_dict[elements_tree.tag].update(
{f"@{key}": value for key, value in elements_tree.attrib.items()}
)

# 加入文字內容 (Add text content)
elements_dict[tag] = _children_to_dict(children)

if has_attrs:
elements_dict[tag].update({f"@{key}": value for key, value in elements_tree.attrib.items()})

if elements_tree.text:
text = elements_tree.text.strip()
if children or elements_tree.attrib:
if text:
elements_dict[elements_tree.tag]["#text"] = text
else:
elements_dict[elements_tree.tag] = text
_attach_text(elements_dict, tag, elements_tree.text.strip(), bool(children) or has_attrs)

return elements_dict


def _set_text_node(root: _ElementTreeBuilder.Element, key: str, value: Any) -> None:
if key != "#text" or not isinstance(value, str):
raise TypeError(f"Invalid text node: {key} -> {value}")
root.text = value


def _set_attribute(root: _ElementTreeBuilder.Element, key: str, value: Any) -> None:
if not isinstance(value, str):
raise TypeError(f"Invalid attribute value: {key} -> {value}")
root.set(key[1:], value)


def _build_element(value: Any, root: _ElementTreeBuilder.Element) -> None:
if isinstance(value, str):
root.text = value
elif isinstance(value, dict):
_build_from_dict(value, root)
else:
raise TypeError(f"Invalid type in dict_to_elements_tree: {type(value)}")


def _build_from_dict(mapping: Dict[str, Any], root: _ElementTreeBuilder.Element) -> None:
for key, value in mapping.items():
if key.startswith("#"):
_set_text_node(root, key, value)
elif key.startswith("@"):
_set_attribute(root, key, value)
elif isinstance(value, list):
for element in value:
_build_element(element, _ElementTreeBuilder.SubElement(root, key))
else:
_build_element(value, _ElementTreeBuilder.SubElement(root, key))


def dict_to_elements_tree(json_dict: Dict[str, Any]) -> str:
"""
將字典轉換為 XML 字串
Expand All @@ -51,32 +91,10 @@ def dict_to_elements_tree(json_dict: Dict[str, Any]) -> str:
:param json_dict: JSON 格式字典 (Dictionary in JSON-like format)
:return: XML 字串 (XML string)
"""

def _to_elements_tree(json_dict: Any, root: _ElementTreeBuilder.Element) -> None:
if isinstance(json_dict, str):
root.text = json_dict
elif isinstance(json_dict, dict):
for key, value in json_dict.items():
if key.startswith("#"): # 處理文字節點
if key != "#text" or not isinstance(value, str):
raise TypeError(f"Invalid text node: {key} -> {value}")
root.text = value
elif key.startswith("@"): # 處理屬性
if not isinstance(value, str):
raise TypeError(f"Invalid attribute value: {key} -> {value}")
root.set(key[1:], value)
elif isinstance(value, list): # 處理子節點清單
for element in value:
_to_elements_tree(element, _ElementTreeBuilder.SubElement(root, key))
else: # 處理單一子節點
_to_elements_tree(value, _ElementTreeBuilder.SubElement(root, key))
else:
raise TypeError(f"Invalid type in dict_to_elements_tree: {type(json_dict)}")

if not isinstance(json_dict, dict) or len(json_dict) != 1:
raise ValueError("Input must be a dictionary with a single root element")

tag, body = next(iter(json_dict.items()))
node = _ElementTreeBuilder.Element(tag)
_to_elements_tree(body, node)
return _ElementTreeBuilder.tostring(node, encoding="utf-8").decode("utf-8")
_build_element(body, node)
return _ElementTreeBuilder.tostring(node, encoding="utf-8").decode("utf-8")
2 changes: 1 addition & 1 deletion test/test_callback_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def _dummy_trigger(**kwargs):


def _dummy_callback(*args, **kwargs):
pass
"""No-op stub used to verify the executor invokes the callback path."""


class TestCallbackFunctionExecutor:
Expand Down
8 changes: 4 additions & 4 deletions test/test_proxy_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ def test_init_defaults(self):

def test_configure(self):
user = ProxyHTTPUser()
detail = {"user": "http_user", "host": "http://localhost"}
detail = {"user": "http_user", "host": "https://localhost"}
tasks = {
"get": {"request_url": "http://example.com/get"},
"post": {"request_url": "http://example.com/post"},
"get": {"request_url": "https://example.com/get"},
"post": {"request_url": "https://example.com/post"},
}
user.configure(detail, tasks)
assert user.user_detail_dict == detail
Expand All @@ -40,7 +40,7 @@ def test_init_defaults(self):
def test_configure(self):
user = ProxyFastHTTPUser()
detail = {"user": "fast_http_user"}
tasks = {"get": {"request_url": "http://example.com"}}
tasks = {"get": {"request_url": "https://example.com"}}
user.configure(detail, tasks)
assert user.user_detail_dict == detail
assert user.tasks == tasks
Expand Down
6 changes: 3 additions & 3 deletions test/test_report_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

_SUCCESS_RECORD = {
"Method": "GET",
"test_url": "http://example.com/get",
"test_url": "https://example.com/get",
"name": "/get",
"status_code": "200",
"text": "OK",
Expand All @@ -25,7 +25,7 @@

_FAILURE_RECORD = {
"Method": "POST",
"test_url": "http://example.com/post",
"test_url": "https://example.com/post",
"name": "/post",
"status_code": "500",
"error": "Internal Server Error",
Expand Down Expand Up @@ -111,7 +111,7 @@ def test_no_data_raises(self):

def test_success_xml(self):
test_record_instance.test_record_list.append(_SUCCESS_RECORD)
success_xml, failure_xml = generate_xml()
success_xml, _ = generate_xml()
assert "<Method>GET</Method>" in success_xml
assert "<xml_data" in success_xml

Expand Down
4 changes: 2 additions & 2 deletions test/test_xml_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def test_dict_to_xml_structure(self):
"xml_data": {
"Success_Test1": {
"Method": "GET",
"test_url": "http://example.com",
"test_url": "https://example.com",
"name": "test",
"status_code": "200",
"text": "OK",
Expand All @@ -117,4 +117,4 @@ def test_dict_to_xml_structure(self):
}
xml_str = dict_to_elements_tree(data)
assert "<Method>GET</Method>" in xml_str
assert "<test_url>http://example.com</test_url>" in xml_str
assert "<test_url>https://example.com</test_url>" in xml_str
Loading