Spaces:
Sleeping
Sleeping
| import pytest | |
| import yaml | |
| import json | |
| from unittest.mock import patch | |
| # Import the Settings class specifically to allow for instance management in tests | |
| from blossomtune_gradio.settings import Settings | |
| def reset_settings_singleton(): | |
| """ | |
| Fixture to automatically reset the Settings singleton before each test. | |
| This allows creating a new, clean instance for each test scenario by | |
| directly resetting the internal `_instance` variable. | |
| """ | |
| Settings._instance = None | |
| def valid_config_files(tmp_path): | |
| """Creates a valid config and schema file in a temporary directory.""" | |
| config_dir = tmp_path / "config" | |
| config_dir.mkdir() | |
| config_content = { | |
| "ui": { | |
| "welcome_message_md": "Hello, {{ name }}!", | |
| "error_message_md": "An error occurred.", | |
| } | |
| } | |
| schema_content = { | |
| "$schema": "http://json-schema.org/draft-07/schema#", | |
| "type": "object", | |
| "properties": { | |
| "ui": { | |
| "type": "object", | |
| "properties": { | |
| "welcome_message_md": {"type": "string"}, | |
| "error_message_md": {"type": "string"}, | |
| }, | |
| "required": ["welcome_message_md", "error_message_md"], | |
| } | |
| }, | |
| "required": ["ui"], | |
| } | |
| config_path = config_dir / "blossomtune.yaml" | |
| schema_path = config_dir / "blossomtune.schema.json" | |
| with open(config_path, "w") as f: | |
| yaml.dump(config_content, f) | |
| with open(schema_path, "w") as f: | |
| json.dump(schema_content, f) | |
| return str(config_path), str(schema_path) | |
| def test_load_valid_config(valid_config_files): | |
| """Tests successful loading of a valid configuration.""" | |
| config_path, schema_path = valid_config_files | |
| settings = Settings(config_path=config_path, schema_path=schema_path) | |
| assert "welcome_message_md" in settings.templates | |
| assert "error_message_md" in settings.templates | |
| rendered_text = settings.get_text("welcome_message_md", name="World") | |
| assert rendered_text == "Hello, World!" | |
| def test_missing_config_file(tmp_path, capsys): | |
| """Tests handling of a missing configuration file and captures stdout.""" | |
| schema_path = tmp_path / "schema.json" | |
| schema_path.touch() # Create an empty schema for the test | |
| settings = Settings(config_path="nonexistent.yaml", schema_path=str(schema_path)) | |
| assert not settings.templates | |
| # Check that an error was printed to the console | |
| captured = capsys.readouterr() | |
| assert "Error: Configuration file not found" in captured.out | |
| def test_invalid_yaml_file(tmp_path, capsys): | |
| """Tests handling of a syntactically incorrect YAML file.""" | |
| config_path = tmp_path / "invalid.yaml" | |
| schema_path = tmp_path / "schema.json" | |
| schema_path.touch() | |
| with open(config_path, "w") as f: | |
| f.write("ui: { welcome: 'Hello'") # Malformed YAML | |
| settings = Settings(config_path=str(config_path), schema_path=str(schema_path)) | |
| assert not settings.templates | |
| captured = capsys.readouterr() | |
| assert "Error parsing YAML file" in captured.out | |
| def test_schema_validation_failure(tmp_path, capsys): | |
| """Tests that validation fails if the config doesn't match the schema.""" | |
| config_dir = tmp_path / "config" | |
| config_dir.mkdir() | |
| # Config is missing the required 'error_message' | |
| config_content = {"ui": {"welcome_message_md": "Hello!"}} | |
| schema_content = { | |
| "type": "object", | |
| "properties": {"ui": {"type": "object", "required": ["error_message_md"]}}, | |
| } | |
| config_path = config_dir / "blossomtune.yaml" | |
| schema_path = config_dir / "blossomtune.schema.json" | |
| with open(config_path, "w") as f: | |
| yaml.dump(config_content, f) | |
| with open(schema_path, "w") as f: | |
| json.dump(schema_content, f) | |
| settings = Settings(config_path=str(config_path), schema_path=str(schema_path)) | |
| assert not settings.templates | |
| captured = capsys.readouterr() | |
| assert "Error: YAML configuration is invalid" in captured.out | |
| def test_load_from_env_variable(mock_config_env, valid_config_files): | |
| """Tests loading the config path from an environment variable.""" | |
| config_path, schema_path = valid_config_files | |
| mock_config_env = config_path | |
| # By patching the config module, the Settings constructor will pick it up | |
| with patch("blossomtune_gradio.settings.cfg.BLOSSOMTUNE_CONFIG", mock_config_env): | |
| settings = Settings(schema_path=schema_path) | |
| assert settings.config_path == config_path | |
| rendered_text = settings.get_text("welcome_message_md", name="From Env") | |
| assert rendered_text == "Hello, From Env!" | |
| def test_singleton_pattern(valid_config_files): | |
| """Tests that the same instance of Settings is always returned.""" | |
| config_path, schema_path = valid_config_files | |
| s1 = Settings(config_path=config_path, schema_path=schema_path) | |
| s2 = Settings() # Should return the same instance as s1 | |
| assert s1 is s2 | |
| # Verify s2 is configured, proving it's the same instance | |
| assert "welcome_message_md" in s2.templates | |