@@ -0,0 +1,423 @@
1 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ """Tests for utils.enhance."""
2 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ import json
3 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ import os
4 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ import tempfile
5 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ import unittest
6 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ from unittest.mock import patch
7 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
8 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ from hugoifier.utils.enhance import (
9 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ _chunks,
10 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ _find_baseof,
11 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ _parse_ai_json,
12 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ _parse_frontmatter,
13 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ _read_body,
14 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ _read_site_context,
15 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ _seo_og_tags,
16 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ _update_frontmatter,
17 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ alt_text,
18 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ generate,
19 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ seo,
20 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ )
21 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
22 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
23 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestReadSiteContext(unittest.TestCase):
24 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_reads_title_from_hugo_toml(self):
25 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
26 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(os.path.join(tmp, "hugo.toml"), "w") as f:
27 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write('title = "My Test Site"\n')
28 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ctx = _read_site_context(tmp)
29 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(ctx["title"], "My Test Site")
30 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
31 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_reads_title_from_config_toml(self):
32 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
33 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(os.path.join(tmp, "config.toml"), "w") as f:
34 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write('title = "Legacy Config"\n')
35 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ctx = _read_site_context(tmp)
36 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(ctx["title"], "Legacy Config")
37 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
38 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_hugo_toml_takes_precedence_over_config_toml(self):
39 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
40 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(os.path.join(tmp, "hugo.toml"), "w") as f:
41 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write('title = "Hugo"\n')
42 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(os.path.join(tmp, "config.toml"), "w") as f:
43 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write('title = "Config"\n')
44 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ctx = _read_site_context(tmp)
45 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(ctx["title"], "Hugo")
46 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
47 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_reads_description(self):
48 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
49 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(os.path.join(tmp, "hugo.toml"), "w") as f:
50 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write('title = "Site"\ndescription = "A fine site"\n')
51 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ctx = _read_site_context(tmp)
52 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(ctx["description"], "A fine site")
53 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
54 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_finds_content_sections(self):
55 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
56 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ os.makedirs(os.path.join(tmp, "content", "blog"))
57 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ os.makedirs(os.path.join(tmp, "content", "about"))
58 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ctx = _read_site_context(tmp)
59 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIn("blog", ctx["content_sections"])
60 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIn("about", ctx["content_sections"])
61 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
62 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_defaults_when_no_config(self):
63 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
64 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ctx = _read_site_context(tmp)
65 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(ctx["title"], "My Hugo Site")
66 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(ctx["description"], "")
67 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(ctx["content_sections"], [])
68 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
69 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_handles_missing_content_dir(self):
70 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
71 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ctx = _read_site_context(tmp)
72 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(ctx["content_sections"], [])
73 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(ctx["sample_content"], "")
74 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
75 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_reads_sample_content(self):
76 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
77 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ content = os.path.join(tmp, "content")
78 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ os.makedirs(content)
79 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(os.path.join(content, "page.md"), "w") as f:
80 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write("---\ntitle: Test\n---\n\nSome content.\n")
81 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ctx = _read_site_context(tmp)
82 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIn("Some content.", ctx["sample_content"])
83 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
84 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
85 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestParseFrontmatter(unittest.TestCase):
86 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_parses_yaml_frontmatter(self):
87 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
88 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ path = os.path.join(tmp, "page.md")
89 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(path, "w") as f:
90 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write("---\ntitle: Hello\ndate: 2024-01-01\ndraft: false\n---\n\nBody.\n")
91 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = _parse_frontmatter(path)
92 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(result["title"], "Hello")
93 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertFalse(result["draft"])
94 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
95 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_returns_empty_dict_for_missing_frontmatter(self):
96 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
97 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ path = os.path.join(tmp, "bare.md")
98 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(path, "w") as f:
99 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write("Just some text.\n")
100 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(_parse_frontmatter(path), {})
101 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
102 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_returns_empty_dict_for_missing_file(self):
103 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(_parse_frontmatter("/nonexistent/path.md"), {})
104 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
105 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_returns_empty_dict_for_empty_frontmatter(self):
106 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
107 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ path = os.path.join(tmp, "empty_fm.md")
108 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(path, "w") as f:
109 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write("---\n\n---\nBody.\n")
110 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(_parse_frontmatter(path), {})
111 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
112 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
113 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestUpdateFrontmatter(unittest.TestCase):
114 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_adds_new_field(self):
115 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
116 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ path = os.path.join(tmp, "post.md")
117 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(path, "w") as f:
118 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write("---\ntitle: Hello\n---\nBody text here.\n")
119 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ _update_frontmatter(path, {"description": "A great post"})
120 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ fm = _parse_frontmatter(path)
121 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(fm["description"], "A great post")
122 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(fm["title"], "Hello")
123 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
124 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_preserves_body(self):
125 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
126 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ path = os.path.join(tmp, "post.md")
127 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(path, "w") as f:
128 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write("---\ntitle: Hello\n---\nBody text here.\n")
129 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ _update_frontmatter(path, {"description": "desc"})
130 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ body = _read_body(path)
131 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIn("Body text here.", body)
132 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
133 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_updates_existing_field(self):
134 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
135 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ path = os.path.join(tmp, "post.md")
136 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(path, "w") as f:
137 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write("---\ntitle: Old Title\n---\nBody.\n")
138 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ _update_frontmatter(path, {"title": "New Title"})
139 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ fm = _parse_frontmatter(path)
140 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(fm["title"], "New Title")
141 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
142 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_noop_without_frontmatter(self):
143 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
144 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ path = os.path.join(tmp, "bare.md")
145 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(path, "w") as f:
146 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write("No frontmatter here.\n")
147 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ _update_frontmatter(path, {"description": "test"})
148 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(path, "r") as f:
149 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(f.read(), "No frontmatter here.\n")
150 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
151 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
152 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestReadBody(unittest.TestCase):
153 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_extracts_body_after_frontmatter(self):
154 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
155 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ path = os.path.join(tmp, "post.md")
156 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(path, "w") as f:
157 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write("---\ntitle: Test\n---\n\nThe body content.\n")
158 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ body = _read_body(path)
159 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(body, "The body content.")
160 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
161 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_returns_full_content_without_frontmatter(self):
162 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
163 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ path = os.path.join(tmp, "bare.md")
164 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(path, "w") as f:
165 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write("Just text, no frontmatter.\n")
166 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ body = _read_body(path)
167 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIn("Just text", body)
168 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
169 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_returns_empty_for_missing_file(self):
170 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(_read_body("/nonexistent/path.md"), "")
171 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
172 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
173 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestFindBaseof(unittest.TestCase):
174 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_finds_baseof_in_layouts(self):
175 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
176 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ baseof = os.path.join(tmp, "layouts", "_default", "baseof.html")
177 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ os.makedirs(os.path.dirname(baseof))
178 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(baseof, "w") as f:
179 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write("<html></html>")
180 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(_find_baseof(tmp), baseof)
181 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
182 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_finds_baseof_in_themes(self):
183 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
184 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ baseof = os.path.join(tmp, "themes", "mytheme", "layouts", "_default", "baseof.html")
185 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ os.makedirs(os.path.dirname(baseof))
186 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(baseof, "w") as f:
187 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write("<html></html>")
188 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(_find_baseof(tmp), baseof)
189 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
190 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_prefers_layouts_over_themes(self):
191 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
192 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ layouts_baseof = os.path.join(tmp, "layouts", "_default", "baseof.html")
193 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ os.makedirs(os.path.dirname(layouts_baseof))
194 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(layouts_baseof, "w") as f:
195 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write("<html>layouts</html>")
196 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ theme_baseof = os.path.join(tmp, "themes", "t", "layouts", "_default", "baseof.html")
197 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ os.makedirs(os.path.dirname(theme_baseof))
198 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(theme_baseof, "w") as f:
199 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write("<html>theme</html>")
200 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(_find_baseof(tmp), layouts_baseof)
201 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
202 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_returns_none_when_missing(self):
203 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
204 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIsNone(_find_baseof(tmp))
205 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
206 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
207 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestParseAiJson(unittest.TestCase):
208 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_parses_valid_json(self):
209 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = _parse_ai_json('{"key": "value"}')
210 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(result, {"key": "value"})
211 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
212 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_parses_fenced_json(self):
213 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = _parse_ai_json('```json\n{"key": "value"}\n```')
214 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(result, {"key": "value"})
215 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
216 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_parses_json_embedded_in_prose(self):
217 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = _parse_ai_json('Here is the result:\n{"title": "Hello"}\nDone.')
218 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(result, {"title": "Hello"})
219 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
220 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_returns_none_for_invalid(self):
221 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIsNone(_parse_ai_json("not json at all"))
222 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
223 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_returns_none_for_json_list(self):
224 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIsNone(_parse_ai_json('[1, 2, 3]'))
225 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
226 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_returns_none_for_empty_string(self):
227 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIsNone(_parse_ai_json(""))
228 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
229 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_parses_fenced_json_without_language(self):
230 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = _parse_ai_json('```\n{"a": 1}\n```')
231 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(result, {"a": 1})
232 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
233 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
234 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestChunks(unittest.TestCase):
235 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_splits_evenly(self):
236 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = list(_chunks([1, 2, 3, 4], 2))
237 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(result, [[1, 2], [3, 4]])
238 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
239 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_handles_remainder(self):
240 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = list(_chunks([1, 2, 3, 4, 5], 2))
241 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(result, [[1, 2], [3, 4], [5]])
242 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
243 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_empty_list(self):
244 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = list(_chunks([], 3))
245 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(result, [])
246 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
247 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_chunk_larger_than_list(self):
248 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = list(_chunks([1, 2], 10))
249 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(result, [[1, 2]])
250 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
251 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_chunk_size_one(self):
252 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = list(_chunks([1, 2, 3], 1))
253 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(result, [[1], [2], [3]])
254 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
255 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
256 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestSeoOgTags(unittest.TestCase):
257 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_injects_og_tags(self):
258 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
259 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ baseof = os.path.join(tmp, "layouts", "_default", "baseof.html")
260 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ os.makedirs(os.path.dirname(baseof))
261 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(baseof, "w") as f:
262 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write("<html><head><title>Test</title></head><body></body></html>")
263 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = _seo_og_tags(tmp)
264 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIn("OG tags", result)
265 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(baseof, "r") as f:
266 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ html = f.read()
267 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIn("og:title", html)
268 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIn("og:description", html)
269 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIn("og:url", html)
270 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
271 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_skips_if_already_present(self):
272 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
273 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ baseof = os.path.join(tmp, "layouts", "_default", "baseof.html")
274 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ os.makedirs(os.path.dirname(baseof))
275 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(baseof, "w") as f:
276 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write('<html><head><meta property="og:title" content="x" /></head></html>')
277 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = _seo_og_tags(tmp)
278 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIn("already present", result)
279 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
280 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_returns_message_when_no_baseof(self):
281 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
282 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = _seo_og_tags(tmp)
283 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIn("No baseof.html found", result)
284 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
285 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
286 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestGenerate(unittest.TestCase):
287 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @patch("hugoifier.utils.enhance.call_ai")
288 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_creates_content_files(self, mock_ai):
289 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ai_response = json.dumps({
290 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "blog/first-post.md": "---\ntitle: First Post\ndate: 2026-03-17\ndescription: A post\n---\n\nHello world.\n",
291 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "blog/second-post.md": "---\ntitle: Second Post\ndate: 2026-03-17\ndescription: Another post\n---\n\nGoodbye world.\n",
292 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ })
293 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mock_ai.return_value = ai_response
294 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
295 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
296 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(os.path.join(tmp, "hugo.toml"), "w") as f:
297 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write('title = "Test"\n')
298 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = generate(tmp, prompt="Write blog posts")
299 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIn("Generated 2", result)
300 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertTrue(os.path.exists(os.path.join(tmp, "content", "blog", "first-post.md")))
301 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertTrue(os.path.exists(os.path.join(tmp, "content", "blog", "second-post.md")))
302 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(os.path.join(tmp, "content", "blog", "first-post.md"), "r") as f:
303 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIn("Hello world.", f.read())
304 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
305 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @patch("hugoifier.utils.enhance.call_ai")
306 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_handles_invalid_ai_response(self, mock_ai):
307 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mock_ai.return_value = "not valid json"
308 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
309 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = generate(tmp, prompt="Write posts")
310 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIn("Could not generate content", result)
311 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
312 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @patch("hugoifier.utils.enhance.call_ai")
313 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_from_file_reads_example(self, mock_ai):
314 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ ai_response = json.dumps({
315 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "page.md": "---\ntitle: New Page\ndate: 2026-03-17\ndescription: New\n---\n\nContent.\n",
316 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ })
317 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mock_ai.return_value = ai_response
318 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
319 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
320 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ example = os.path.join(tmp, "example.md")
321 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(example, "w") as f:
322 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write("---\ntitle: Example\n---\n\nExample content.\n")
323 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(os.path.join(tmp, "hugo.toml"), "w") as f:
324 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write('title = "Test"\n')
325 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = generate(tmp, from_file=example)
326 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIn("Generated 1", result)
327 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # Verify call_ai was called with the example content
328 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ prompt_arg = mock_ai.call_args[0][0]
329 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIn("Example content.", prompt_arg)
330 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
331 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
332 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestSeo(unittest.TestCase):
333 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @patch("hugoifier.utils.enhance.call_ai")
334 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_finds_missing_descriptions(self, mock_ai):
335 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mock_ai.return_value = json.dumps({"My Post": "A short description."})
336 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
337 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(os.path.join(tmp, "hugo.toml"), "w") as f:
338 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write('title = "Test"\n')
339 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ content = os.path.join(tmp, "content")
340 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ os.makedirs(content)
341 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ path = os.path.join(content, "post.md")
342 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(path, "w") as f:
343 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write("---\ntitle: My Post\n---\n\nSome body text.\n")
344 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = seo(tmp)
345 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIn("Added meta descriptions to 1", result)
346 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ fm = _parse_frontmatter(path)
347 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertEqual(fm["description"], "A short description.")
348 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
349 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @patch("hugoifier.utils.enhance.call_ai")
350 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_skips_files_with_descriptions(self, mock_ai):
351 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
352 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(os.path.join(tmp, "hugo.toml"), "w") as f:
353 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write('title = "Test"\n')
354 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ content = os.path.join(tmp, "content")
355 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ os.makedirs(content)
356 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(os.path.join(content, "post.md"), "w") as f:
357 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write("---\ntitle: My Post\ndescription: Already set\n---\n\nBody.\n")
358 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = seo(tmp)
359 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIn("already have descriptions", result)
360 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mock_ai.assert_not_called()
361 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
362 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_handles_missing_content_dir(self):
363 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
364 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = seo(tmp)
365 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIn("No content/", result)
366 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
367 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
368 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestAltText(unittest.TestCase):
369 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @patch("hugoifier.utils.enhance.call_ai")
370 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_finds_images_without_alt(self, mock_ai):
371 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mock_ai.return_value = json.dumps({"logo.png": "Company logo"})
372 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
373 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(os.path.join(tmp, "hugo.toml"), "w") as f:
374 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write('title = "Test"\n')
375 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ layouts = os.path.join(tmp, "layouts")
376 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ os.makedirs(layouts)
377 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ tpl = os.path.join(layouts, "index.html")
378 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(tpl, "w") as f:
379 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write('<html><body><img src="logo.png"></body></html>')
380 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = alt_text(tmp)
381 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIn("Added alt text to 1", result)
382 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(tpl, "r") as f:
383 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ html = f.read()
384 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIn('alt="Company logo"', html)
385 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
386 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @patch("hugoifier.utils.enhance.call_ai")
387 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_skips_images_with_alt(self, mock_ai):
388 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
389 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(os.path.join(tmp, "hugo.toml"), "w") as f:
390 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write('title = "Test"\n')
391 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ layouts = os.path.join(tmp, "layouts")
392 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ os.makedirs(layouts)
393 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ tpl = os.path.join(layouts, "index.html")
394 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(tpl, "w") as f:
395 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write('<html><body><img src="logo.png" alt="A logo"></body></html>')
396 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = alt_text(tmp)
397 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIn("All images already have alt text", result)
398 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mock_ai.assert_not_called()
399 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
400 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @patch("hugoifier.utils.enhance.call_ai")
401 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_finds_images_with_empty_alt(self, mock_ai):
402 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mock_ai.return_value = json.dumps({"photo.jpg": "A photo"})
403 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
404 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(os.path.join(tmp, "hugo.toml"), "w") as f:
405 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write('title = "Test"\n')
406 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ layouts = os.path.join(tmp, "layouts")
407 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ os.makedirs(layouts)
408 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ tpl = os.path.join(layouts, "page.html")
409 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(tpl, "w") as f:
410 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write('<html><body><img src="photo.jpg" alt=""></body></html>')
411 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = alt_text(tmp)
412 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIn("Added alt text to 1", result)
413 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
414 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_no_templates_returns_message(self):
415 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with tempfile.TemporaryDirectory() as tmp:
416 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with open(os.path.join(tmp, "hugo.toml"), "w") as f:
417 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ f.write('title = "Test"\n')
418 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = alt_text(tmp)
419 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.assertIn("All images already have alt text", result)
420 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
421 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
422 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ if __name__ == "__main__":
423 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ unittest.main()