MCPunk

  • tests
import logging import os from pathlib import Path from string import ascii_lowercase import pytest from mcpunk.util import create_file_tree, log_inputs_outputs, matches_filter, rand_str @pytest.mark.parametrize("log_level", (logging.DEBUG, logging.INFO, "WARNING")) def test_log_inputs( caplog: pytest.LogCaptureFixture, log_level: int | str, ) -> None: """Test log_inputs decorator captures function inputs and outputs.""" caplog.set_level(logging.DEBUG) @log_inputs_outputs(log_level=log_level) def example_func(a: int, *, b: str = "test") -> str: return f"{a}{b}" result = example_func(1, b="value") assert result == "1value" expect_log_to_contain_snippets = [ "Calling tool example_func with inputs:", "Arg_0=1", "b='value'", "resp='1value'", ] for t in expect_log_to_contain_snippets: assert t in caplog.text, t for record in caplog.records: if t in record.message: assert log_level in (record.levelno, record.levelname), record.levelno assert "Calling tool example_func with inputs:" in caplog.text assert "Arg_0=1" in caplog.text assert "b='value'" in caplog.text assert "resp='1value'" in caplog.text def test_create_file_tree(tmp_path: Path) -> None: """Test create_file_tree generates correct compact text output.""" # Set up test files (tmp_path / "dir1").mkdir() (tmp_path / "dir1/file1.txt").touch() (tmp_path / "dir1/other.txt").touch() (tmp_path / "dir1/subdir").mkdir() (tmp_path / "dir1/subdir/file2.txt").touch() (tmp_path / "file3.txt").touch() (tmp_path / "dir2/dir4/dir5").mkdir(parents=True) (tmp_path / "logs").mkdir() (tmp_path / "logs/app.log").touch() (tmp_path / "logs/error.log").touch() paths = { tmp_path / "dir1", tmp_path / "dir1/file1.txt", tmp_path / "dir1/other.txt", tmp_path / "dir1/subdir", tmp_path / "dir1/subdir/file2.txt", tmp_path / "file3.txt", tmp_path / "dir2/dir4/dir5", tmp_path / "logs", tmp_path / "logs/app.log", tmp_path / "logs/error.log", } result = create_file_tree( project_root=tmp_path, paths=paths, ) sep = os.path.sep expected = ( f".: file3.txt\ndir1: file1.txt; other.txt\ndir1{sep}subdir: file2.txt\n" "logs: app.log; error.log\n" ) assert result == expected def test_create_file_tree_with_filter(tmp_path: Path) -> None: """Test create_file_tree with filter parameter.""" (tmp_path / "test.py").touch() (tmp_path / "main.py").touch() (tmp_path / "data.txt").touch() paths = { tmp_path / "test.py", tmp_path / "main.py", tmp_path / "data.txt", } result = create_file_tree( project_root=tmp_path, paths=paths, filter_=[".py"], ) assert result == ".: main.py; test.py\n" def test_create_file_tree_depth_limit(tmp_path: Path) -> None: """Test create_file_tree with depth limit.""" (tmp_path / "file0.txt").touch() (tmp_path / "dir1/dir2/dir3").mkdir(parents=True) (tmp_path / "dir1/file1.txt").touch() (tmp_path / "dir1/dir2/file2.txt").touch() (tmp_path / "dir1/dir2/dir3/file3.txt").touch() paths = { tmp_path / p for p in [ "file0.txt", "dir1", "dir1/file1.txt", "dir1/dir2", "dir1/dir2/file2.txt", "dir1/dir2/dir3", "dir1/dir2/dir3/file3.txt", ] } result = create_file_tree( project_root=tmp_path, paths=paths, limit_depth_from_root=2, ) assert result == ".: file0.txt\ndir1: file1.txt\n" def test_rand_str() -> None: """Test rand_str generates strings correctly.""" # Test default length result = rand_str() assert len(result) == 10 assert all(c in ascii_lowercase for c in result) # Test custom length result = rand_str(n=5) assert len(result) == 5 # Test custom characters result = rand_str(chars="ABC") assert len(result) == 10 assert all(c in "ABC" for c in result) def test_matches_filter() -> None: """Test matches_filter with different filter types.""" # Test None filter assert matches_filter(None, "test") is True assert matches_filter(None, None) is True # Test list filter assert matches_filter(["abc", "def"], "abcdef") is True assert matches_filter(["xyz", "123"], "abcdef") is False assert matches_filter(["abc"], None) is False