Files
q3alique acc1b4f3e7 Initial release of codeflow
Static taint-analysis and visualization tool for source-code security review.
Supports deep analysis for Python, JavaScript/TypeScript, Java, Go, and C#,
with structural support for all other languages via the generic extractor.

Outputs: interactive HTML report, LLM-ready Markdown review document,
and optional Burp Suite JSON export. Self-bootstrapping launcher (run.py)
requires no virtual environment.
2026-06-08 00:55:14 +02:00

130 lines
3.5 KiB
Python

"""Task 005 tests: Tree-sitter AST parser wrapper."""
import pytest
from pathlib import Path
from codeflow.analysis.ast_parser import (
parse_file, query_tree, get_node_text, SUPPORTED_LANGUAGES,
_PARSER_CACHE, _get_cached_parser,
)
def test_parse_python(tmp_path):
f = tmp_path / "test.py"
f.write_text("def hello():\n pass")
tree = parse_file(str(f), "python")
assert tree is not None
assert tree.root_node.type == "module"
def test_parse_js(tmp_path):
f = tmp_path / "test.js"
f.write_text("function hello() {}")
tree = parse_file(str(f), "javascript")
assert tree is not None
assert tree.root_node.type == "program"
def test_parse_unknown_language(tmp_path):
f = tmp_path / "test.py"
f.write_text("x = 1")
tree = parse_file(str(f), "unknown")
assert tree is None
def test_parse_unsupported_language(tmp_path):
f = tmp_path / "test.py"
f.write_text("x = 1")
tree = parse_file(str(f), "cobol")
assert tree is None
def test_parse_nonexistent_file():
tree = parse_file("/nonexistent/file.py", "python")
assert tree is None
def test_parse_empty_file(tmp_path):
f = tmp_path / "empty.py"
f.write_text("")
tree = parse_file(str(f), "python")
assert tree is not None
def test_parse_syntax_error(tmp_path):
f = tmp_path / "broken.py"
f.write_text("def broken(")
tree = parse_file(str(f), "python")
assert tree is not None
def test_get_node_text(tmp_path):
f = tmp_path / "test.py"
source = "def foo():\n pass"
f.write_text(source)
source_bytes = source.encode("utf-8")
tree = parse_file(str(f), "python")
assert tree is not None
root = tree.root_node
text = get_node_text(root, source_bytes)
assert "def foo" in text
def test_query_tree(tmp_path):
f = tmp_path / "test.py"
f.write_text("def hello():\n pass\ndef world():\n pass")
tree = parse_file(str(f), "python")
assert tree is not None
source_bytes = f.read_bytes()
captures = query_tree(tree, "python", """
(function_definition
name: (identifier) @func_name) @func_def
""")
assert len(captures) >= 4
def test_query_tree_invalid(tmp_path):
f = tmp_path / "test.py"
f.write_text("x = 1")
tree = parse_file(str(f), "python")
assert tree is not None
captures = query_tree(tree, "python", "(invalid query!!!")
assert captures == []
def test_parser_cache(mocker):
_PARSER_CACHE.clear()
spy = mocker.patch("codeflow.analysis.ast_parser.get_parser", wraps=mocker.patch("tree_sitter_languages.get_parser"))
p1 = _get_cached_parser("python")
p2 = _get_cached_parser("python")
assert p1 is p2
_PARSER_CACHE.clear()
def test_supported_languages():
assert "python" in SUPPORTED_LANGUAGES
assert "javascript" in SUPPORTED_LANGUAGES
assert "typescript" in SUPPORTED_LANGUAGES
assert "java" in SUPPORTED_LANGUAGES
assert "go" in SUPPORTED_LANGUAGES
def test_parse_typescript(tmp_path):
f = tmp_path / "test.ts"
f.write_text("function hello(): void {}")
tree = parse_file(str(f), "typescript")
assert tree is not None
assert tree.root_node.type in ("program", "statement_block")
def test_parse_go(tmp_path):
f = tmp_path / "main.go"
f.write_text("package main\nfunc main() {}")
tree = parse_file(str(f), "go")
assert tree is not None
def test_parse_rust(tmp_path):
f = tmp_path / "main.rs"
f.write_text("fn main() {}")
tree = parse_file(str(f), "rust")
assert tree is not None