File size: 5,982 Bytes
31e282f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
"""
conftest.py -- Shared pytest fixtures for the ctx test suite.
"""

import sys
import textwrap
from pathlib import Path

import pytest

# ---------------------------------------------------------------------------
# Ensure the project root is on sys.path so imports work from any working dir
# ---------------------------------------------------------------------------
_PROJECT_ROOT = Path(__file__).resolve().parent.parent
if str(_PROJECT_ROOT) not in sys.path:
    sys.path.insert(0, str(_PROJECT_ROOT))

from ctx.core.wiki.wiki_sync import ensure_wiki  # noqa: E402  (import after path manipulation)


# ---------------------------------------------------------------------------
# Markers
# ---------------------------------------------------------------------------


def pytest_addoption(parser: pytest.Parser) -> None:
    """Register opt-in integration gates."""
    parser.addoption(
        "--run-live-mcp",
        action="store_true",
        default=False,
        help="run trusted live MCP compatibility tests",
    )
    parser.addoption(
        "--live-mcp-config",
        action="append",
        default=[],
        metavar="PATH",
        help="trusted live MCP server config JSON; may be passed more than once",
    )


def pytest_configure(config: pytest.Config) -> None:
    """Register custom markers so pytest doesn't warn on unknown-mark usage.

    ``integration`` is used by tests that load real models (e.g. MiniLM for
    the similarity precision/recall harness). Skip them in fast CI with
    ``-m 'not integration'``.
    """
    config.addinivalue_line(
        "markers",
        "integration: tests that load real embedders or external services "
        "(skip with -m 'not integration')",
    )


# ---------------------------------------------------------------------------
# Fixtures
# ---------------------------------------------------------------------------


@pytest.fixture()
def project_root() -> Path:
    """Return the ctx project root directory as a Path."""
    return _PROJECT_ROOT


@pytest.fixture()
def tmp_wiki(tmp_path: Path) -> Path:
    """
    Create a temporary wiki directory using wiki_sync.ensure_wiki.

    The returned Path is the wiki root (tmp_path / "skill-wiki").
    All required subdirectories and seed files are created by ensure_wiki.
    """
    wiki_dir = tmp_path / "skill-wiki"
    ensure_wiki(str(wiki_dir))
    return wiki_dir


@pytest.fixture()
def tmp_skills_dir(tmp_path: Path) -> Path:
    """
    Create a temporary skills directory with three fake SKILL.md files:

    - short-skill/SKILL.md  (~50 lines)
    - medium-skill/SKILL.md (~100 lines)
    - long-skill/SKILL.md   (~250 lines)
    """
    skills_dir = tmp_path / "skills"

    # ── Short skill (~50 lines) ───────────────────────────────────────────
    short_dir = skills_dir / "short-skill"
    short_dir.mkdir(parents=True)
    short_lines = textwrap.dedent("""\
        ---
        title: short-skill
        tags: [python, testing]
        ---

        # Short Skill

        ## Overview
        A short demonstration skill used for testing.

        ## Usage
        Import and call the helper function.

        ## Examples
        ```python
        from short_skill import helper
        helper()
        ```
    """)
    # Pad to ~50 lines
    short_lines += "\n".join(f"# line {i}" for i in range(1, 35)) + "\n"
    (short_dir / "SKILL.md").write_text(short_lines, encoding="utf-8")

    # ── Medium skill (~100 lines) ─────────────────────────────────────────
    medium_dir = skills_dir / "medium-skill"
    medium_dir.mkdir(parents=True)
    medium_lines = textwrap.dedent("""\
        ---
        title: medium-skill
        tags: [python, fastapi]
        ---

        # Medium Skill

        ## Overview
        A medium-length demonstration skill used for testing.

        ## Background
        Provides patterns for FastAPI service construction.

        ## Usage
        Configure the app factory and mount routers.

        ## Configuration
        Set environment variables before startup.

        ## Examples
        ```python
        from medium_skill import create_app
        app = create_app()
        ```

        ## Notes
        Remember to add lifespan handlers.
    """)
    # Pad to ~100 lines
    medium_lines += "\n".join(f"# line {i}" for i in range(1, 73)) + "\n"
    (medium_dir / "SKILL.md").write_text(medium_lines, encoding="utf-8")

    # ── Long skill (~250 lines) ───────────────────────────────────────────
    long_dir = skills_dir / "long-skill"
    long_dir.mkdir(parents=True)
    long_lines = textwrap.dedent("""\
        ---
        title: long-skill
        tags: [python, architecture, patterns]
        ---

        # Long Skill

        ## Overview
        A long demonstration skill used for testing the line_threshold logic.

        ## Stage 1: Discovery
        Locate relevant files in the repository.

        ## Stage 2: Analysis
        Parse and classify each file by type.

        ## Stage 3: Extraction
        Pull out the key patterns and idioms.

        ## Stage 4: Synthesis
        Combine findings into a coherent summary.

        ## Stage 5: Output
        Write the final report to disk.

        ## Configuration Reference
        All options are documented below.

        ## Advanced Usage
        Chain multiple stages for batch processing.

        ## Troubleshooting
        Common issues and their resolutions.

        ## See Also
        Related skills and external references.
    """)
    # Pad to ~250 lines
    long_lines += "\n".join(f"# line {i}" for i in range(1, 210)) + "\n"
    (long_dir / "SKILL.md").write_text(long_lines, encoding="utf-8")

    return skills_dir