From 1f23fd17b6f9132aaa15adc3d0548d64aa6e6f01 Mon Sep 17 00:00:00 2001 From: Zhengchao An Date: Wed, 19 Aug 2026 23:07:21 +0800 Subject: [PATCH] fix(scripts): stop the assertless-test census truncating bodies at string braces (#6280) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The census matched braces over raw source, so a `{` inside a string literal unbalanced the count and cut the test body short. `test_find_ellipses_patterns_leftover_brace_error_does_not_echo_input` was reported as assertionless because its input — `"http://:brace-secret@server/{1...2}}"` — ended the body before the `assert!` two lines below it. Brace matching now runs over a literal-stripped view. The stripper carries state across lines, because the JSON and `r#"..."#` fixtures these tests are built from routinely span several; a per-line version falls out of phase on the first multi-line string and truncates far more than it fixes. Raw strings are closed on their own hash count, and a lone `'` is left alone so a lifetime (`&'a str`) is not mistaken for a char literal. The candidate count is unchanged at 15, which is the interesting part: one entry left and one arrived. `utils/src/string.rs:942` drops out, correctly — it does assert. `io-metrics/src/lib.rs:3308` appears, also correctly — `test_record_get_object_path_and_stage` makes twenty-odd `record_*` calls and asserts nothing, the same shape #6238 fixed elsewhere in that file. It had been hidden behind a truncated body. Refs backlog#1836 --- scripts/find_assertless_tests.py | 75 +++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/scripts/find_assertless_tests.py b/scripts/find_assertless_tests.py index 094d051af..84559f7ad 100755 --- a/scripts/find_assertless_tests.py +++ b/scripts/find_assertless_tests.py @@ -81,6 +81,78 @@ FN_LINE = re.compile(r"^\s*(?:pub\s+)?(?:async\s+)?fn\s+([a-zA-Z0-9_]+)") +# A char literal is 'x' or '\n'; a lone `'` is a lifetime (`&'a str`), and +# consuming to the next quote on one would swallow the rest of the line. +CHAR_LITERAL = re.compile(r"'(?:[^'\\]|\\.)'") +RAW_STRING_OPEN = re.compile(r'r(#*)"') + + +class LiteralStripper: + """Blanks out literals and comments so brace matching sees only code. + + Carries state across lines: Rust string literals — the JSON and `r#"..."#` + fixtures these tests are full of — routinely span lines, and a per-line + scanner falls out of phase on the first one. A `{` inside a string would + otherwise unbalance the count and truncate a test body before its + assertions. + """ + + def __init__(self) -> None: + self.in_string = False + self.raw_hashes = None # None when the open string is not raw + + def feed(self, line: str) -> str: + out = [] + i = 0 + n = len(line) + while i < n: + if self.in_string: + if self.raw_hashes is not None: + close = '"' + "#" * self.raw_hashes + idx = line.find(close, i) + if idx == -1: + return "".join(out) + i = idx + len(close) + self.in_string = False + self.raw_hashes = None + continue + if line[i] == "\\": + i += 2 + continue + if line[i] == '"': + self.in_string = False + i += 1 + continue + i += 1 + continue + + ch = line[i] + if ch == "/" and i + 1 < n and line[i + 1] == "/": + break + m = RAW_STRING_OPEN.match(line, i) + if m: + self.in_string = True + self.raw_hashes = len(m.group(1)) + i = m.end() + continue + if ch == '"': + self.in_string = True + self.raw_hashes = None + i += 1 + continue + if ch == "'": + cm = CHAR_LITERAL.match(line, i) + if cm: + i = cm.end() + continue + out.append(ch) + i += 1 + continue + out.append(ch) + i += 1 + return "".join(out) + + def extract_body(text: str) -> str: """Return what is between the outermost braces of a scanned function.""" start = text.find("{") @@ -121,8 +193,9 @@ def scan_file(path: Path): begun = False body = [] k = j + stripper = LiteralStripper() while k < len(lines): - for ch in lines[k]: + for ch in stripper.feed(lines[k]): if ch == "{": depth += 1 begun = True