"""Tests for tag-preprocessor orchestrator (analyze.py).""" from pathlib import Path, PurePath import tempfile import sys sys.path.insert(0, str(Path(__file__).parent.parent)) from bex.tag_preprocessor.analyze import ( scan_directory, frequency_filter, infer, analyze_directory, _match_glob, _file_to_package, _top_packages, _extract_imports, ) from bex.tag_preprocessor.code import _summarize_arg_info, _classify_arg_node def test_scan_directory_empty(): with tempfile.TemporaryDirectory() as td: result = scan_directory(td) assert result == {} print(" PASS test_scan_directory_empty") def test_scan_directory_groups_by_extension(): with tempfile.TemporaryDirectory() as td: d = Path(td) (d / "a.py").write_text("x = 1") (d / "b.py").write_text("y = 2") (d / "c.js").write_text("let x = 1;") (d / "d.rs").write_text("fn main() {}") result = scan_directory(td) assert ".py" in result assert ".js" in result assert ".rs" in result assert len(result[".py"]) == 2 assert len(result[".js"]) == 1 assert len(result[".rs"]) == 1 print(" PASS test_scan_directory_groups_by_extension") def test_scan_directory_skips_unsupported(): with tempfile.TemporaryDirectory() as td: d = Path(td) (d / "f.py").write_text("x = 1") (d / "f.txt").write_text("hello") (d / "f.md").write_text("# doc") result = scan_directory(td) assert ".py" in result assert ".txt" not in result assert ".md" not in result print(" PASS test_scan_directory_skips_unsupported") def test_scan_directory_nested(): with tempfile.TemporaryDirectory() as td: d = Path(td) (d / "sub").mkdir() (d / "sub" / "a.py").write_text("x = 1") (d / "b.py").write_text("y = 2") result = scan_directory(td) assert len(result[".py"]) == 2 print(" PASS test_scan_directory_nested") def test_scan_directory_skips_build_dirs(): with tempfile.TemporaryDirectory() as td: d = Path(td) (d / "src" / "main").mkdir(parents=True) (d / "build" / "reports").mkdir(parents=True) (d / "node_modules" / "pkg").mkdir(parents=True) (d / "src" / "main" / "app.py").write_text("x = 1") (d / "build" / "reports" / "report.js").write_text("let x = 1;") (d / "node_modules" / "pkg" / "index.js").write_text("let y = 2;") result = scan_directory(td) assert ".py" in result assert ".js" not in result assert len(result[".py"]) == 1 print(" PASS test_scan_directory_skips_build_dirs") def test_frequency_filter_nothing_to_filter(): sequences = [ [("function", "foo", 1), ("keyword.return", "return", 2)], [("function", "bar", 1), ("keyword.return", "return", 2)], ] filtered = frequency_filter(sequences, min_coverage=0.5) assert len(filtered) == 2 assert filtered == sequences print(" PASS test_frequency_filter_nothing_to_filter") def test_frequency_filter_removes_infrequent_symbol(): sequences = [ [("keyword.return", "return", 1)], [("keyword.return", "return", 1)], [("function", "rare_fn", 1)], ] filtered = frequency_filter(sequences, min_coverage=0.67) assert len(filtered) == 3 assert len(filtered[0]) == 1 # "return" kept assert len(filtered[1]) == 1 # "return" kept assert len(filtered[2]) == 0 # "rare_fn" removed print(" PASS test_frequency_filter_removes_infrequent_symbol") def test_frequency_filter_edge_empty_sequences(): assert frequency_filter([], min_coverage=0.5) == [] assert frequency_filter([[], []], min_coverage=0.5) == [[], []] print(" PASS test_frequency_filter_edge_empty_sequences") def test_infer_returns_ensemble_dict(): with tempfile.TemporaryDirectory() as td: d = Path(td) (d / "a.py").write_text("def foo():\n return 1") (d / "b.py").write_text("def bar():\n return 2") result = infer([str(d / "a.py"), str(d / "b.py")], ".py", min_coverage=0.5) assert isinstance(result, dict) assert "best" in result assert "all" in result assert "why" in result print(" PASS test_infer_returns_ensemble_dict") def test_match_glob(): assert _match_glob("/repo/src/main/app.kt", "**/src/main/**") assert _match_glob("/repo/src/main/org/app.kt", "**/src/main/**") assert _match_glob("/repo/src/main/deep/nested/app.kt", "**/src/main/**") assert not _match_glob("/repo/src/test/app.kt", "**/src/main/**") assert not _match_glob("/repo/build/app.kt", "**/src/main/**") print(" PASS test_match_glob") def test_analyze_directory_include_glob(): with tempfile.TemporaryDirectory() as td: d = Path(td) (d / "src" / "main").mkdir(parents=True) (d / "src" / "test").mkdir(parents=True) (d / "src" / "main" / "prod.py").write_text("def setup():\n pass\ndef run():\n return x") (d / "src" / "test" / "test_prod.py").write_text("def test_run():\n assert run() == x") results = analyze_directory(td, include="**/src/main/**") assert ".py" in results assert len(results[".py"]) >= 1 for label, r, count, meta in results[".py"]: if r and r.get("best"): assert r["best"]["grammar"] is not None print(" PASS test_analyze_directory_include_glob") def test_infer_low_coverage_filters_noise(): with tempfile.TemporaryDirectory() as td: d = Path(td) (d / "common.py").write_text( "def setup():\n pass\ndef teardown():\n pass" ) (d / "rare.py").write_text( "def setup():\n pass\ndef one_off():\n raise Exception('boom')" ) result = infer( [str(d / "common.py"), str(d / "rare.py")], ".py", min_coverage=0.6 ) assert result["best"] is not None assert result["best"]["grammar"] is not None print(" PASS test_infer_low_coverage_filters_noise") def test_file_to_package(): assert _file_to_package( "/repo/src/main/kotlin/com/example/app/Foo.kt", ".kt" ) == "com/example/app" assert _file_to_package( "/repo/src/test/java/com/example/FooTest.java", ".java" ) == "com/example" assert _file_to_package( "/repo/src/main/python/mypackage/module.py", ".py" ) == "mypackage" assert _file_to_package("/repo/lib/foo.py", ".py") == "lib" print(" PASS test_file_to_package") def test_top_packages(): fps = { "/repo/src/main/kotlin/com/example/a/Foo.kt", "/repo/src/main/kotlin/com/example/a/Bar.kt", "/repo/src/main/kotlin/com/example/b/Baz.kt", } pkgs = _top_packages(fps, ".kt") assert pkgs[0] == "com/example/a" assert pkgs[1] == "com/example/b" print(" PASS test_top_packages") def test_extract_imports(): with tempfile.TemporaryDirectory() as td: d = Path(td) (d / "a.kt").write_text( "package com.example\nimport io.mockk.every\nimport io.mockk.verify\n\nclass Foo" ) (d / "b.kt").write_text( "package com.example\nimport org.junit.Test\n\nclass Bar" ) result = _extract_imports({str(d / "a.kt"), str(d / "b.kt")}) assert "import io.mockk.every" in result assert "import io.mockk.verify" in result assert "import org.junit.Test" in result assert len(result) == 3 print(" PASS test_extract_imports") def test_extract_imports_empty(): assert _extract_imports(set()) == [] print(" PASS test_extract_imports_empty") def test_extract_imports_no_imports(): with tempfile.TemporaryDirectory() as td: d = Path(td) (d / "a.py").write_text("x = 1\ny = 2") result = _extract_imports({str(d / "a.py")}) assert result == [] print(" PASS test_extract_imports_no_imports") def test_extract_arg_info_python(): with tempfile.TemporaryDirectory() as td: d = Path(td) (d / "a.py").write_text( "def test_foo():\n" " result = compute(42)\n" " assert result == 0\n" " run(mock, times=1)\n" ) from bex.tag_preprocessor.code import extract_arg_info fp = str(d / "a.py") code = Path(fp).read_text() info = extract_arg_info(fp, code) # compute(42) -> 1 arg: literal assert "compute" in info obs = info["compute"] assert any(n == 1 and ts == ("lit",) for n, ts in obs) # run(mock, times=1) -> 2 args: var + kwarg assert "run" in info obs2 = info["run"] assert any(n == 2 for n, ts in obs2) assert any(ts == ("var", "kwarg") for n, ts in obs2) print(" PASS test_extract_arg_info_python") def test_summarize_arg_info(): info = { "foo": [(2, ("var", "lit")), (2, ("var", "lit")), (3, ("var", "lit", "lit"))], "bar": [(0, ()), (1, ("lambda",))], } summary = _summarize_arg_info(info) assert summary["foo"]["occurrences"] == 3 assert summary["foo"]["arg_count"]["min"] == 2 assert summary["foo"]["arg_count"]["max"] == 3 assert summary["foo"]["arg_count"]["common"] == 2 assert len(summary["foo"]["patterns"]) == 2 assert summary["bar"]["occurrences"] == 2 assert summary["bar"]["arg_count"]["min"] == 0 print(" PASS test_summarize_arg_info") def run_all(): tests = [ test_scan_directory_empty, test_scan_directory_groups_by_extension, test_scan_directory_skips_unsupported, test_scan_directory_nested, test_scan_directory_skips_build_dirs, test_match_glob, test_analyze_directory_include_glob, test_frequency_filter_nothing_to_filter, test_frequency_filter_removes_infrequent_symbol, test_frequency_filter_edge_empty_sequences, test_infer_returns_ensemble_dict, test_infer_low_coverage_filters_noise, test_file_to_package, test_top_packages, test_extract_imports, test_extract_imports_empty, test_extract_imports_no_imports, test_extract_arg_info_python, test_summarize_arg_info, ] passed = 0 failed = 0 for t in tests: try: t() passed += 1 except Exception as e: print(f" FAIL {t.__name__}: {e}") failed += 1 print(f"\n{passed} passed, {failed} failed") if __name__ == "__main__": run_all()