275
tests/test_cli.py
Normal file
275
tests/test_cli.py
Normal file
@@ -0,0 +1,275 @@
|
||||
"""Tests for CLI commands."""
|
||||
import json
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
from click.testing import CliRunner
|
||||
|
||||
from i18n_key_sync.cli import main
|
||||
|
||||
|
||||
class TestCLIExtract:
|
||||
"""Tests for extract command."""
|
||||
|
||||
def test_extract_from_python_file(self, sample_python_code):
|
||||
"""Test extracting keys from Python file."""
|
||||
with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f:
|
||||
f.write(sample_python_code)
|
||||
f.flush()
|
||||
f_path = f.name
|
||||
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["extract", f_path])
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert "hello" in result.output or "hello" in result.output.lower()
|
||||
assert "goodbye" in result.output or "goodbye" in result.output.lower()
|
||||
|
||||
Path(f_path).unlink()
|
||||
|
||||
def test_extract_json_output(self, sample_python_code):
|
||||
"""Test extract with JSON output format."""
|
||||
with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f:
|
||||
f.write('_("test_key")')
|
||||
f.flush()
|
||||
f_path = f.name
|
||||
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["--output-format", "json", "extract", f_path])
|
||||
|
||||
assert result.exit_code == 0
|
||||
data = json.loads(result.output)
|
||||
assert "test_key" in data
|
||||
|
||||
Path(f_path).unlink()
|
||||
|
||||
def test_extract_with_patterns(self, sample_python_code):
|
||||
"""Test extract with custom patterns."""
|
||||
with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as f:
|
||||
f.write('t("custom_key")')
|
||||
f.flush()
|
||||
f_path = f.name
|
||||
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["extract", f_path, "--patterns", "t"])
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert "custom_key" in result.output
|
||||
|
||||
Path(f_path).unlink()
|
||||
|
||||
|
||||
class TestCLIValidate:
|
||||
"""Tests for validate command."""
|
||||
|
||||
def test_validate_valid_keys(self, temp_project_dir, temp_locale_dir):
|
||||
"""Test validation with all keys present."""
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, [
|
||||
"--locale-dir", str(temp_locale_dir),
|
||||
"validate",
|
||||
str(temp_project_dir / "src"),
|
||||
])
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert "valid" in result.output.lower() or "matching" in result.output.lower()
|
||||
|
||||
def test_validate_missing_keys(self, tmp_path, temp_locale_dir):
|
||||
"""Test validation with missing keys."""
|
||||
src_dir = tmp_path / "src"
|
||||
src_dir.mkdir()
|
||||
|
||||
code_file = src_dir / "main.py"
|
||||
code_file.write_text('_("nonexistent_key")')
|
||||
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, [
|
||||
"--locale-dir", str(temp_locale_dir),
|
||||
"validate",
|
||||
str(src_dir),
|
||||
])
|
||||
|
||||
assert result.exit_code in [0, 1]
|
||||
assert "missing" in result.output.lower() or "nonexistent_key" in result.output
|
||||
|
||||
def test_validate_strict_mode(self, tmp_path, temp_locale_dir):
|
||||
"""Test validation in strict mode."""
|
||||
src_dir = tmp_path / "src"
|
||||
src_dir.mkdir()
|
||||
|
||||
code_file = src_dir / "main.py"
|
||||
code_file.write_text('_("missing_key")\n_("unused_in_locale")')
|
||||
|
||||
locale_file = temp_locale_dir / "en.json"
|
||||
locale_data = json.loads(locale_file.read_text())
|
||||
locale_data["unused_in_locale"] = "Unused"
|
||||
locale_file.write_text(json.dumps(locale_data, indent=2))
|
||||
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, [
|
||||
"--locale-dir", str(temp_locale_dir),
|
||||
"validate",
|
||||
str(src_dir),
|
||||
"--strict",
|
||||
])
|
||||
|
||||
assert result.exit_code == 3
|
||||
|
||||
def test_validate_json_output(self, temp_project_dir, temp_locale_dir):
|
||||
"""Test validate with JSON output."""
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, [
|
||||
"--output-format", "json",
|
||||
"--locale-dir", str(temp_locale_dir),
|
||||
"validate",
|
||||
str(temp_project_dir / "src"),
|
||||
])
|
||||
|
||||
assert result.exit_code == 0
|
||||
data = json.loads(result.output)
|
||||
assert "missing_keys" in data
|
||||
assert "unused_keys" in data
|
||||
assert "matching_keys" in data
|
||||
|
||||
|
||||
class TestCLISync:
|
||||
"""Tests for sync command."""
|
||||
|
||||
def test_sync_dry_run(self, tmp_path, temp_locale_dir):
|
||||
"""Test sync in dry run mode."""
|
||||
src_dir = tmp_path / "src"
|
||||
src_dir.mkdir()
|
||||
|
||||
code_file = src_dir / "main.py"
|
||||
code_file.write_text('_("new_key")')
|
||||
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, [
|
||||
"--locale-dir", str(temp_locale_dir),
|
||||
"sync",
|
||||
str(src_dir),
|
||||
"--dry-run",
|
||||
])
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert "DRY RUN" in result.output or "dry" in result.output.lower()
|
||||
|
||||
locale_file = temp_locale_dir / "en.json"
|
||||
locale_data = json.loads(locale_file.read_text())
|
||||
assert "new_key" not in locale_data
|
||||
|
||||
def test_sync_actual(self, tmp_path, temp_locale_dir):
|
||||
"""Test actual sync modifies files."""
|
||||
src_dir = tmp_path / "src"
|
||||
src_dir.mkdir()
|
||||
|
||||
code_file = src_dir / "main.py"
|
||||
code_file.write_text('_("new_sync_key")')
|
||||
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, [
|
||||
"--locale-dir", str(temp_locale_dir),
|
||||
"sync",
|
||||
str(src_dir),
|
||||
])
|
||||
|
||||
assert result.exit_code == 0
|
||||
|
||||
locale_file = temp_locale_dir / "en.json"
|
||||
locale_data = json.loads(locale_file.read_text())
|
||||
assert "new_sync_key" in locale_data
|
||||
|
||||
def test_sync_custom_placeholder(self, tmp_path, temp_locale_dir):
|
||||
"""Test sync with custom placeholder value."""
|
||||
src_dir = tmp_path / "src"
|
||||
src_dir.mkdir()
|
||||
|
||||
code_file = src_dir / "main.py"
|
||||
code_file.write_text('_("placeholder_key")')
|
||||
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, [
|
||||
"--locale-dir", str(temp_locale_dir),
|
||||
"sync",
|
||||
str(src_dir),
|
||||
"--value", "TRANSLATE_ME",
|
||||
])
|
||||
|
||||
assert result.exit_code == 0
|
||||
|
||||
locale_file = temp_locale_dir / "en.json"
|
||||
locale_data = json.loads(locale_file.read_text())
|
||||
assert locale_data["placeholder_key"] == "TRANSLATE_ME"
|
||||
|
||||
|
||||
class TestCLIReport:
|
||||
"""Tests for report command."""
|
||||
|
||||
def test_report_generates_output(self, temp_project_dir, temp_locale_dir):
|
||||
"""Test report command generates output."""
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, [
|
||||
"--locale-dir", str(temp_locale_dir),
|
||||
"report",
|
||||
str(temp_project_dir / "src"),
|
||||
])
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert len(result.output) > 0
|
||||
|
||||
def test_report_json_format(self, temp_project_dir, temp_locale_dir):
|
||||
"""Test report with JSON format."""
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, [
|
||||
"--locale-dir", str(temp_locale_dir),
|
||||
"report",
|
||||
str(temp_project_dir / "src"),
|
||||
"--format", "json",
|
||||
])
|
||||
|
||||
assert result.exit_code == 0
|
||||
data = json.loads(result.output)
|
||||
assert "summary" in data
|
||||
|
||||
def test_report_markdown_format(self, temp_project_dir, temp_locale_dir):
|
||||
"""Test report with markdown format."""
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, [
|
||||
"--locale-dir", str(temp_locale_dir),
|
||||
"report",
|
||||
str(temp_project_dir / "src"),
|
||||
"--format", "markdown",
|
||||
])
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert "# i18n Key Report" in result.output
|
||||
|
||||
def test_report_to_file(self, temp_project_dir, temp_locale_dir, tmp_path):
|
||||
"""Test report output to file."""
|
||||
output_file = tmp_path / "report.md"
|
||||
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, [
|
||||
"--locale-dir", str(temp_locale_dir),
|
||||
"report",
|
||||
str(temp_project_dir / "src"),
|
||||
"--output", str(output_file),
|
||||
"--format", "markdown",
|
||||
])
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert output_file.exists()
|
||||
content = output_file.read_text()
|
||||
assert "# i18n Key Report" in content
|
||||
|
||||
|
||||
class TestCLIVersion:
|
||||
"""Tests for version flag."""
|
||||
|
||||
def test_version_flag(self):
|
||||
"""Test --version flag displays version."""
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["--version"])
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert "i18n-key-sync" in result.output
|
||||
Reference in New Issue
Block a user