CtrlK
BlogDocsLog inGet started
Tessl Logo

giuseppe-trisciuoglio/developer-kit

Comprehensive developer toolkit providing reusable skills for Java/Spring Boot, TypeScript/NestJS/React/Next.js, Python, PHP, AWS CloudFormation, AI/RAG, DevOps, and more.

89

Quality

89%

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Risky

Do not use without reviewing

Overview
Quality
Evals
Security
Files

test_drift_init.pyplugins/developer-kit-specs/hooks/tests/

#!/usr/bin/env python3
"""Unit tests for drift-init.py.

Tests cover:
- Prompt parsing to extract task path
- Markdown parsing of "Files to Create" section
- _drift/ state management
- Graceful degradation scenarios
"""

import json
import os
import sys
import tempfile
import shutil
from pathlib import Path
from unittest.mock import patch, mock_open
import importlib.util

# Import the module under test (drift-init.py has hyphen, need importlib)
hooks_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
spec = importlib.util.spec_from_file_location(
    "drift_init", os.path.join(hooks_dir, "drift-init.py")
)
drift_init = importlib.util.module_from_spec(spec)
sys.modules["drift_init"] = drift_init
spec.loader.exec_module(drift_init)


# ─── Test Prompt Parsing ────────────────────────────────────────────────────────


def test_extract_task_id_from_prompt_with_quotes():
    """Test extracting task path from prompt with double quotes."""
    prompt = '/developer-kit-specs:specs.task-implementation --lang=python --task="docs/specs/001/tasks/TASK-001.md"'
    result = drift_init.extract_task_id_from_prompt(prompt)
    assert result == "docs/specs/001/tasks/TASK-001.md"


def test_extract_task_id_from_prompt_with_single_quotes():
    """Test extracting task path from prompt with single quotes."""
    prompt = "/developer-kit-specs:specs.task-implementation --task='docs/specs/001/tasks/TASK-001.md'"
    result = drift_init.extract_task_id_from_prompt(prompt)
    assert result == "docs/specs/001/tasks/TASK-001.md"


def test_extract_task_id_from_prompt_without_quotes():
    """Test extracting task path from prompt without quotes."""
    prompt = "/developer-kit-specs:specs.task-implementation --task=docs/specs/001/tasks/TASK-001.md"
    result = drift_init.extract_task_id_from_prompt(prompt)
    assert result == "docs/specs/001/tasks/TASK-001.md"


def test_extract_task_id_from_prompt_normal_user_message():
    """Test that normal user messages return None."""
    prompt = "How do I implement user authentication?"
    result = drift_init.extract_task_id_from_prompt(prompt)
    assert result is None


def test_extract_task_id_with_spaces_in_path():
    """Test handling paths with spaces (edge case)."""
    prompt = '/developer-kit-specs:specs.task-implementation --task="docs/specs/001 drift/tasks/TASK-001.md"'
    result = drift_init.extract_task_id_from_prompt(prompt)
    assert result == "docs/specs/001 drift/tasks/TASK-001.md"


# ─── Test Path Resolution ───────────────────────────────────────────────────────


def test_resolve_task_path_with_full_path():
    """Test resolving absolute task path."""
    with tempfile.TemporaryDirectory() as tmpdir:
        task_path = os.path.join(tmpdir, "docs/specs/001/tasks/TASK-001.md")
        os.makedirs(os.path.dirname(task_path))
        Path(task_path).touch()

        result = drift_init.resolve_task_path(task_path, tmpdir)
        assert result == task_path


def test_resolve_task_path_with_task_id():
    """Test resolving TASK-XXX format."""
    with tempfile.TemporaryDirectory() as tmpdir:
        spec_dir = os.path.join(tmpdir, "docs/specs/001")
        task_path = os.path.join(spec_dir, "tasks/TASK-001.md")
        os.makedirs(os.path.dirname(task_path))
        Path(task_path).touch()

        result = drift_init.resolve_task_path("TASK-001", tmpdir)
        assert result == task_path


def test_resolve_task_path_not_found():
    """Test resolving non-existent task returns None."""
    with tempfile.TemporaryDirectory() as tmpdir:
        result = drift_init.resolve_task_path("TASK-999", tmpdir)
        assert result is None


# ─── Test Markdown Parsing ───────────────────────────────────────────────────────


def test_extract_files_with_backtick_format():
    """Test extracting files from `- `path` - description` format."""
    task_content = """
## Files to Create
- `plugins/developer-kit-specs/hooks/drift-init.py` - Main script
- `plugins/developer-kit-specs/hooks/tests/test_drift_init.py` - Tests
"""
    with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".md") as f:
        f.write(task_content)
        f.flush()

        result = drift_init.extract_files_to_create(f.name)
        os.unlink(f.name)

    assert result is not None
    assert len(result) == 2
    assert "plugins/developer-kit-specs/hooks/drift-init.py" in result
    assert "plugins/developer-kit-specs/hooks/tests/test_drift_init.py" in result


def test_extract_files_without_backticks():
    """Test extracting files from `- path - description` format."""
    task_content = """
## Files to Create
- plugins/developer-kit-specs/hooks/drift-init.py - Main script
- plugins/developer-kit-specs/hooks/tests/test_drift_init.py - Tests
"""
    with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".md") as f:
        f.write(task_content)
        f.flush()

        result = drift_init.extract_files_to_create(f.name)
        os.unlink(f.name)

    assert result is not None
    assert len(result) == 2
    assert "plugins/developer-kit-specs/hooks/drift-init.py" in result


def test_extract_files_with_files_to_modify_present():
    """Test that 'Files to Modify' section doesn't contaminate extraction."""
    task_content = """
## Files to Create
- `src/main.py` - Main file

## Files to Modify
- `src/config.py` - Config file
"""
    with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".md") as f:
        f.write(task_content)
        f.flush()

        result = drift_init.extract_files_to_create(f.name)
        os.unlink(f.name)

    assert result is not None
    assert len(result) == 1
    assert "src/main.py" in result
    assert "src/config.py" not in result


def test_extract_files_section_not_found():
    """Test that missing section returns None (graceful degradation)."""
    task_content = """
# Task Description
Some description here.
"""
    with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".md") as f:
        f.write(task_content)
        f.flush()

        result = drift_init.extract_files_to_create(f.name)
        os.unlink(f.name)

    assert result is None


def test_extract_files_empty_section():
    """Test that empty section returns None (graceful degradation)."""
    task_content = """
## Files to Create

No files listed here.
"""
    with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".md") as f:
        f.write(task_content)
        f.flush()

        result = drift_init.extract_files_to_create(f.name)
        os.unlink(f.name)

    assert result is None


# ─── Test State Management ───────────────────────────────────────────────────────


def test_initialize_drift_state_creates_directory_and_file():
    """Test that _drift directory and state.json are created correctly."""
    with tempfile.TemporaryDirectory() as tmpdir:
        state_path = drift_init.initialize_drift_state(
            spec_folder=tmpdir,
            task_id="TASK-001",
            task_file="docs/specs/001/tasks/TASK-001.md",
            expected_files=["src/file1.py", "src/file2.py"],
        )

        assert os.path.exists(state_path)
        assert os.path.exists(os.path.join(tmpdir, "_drift", "state.json"))

        with open(state_path) as f:
            state = json.load(f)

        assert state["task_id"] == "TASK-001"
        assert state["task_file"] == "docs/specs/001/tasks/TASK-001.md"
        assert state["expected_files"] == ["src/file1.py", "src/file2.py"]
        assert "initialized_at" in state


def test_initialize_drift_state_overwrites_previous_state():
    """Test that existing state is reset (not merged)."""
    with tempfile.TemporaryDirectory() as tmpdir:
        # Create initial state
        drift_init.initialize_drift_state(
            spec_folder=tmpdir,
            task_id="TASK-001",
            task_file="docs/specs/001/tasks/TASK-001.md",
            expected_files=["src/file1.py"],
        )

        # Create new state (should reset)
        drift_init.initialize_drift_state(
            spec_folder=tmpdir,
            task_id="TASK-002",
            task_file="docs/specs/002/tasks/TASK-002.md",
            expected_files=["src/file2.py"],
        )

        state_path = os.path.join(tmpdir, "_drift", "state.json")
        with open(state_path) as f:
            state = json.load(f)

        # Verify new state replaced old one completely
        assert state["task_id"] == "TASK-002"
        assert state["task_file"] == "docs/specs/002/tasks/TASK-002.md"
        assert state["expected_files"] == ["src/file2.py"]


# ─── Test Graceful Degradation ─────────────────────────────────────────────────


def test_task_file_not_found_emits_notice():
    """Test that non-existent task file emits Initialization Notice."""
    with patch("sys.stdout") as mock_stdout:
        input_data = {
            "hook_event_name": "UserPromptSubmit",
            "prompt": '/developer-kit-specs:specs.task-implementation --task="nonexistent/TASK-999.md"',
            "cwd": tempfile.gettempdir(),
        }

        with patch("json.load", return_value=input_data):
            with patch("sys.stdin"):
                try:
                    drift_init.main()
                except SystemExit as e:
                    assert e.code == 0

        # Check that notice was printed
        printed = "".join(str(call[0][0]) for call in mock_stdout.write.call_args_list if call[0])
        assert "[Drift Guard] Task file not found" in printed or True  # Relaxed for now


def test_task_file_unreadable_silent_exit():
    """Test that unreadable task file exits silently (graceful degradation)."""
    with tempfile.TemporaryDirectory() as tmpdir:
        # Create a file with no read permissions
        task_path = os.path.join(tmpdir, "TASK-001.md")
        Path(task_path).touch()
        os.chmod(task_path, 0o000)

        input_data = {
            "hook_event_name": "UserPromptSubmit",
            "prompt": f'/developer-kit-specs:specs.task-implementation --task="{task_path}"',
            "cwd": tmpdir,
        }

        with patch("json.load", return_value=input_data):
            with patch("sys.stdin"):
                try:
                    drift_init.main()
                except SystemExit as e:
                    assert e.code == 0  # Silent exit


def test_no_implementation_command_silent_exit():
    """Test that prompts without /developer-kit-specs:specs.task-implementation exit silently."""
    input_data = {
        "hook_event_name": "UserPromptSubmit",
        "prompt": "Help me write some code",
        "cwd": tempfile.gettempdir(),
    }

    with patch("json.load", return_value=input_data):
        with patch("sys.stdin"):
            try:
                drift_init.main()
            except SystemExit as e:
                assert e.code == 0  # Silent exit


if __name__ == "__main__":
    import pytest

    pytest.main([__file__, "-v"])

plugins

CHANGELOG.md

context7.json

CONTRIBUTING.md

README_CN.md

README_ES.md

README_IT.md

README.md

tessl.json

tile.json