diff --git a/tests/integration/test_cli.py b/tests/integration/test_cli.py new file mode 100644 index 0000000..d6393c4 --- /dev/null +++ b/tests/integration/test_cli.py @@ -0,0 +1,216 @@ +"""Integration tests for ConfigForge CLI.""" + +import json +import os +import tempfile + +import pytest +from click.testing import CliRunner + +from configforge.cli import main + + +class TestCLIValidateCommand: + """Integration tests for the validate command.""" + + def test_validate_command_help(self): + """Test validate command help output.""" + runner = CliRunner() + result = runner.invoke(main, ["validate", "--help"]) + assert result.exit_code == 0 + assert "CONFIG_FILE" in result.output + assert "SCHEMA_FILE" in result.output + + def test_validate_missing_config_file(self): + """Test validate with missing config file.""" + runner = CliRunner() + result = runner.invoke(main, ["validate", "nonexistent.json", "schema.json"]) + assert result.exit_code != 0 + assert "not found" in result.output.lower() or result.exit_code != 0 + + def test_validate_missing_schema_file(self): + """Test validate with missing schema file.""" + with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f: + json.dump({"key": "value"}, f) + config_file = f.name + + try: + runner = CliRunner() + result = runner.invoke(main, ["validate", config_file, "nonexistent.json"]) + assert result.exit_code != 0 + finally: + os.unlink(config_file) + + +class TestCLIConvertCommand: + """Integration tests for the convert command.""" + + def test_convert_command_help(self): + """Test convert command help output.""" + runner = CliRunner() + result = runner.invoke(main, ["convert", "--help"]) + assert result.exit_code == 0 + assert "INPUT_FILE" in result.output + + def test_convert_json_to_yaml(self, sample_json_config): + """Test converting JSON to YAML.""" + with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f: + json.dump(sample_json_config, f) + input_file = f.name + + try: + runner = CliRunner() + result = runner.invoke(main, ["convert", input_file, "--format", "yaml"]) + assert result.exit_code == 0 + assert "database:" in result.output + finally: + os.unlink(input_file) + + def test_convert_json_to_toml(self, sample_json_config): + """Test converting JSON to TOML.""" + with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f: + json.dump(sample_json_config, f) + input_file = f.name + + try: + runner = CliRunner() + result = runner.invoke(main, ["convert", input_file, "--format", "toml"]) + assert result.exit_code == 0 + assert "[database]" in result.output + finally: + os.unlink(input_file) + + def test_convert_json_to_env(self, sample_json_config): + """Test converting JSON to ENV.""" + with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f: + json.dump(sample_json_config, f) + input_file = f.name + + try: + runner = CliRunner() + result = runner.invoke(main, ["convert", input_file, "--format", "env"]) + assert result.exit_code == 0 + assert "host" in result.output + finally: + os.unlink(input_file) + + def test_convert_with_output_file(self, sample_json_config): + """Test converting with output file.""" + with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f: + json.dump(sample_json_config, f) + input_file = f.name + + with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f: + output_file = f.name + + try: + runner = CliRunner() + result = runner.invoke(main, ["convert", input_file, "-o", output_file]) + assert result.exit_code == 0 + assert os.path.exists(output_file) + with open(output_file) as f: + content = f.read() + assert "database:" in content + finally: + os.unlink(input_file) + if os.path.exists(output_file): + os.unlink(output_file) + + +class TestCLIGenerateCommand: + """Integration tests for the generate command.""" + + def test_generate_command_help(self): + """Test generate command help output.""" + runner = CliRunner() + result = runner.invoke(main, ["generate", "--help"]) + assert result.exit_code == 0 + assert "INPUT_FILE" in result.output + + def test_generate_from_schema(self, sample_json_schema): + """Test generating TypeScript from schema.""" + with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f: + json.dump(sample_json_schema, f) + input_file = f.name + + try: + runner = CliRunner() + result = runner.invoke(main, ["generate", input_file, "--interface-name", "Config"]) + assert result.exit_code == 0 + assert "interface Config" in result.output + finally: + os.unlink(input_file) + + def test_generate_from_data(self, sample_json_config): + """Test generating TypeScript from config data.""" + with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f: + json.dump(sample_json_config, f) + input_file = f.name + + try: + runner = CliRunner() + result = runner.invoke(main, ["generate", input_file, "--from-data"]) + assert result.exit_code == 0 + assert "interface" in result.output + finally: + os.unlink(input_file) + + +class TestCLISchemaCommand: + """Integration tests for the schema command.""" + + def test_schema_command_help(self): + """Test schema command help output.""" + runner = CliRunner() + result = runner.invoke(main, ["schema", "--help"]) + assert result.exit_code == 0 + assert "--output" in result.output + + def test_schema_from_config(self, sample_json_config): + """Test generating schema from config file.""" + with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f: + json.dump(sample_json_config, f) + config_file = f.name + + with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f: + output_file = f.name + + try: + runner = CliRunner() + result = runner.invoke(main, ["schema", "--from-config", config_file, "-o", output_file]) + assert result.exit_code == 0 + assert os.path.exists(output_file) + with open(output_file) as f: + schema = json.load(f) + assert "properties" in schema + finally: + os.unlink(config_file) + if os.path.exists(output_file): + os.unlink(output_file) + + +class TestCLIMain: + """Integration tests for main CLI entry point.""" + + def test_main_help(self): + """Test main help output.""" + runner = CliRunner() + result = runner.invoke(main, ["--help"]) + assert result.exit_code == 0 + assert "validate" in result.output + assert "convert" in result.output + assert "generate" in result.output + assert "schema" in result.output + + def test_main_version(self): + """Test version output.""" + runner = CliRunner() + result = runner.invoke(main, ["--version"]) + assert result.exit_code == 0 + assert "ConfigForge" in result.output + + def test_main_invalid_command(self): + """Test invalid command handling.""" + runner = CliRunner() + result = runner.invoke(main, ["invalid-command"]) + assert result.exit_code != 0