diff --git a/tests/test_converters.py b/tests/test_converters.py index a1cf1b7..d3f771d 100644 --- a/tests/test_converters.py +++ b/tests/test_converters.py @@ -1,116 +1,226 @@ -"""Tests for the converter module.""" +"""Tests for format converters.""" import json +import tempfile +from pathlib import Path + import pytest -from configconverter.converters import Converter -from configconverter.exceptions import ParseError, InvalidFormatError, UnsupportedConversionError +from config_converter.converters import ( + JsonConverter, + YamlConverter, + TomlConverter, + IniConverter, + BaseConverter, + ConversionError, +) -class TestConverter: - """Tests for the Converter class.""" +class TestJsonConverter: + """Tests for JSON converter.""" - @pytest.fixture - def converter(self): - return Converter() + def setup_method(self) -> None: + self.converter = JsonConverter() - def test_detect_json_format(self, converter): - content = '{"name": "test", "value": 123}' - assert converter.detect_format(content) == "json" + def test_read_valid_json(self) -> None: + """Test reading valid JSON file.""" + with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f: + json.dump({"key": "value", "number": 42}, f) + f.flush() + result = self.converter.read(f.name) + assert result == {"key": "value", "number": 42} - def test_detect_json_array(self, converter): - content = '[{"id": 1}, {"id": 2}]' - assert converter.detect_format(content) == "json" + def test_read_invalid_json(self) -> None: + """Test reading invalid JSON raises error.""" + with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f: + f.write("{invalid json}") + f.flush() + with pytest.raises(ConversionError): + self.converter.read(f.name) - def test_detect_yaml_format(self, converter): - content = 'name: test\nvalue: 123\n' - assert converter.detect_format(content) == "yaml" + def test_read_file_not_found(self) -> None: + """Test reading non-existent file raises error.""" + with pytest.raises(ConversionError): + self.converter.read("/nonexistent/path/file.json") - def test_detect_toml_format(self, converter): - content = 'name = "test"\nvalue = 123\n' - result = converter.detect_format(content) - assert result in ("toml", "yaml") - - def test_convert_json_to_yaml(self, converter): - json_content = '{"name": "test", "value": 123}' - result = converter.convert(json_content, "json", "yaml") - assert "name: test" in result - assert "value: 123" in result - - def test_convert_json_to_toml(self, converter): - json_content = '{"name": "test", "value": 123}' - result = converter.convert(json_content, "json", "toml") - assert 'name = "test"' in result - assert "value = 123" in result - - def test_convert_yaml_to_json(self, converter): - yaml_content = 'name: test\nvalue: 123\n' - result = converter.convert(yaml_content, "yaml", "json") - data = json.loads(result) - assert data["name"] == "test" - assert data["value"] == 123 - - def test_convert_yaml_to_toml(self, converter): - yaml_content = 'name: test\nvalue: 123\n' - result = converter.convert(yaml_content, "yaml", "toml") - assert 'name = "test"' in result - - def test_convert_toml_to_json(self, converter): - toml_content = 'name = "test"\nvalue = 123\n' - result = converter.convert(toml_content, "toml", "json") - data = json.loads(result) - assert data["name"] == "test" - assert data["value"] == 123 - - def test_convert_toml_to_yaml(self, converter): - toml_content = 'name = "test"\nvalue = 123\n' - result = converter.convert(toml_content, "toml", "yaml") - assert "name: test" in result - - def test_invalid_json_syntax(self, converter): - content = '{"name": "test",}' - with pytest.raises(ParseError): - converter.convert(content, "json", "yaml") - - def test_invalid_yaml_syntax(self, converter): - content = "name: test\n value: 123\n" - with pytest.raises(ParseError): - converter.convert(content, "yaml", "json") - - def test_invalid_toml_syntax(self, converter): - content = 'name = "test"\nvalue = 123\ninvalid line here\n' - with pytest.raises(ParseError): - converter.convert(content, "toml", "json") - - def test_unsupported_format(self, converter): - content = "some random text that is not valid" + def test_write_json(self) -> None: + """Test writing JSON file.""" + with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f: + output_path = f.name try: - converter.detect_format(content) - except (InvalidFormatError, Exception): - pass + self.converter.write({"test": "data"}, output_path) + with open(output_path, "r") as f: + result = json.load(f) + assert result == {"test": "data"} + finally: + Path(output_path).unlink(missing_ok=True) - def test_unsupported_conversion_direction(self, converter): - content = '{"name": "test"}' - with pytest.raises(UnsupportedConversionError): - converter.convert(content, "json", "xml") + def test_parse_json_string(self) -> None: + """Test parsing JSON string.""" + result = self.converter.parse('{"key": "value"}') + assert result == {"key": "value"} - def test_nested_structure_json_to_yaml(self, converter): - json_content = json.dumps({ - "server": { - "host": "localhost", - "port": 8080 - }, - "databases": [ - {"name": "db1", "enabled": True}, - {"name": "db2", "enabled": False} - ] - }) - result = converter.convert(json_content, "json", "yaml") - assert "server:" in result - assert "host: localhost" in result - assert "databases:" in result + def test_format_json_string(self) -> None: + """Test formatting data to JSON string.""" + result = self.converter.format({"key": "value"}) + assert result == '{\n "key": "value"\n}' - def test_case_insensitive_format(self, converter): - json_content = '{"name": "test"}' - result = converter.convert(json_content, "JSON", "YAML") - assert "name: test" in result + +class TestYamlConverter: + """Tests for YAML converter.""" + + def setup_method(self) -> None: + self.converter = YamlConverter() + + def test_read_valid_yaml(self) -> None: + """Test reading valid YAML file.""" + with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f: + f.write("key: value\nnumber: 42\n") + f.flush() + result = self.converter.read(f.name) + assert result == {"key": "value", "number": 42} + + def test_read_yaml_with_yml_extension(self) -> None: + """Test reading YAML file with yml extension.""" + with tempfile.NamedTemporaryFile(mode="w", suffix=".yml", delete=False) as f: + f.write("key: value\n") + f.flush() + result = self.converter.read(f.name) + assert result == {"key": "value"} + + def test_write_yaml(self) -> None: + """Test writing YAML file.""" + with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f: + output_path = f.name + try: + self.converter.write({"test": "data"}, output_path) + with open(output_path, "r") as f: + result = f.read() + assert "test: data" in result + finally: + Path(output_path).unlink(missing_ok=True) + + def test_parse_yaml_string(self) -> None: + """Test parsing YAML string.""" + result = self.converter.parse("key: value") + assert result == {"key": "value"} + + +class TestTomlConverter: + """Tests for TOML converter.""" + + def setup_method(self) -> None: + self.converter = TomlConverter() + + def test_read_valid_toml(self) -> None: + """Test reading valid TOML file.""" + with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f: + f.write('key = "value"\nnumber = 42\n') + f.flush() + result = self.converter.read(f.name) + assert result["key"] == "value" + assert result["number"] == 42 + + def test_write_toml(self) -> None: + """Test writing TOML file.""" + with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f: + output_path = f.name + try: + self.converter.write({"test": "data"}, output_path) + with open(output_path, "r") as f: + result = f.read() + assert 'test = "data"' in result + finally: + Path(output_path).unlink(missing_ok=True) + + def test_parse_toml_string(self) -> None: + """Test parsing TOML string.""" + result = self.converter.parse('key = "value"') + assert result["key"] == "value" + + +class TestIniConverter: + """Tests for INI converter.""" + + def setup_method(self) -> None: + self.converter = IniConverter() + + def test_read_valid_ini(self) -> None: + """Test reading valid INI file.""" + with tempfile.NamedTemporaryFile(mode="w", suffix=".ini", delete=False) as f: + f.write("[section]\nkey = value\n") + f.flush() + result = self.converter.read(f.name) + assert "section" in result + assert result["section"]["key"] == "value" + + def test_write_ini(self) -> None: + """Test writing INI file.""" + with tempfile.NamedTemporaryFile(mode="w", suffix=".ini", delete=False) as f: + output_path = f.name + try: + self.converter.write({"section": {"key": "value"}}, output_path) + with open(output_path, "r") as f: + result = f.read() + assert "[section]" in result + finally: + Path(output_path).unlink(missing_ok=True) + + def test_parse_ini_string(self) -> None: + """Test parsing INI string.""" + result = self.converter.parse("[section]\nkey = value") + assert "section" in result + + +class TestBaseConverter: + """Tests for base converter.""" + + def test_get_converter_json(self) -> None: + """Test getting JSON converter.""" + converter = BaseConverter.get_converter("json") + assert isinstance(converter, JsonConverter) + + def test_get_converter_yaml(self) -> None: + """Test getting YAML converter.""" + converter = BaseConverter.get_converter("yaml") + assert isinstance(converter, YamlConverter) + + def test_get_converter_toml(self) -> None: + """Test getting TOML converter.""" + converter = BaseConverter.get_converter("toml") + assert isinstance(converter, TomlConverter) + + def test_get_converter_ini(self) -> None: + """Test getting INI converter.""" + converter = BaseConverter.get_converter("ini") + assert isinstance(converter, IniConverter) + + def test_get_converter_unsupported(self) -> None: + """Test getting unsupported converter raises error.""" + with pytest.raises(ConversionError): + BaseConverter.get_converter("unsupported") + + def test_guess_format_json(self) -> None: + """Test guessing JSON format from extension.""" + assert BaseConverter.guess_format("file.json") == "json" + + def test_guess_format_yaml(self) -> None: + """Test guessing YAML format from extension.""" + assert BaseConverter.guess_format("file.yaml") == "yaml" + assert BaseConverter.guess_format("file.yml") == "yaml" + + def test_guess_format_toml(self) -> None: + """Test guessing TOML format from extension.""" + assert BaseConverter.guess_format("file.toml") == "toml" + + def test_guess_format_ini(self) -> None: + """Test guessing INI format from extension.""" + assert BaseConverter.guess_format("file.ini") == "ini" + + def test_get_supported_formats(self) -> None: + """Test getting supported formats.""" + formats = BaseConverter.get_supported_formats() + assert "json" in formats + assert "yaml" in formats + assert "toml" in formats + assert "ini" in formats