from pathlib import Path import pytest from omicron.ssg.config import SiteConfig, ConfigError, DEFAULT_ITEMS_PER_PAGE @pytest.mark.parametrize( "value, expected_origin, expected_path", [ (None, "", Path("/")), ("http://example.com/blog", "http://example.com", Path("/blog")), ("http://example.com", "http://example.com", Path("/")), ("//example.com/blog", "//example.com", Path("/blog")), ("/blog", "", Path("/blog")), ], ) def test_parse_base_url(value, expected_origin, expected_path): origin, path = SiteConfig.parse_base_url(value) assert origin == expected_origin assert path == expected_path @pytest.mark.parametrize( "value, expected_message", [ ("https://[::1", "invalid url format"), ("relative/path", "relative path"), ], ) def test_parse_base_url_error(value, expected_message): with pytest.raises(ConfigError, match=expected_message): origin, path = SiteConfig.parse_base_url(value) def test_from_dict_minimal(): config = SiteConfig.from_dict({"name": "My Site", "template": "plain"}) assert config.name == "My Site" assert config.template == "plain" assert config.items_per_page == DEFAULT_ITEMS_PER_PAGE assert config.origin == "" assert config.base_dir == Path("/") def test_from_dict_full(): config = SiteConfig.from_dict( { "name": "My Site", "template": "plain", "base_url": "http://example.com/blog", "items_per_page": 42, } ) assert config.name == "My Site" assert config.template == "plain" assert config.items_per_page == 42 assert config.origin == "http://example.com" assert config.base_dir == Path("/blog") MISSING = object() @pytest.mark.parametrize( "overrides, expected_message", [ ({"name": MISSING}, "must contain a name property"), ({"template": MISSING}, "must contain a template property"), ({"name": 123}, "name config property must be a string"), ({"template": 123}, "template config property must be a string"), ({"base_url": 123}, "base_url config property must be a string"), ({"base_url": "relative/path"}, "relative path"), ({"base_url": "https://[::1"}, "invalid url format"), ( {"items_per_page": "10"}, "items_per_page config property must be a positive integer", ), ( {"items_per_page": 0}, "items_per_page config property must be a positive integer", ), ( {"items_per_page": -1}, "items_per_page config property must be a positive integer", ), ], ) def test_from_dict_error(overrides, expected_message): config = {"name": "My Site", "template": "plain"} for key, value in overrides.items(): if value is MISSING: config.pop(key, None) else: config[key] = value with pytest.raises(ConfigError, match=expected_message): SiteConfig.from_dict(config) def test_from_file_minimal(tmp_path): path = tmp_path / "config.yml" path.write_text("name: My Site\ntemplate: plain\n") config = SiteConfig.from_file(path) assert config.name == "My Site" assert config.template == "plain" assert config.items_per_page == DEFAULT_ITEMS_PER_PAGE assert config.origin == "" assert config.base_dir == Path("/") def test_from_file_full(tmp_path): path = tmp_path / "config.yml" path.write_text( "name: My Site\n" "template: plain\n" "base_url: http://example.com/blog\n" "items_per_page: 42\n" ) config = SiteConfig.from_file(path) assert config.name == "My Site" assert config.template == "plain" assert config.items_per_page == 42 assert config.origin == "http://example.com" assert config.base_dir == Path("/blog") def test_from_file_missing(tmp_path): path = tmp_path / "config.yml" with pytest.raises(ConfigError, match="config file missing"): SiteConfig.from_file(path) @pytest.mark.parametrize( "yaml_text, expected_message", [ ("- a\n- b\n", "must be a YAML mapping"), ("just a string\n", "must be a YAML mapping"), ("123: value\n", "must be a YAML mapping"), ("name: [1, 2]\n", "must be a YAML mapping"), ("name: true\n", "must be a YAML mapping"), (":\n bad: yaml: here\n", "must be a valid YAML file"), ("template: plain\n", "must contain a name property"), ("name: My Site\n", "must contain a template property"), ( "name: 123\ntemplate: plain\n", "name config property must be a string", ), ( "name: My Site\ntemplate: 123\n", "template config property must be a string", ), ( "name: My Site\ntemplate: plain\nbase_url: 123\n", "base_url config property must be a string", ), ( "name: My Site\ntemplate: plain\nbase_url: relative/path\n", "relative path", ), ( "name: My Site\ntemplate: plain\nbase_url: https://[::1\n", "invalid url format", ), ( 'name: My Site\ntemplate: plain\nitems_per_page: "10"\n', "items_per_page config property must be a positive integer", ), ( "name: My Site\ntemplate: plain\nitems_per_page: 0\n", "items_per_page config property must be a positive integer", ), ( "name: My Site\ntemplate: plain\nitems_per_page: -1\n", "items_per_page config property must be a positive integer", ), ], ) def test_from_file_error(tmp_path, yaml_text, expected_message): path = tmp_path / "config.yml" path.write_text(yaml_text) with pytest.raises(ConfigError, match=expected_message): SiteConfig.from_file(path)