Co-authored-by: Clément Drouin <clement.drouin@mistral.ai> Co-authored-by: Corentin André <corentin.andre@mistral.ai> Co-authored-by: Guillaume LE GOFF <guillaume.lgf@gmail.com> Co-authored-by: Kim-Adeline Miguel <51720070+kimadeline@users.noreply.github.com> Co-authored-by: Maxime Dolores <maxime.dolores@ext.mistral.ai> Co-authored-by: Nelson PROIA <144663685+Nelson-PROIA@users.noreply.github.com> Co-authored-by: Peter Evers <pevers90@gmail.com> Co-authored-by: Pierre Rossinès <pierre.rossines@mistral.ai> Co-authored-by: Quentin <quentin.torroba@mistral.ai> Co-authored-by: Vincent G <10739306+VinceOPS@users.noreply.github.com> Co-authored-by: MichisGitIsKing <MichisGitIsKing@users.noreply.github.com> Co-authored-by: Mistral Vibe <vibe@mistral.ai>
195 lines
8.5 KiB
Python
195 lines
8.5 KiB
Python
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
from vibe.core.paths._local_config_walk import (
|
|
_MAX_DIRS,
|
|
WALK_MAX_DEPTH,
|
|
ConfigWalkResult,
|
|
walk_local_config_dirs,
|
|
)
|
|
|
|
|
|
class TestWalkTools:
|
|
def test_finds_config_at_root(self, tmp_path: Path) -> None:
|
|
(tmp_path / ".vibe" / "tools").mkdir(parents=True)
|
|
result = walk_local_config_dirs(tmp_path)
|
|
assert tmp_path.resolve() / ".vibe" / "tools" in result.tools
|
|
|
|
def test_finds_config_within_depth_limit(self, tmp_path: Path) -> None:
|
|
nested = tmp_path
|
|
for i in range(WALK_MAX_DEPTH):
|
|
nested = nested / f"level{i}"
|
|
(nested / ".vibe" / "skills").mkdir(parents=True)
|
|
result = walk_local_config_dirs(tmp_path)
|
|
assert nested.resolve() / ".vibe" / "skills" in result.skills
|
|
|
|
def test_does_not_find_config_beyond_depth_limit(self, tmp_path: Path) -> None:
|
|
nested = tmp_path
|
|
for i in range(WALK_MAX_DEPTH + 1):
|
|
nested = nested / f"level{i}"
|
|
(nested / ".vibe" / "tools").mkdir(parents=True)
|
|
result = walk_local_config_dirs(tmp_path)
|
|
assert not result.tools
|
|
assert not result.skills
|
|
assert not result.agents
|
|
|
|
def test_respects_dir_count_limit(self, tmp_path: Path) -> None:
|
|
for i in range(_MAX_DIRS + 10):
|
|
(tmp_path / f"dir{i:05d}").mkdir()
|
|
(tmp_path / "zzz_last" / ".vibe" / "tools").mkdir(parents=True)
|
|
result = walk_local_config_dirs(tmp_path)
|
|
assert isinstance(result.tools, tuple)
|
|
|
|
def test_skips_ignored_directories(self, tmp_path: Path) -> None:
|
|
(tmp_path / "node_modules" / ".vibe" / "tools").mkdir(parents=True)
|
|
(tmp_path / ".vibe" / "tools").mkdir(parents=True)
|
|
result = walk_local_config_dirs(tmp_path)
|
|
assert result.tools == (tmp_path.resolve() / ".vibe" / "tools",)
|
|
|
|
def test_skips_dot_directories(self, tmp_path: Path) -> None:
|
|
(tmp_path / ".hidden" / ".vibe" / "tools").mkdir(parents=True)
|
|
result = walk_local_config_dirs(tmp_path)
|
|
assert not result.tools
|
|
|
|
def test_preserves_alphabetical_ordering(self, tmp_path: Path) -> None:
|
|
(tmp_path / "bbb" / ".vibe" / "tools").mkdir(parents=True)
|
|
(tmp_path / "aaa" / ".vibe" / "tools").mkdir(parents=True)
|
|
(tmp_path / ".vibe" / "tools").mkdir(parents=True)
|
|
result = walk_local_config_dirs(tmp_path)
|
|
resolved = tmp_path.resolve()
|
|
assert result.tools == (
|
|
resolved / ".vibe" / "tools",
|
|
resolved / "aaa" / ".vibe" / "tools",
|
|
resolved / "bbb" / ".vibe" / "tools",
|
|
)
|
|
|
|
def test_finds_agents_skills(self, tmp_path: Path) -> None:
|
|
(tmp_path / ".agents" / "skills").mkdir(parents=True)
|
|
result = walk_local_config_dirs(tmp_path)
|
|
assert tmp_path.resolve() / ".agents" / "skills" in result.skills
|
|
|
|
def test_finds_all_config_types(self, tmp_path: Path) -> None:
|
|
(tmp_path / ".vibe" / "tools").mkdir(parents=True)
|
|
(tmp_path / ".vibe" / "skills").mkdir(parents=True)
|
|
(tmp_path / ".vibe" / "agents").mkdir(parents=True)
|
|
(tmp_path / ".agents" / "skills").mkdir(parents=True)
|
|
result = walk_local_config_dirs(tmp_path)
|
|
resolved = tmp_path.resolve()
|
|
assert resolved / ".vibe" / "tools" in result.tools
|
|
assert resolved / ".vibe" / "skills" in result.skills
|
|
assert resolved / ".vibe" / "agents" in result.agents
|
|
assert resolved / ".agents" / "skills" in result.skills
|
|
|
|
|
|
class TestWalkConfigDirs:
|
|
def test_finds_vibe_with_tools(self, tmp_path: Path) -> None:
|
|
(tmp_path / ".vibe" / "tools").mkdir(parents=True)
|
|
result = walk_local_config_dirs(tmp_path)
|
|
assert tmp_path.resolve() / ".vibe" in result.config_dirs
|
|
|
|
def test_finds_vibe_with_skills(self, tmp_path: Path) -> None:
|
|
(tmp_path / ".vibe" / "skills").mkdir(parents=True)
|
|
result = walk_local_config_dirs(tmp_path)
|
|
assert tmp_path.resolve() / ".vibe" in result.config_dirs
|
|
|
|
def test_finds_agents_with_skills(self, tmp_path: Path) -> None:
|
|
(tmp_path / ".agents" / "skills").mkdir(parents=True)
|
|
result = walk_local_config_dirs(tmp_path)
|
|
assert tmp_path.resolve() / ".agents" in result.config_dirs
|
|
|
|
def test_ignores_empty_vibe_dir(self, tmp_path: Path) -> None:
|
|
(tmp_path / ".vibe").mkdir()
|
|
result = walk_local_config_dirs(tmp_path)
|
|
assert result.config_dirs == ()
|
|
|
|
def test_ignores_empty_agents_dir(self, tmp_path: Path) -> None:
|
|
(tmp_path / ".agents").mkdir()
|
|
result = walk_local_config_dirs(tmp_path)
|
|
assert result.config_dirs == ()
|
|
|
|
def test_returns_empty_when_empty(self, tmp_path: Path) -> None:
|
|
result = walk_local_config_dirs(tmp_path)
|
|
assert result.config_dirs == ()
|
|
|
|
def test_finds_shallow_nested(self, tmp_path: Path) -> None:
|
|
(tmp_path / "sub" / ".vibe" / "skills").mkdir(parents=True)
|
|
result = walk_local_config_dirs(tmp_path)
|
|
assert tmp_path.resolve() / "sub" / ".vibe" in result.config_dirs
|
|
|
|
def test_finds_at_depth_2(self, tmp_path: Path) -> None:
|
|
(tmp_path / "a" / "b" / ".agents" / "skills").mkdir(parents=True)
|
|
result = walk_local_config_dirs(tmp_path)
|
|
assert tmp_path.resolve() / "a" / "b" / ".agents" in result.config_dirs
|
|
|
|
def test_returns_empty_beyond_default_depth(self, tmp_path: Path) -> None:
|
|
(tmp_path / "a" / "b" / "c" / "d" / "e" / ".vibe" / "tools").mkdir(parents=True)
|
|
result = walk_local_config_dirs(tmp_path)
|
|
assert result.config_dirs == ()
|
|
|
|
def test_custom_depth(self, tmp_path: Path) -> None:
|
|
(tmp_path / "a" / "b" / "c" / "d" / "e" / ".vibe" / "tools").mkdir(parents=True)
|
|
result = walk_local_config_dirs(tmp_path, max_depth=5)
|
|
assert (
|
|
tmp_path.resolve() / "a" / "b" / "c" / "d" / "e" / ".vibe"
|
|
in result.config_dirs
|
|
)
|
|
|
|
def test_finds_match_among_many_dirs(self, tmp_path: Path) -> None:
|
|
(tmp_path / ".vibe" / "tools").mkdir(parents=True)
|
|
for i in range(100):
|
|
(tmp_path / f"dir{i}").mkdir()
|
|
result = walk_local_config_dirs(tmp_path)
|
|
assert tmp_path.resolve() / ".vibe" in result.config_dirs
|
|
|
|
def test_skips_ignored_directories(self, tmp_path: Path) -> None:
|
|
(tmp_path / "node_modules" / ".vibe" / "skills").mkdir(parents=True)
|
|
result = walk_local_config_dirs(tmp_path)
|
|
assert result.config_dirs == ()
|
|
|
|
def test_finds_vibe_with_prompts(self, tmp_path: Path) -> None:
|
|
(tmp_path / ".vibe" / "prompts").mkdir(parents=True)
|
|
result = walk_local_config_dirs(tmp_path)
|
|
assert tmp_path.resolve() / ".vibe" in result.config_dirs
|
|
|
|
def test_finds_vibe_with_config_toml(self, tmp_path: Path) -> None:
|
|
(tmp_path / ".vibe").mkdir()
|
|
(tmp_path / ".vibe" / "config.toml").write_text("")
|
|
result = walk_local_config_dirs(tmp_path)
|
|
assert tmp_path.resolve() / ".vibe" in result.config_dirs
|
|
|
|
def test_finds_multiple_config_dirs(self, tmp_path: Path) -> None:
|
|
(tmp_path / ".vibe" / "skills").mkdir(parents=True)
|
|
(tmp_path / ".agents" / "skills").mkdir(parents=True)
|
|
(tmp_path / "sub" / ".vibe" / "tools").mkdir(parents=True)
|
|
result = walk_local_config_dirs(tmp_path)
|
|
resolved = tmp_path.resolve()
|
|
assert resolved / ".vibe" in result.config_dirs
|
|
assert resolved / ".agents" in result.config_dirs
|
|
assert resolved / "sub" / ".vibe" in result.config_dirs
|
|
|
|
|
|
class TestConfigWalkResultOr:
|
|
def test_or_concatenates_each_field(self) -> None:
|
|
a = ConfigWalkResult(
|
|
config_dirs=(Path("/a/.vibe"),),
|
|
tools=(Path("/a/.vibe/tools"),),
|
|
skills=(Path("/a/.vibe/skills"),),
|
|
agents=(Path("/a/.vibe/agents"),),
|
|
)
|
|
b = ConfigWalkResult(
|
|
config_dirs=(Path("/b/.vibe"),),
|
|
tools=(Path("/b/.vibe/tools"),),
|
|
skills=(Path("/b/.vibe/skills"),),
|
|
agents=(Path("/b/.vibe/agents"),),
|
|
)
|
|
merged = a | b
|
|
assert merged.config_dirs == (Path("/a/.vibe"), Path("/b/.vibe"))
|
|
assert merged.tools == (Path("/a/.vibe/tools"), Path("/b/.vibe/tools"))
|
|
assert merged.skills == (Path("/a/.vibe/skills"), Path("/b/.vibe/skills"))
|
|
assert merged.agents == (Path("/a/.vibe/agents"), Path("/b/.vibe/agents"))
|
|
|
|
def test_or_with_empty_is_identity(self) -> None:
|
|
a = ConfigWalkResult(tools=(Path("/a/.vibe/tools"),))
|
|
assert (a | ConfigWalkResult()) == a
|
|
assert (ConfigWalkResult() | a) == a
|