Compare commits

...
2 Commits
4 changed files with 194 additions and 21 deletions
+3
View File
@@ -42,6 +42,9 @@ class SiteConfig:
else: else:
path = Path("/") path = Path("/")
if not path.is_absolute():
raise ConfigError("base_url config property must not be a relative path")
return (origin, path) return (origin, path)
@staticmethod @staticmethod
-2
View File
@@ -183,8 +183,6 @@ class Site:
"base_url config value is missing a domain name, " "base_url config value is missing a domain name, "
"can't add canonical url to content" "can't add canonical url to content"
) )
if not self.config.base_dir.is_absolute():
raise ConfigError("base_url config value must be an absolute path")
self.discover() self.discover()
outputs: list[Output] = [*self.directories, *self.content] outputs: list[Output] = [*self.directories, *self.content]
for output in sorted(outputs, key=lambda o: o.destination.as_posix()): for output in sorted(outputs, key=lambda o: o.destination.as_posix()):
+188
View File
@@ -0,0 +1,188 @@
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)
+3 -19
View File
@@ -3,21 +3,6 @@ import pytest
from omicron.ssg.output import ContentError, Directory, OutputError from omicron.ssg.output import ContentError, Directory, OutputError
from omicron.ssg.site import ConfigError, Site from omicron.ssg.site import ConfigError, Site
# @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 = Site.parse_base_url(value)
# assert origin == expected_origin
# assert path == expected_path
def test_discover_raises_on_duplicate_destination(make_site): def test_discover_raises_on_duplicate_destination(make_site):
site = make_site("duplicate_slug") site = make_site("duplicate_slug")
@@ -58,13 +43,12 @@ def test_read_config_errors(site_dir):
Site(path) Site(path)
def test_build_raises_for_relative_base_url(site_dir): def test_site_relative_base_url(site_dir):
path = site_dir("thin_site") path = site_dir("thin_site")
(path / "config.yml").write_text("name: test\ntemplate: plain\nbase_url: blog\n") (path / "config.yml").write_text("name: test\ntemplate: plain\nbase_url: blog\n")
site = Site(path) with pytest.raises(ConfigError, match="relative path"):
with pytest.raises(ConfigError, match="absolute path"): site = Site(path)
site.build()
def test_discover_skips_drafts_by_default(make_site): def test_discover_skips_drafts_by_default(make_site):