Translate Types and Utilities parity tests
Some checks failed
Rust API gates / api-gates (push) Has been cancelled
Some checks failed
Rust API gates / api-gates (push) Has been cancelled
This commit is contained in:
@@ -70,7 +70,7 @@ PARITY_MARKER_RE = re.compile(
|
||||
re.MULTILINE,
|
||||
)
|
||||
RUST_TEST_RE = re.compile(r"(?:#\[[^\]]+\]\s*)*fn\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(", re.MULTILINE)
|
||||
EXPECTED_TESTS = 1295
|
||||
EXPECTED_TESTS = 1289
|
||||
PARITY_FILES = (
|
||||
Path("tests/compat/tests/generated_parity.rs"),
|
||||
Path("tests/PARITY.md"),
|
||||
@@ -106,6 +106,50 @@ def source_files(root: Path) -> list[Path]:
|
||||
return sorted(p for p in root.rglob("*.cs") if "obj" not in p.parts and "bin" not in p.parts)
|
||||
|
||||
|
||||
def mask_csharp_comments(text: str) -> str:
|
||||
"""Blank comments without shifting source offsets or touching string literals."""
|
||||
masked = list(text)
|
||||
index = 0
|
||||
state = "code"
|
||||
while index < len(text):
|
||||
char = text[index]
|
||||
following = text[index + 1] if index + 1 < len(text) else ""
|
||||
if state == "code":
|
||||
if char == '"':
|
||||
state = "string"
|
||||
elif char == "'":
|
||||
state = "char"
|
||||
elif char == "/" and following == "/":
|
||||
masked[index] = masked[index + 1] = " "
|
||||
index += 1
|
||||
state = "line_comment"
|
||||
elif char == "/" and following == "*":
|
||||
masked[index] = masked[index + 1] = " "
|
||||
index += 1
|
||||
state = "block_comment"
|
||||
elif state == "string":
|
||||
if char == '"' and following == '"':
|
||||
index += 1
|
||||
elif char == '"' and (index == 0 or text[index - 1] != "\\"):
|
||||
state = "code"
|
||||
elif state == "char":
|
||||
if char == "'" and (index == 0 or text[index - 1] != "\\"):
|
||||
state = "code"
|
||||
elif state == "line_comment":
|
||||
if char in "\r\n":
|
||||
state = "code"
|
||||
else:
|
||||
masked[index] = " "
|
||||
elif char == "*" and following == "/":
|
||||
masked[index] = masked[index + 1] = " "
|
||||
index += 1
|
||||
state = "code"
|
||||
elif char not in "\r\n":
|
||||
masked[index] = " "
|
||||
index += 1
|
||||
return "".join(masked)
|
||||
|
||||
|
||||
def namespace_at(text: str, position: int) -> str:
|
||||
matches = [m for m in NAMESPACE_RE.finditer(text) if m.start() <= position]
|
||||
return matches[-1].group(1) if matches else ""
|
||||
@@ -278,10 +322,11 @@ def helper_types(roots: tuple[Path, ...], upstream: Path) -> dict[str, str]:
|
||||
for root in roots:
|
||||
for path in source_files(root):
|
||||
text = path.read_text(encoding="utf-8-sig")
|
||||
if TEST_ATTR_RE.search(text):
|
||||
searchable = mask_csharp_comments(text)
|
||||
if TEST_ATTR_RE.search(searchable):
|
||||
continue
|
||||
relative = path.relative_to(upstream).as_posix()
|
||||
for match in CLASS_RE.finditer(text):
|
||||
for match in CLASS_RE.finditer(searchable):
|
||||
helpers.setdefault(match.group(1), relative)
|
||||
return helpers
|
||||
|
||||
@@ -293,29 +338,33 @@ def extract_tests(upstream: Path) -> list[dict[str, object]]:
|
||||
for root in roots:
|
||||
for path in source_files(root):
|
||||
text = path.read_text(encoding="utf-8-sig")
|
||||
searchable = mask_csharp_comments(text)
|
||||
relative = path.relative_to(upstream).as_posix()
|
||||
dependencies = sorted(
|
||||
helper_path
|
||||
for helper, helper_path in helpers.items()
|
||||
if helper_path != relative and re.search(rf"\b{re.escape(helper)}\b", text)
|
||||
if helper_path != relative and re.search(rf"\b{re.escape(helper)}\b", searchable)
|
||||
)
|
||||
attrs = list(TEST_ATTR_RE.finditer(text))
|
||||
attrs = list(TEST_ATTR_RE.finditer(searchable))
|
||||
for attr_index, attr in enumerate(attrs):
|
||||
next_attr = attrs[attr_index + 1].start() if attr_index + 1 < len(attrs) else len(text)
|
||||
method = METHOD_RE.search(text, attr.end(), next_attr + 1200)
|
||||
next_attr = attrs[attr_index + 1].start() if attr_index + 1 < len(attrs) else len(searchable)
|
||||
method = METHOD_RE.search(searchable, attr.end(), next_attr + 1200)
|
||||
if method is None:
|
||||
method = METHOD_RE.search(text, attr.end())
|
||||
method = METHOD_RE.search(searchable, attr.end())
|
||||
if method is None:
|
||||
raise RuntimeError(f"No test method after {relative}:{text.count(chr(10), 0, attr.start()) + 1}")
|
||||
attribute_block = searchable[searchable.rfind("}", 0, method.start()) + 1 : method.start()]
|
||||
if attr.group(1) == "Test" and "[TestCase" in attribute_block:
|
||||
continue
|
||||
name = method.group(1)
|
||||
class_match = enclosing_class_match(text, method.start())
|
||||
class_match = enclosing_class_match(searchable, method.start())
|
||||
fixture = class_match.group(1) if class_match else "UnknownFixture"
|
||||
attr_text = " ".join(attr.group(0).split())
|
||||
parameters = " ".join((attr.group(2) or "").split()) or None
|
||||
line = text.count("\n", 0, attr.start()) + 1
|
||||
category_text = text[attr.start() : method.start()]
|
||||
category_text = searchable[attr.start() : method.start()]
|
||||
if class_match:
|
||||
category_text += attributes_before(text, class_match.start())
|
||||
category_text += attributes_before(searchable, class_match.start())
|
||||
categories = sorted(set(CATEGORY_RE.findall(category_text)))
|
||||
tests.append(
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user