nanobot/tests/test_commands.py

135 lines
4.4 KiB
Python

import os
import shutil
from pathlib import Path
from unittest.mock import MagicMock, patch
import pytest
from typer.testing import CliRunner
from nanobot.cli.commands import app
runner = CliRunner()
@pytest.fixture
def mock_paths():
"""Mock configuration and workspace paths for isolation."""
with patch("nanobot.config.loader.get_config_path") as mock_config_path, \
patch("nanobot.config.loader.save_config") as mock_save_config, \
patch("nanobot.utils.helpers.get_workspace_path") as mock_ws_path:
# Create temporary paths
base_dir = Path("./test_onboard_data")
if base_dir.exists():
shutil.rmtree(base_dir)
base_dir.mkdir()
config_file = base_dir / "config.json"
workspace_dir = base_dir / "workspace"
mock_config_path.return_value = config_file
mock_ws_path.return_value = workspace_dir
# We need save_config to actually write the file for existence checks to work
def side_effect_save_config(config):
with open(config_file, "w") as f:
f.write("{}")
mock_save_config.side_effect = side_effect_save_config
yield config_file, workspace_dir
# Cleanup
if base_dir.exists():
shutil.rmtree(base_dir)
def test_onboard_fresh_install(mock_paths):
"""Test onboarding with no existing files."""
config_file, workspace_dir = mock_paths
result = runner.invoke(app, ["onboard"])
assert result.exit_code == 0
assert "Created config" in result.stdout
assert "Created workspace" in result.stdout
assert "nanobot is ready" in result.stdout
assert config_file.exists()
assert workspace_dir.exists()
assert (workspace_dir / "AGENTS.md").exists()
assert (workspace_dir / "memory" / "MEMORY.md").exists()
def test_onboard_existing_config_no_overwrite(mock_paths):
"""Test onboarding with existing config, user declines overwrite."""
config_file, workspace_dir = mock_paths
# Pre-create config
config_file.write_text('{"existing": true}')
# Input "n" for overwrite prompt
result = runner.invoke(app, ["onboard"], input="n\n")
assert result.exit_code == 0
assert "Config already exists" in result.stdout
# Verify config was NOT changed
assert '{"existing": true}' in config_file.read_text()
# Verify workspace was still created
assert "Created workspace" in result.stdout
assert workspace_dir.exists()
assert (workspace_dir / "AGENTS.md").exists()
def test_onboard_existing_config_overwrite(mock_paths):
"""Test onboarding with existing config, user checks overwrite."""
config_file, workspace_dir = mock_paths
# Pre-create config
config_file.write_text('{"existing": true}')
# Input "y" for overwrite prompt
result = runner.invoke(app, ["onboard"], input="y\n")
assert result.exit_code == 0
assert "Config already exists" in result.stdout
assert "Created config" in result.stdout
# Verify config WAS changed (our mock writes "{}")
test_content = config_file.read_text()
assert test_content == "{}" or test_content == ""
assert workspace_dir.exists()
def test_onboard_existing_workspace_safe_create(mock_paths):
"""Test onboarding with existing workspace safely creates templates without prompting."""
config_file, workspace_dir = mock_paths
# Pre-create workspace
workspace_dir.mkdir(parents=True)
# Scenario: Config exists (keep it), Workspace exists (add templates automatically)
config_file.write_text("{}")
inputs = "n\n" # No overwrite config
result = runner.invoke(app, ["onboard"], input=inputs)
assert result.exit_code == 0
# Workspace exists message
# Depending on implementation, it might say "Workspace already exists" or just proceed.
# Code in commands.py Line 180: if not workspace.exists(): ...
# It does NOT print "Workspace already exists" if it exists.
# It only prints "Created workspace" if it created it.
assert "Created workspace" not in result.stdout
# Should NOT prompt for templates
assert "Create missing default templates?" not in result.stdout
# But SHOULD create them (since _create_workspace_templates is called unconditionally)
assert "Created AGENTS.md" in result.stdout
assert (workspace_dir / "AGENTS.md").exists()