"""Shared fixtures for Code Migration environment tests.""" from __future__ import annotations import json import os import tempfile from pathlib import Path from unittest.mock import MagicMock, patch import pytest from code_migration.dataset_loader import Task # --------------------------------------------------------------------------- # Sample Task factory # --------------------------------------------------------------------------- def make_task(**overrides) -> Task: """Create a Task with sensible defaults. Override any field via kwargs.""" defaults = { "repo_name": "test-owner/test-repo", "repo_url": "https://github.com/test-owner/test-repo.git", "commit_hash": "abc123def456", "patch": "--- a.txt\n+++ a.txt\n@@ -1 +1 @@\n-old\n+new\n", "test_patch": "", "gold_patch": "--- src/main.py\n+++ src/main.py\n@@ -1 +1 @@\n-broken\n+fixed\n", "reproduction_target_date": "2020-01-01", "reproduction_target_version": "3.8.1", "migration_target_date": "2025-07-31", "migration_target_version": "3.12.11", "dockerfile": ( "FROM python:3.12.11\nWORKDIR /work\nCOPY . .\n" "RUN pip install -r requirements.txt\nCMD [\"python\", \"-m\", \"pytest\"]\n" ), "version_source": "default", "script_source": "requirements.txt", "dependency_versions": "numpy==1.26.0\npandas==2.1.0\n", "test_type": "pytest", "test_files": "tests/test_main.py", "test_count": 5, "related_modules": "numpy", "py_file_count": 10, "total_loc_python": 500, "difficulty": "Easy", "license": "MIT", } defaults.update(overrides) return Task(**defaults) @pytest.fixture def sample_task() -> Task: """A single sample Task.""" return make_task() # --------------------------------------------------------------------------- # Fixture JSONL file # --------------------------------------------------------------------------- def _task_to_dict(task: Task) -> dict: """Convert a Task dataclass to a plain dict.""" from dataclasses import asdict return asdict(task) @pytest.fixture def fixture_jsonl(tmp_path: Path) -> Path: """Write a small JSONL fixture with 3 tasks of varying difficulty.""" tasks = [ make_task(repo_name="owner/easy-repo", difficulty="Easy"), make_task(repo_name="owner/medium-repo", difficulty="Medium"), make_task(repo_name="owner/hard-repo", difficulty="Hard"), ] jsonl_path = tmp_path / "test_dataset.jsonl" with open(jsonl_path, "w") as fh: for t in tasks: fh.write(json.dumps(_task_to_dict(t)) + "\n") return jsonl_path @pytest.fixture def malformed_jsonl(tmp_path: Path) -> Path: """Write a JSONL file with a malformed line at line 2.""" good = json.dumps(_task_to_dict(make_task())) jsonl_path = tmp_path / "bad_dataset.jsonl" with open(jsonl_path, "w") as fh: fh.write(good + "\n") fh.write("{this is not valid json}\n") fh.write(good + "\n") return jsonl_path # --------------------------------------------------------------------------- # Temp workspace helpers # --------------------------------------------------------------------------- @pytest.fixture def workspace_dir(tmp_path: Path) -> Path: """Create a temporary workspace directory mimicking /work structure.""" ws = tmp_path / "workspace" ws.mkdir() # Create some sample files (ws / "src").mkdir() (ws / "src" / "main.py").write_text("print('hello')\n") (ws / "tests").mkdir() (ws / "tests" / "test_main.py").write_text("def test_one(): pass\n") (ws / "setup.py").write_text("from setuptools import setup\nsetup()\n") (ws / ".hidden_file").write_text("secret\n") (ws / "setup_test-owner__test-repo.sh").write_text("#!/bin/bash\n") (ws / "test_test-owner__test-repo.sh").write_text("#!/bin/bash\n") return ws # --------------------------------------------------------------------------- # Mock subprocess helpers # --------------------------------------------------------------------------- @pytest.fixture def mock_subprocess_run(): """Patch subprocess.run to prevent real process execution.""" with patch("subprocess.run") as mock_run: mock_run.return_value = MagicMock( returncode=0, stdout="", stderr="" ) yield mock_run