Files
Open_Ultra_SAST/tests/test_independent_freeze.py
T
Marius CiepluchandClaude Fable 5.1 062a7b780e refactor(p1): one source-facts module owns function ranges, callers, declaration tables and language aliases
src/openultrasast/source.py replaces the copies in semantic/functions.py,
plane/tasks/repo_facts.py, learn/features.py, learn/excerpt.py and
plane/tasks/verify.py. Two engines share one sentinel (<module>), one
DECLARATION/KEYWORDS/RESERVED set and one alias map: the parser engine
(ranges, enclosing, bounds, call_sites, callers_of, facts_for) for the
scorer, the overlay and the hunter's annotations; the line-pattern engine
(declared_functions, enclosing_at, function_span, function_bounds, the brace
matcher) that labels, features, roles, excerpts and plane facts were built
on. learn no longer imports plane.tasks. Frozen records that store the old
sentinel are mapped on read (module_function).

Gate: labels rebuilt before and after are identical, 7,921 rows, after
sentinel normalisation (benchmarks/measurements/2026-10-13-source-module-
label-diff/record.json). 490 targeted tests pass; 3,312 collect. Net: 657
lines deleted, 212 added. benchmarks/unseen keeps <global> for its own
frozen manifests.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-10-13 12:00:37 +02:00

60 lines
1.9 KiB
Python

"""freeze.py resolves an advisory's file-only site to the function the fix changes (population v3, decision 2).
The resolver reads PHP text only; it must not be fooled by braces in strings, comments or inline HTML, and a line
outside every function is `<module>`."""
from __future__ import annotations
import importlib.util
from pathlib import Path
SPEC = importlib.util.spec_from_file_location("freeze", Path(__file__).resolve().parents[1] / "benchmarks" / "independent" / "freeze.py")
freeze = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(freeze)
PHP = """<html>{ not code }</html>
<?php
// a comment with { brace
class Box
{
public function open($x)
{
$s = "}{ in a string";
return function ($y) { return $y; };
}
abstract protected function shape();
private static function &close() {
/* } */
return <<<EOT
} heredoc {
EOT;
}
}
$top = 1;
?>
<div>{</div>
<?php function helper() { return '#{'; }
"""
def test_named_functions_and_their_lines() -> None:
spans = {name: (first, last) for name, first, last in freeze.php_functions(PHP)}
assert spans == {"open": (6, 10), "close": (14, 19), "helper": (24, 24)}
def test_a_line_resolves_to_its_innermost_named_function_or_global() -> None:
spans = freeze.php_functions(PHP)
assert freeze.enclosing(spans, 9) == "open" # inside the closure: the named function owns it
assert freeze.enclosing(spans, 17) == "close"
assert freeze.enclosing(spans, 21) == "<module>"
assert freeze.enclosing(spans, 1) == "<module>"
def test_an_insertion_after_a_closing_brace_is_outside_the_function() -> None:
spans = freeze.php_functions(PHP)
assert freeze.enclosing(spans, 10) == "open" # a changed line on the closing brace
assert freeze.enclosing(spans, 10, inserted=True) == "<module>" # new code that follows it
assert freeze.enclosing(spans, 8, inserted=True) == "open"