The function was removed in the dead code cleanup but the test file still imported it and had a TestCreatePyprojectToml class, causing ImportError. Co-authored-by: Kevin Turcios <undefined@users.noreply.github.com> Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
340 lines
12 KiB
Python
340 lines
12 KiB
Python
"""Tests for config schema and config writer."""
|
|
|
|
import json
|
|
|
|
import tomlkit
|
|
|
|
from codeflash.setup.config_schema import CodeflashConfig
|
|
from codeflash.setup.config_writer import (
|
|
_write_package_json,
|
|
_write_pyproject_toml,
|
|
remove_config,
|
|
write_config,
|
|
)
|
|
from codeflash.setup.detector import detect_project
|
|
|
|
|
|
class TestCodeflashConfig:
|
|
"""Tests for CodeflashConfig Pydantic model."""
|
|
|
|
def test_default_values(self):
|
|
"""Should have sensible defaults."""
|
|
config = CodeflashConfig(language="python")
|
|
|
|
assert config.language == "python"
|
|
assert config.module_root == "."
|
|
assert config.tests_root is None
|
|
assert config.formatter_cmds == []
|
|
assert config.git_remote == "origin"
|
|
assert config.disable_telemetry is False
|
|
|
|
def test_all_fields(self):
|
|
"""Should accept all fields."""
|
|
config = CodeflashConfig(
|
|
language="javascript",
|
|
module_root="src",
|
|
tests_root="tests",
|
|
test_framework="jest",
|
|
formatter_cmds=["npx prettier --write $file"],
|
|
ignore_paths=["dist", "node_modules"],
|
|
benchmarks_root="benchmarks",
|
|
git_remote="upstream",
|
|
disable_telemetry=True,
|
|
)
|
|
|
|
assert config.language == "javascript"
|
|
assert config.module_root == "src"
|
|
assert config.tests_root == "tests"
|
|
assert config.test_framework == "jest"
|
|
assert config.formatter_cmds == ["npx prettier --write $file"]
|
|
assert config.ignore_paths == ["dist", "node_modules"]
|
|
assert config.git_remote == "upstream"
|
|
assert config.disable_telemetry is True
|
|
|
|
def test_to_pyproject_dict(self):
|
|
"""Should convert to pyproject.toml format with kebab-case."""
|
|
config = CodeflashConfig(
|
|
language="python",
|
|
module_root="codeflash",
|
|
tests_root="tests",
|
|
formatter_cmds=["ruff format $file"],
|
|
ignore_paths=["dist"],
|
|
)
|
|
|
|
result = config.to_pyproject_dict()
|
|
|
|
assert result["module-root"] == "codeflash"
|
|
assert result["tests-root"] == "tests"
|
|
assert result["formatter-cmds"] == ["ruff format $file"]
|
|
assert result["ignore-paths"] == ["dist"]
|
|
# Should not include default values
|
|
assert "git-remote" not in result
|
|
assert "disable-telemetry" not in result
|
|
|
|
def test_to_pyproject_dict_minimal(self):
|
|
"""Should only include non-default values."""
|
|
config = CodeflashConfig(language="python", module_root="src")
|
|
|
|
result = config.to_pyproject_dict()
|
|
|
|
assert "module-root" in result
|
|
# Empty formatter should result in "disabled"
|
|
assert result.get("formatter-cmds") == ["disabled"]
|
|
|
|
def test_to_package_json_dict(self):
|
|
"""Should convert to package.json format with camelCase."""
|
|
config = CodeflashConfig(
|
|
language="javascript",
|
|
module_root="lib", # Non-default
|
|
formatter_cmds=["npx prettier --write $file"],
|
|
ignore_paths=["dist"],
|
|
disable_telemetry=True,
|
|
)
|
|
|
|
result = config.to_package_json_dict()
|
|
|
|
assert result["moduleRoot"] == "lib"
|
|
assert result["formatterCmds"] == ["npx prettier --write $file"]
|
|
assert result["ignorePaths"] == ["dist"]
|
|
assert result["disableTelemetry"] is True
|
|
# Should not include default values
|
|
assert "gitRemote" not in result
|
|
|
|
def test_to_package_json_dict_minimal(self):
|
|
"""Should be empty when all values are defaults."""
|
|
config = CodeflashConfig(
|
|
language="javascript",
|
|
module_root="src", # Default for JS
|
|
)
|
|
|
|
result = config.to_package_json_dict()
|
|
|
|
# src is a default, should not be included
|
|
assert "moduleRoot" not in result
|
|
|
|
def test_from_detected_project(self, tmp_path):
|
|
"""Should create config from DetectedProject."""
|
|
# Create a simple Python project
|
|
(tmp_path / "pyproject.toml").write_text('[project]\nname = "test"')
|
|
(tmp_path / "test").mkdir()
|
|
(tmp_path / "test" / "__init__.py").write_text("")
|
|
(tmp_path / "tests").mkdir()
|
|
|
|
detected = detect_project(tmp_path)
|
|
config = CodeflashConfig.from_detected_project(detected)
|
|
|
|
assert config.language == detected.language
|
|
assert config.test_framework == detected.test_runner
|
|
|
|
def test_from_pyproject_dict(self):
|
|
"""Should create config from pyproject.toml dict."""
|
|
data = {
|
|
"module-root": "src",
|
|
"tests-root": "tests",
|
|
"formatter-cmds": ["black $file"],
|
|
"disable-telemetry": True,
|
|
}
|
|
|
|
config = CodeflashConfig.from_pyproject_dict(data)
|
|
|
|
assert config.module_root == "src"
|
|
assert config.tests_root == "tests"
|
|
assert config.formatter_cmds == ["black $file"]
|
|
assert config.disable_telemetry is True
|
|
assert config.language == "python" # Default for pyproject
|
|
|
|
def test_from_package_json_dict(self):
|
|
"""Should create config from package.json dict."""
|
|
data = {"moduleRoot": "lib", "formatterCmds": ["npx prettier --write $file"], "disableTelemetry": True}
|
|
|
|
config = CodeflashConfig.from_package_json_dict(data)
|
|
|
|
assert config.module_root == "lib"
|
|
assert config.formatter_cmds == ["npx prettier --write $file"]
|
|
assert config.disable_telemetry is True
|
|
assert config.language == "javascript" # Default for package.json
|
|
|
|
|
|
class TestWritePyprojectToml:
|
|
"""Tests for writing to pyproject.toml."""
|
|
|
|
def test_creates_new_pyproject(self, tmp_path):
|
|
"""Should create pyproject.toml if it doesn't exist."""
|
|
config = CodeflashConfig(language="python", module_root="src", tests_root="tests")
|
|
|
|
success, message = _write_pyproject_toml(tmp_path, config)
|
|
|
|
assert success is True
|
|
assert (tmp_path / "pyproject.toml").exists()
|
|
|
|
# Verify content
|
|
content = (tmp_path / "pyproject.toml").read_text()
|
|
data = tomlkit.parse(content)
|
|
assert "tool" in data
|
|
assert "codeflash" in data["tool"]
|
|
assert data["tool"]["codeflash"]["module-root"] == "src"
|
|
|
|
def test_preserves_existing_content(self, tmp_path):
|
|
"""Should preserve existing pyproject.toml content."""
|
|
(tmp_path / "pyproject.toml").write_text(
|
|
'[project]\nname = "myapp"\nversion = "1.0.0"\n\n[tool.ruff]\nline-length = 120'
|
|
)
|
|
|
|
config = CodeflashConfig(language="python", module_root="src")
|
|
|
|
success, message = _write_pyproject_toml(tmp_path, config)
|
|
|
|
assert success is True
|
|
|
|
# Verify existing content preserved
|
|
content = (tmp_path / "pyproject.toml").read_text()
|
|
data = tomlkit.parse(content)
|
|
assert data["project"]["name"] == "myapp"
|
|
assert data["tool"]["ruff"]["line-length"] == 120
|
|
assert data["tool"]["codeflash"]["module-root"] == "src"
|
|
|
|
def test_updates_existing_codeflash_section(self, tmp_path):
|
|
"""Should update existing codeflash section."""
|
|
(tmp_path / "pyproject.toml").write_text('[tool.codeflash]\nmodule-root = "old"\ntests-root = "old_tests"')
|
|
|
|
config = CodeflashConfig(language="python", module_root="new", tests_root="new_tests")
|
|
|
|
success, message = _write_pyproject_toml(tmp_path, config)
|
|
|
|
assert success is True
|
|
|
|
content = (tmp_path / "pyproject.toml").read_text()
|
|
data = tomlkit.parse(content)
|
|
assert data["tool"]["codeflash"]["module-root"] == "new"
|
|
assert data["tool"]["codeflash"]["tests-root"] == "new_tests"
|
|
|
|
|
|
class TestWritePackageJson:
|
|
"""Tests for writing to package.json."""
|
|
|
|
def test_adds_codeflash_section(self, tmp_path):
|
|
"""Should add codeflash section to package.json."""
|
|
(tmp_path / "package.json").write_text(json.dumps({"name": "myapp", "version": "1.0.0"}, indent=2))
|
|
|
|
config = CodeflashConfig(
|
|
language="javascript", module_root="lib", formatter_cmds=["npx prettier --write $file"]
|
|
)
|
|
|
|
success, message = _write_package_json(tmp_path, config)
|
|
|
|
assert success is True
|
|
|
|
# Verify content
|
|
with (tmp_path / "package.json").open() as f:
|
|
data = json.load(f)
|
|
assert data["name"] == "myapp" # Preserved
|
|
assert "codeflash" in data
|
|
assert data["codeflash"]["moduleRoot"] == "lib"
|
|
|
|
def test_preserves_existing_content(self, tmp_path):
|
|
"""Should preserve existing package.json content."""
|
|
(tmp_path / "package.json").write_text(
|
|
json.dumps(
|
|
{"name": "myapp", "dependencies": {"lodash": "^4.17.0"}, "devDependencies": {"jest": "^29.0.0"}},
|
|
indent=2,
|
|
)
|
|
)
|
|
|
|
config = CodeflashConfig(language="javascript", module_root="lib")
|
|
|
|
success, message = _write_package_json(tmp_path, config)
|
|
|
|
assert success is True
|
|
|
|
with (tmp_path / "package.json").open() as f:
|
|
data = json.load(f)
|
|
assert data["dependencies"]["lodash"] == "^4.17.0"
|
|
assert data["devDependencies"]["jest"] == "^29.0.0"
|
|
|
|
def test_removes_empty_codeflash_section(self, tmp_path):
|
|
"""Should remove codeflash section if all defaults."""
|
|
(tmp_path / "package.json").write_text(
|
|
json.dumps({"name": "myapp", "codeflash": {"moduleRoot": "old"}}, indent=2)
|
|
)
|
|
|
|
# Config with all defaults - should result in empty dict
|
|
config = CodeflashConfig(
|
|
language="javascript",
|
|
module_root="src", # Default
|
|
)
|
|
|
|
success, message = _write_package_json(tmp_path, config)
|
|
|
|
assert success is True
|
|
|
|
with (tmp_path / "package.json").open() as f:
|
|
data = json.load(f)
|
|
# Empty codeflash section should be removed
|
|
assert "codeflash" not in data
|
|
|
|
def test_fails_if_no_package_json(self, tmp_path):
|
|
"""Should fail if package.json doesn't exist."""
|
|
config = CodeflashConfig(language="javascript")
|
|
|
|
success, message = _write_package_json(tmp_path, config)
|
|
|
|
assert success is False
|
|
assert message == f"No package.json found at {tmp_path}"
|
|
|
|
|
|
class TestWriteConfig:
|
|
"""Tests for the unified write_config function."""
|
|
|
|
def test_writes_to_pyproject_for_python(self, tmp_path):
|
|
"""Should write to pyproject.toml for Python projects."""
|
|
(tmp_path / "pyproject.toml").write_text('[project]\nname = "test"')
|
|
(tmp_path / "src").mkdir()
|
|
(tmp_path / "src" / "__init__.py").write_text("")
|
|
|
|
detected = detect_project(tmp_path)
|
|
success, message = write_config(detected)
|
|
|
|
assert success is True
|
|
assert message == f"Config saved to {tmp_path / 'pyproject.toml'}"
|
|
|
|
def test_writes_to_package_json_for_js(self, tmp_path):
|
|
"""Should write to package.json for JavaScript projects."""
|
|
(tmp_path / "package.json").write_text('{"name": "test"}')
|
|
(tmp_path / "src").mkdir()
|
|
|
|
detected = detect_project(tmp_path)
|
|
success, message = write_config(detected)
|
|
|
|
assert success is True
|
|
|
|
|
|
class TestRemoveConfig:
|
|
"""Tests for remove_config function."""
|
|
|
|
def test_removes_from_pyproject(self, tmp_path):
|
|
"""Should remove codeflash section from pyproject.toml."""
|
|
(tmp_path / "pyproject.toml").write_text('[project]\nname = "test"\n\n[tool.codeflash]\nmodule-root = "src"')
|
|
|
|
success, message = remove_config(tmp_path, "python")
|
|
|
|
assert success is True
|
|
|
|
content = (tmp_path / "pyproject.toml").read_text()
|
|
data = tomlkit.parse(content)
|
|
assert data["project"]["name"] == "test" # Preserved
|
|
assert "codeflash" not in data.get("tool", {})
|
|
|
|
def test_removes_from_package_json(self, tmp_path):
|
|
"""Should remove codeflash section from package.json."""
|
|
(tmp_path / "package.json").write_text(
|
|
json.dumps({"name": "test", "codeflash": {"moduleRoot": "src"}}, indent=2)
|
|
)
|
|
|
|
success, message = remove_config(tmp_path, "javascript")
|
|
|
|
assert success is True
|
|
|
|
with (tmp_path / "package.json").open() as f:
|
|
data = json.load(f)
|
|
assert data["name"] == "test" # Preserved
|
|
assert "codeflash" not in data
|