from __future__ import annotations import json from pathlib import Path import testing.ci.quality_gate as quality_gate_module from testing.ci.quality_gate import ( _js_node_issues, _python_node_issues, check_coverage, check_file_sizes, run_gate, ) def test_check_file_sizes_flags_overlong_files(tmp_path: Path) -> None: path = tmp_path / "tool.py" path.write_text("\n".join(f"line {idx}" for idx in range(7))) issues = check_file_sizes([path], max_lines=5) assert issues and issues[0].check == "loc" assert "exceeds 5" in issues[0].message def test_docstring_helpers_accept_contract_comments_and_docstrings(tmp_path: Path) -> None: py_path = tmp_path / "sample.py" py_path.write_text( '"""module docs"""\n\n' 'def documented():\n' ' """Explain what the helper does."""\n' ' return 1\n\n' 'def tiny_private_helper():\n' ' return 2\n\n' 'def missing_contract(value):\n' ' if value:\n' ' return value\n' ' if value == 0:\n' ' return "zero"\n' ' if value is None:\n' ' return "none"\n' ' if isinstance(value, str):\n' ' return value.strip()\n' ' return "fallback"\n' ) js_path = tmp_path / "sample.js" js_path.write_text( '/**\n' ' * WHY: the helper needs a contract for the gate.\n' ' * @param {string} name - service name.\n' ' * @returns {string} icon label.\n' ' */\n' 'function pickIcon(name) {\n' ' return name;\n' '}\n' ) py_issues = _python_node_issues(py_path) js_issues = _js_node_issues(js_path) assert any(issue.message.endswith("missing_contract") for issue in py_issues) assert js_issues == [] def test_check_coverage_reads_backend_and_frontend_reports(tmp_path: Path) -> None: backend_report = tmp_path / "backend.xml" backend_report.write_text( '' '' '' ) frontend_report = tmp_path / "frontend.json" frontend_report.write_text( json.dumps( { "src/auth.js": { "lines": {"pct": 100}, "statements": {"pct": 100}, "branches": {"pct": 100}, "functions": {"pct": 100}, } } ) ) issues = check_coverage( [Path("backend/atlas_portal/app_factory.py"), Path("frontend/src/auth.js")], backend_report=backend_report, frontend_report=frontend_report, threshold=95, ) assert issues == [] def test_run_gate_reports_workspace_coverage_and_loc_totals(tmp_path: Path) -> None: root_before = quality_gate_module.ROOT quality_gate_module.ROOT = tmp_path try: backend_dir = tmp_path / "backend" / "atlas_portal" frontend_dir = tmp_path / "frontend" / "src" backend_dir.mkdir(parents=True) frontend_dir.mkdir(parents=True) (backend_dir / "app_factory.py").write_text( '"""Factory docs."""\n\n' "def create_app():\n" ' """Create the app."""\n' " return object()\n" ) (backend_dir / "too_long.py").write_text("\n".join(f"line_{idx}" for idx in range(501))) (frontend_dir / "auth.js").write_text( "/**\n" " * WHY: auth wrapper exists.\n" " * @param {string} token - jwt.\n" " * @returns {string} token.\n" " */\n" "function auth(token) {\n" " return token;\n" "}\n" ) backend_report = tmp_path / "backend.xml" backend_report.write_text( '' '' '' ) frontend_report = tmp_path / "frontend.json" frontend_report.write_text( json.dumps( { "src/auth.js": { "lines": {"pct": 100}, "statements": {"pct": 100}, "branches": {"pct": 100}, "functions": {"pct": 100}, } } ) ) contract = { "managed_files": [ "backend/atlas_portal/app_factory.py", "backend/atlas_portal/too_long.py", ], "docstring_files": ["backend/atlas_portal/app_factory.py"], "coverage_files": [ "backend/atlas_portal/app_factory.py", "frontend/src/auth.js", ], "max_lines": 500, "coverage_threshold_pct": 95, } contract_path = tmp_path / "contract.json" contract_path.write_text(json.dumps(contract)) issues, report = run_gate(contract_path, backend_coverage=backend_report, frontend_coverage=frontend_report) assert any(issue.check == "loc" for issue in issues) assert report["workspace_line_coverage_percent"] == 100.0 assert report["source_lines_over_500"] == 1 finally: quality_gate_module.ROOT = root_before