"""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