Hugoifier

test: replace all stub tests with real unit tests (87 tests, 0 failures) Closes #9

lmata 2026-03-12 21:55 trunk
Commit 6272677ca26ac7f987bae388c97d39a0b304730bd5acfc1272be5fc1d6afe5c5
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -0,0 +1,4 @@
1
+"""Add src/ to sys.path so tests can import from utils.* direcs
2
+
3
+sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
4
+, 'src'
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -0,0 +1,4 @@
 
 
 
 
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -0,0 +1,4 @@
1 """Add src/ to sys.path so tests can import from utils.* direcs
2
3 sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
4 , 'src'
--- tests/test_analyze.py
+++ tests/test_analyze.py
@@ -1,19 +1,60 @@
1
+"""Tests for utils.analyze."""
2
+import os
3
+import tempfile
14
import unittest
2
-from src.utils.analyze import analyze
3
-
4
-class TestAnalyze(unittest.TestCase):
5
-
6
- def setUp(self):
7
- # Set up any necessary test data
8
- pass
9
-
10
- def tearDown(self):
11
- # Clean up after tests
12
- pass
13
-
14
- def test_analyze(self):
15
- # Placeholder for analyze function test
16
- pass
17
-
18
-if __name__ == '__main__':
19
- unittest.main()
5
+
6
+from utils.analyze import _analyze_hugo_theme
7
+
8
+
9
+class TestAnalyzeHugoTheme(unittest.TestCase):
10
+ def _make_theme_info(self, tmp, layouts=None, example_site=None):
11
+ theme_dir = os.path.join(tmp, "test-theme")
12
+ layouts_dir = os.path.join(theme_dir, "layouts", "_default")
13
+ os.makedirs(layouts_dir)
14
+ for name in (layouts or ["baseof.html", "single.html"]):
15
+ open(os.path.join(layouts_dir, name), "w").close()
16
+ return {
17
+ "theme_dir": theme_dir,
18
+ "theme_name": "test-theme",
19
+ "example_site": example_site,
20
+ "is_hugo_theme": True,
21
+ }
22
+
23
+ def test_reports_theme_name(self):
24
+ with tempfile.TemporaryDirectory() as tmp:
25
+ info = self._make_theme_info(tmp)
26
+ result = _analyze_hugo_theme(info)
27
+ self.assertIn("test-theme", result)
28
+
29
+ def test_lists_layout_files(self):
30
+ with tempfile.TemporaryDirectory() as tmp:
31
+ info = self._make_theme_info(tmp, layouts=["baseof.html", "single.html"])
32
+ result = _analyze_hugo_theme(info)
33
+ self.assertIn("baseof.html", result)
34
+ self.assertIn("single.html", result)
35
+
36
+ def test_reports_no_example_site(self):
37
+ with tempfile.TemporaryDirectory() as tmp:
38
+ info = self._make_theme_info(tmp, example_site=None)
39
+ result = _analyze_hugo_theme(info)
40
+ self.assertIn("none", result.lower())
41
+
42
+ def test_reports_content_types_from_example_site(self):
43
+ with tempfile.TemporaryDirectory() as tmp:
44
+ info = self._make_theme_info(tmp)
45
+ example = os.path.join(tmp, "exampleSite")
46
+ content = os.path.join(example, "content", "blog")
47
+ os.makedirs(content)
48
+ info["example_site"] = example
49
+ result = _analyze_hugo_theme(info)
50
+ self.assertIn("blog", result)
51
+
52
+ def test_suggests_complete_command(self):
53
+ with tempfile.TemporaryDirectory() as tmp:
54
+ info = self._make_theme_info(tmp)
55
+ result = _analyze_hugo_theme(info)
56
+ self.assertIn("complete", result)
57
+
58
+
59
+if __name__ == "__main__":
60
+ unittest.main()
2061
--- tests/test_analyze.py
+++ tests/test_analyze.py
@@ -1,19 +1,60 @@
 
 
 
1 import unittest
2 from src.utils.analyze import analyze
3
4 class TestAnalyze(unittest.TestCase):
5
6 def setUp(self):
7 # Set up any necessary test data
8 pass
9
10 def tearDown(self):
11 # Clean up after tests
12 pass
13
14 def test_analyze(self):
15 # Placeholder for analyze function test
16 pass
17
18 if __name__ == '__main__':
19 unittest.main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
--- tests/test_analyze.py
+++ tests/test_analyze.py
@@ -1,19 +1,60 @@
1 """Tests for utils.analyze."""
2 import os
3 import tempfile
4 import unittest
5
6 from utils.analyze import _analyze_hugo_theme
7
8
9 class TestAnalyzeHugoTheme(unittest.TestCase):
10 def _make_theme_info(self, tmp, layouts=None, example_site=None):
11 theme_dir = os.path.join(tmp, "test-theme")
12 layouts_dir = os.path.join(theme_dir, "layouts", "_default")
13 os.makedirs(layouts_dir)
14 for name in (layouts or ["baseof.html", "single.html"]):
15 open(os.path.join(layouts_dir, name), "w").close()
16 return {
17 "theme_dir": theme_dir,
18 "theme_name": "test-theme",
19 "example_site": example_site,
20 "is_hugo_theme": True,
21 }
22
23 def test_reports_theme_name(self):
24 with tempfile.TemporaryDirectory() as tmp:
25 info = self._make_theme_info(tmp)
26 result = _analyze_hugo_theme(info)
27 self.assertIn("test-theme", result)
28
29 def test_lists_layout_files(self):
30 with tempfile.TemporaryDirectory() as tmp:
31 info = self._make_theme_info(tmp, layouts=["baseof.html", "single.html"])
32 result = _analyze_hugo_theme(info)
33 self.assertIn("baseof.html", result)
34 self.assertIn("single.html", result)
35
36 def test_reports_no_example_site(self):
37 with tempfile.TemporaryDirectory() as tmp:
38 info = self._make_theme_info(tmp, example_site=None)
39 result = _analyze_hugo_theme(info)
40 self.assertIn("none", result.lower())
41
42 def test_reports_content_types_from_example_site(self):
43 with tempfile.TemporaryDirectory() as tmp:
44 info = self._make_theme_info(tmp)
45 example = os.path.join(tmp, "exampleSite")
46 content = os.path.join(example, "content", "blog")
47 os.makedirs(content)
48 info["example_site"] = example
49 result = _analyze_hugo_theme(info)
50 self.assertIn("blog", result)
51
52 def test_suggests_complete_command(self):
53 with tempfile.TemporaryDirectory() as tmp:
54 info = self._make_theme_info(tmp)
55 result = _analyze_hugo_theme(info)
56 self.assertIn("complete", result)
57
58
59 if __name__ == "__main__":
60 unittest.main()
61
--- tests/test_cloudflare.py
+++ tests/test_cloudflare.py
@@ -1,19 +1,18 @@
1
-import unittest
2
-from src.utils.cloudflare import configure_cloudflare
3
-
4
-class TestCloudflare(unittest.TestCase):
5
-
6
- def setUp(self):
7
- # Set up any necessary test data
8
- pass
9
-
10
- def tearDown(self):
11
- # Clean up after tests
12
- pass
13
-
14
- def test_configure_cloudflare(self):
15
- # Placeholder for configure_cloudflare function test
16
- pass
17
-
18
-if __name__ == '__main__':
19
- unittest.main()
1
+"""Tests for utils.cloudflare."""
2
+import unittest
3
+
4
+from utils.cloudflare import configure_cloudflare
5
+
6
+
7
+class TestConfigureCloudflare(unittest.TestCase):
8
+ def test_returns_complete_message(self):
9
+ result = configure_cloudflare("/some/path", "example.com")
10
+ self.assertIn("complete", result.lower())
11
+
12
+ def test_accepts_path_and_zone(self):
13
+ result = configure_cloudflare("/tmp/site", "zone-id-123")
14
+ self.assertIsInstance(result, str)
15
+
16
+
17
+if __name__ == "__main__":
18
+ unittest.main()
2019
--- tests/test_cloudflare.py
+++ tests/test_cloudflare.py
@@ -1,19 +1,18 @@
1 import unittest
2 from src.utils.cloudflare import configure_cloudflare
3
4 class TestCloudflare(unittest.TestCase):
5
6 def setUp(self):
7 # Set up any necessary test data
8 pass
9
10 def tearDown(self):
11 # Clean up after tests
12 pass
13
14 def test_configure_cloudflare(self):
15 # Placeholder for configure_cloudflare function test
16 pass
17
18 if __name__ == '__main__':
19 unittest.main()
20
--- tests/test_cloudflare.py
+++ tests/test_cloudflare.py
@@ -1,19 +1,18 @@
1 """Tests for utils.cloudflare."""
2 import unittest
3
4 from utils.cloudflare import configure_cloudflare
5
6
7 class TestConfigureCloudflare(unittest.TestCase):
8 def test_returns_complete_message(self):
9 result = configure_cloudflare("/some/path", "example.com")
10 self.assertIn("complete", result.lower())
11
12 def test_accepts_path_and_zone(self):
13 result = configure_cloudflare("/tmp/site", "zone-id-123")
14 self.assertIsInstance(result, str)
15
16
17 if __name__ == "__main__":
18 unittest.main()
 
19
--- tests/test_complete.py
+++ tests/test_complete.py
@@ -1,19 +1,114 @@
1
+"""Tests for utils.complete helpers."""
2
+import os
3
+import tempfile
14
import unittest
2
-from src.utils.complete import complete
3
-
4
-class TestComplete(unittest.TestCase):
5
-
6
- def setUp(self):
7
- # Set up any necessary test data
8
- pass
9
-
10
- def tearDown(self):
11
- # Clean up after tests
12
- pass
13
-
14
- def test_complete(self):
15
- # Placeholder for complete function test
16
- pass
17
-
18
-if __name__ == '__main__':
19
- unittest.main()
5
+
6
+from utils.complete import _pick_main_html, _copy_dir, _find_config, _write_minimal_hugo_toml
7
+
8
+
9
+class TestPickMainHtml(unittest.TestCase):
10
+ def test_prefers_index_html(self):
11
+ files = ["/path/about.html", "/path/index.html", "/path/contact.html"]
12
+ self.assertEqual(_pick_main_html(files), "/path/index.html")
13
+
14
+ def test_prefers_home_html(self):
15
+ files = ["/path/about.html", "/path/home.html"]
16
+ self.assertEqual(_pick_main_html(files), "/path/home.html")
17
+
18
+ def test_falls_back_to_first(self):
19
+ files = ["/path/about.html", "/path/services.html"]
20
+ self.assertEqual(_pick_main_html(files), "/path/about.html")
21
+
22
+
23
+class TestCopyDir(unittest.TestCase):
24
+ def test_copies_files(self):
25
+ with tempfile.TemporaryDirectory() as src, tempfile.TemporaryDirectory() as dst:
26
+ open(os.path.join(src, "file.txt"), "w").close()
27
+ _copy_dir(src, dst)
28
+ self.assertTrue(os.path.exists(os.path.join(dst, "file.txt")))
29
+
30
+ def test_excludes_specified_names(self):
31
+ with tempfile.TemporaryDirectory() as src, tempfile.TemporaryDirectory() as dst:
32
+ open(os.path.join(src, "keep.txt"), "w").close()
33
+ open(os.path.join(src, "skip.txt"), "w").close()
34
+ _copy_dir(src, dst, exclude={"skip.txt"})
35
+ self.assertTrue(os.path.exists(os.path.join(dst, "keep.txt")))
36
+ self.assertFalse(os.path.exists(os.path.join(dst, "skip.txt")))
37
+
38
+ def test_excludes_dotfiles_starting_with_dot_underscore(self):
39
+ with tempfile.TemporaryDirectory() as src, tempfile.TemporaryDirectory() as dst:
40
+ open(os.path.join(src, "._junk"), "w").close()
41
+ open(os.path.join(src, "real.txt"), "w").close()
42
+ _copy_dir(src, dst)
43
+ self.assertFalse(os.path.exists(os.path.join(dst, "._junk")))
44
+ self.assertTrue(os.path.exists(os.path.join(dst, "real.txt")))
45
+
46
+ def test_nonexistent_src_is_safe(self):
47
+ with tempfile.TemporaryDirectory() as dst:
48
+ _copy_dir("/nonexistent/src", dst) # should not raise
49
+
50
+ def test_recurses_into_subdirs(self):
51
+ with tempfile.TemporaryDirectory() as src, tempfile.TemporaryDirectory() as dst:
52
+ nested = os.path.join(src, "sub")
53
+ os.makedirs(nested)
54
+ open(os.path.join(nested, "nested.txt"), "w").close()
55
+ _copy_dir(src, dst)
56
+ self.assertTrue(os.path.exists(os.path.join(dst, "sub", "nested.txt")))
57
+
58
+
59
+class TestFindConfig(unittest.TestCase):
60
+ def test_finds_hugo_toml(self):
61
+ with tempfile.TemporaryDirectory() as tmp:
62
+ path = os.path.join(tmp, "hugo.toml")
63
+ open(path, "w").close()
64
+ self.assertEqual(_find_config(tmp), path)
65
+
66
+ def test_finds_config_toml(self):
67
+ with tempfile.TemporaryDirectory() as tmp:
68
+ path = os.path.join(tmp, "config.toml")
69
+ open(path, "w").close()
70
+ self.assertEqual(_find_config(tmp), path)
71
+
72
+ def test_prefers_hugo_toml_over_config_toml(self):
73
+ with tempfile.TemporaryDirectory() as tmp:
74
+ hugo = os.path.join(tmp, "hugo.toml")
75
+ config = os.path.join(tmp, "config.toml")
76
+ open(hugo, "w").close()
77
+ open(config, "w").close()
78
+ self.assertEqual(_find_config(tmp), hugo)
79
+
80
+ def test_finds_nested_config(self):
81
+ with tempfile.TemporaryDirectory() as tmp:
82
+ nested = os.path.join(tmp, "config", "_default")
83
+ os.makedirs(nested)
84
+ path = os.path.join(nested, "config.toml")
85
+ open(path, "w").close()
86
+ self.assertEqual(_find_config(tmp), path)
87
+
88
+ def test_returns_none_when_missing(self):
89
+ with tempfile.TemporaryDirectory() as tmp:
90
+ self.assertIsNone(_find_config(tmp))
91
+
92
+
93
+class TestWriteMinimalHugoToml(unittest.TestCase):
94
+ def test_writes_valid_toml(self):
95
+ with tempfile.TemporaryDirectory() as tmp:
96
+ _write_minimal_hugo_toml(tmp, "my-theme")
97
+ path = os.path.join(tmp, "hugo.toml")
98
+ self.assertTrue(os.path.exists(path))
99
+ with open(path) as f:
100
+ content = f.read()
101
+ self.assertIn('theme = "my-theme"', content)
102
+ self.assertIn("My Theme", content)
103
+
104
+ def test_sanitizes_quotes_in_theme_name(self):
105
+ with tempfile.TemporaryDirectory() as tmp:
106
+ _write_minimal_hugo_toml(tmp, 'evil"theme')
107
+ with open(os.path.join(tmp, "hugo.toml")) as f:
108
+ content = f.read()
109
+ # Should not contain unescaped quote that breaks TOML
110
+ self.assertNotIn('theme = "evil"theme"', content)
111
+
112
+
113
+if __name__ == "__main__":
114
+ unittest.main()
20115
21116
ADDED tests/test_config.py
--- tests/test_complete.py
+++ tests/test_complete.py
@@ -1,19 +1,114 @@
 
 
 
1 import unittest
2 from src.utils.complete import complete
3
4 class TestComplete(unittest.TestCase):
5
6 def setUp(self):
7 # Set up any necessary test data
8 pass
9
10 def tearDown(self):
11 # Clean up after tests
12 pass
13
14 def test_complete(self):
15 # Placeholder for complete function test
16 pass
17
18 if __name__ == '__main__':
19 unittest.main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
21 DDED tests/test_config.py
--- tests/test_complete.py
+++ tests/test_complete.py
@@ -1,19 +1,114 @@
1 """Tests for utils.complete helpers."""
2 import os
3 import tempfile
4 import unittest
5
6 from utils.complete import _pick_main_html, _copy_dir, _find_config, _write_minimal_hugo_toml
7
8
9 class TestPickMainHtml(unittest.TestCase):
10 def test_prefers_index_html(self):
11 files = ["/path/about.html", "/path/index.html", "/path/contact.html"]
12 self.assertEqual(_pick_main_html(files), "/path/index.html")
13
14 def test_prefers_home_html(self):
15 files = ["/path/about.html", "/path/home.html"]
16 self.assertEqual(_pick_main_html(files), "/path/home.html")
17
18 def test_falls_back_to_first(self):
19 files = ["/path/about.html", "/path/services.html"]
20 self.assertEqual(_pick_main_html(files), "/path/about.html")
21
22
23 class TestCopyDir(unittest.TestCase):
24 def test_copies_files(self):
25 with tempfile.TemporaryDirectory() as src, tempfile.TemporaryDirectory() as dst:
26 open(os.path.join(src, "file.txt"), "w").close()
27 _copy_dir(src, dst)
28 self.assertTrue(os.path.exists(os.path.join(dst, "file.txt")))
29
30 def test_excludes_specified_names(self):
31 with tempfile.TemporaryDirectory() as src, tempfile.TemporaryDirectory() as dst:
32 open(os.path.join(src, "keep.txt"), "w").close()
33 open(os.path.join(src, "skip.txt"), "w").close()
34 _copy_dir(src, dst, exclude={"skip.txt"})
35 self.assertTrue(os.path.exists(os.path.join(dst, "keep.txt")))
36 self.assertFalse(os.path.exists(os.path.join(dst, "skip.txt")))
37
38 def test_excludes_dotfiles_starting_with_dot_underscore(self):
39 with tempfile.TemporaryDirectory() as src, tempfile.TemporaryDirectory() as dst:
40 open(os.path.join(src, "._junk"), "w").close()
41 open(os.path.join(src, "real.txt"), "w").close()
42 _copy_dir(src, dst)
43 self.assertFalse(os.path.exists(os.path.join(dst, "._junk")))
44 self.assertTrue(os.path.exists(os.path.join(dst, "real.txt")))
45
46 def test_nonexistent_src_is_safe(self):
47 with tempfile.TemporaryDirectory() as dst:
48 _copy_dir("/nonexistent/src", dst) # should not raise
49
50 def test_recurses_into_subdirs(self):
51 with tempfile.TemporaryDirectory() as src, tempfile.TemporaryDirectory() as dst:
52 nested = os.path.join(src, "sub")
53 os.makedirs(nested)
54 open(os.path.join(nested, "nested.txt"), "w").close()
55 _copy_dir(src, dst)
56 self.assertTrue(os.path.exists(os.path.join(dst, "sub", "nested.txt")))
57
58
59 class TestFindConfig(unittest.TestCase):
60 def test_finds_hugo_toml(self):
61 with tempfile.TemporaryDirectory() as tmp:
62 path = os.path.join(tmp, "hugo.toml")
63 open(path, "w").close()
64 self.assertEqual(_find_config(tmp), path)
65
66 def test_finds_config_toml(self):
67 with tempfile.TemporaryDirectory() as tmp:
68 path = os.path.join(tmp, "config.toml")
69 open(path, "w").close()
70 self.assertEqual(_find_config(tmp), path)
71
72 def test_prefers_hugo_toml_over_config_toml(self):
73 with tempfile.TemporaryDirectory() as tmp:
74 hugo = os.path.join(tmp, "hugo.toml")
75 config = os.path.join(tmp, "config.toml")
76 open(hugo, "w").close()
77 open(config, "w").close()
78 self.assertEqual(_find_config(tmp), hugo)
79
80 def test_finds_nested_config(self):
81 with tempfile.TemporaryDirectory() as tmp:
82 nested = os.path.join(tmp, "config", "_default")
83 os.makedirs(nested)
84 path = os.path.join(nested, "config.toml")
85 open(path, "w").close()
86 self.assertEqual(_find_config(tmp), path)
87
88 def test_returns_none_when_missing(self):
89 with tempfile.TemporaryDirectory() as tmp:
90 self.assertIsNone(_find_config(tmp))
91
92
93 class TestWriteMinimalHugoToml(unittest.TestCase):
94 def test_writes_valid_toml(self):
95 with tempfile.TemporaryDirectory() as tmp:
96 _write_minimal_hugo_toml(tmp, "my-theme")
97 path = os.path.join(tmp, "hugo.toml")
98 self.assertTrue(os.path.exists(path))
99 with open(path) as f:
100 content = f.read()
101 self.assertIn('theme = "my-theme"', content)
102 self.assertIn("My Theme", content)
103
104 def test_sanitizes_quotes_in_theme_name(self):
105 with tempfile.TemporaryDirectory() as tmp:
106 _write_minimal_hugo_toml(tmp, 'evil"theme')
107 with open(os.path.join(tmp, "hugo.toml")) as f:
108 content = f.read()
109 # Should not contain unescaped quote that breaks TOML
110 self.assertNotIn('theme = "evil"theme"', content)
111
112
113 if __name__ == "__main__":
114 unittest.main()
115
116 DDED tests/test_config.py
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -0,0 +1,22 @@
1
+"""Tests for confsys
2
+import unittest
3
+from, MagicMock
4
+
5
+
6
+class TestCallAiRouting(unittest.TestCase):
7
+ def _get_config(self):
8
+ # Reload config to pick up env var change importimport hugoifier.confanthropic', return_value="response") as mock_fn:
9
+ config.BACKEND = 'anthropic'
10
+ result = config.call_ai("hello")
11
+ mock_fn.assert_called_once()
12
+ self.assertEqual(result, "response")
13
+
14
+ def test_openai_backend_calls_openai(self):
15
+ import import hugoifier.config as config
16
+ with patch.object(config, '_call_openai', return_value="response") as mock_fn:
17
+ config.BACKEND = 'openai'
18
+ result = config.call_ai("hello")
19
+ mock_fn.assert_called_once()
20
+ self.assertEqual(result, "response")
21
+
22
+ def test_google_backend_calls_goimport hugoifier.confgoogle', return_value="response") as m
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -0,0 +1,22 @@
1 """Tests for confsys
2 import unittest
3 from, MagicMock
4
5
6 class TestCallAiRouting(unittest.TestCase):
7 def _get_config(self):
8 # Reload config to pick up env var change importimport hugoifier.confanthropic', return_value="response") as mock_fn:
9 config.BACKEND = 'anthropic'
10 result = config.call_ai("hello")
11 mock_fn.assert_called_once()
12 self.assertEqual(result, "response")
13
14 def test_openai_backend_calls_openai(self):
15 import import hugoifier.config as config
16 with patch.object(config, '_call_openai', return_value="response") as mock_fn:
17 config.BACKEND = 'openai'
18 result = config.call_ai("hello")
19 mock_fn.assert_called_once()
20 self.assertEqual(result, "response")
21
22 def test_google_backend_calls_goimport hugoifier.confgoogle', return_value="response") as m
--- tests/test_decapify.py
+++ tests/test_decapify.py
@@ -1,19 +1,191 @@
1
+"""Tests for utils.decapify."""
2
+import os
3
+import tempfile
14
import unittest
2
-from src.utils.decapify import decapify
5
+
6
+from utils.decapify import (
7
+ _sanitize_color,
8
+ _widget_for_value,
9
+ _parse_frontmatter,
10
+ _infer_fields_for_folder,
11
+ _infer_fields_for_file,
12
+ _build_collections,
13
+ decapify,
14
+)
15
+
16
+
17
+class TestSanitizeColor(unittest.TestCase):
18
+ def test_valid_hex6(self):
19
+ self.assertEqual(_sanitize_color("#2e3748"), "#2e3748")
20
+
21
+ def test_valid_hex3(self):
22
+ self.assertEqual(_sanitize_color("#fff"), "#fff")
23
+
24
+ def test_uppercase(self):
25
+ self.assertEqual(_sanitize_color("#AABBCC"), "#AABBCC")
26
+
27
+ def test_invalid_falls_back(self):
28
+ self.assertEqual(_sanitize_color("red"), "#2e3748")
29
+ self.assertEqual(_sanitize_color("javascript:alert(1)"), "#2e3748")
30
+ self.assertEqual(_sanitize_color("#gggggg"), "#2e3748")
31
+
32
+
33
+class TestWidgetForValue(unittest.TestCase):
34
+ def test_bool(self):
35
+ self.assertEqual(_widget_for_value(True), "boolean")
36
+ self.assertEqual(_widget_for_value(False), "boolean")
37
+
38
+ def test_number(self):
39
+ self.assertEqual(_widget_for_value(42), "number")
40
+ self.assertEqual(_widget_for_value(3.14), "number")
41
+
42
+ def test_list(self):
43
+ self.assertEqual(_widget_for_value([]), "list")
44
+ self.assertEqual(_widget_for_value(["a", "b"]), "list")
45
+
46
+ def test_string_default(self):
47
+ self.assertEqual(_widget_for_value("hello"), "string")
48
+ self.assertEqual(_widget_for_value(None), "string")
49
+
50
+
51
+class TestParseFrontmatter(unittest.TestCase):
52
+ def test_parses_yaml_frontmatter(self):
53
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".md", delete=False) as f:
54
+ f.write("---\ntitle: Hello\ndate: 2024-01-01\ndraft: false\n---\n\nBody text.\n")
55
+ path = f.name
56
+ try:
57
+ result = _parse_frontmatter(path)
58
+ self.assertEqual(result["title"], "Hello")
59
+ self.assertEqual(result["draft"], False)
60
+ finally:
61
+ os.unlink(path)
62
+
63
+ def test_empty_on_missing_frontmatter(self):
64
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".md", delete=False) as f:
65
+ f.write("No frontmatter here.\n")
66
+ path = f.name
67
+ try:
68
+ self.assertEqual(_parse_frontmatter(path), {})
69
+ finally:
70
+ os.unlink(path)
71
+
72
+ def test_empty_on_missing_file(self):
73
+ self.assertEqual(_parse_frontmatter("/nonexistent/path.md"), {})
74
+
75
+
76
+class TestInferFields(unittest.TestCase):
77
+ def _make_md(self, dirpath, name, frontmatter):
78
+ path = os.path.join(dirpath, name)
79
+ with open(path, "w") as f:
80
+ f.write("---\n")
81
+ for k, v in frontmatter.items():
82
+ f.write(f"{k}: {v!r}\n")
83
+ f.write("---\n\nBody.\n")
84
+ return path
85
+
86
+ def test_folder_fields_include_known_keys(self):
87
+ with tempfile.TemporaryDirectory() as tmp:
88
+ self._make_md(tmp, "post1.md", {"title": "Hello", "date": "2024-01-01", "tags": ["a"]})
89
+ fields = _infer_fields_for_folder(tmp, ["post1.md"])
90
+ names = [f["name"] for f in fields]
91
+ self.assertIn("title", names)
92
+ self.assertIn("date", names)
93
+ self.assertIn("tags", names)
94
+ self.assertIn("body", names)
95
+
96
+ def test_folder_fields_always_end_with_body(self):
97
+ with tempfile.TemporaryDirectory() as tmp:
98
+ self._make_md(tmp, "post.md", {"title": "Test"})
99
+ fields = _infer_fields_for_folder(tmp, ["post.md"])
100
+ self.assertEqual(fields[-1]["name"], "body")
101
+ self.assertEqual(fields[-1]["widget"], "markdown")
102
+
103
+ def test_file_fields_include_all_frontmatter_keys(self):
104
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".md", delete=False) as f:
105
+ f.write("---\ntitle: About\nsubtitle: Us\n---\n")
106
+ path = f.name
107
+ try:
108
+ fields = _infer_fields_for_file(path)
109
+ names = [fi["name"] for fi in fields]
110
+ self.assertIn("title", names)
111
+ self.assertIn("subtitle", names)
112
+ self.assertIn("body", names)
113
+ finally:
114
+ os.unlink(path)
115
+
116
+
117
+class TestBuildCollections(unittest.TestCase):
118
+ def test_folder_collection_from_md_files(self):
119
+ with tempfile.TemporaryDirectory() as tmp:
120
+ blog = os.path.join(tmp, "blog")
121
+ os.makedirs(blog)
122
+ for i in range(3):
123
+ with open(os.path.join(blog, f"post{i}.md"), "w") as f:
124
+ f.write("---\ntitle: Post\n---\n")
125
+ collections = _build_collections(tmp)
126
+ self.assertEqual(len(collections), 1)
127
+ self.assertEqual(collections[0]["name"], "blog")
128
+ self.assertIn("folder", collections[0])
129
+
130
+ def test_file_collection_from_index_only(self):
131
+ with tempfile.TemporaryDirectory() as tmp:
132
+ about = os.path.join(tmp, "about")
133
+ os.makedirs(about)
134
+ with open(os.path.join(about, "_index.md"), "w") as f:
135
+ f.write("---\ntitle: About\n---\n")
136
+ collections = _build_collections(tmp)
137
+ self.assertEqual(len(collections), 1)
138
+ self.assertIn("files", collections[0])
139
+
140
+ def test_recursive_md_discovery(self):
141
+ with tempfile.TemporaryDirectory() as tmp:
142
+ deep = os.path.join(tmp, "blog", "2024")
143
+ os.makedirs(deep)
144
+ with open(os.path.join(deep, "post.md"), "w") as f:
145
+ f.write("---\ntitle: Deep Post\n---\n")
146
+ collections = _build_collections(tmp)
147
+ self.assertEqual(len(collections), 1)
148
+ self.assertEqual(collections[0]["name"], "blog")
149
+
150
+ def test_default_collection_when_empty(self):
151
+ with tempfile.TemporaryDirectory() as tmp:
152
+ collections = _build_collections(tmp)
153
+ self.assertEqual(len(collections), 1)
154
+ self.assertEqual(collections[0]["name"], "pages")
155
+
156
+ def test_nonexistent_dir_returns_default(self):
157
+ collections = _build_collections("/nonexistent/content")
158
+ self.assertEqual(len(collections), 1)
159
+ self.assertEqual(collections[0]["name"], "pages")
160
+
3161
4162
class TestDecapify(unittest.TestCase):
5
-
6
- def setUp(self):
7
- # Set up any necessary test data
8
- pass
9
-
10
- def tearDown(self):
11
- # Clean up after tests
12
- pass
13
-
14
- def test_decapify(self):
15
- # Placeholder for decapify function test
16
- pass
17
-
18
-if __name__ == '__main__':
19
- unittest.main()
163
+ def test_creates_admin_files(self):
164
+ with tempfile.TemporaryDirectory() as tmp:
165
+ content = os.path.join(tmp, "content")
166
+ os.makedirs(content)
167
+ with open(os.path.join(content, "_index.md"), "w") as f:
168
+ f.write("---\ntitle: Home\n---\n")
169
+ result = decapify(tmp)
170
+ self.assertIn("complete", result.lower())
171
+ self.assertTrue(os.path.exists(os.path.join(tmp, "static", "admin", "index.html")))
172
+ self.assertTrue(os.path.exists(os.path.join(tmp, "static", "admin", "config.yml")))
173
+
174
+ def test_admin_index_escapes_name(self):
175
+ with tempfile.TemporaryDirectory() as tmp:
176
+ decapify(tmp, cms_name='<script>alert("xss")</script>')
177
+ with open(os.path.join(tmp, "static", "admin", "index.html")) as f:
178
+ html = f.read()
179
+ self.assertNotIn("<script>alert", html)
180
+ self.assertIn("&lt;script&gt;", html)
181
+
182
+ def test_invalid_color_falls_back(self):
183
+ with tempfile.TemporaryDirectory() as tmp:
184
+ decapify(tmp, cms_color="not-a-color")
185
+ with open(os.path.join(tmp, "static", "admin", "index.html")) as f:
186
+ html = f.read()
187
+ self.assertIn("#2e3748", html)
188
+
189
+
190
+if __name__ == "__main__":
191
+ unittest.main()
20192
--- tests/test_decapify.py
+++ tests/test_decapify.py
@@ -1,19 +1,191 @@
 
 
 
1 import unittest
2 from src.utils.decapify import decapify
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
4 class TestDecapify(unittest.TestCase):
5
6 def setUp(self):
7 # Set up any necessary test data
8 pass
9
10 def tearDown(self):
11 # Clean up after tests
12 pass
13
14 def test_decapify(self):
15 # Placeholder for decapify function test
16 pass
17
18 if __name__ == '__main__':
19 unittest.main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
--- tests/test_decapify.py
+++ tests/test_decapify.py
@@ -1,19 +1,191 @@
1 """Tests for utils.decapify."""
2 import os
3 import tempfile
4 import unittest
5
6 from utils.decapify import (
7 _sanitize_color,
8 _widget_for_value,
9 _parse_frontmatter,
10 _infer_fields_for_folder,
11 _infer_fields_for_file,
12 _build_collections,
13 decapify,
14 )
15
16
17 class TestSanitizeColor(unittest.TestCase):
18 def test_valid_hex6(self):
19 self.assertEqual(_sanitize_color("#2e3748"), "#2e3748")
20
21 def test_valid_hex3(self):
22 self.assertEqual(_sanitize_color("#fff"), "#fff")
23
24 def test_uppercase(self):
25 self.assertEqual(_sanitize_color("#AABBCC"), "#AABBCC")
26
27 def test_invalid_falls_back(self):
28 self.assertEqual(_sanitize_color("red"), "#2e3748")
29 self.assertEqual(_sanitize_color("javascript:alert(1)"), "#2e3748")
30 self.assertEqual(_sanitize_color("#gggggg"), "#2e3748")
31
32
33 class TestWidgetForValue(unittest.TestCase):
34 def test_bool(self):
35 self.assertEqual(_widget_for_value(True), "boolean")
36 self.assertEqual(_widget_for_value(False), "boolean")
37
38 def test_number(self):
39 self.assertEqual(_widget_for_value(42), "number")
40 self.assertEqual(_widget_for_value(3.14), "number")
41
42 def test_list(self):
43 self.assertEqual(_widget_for_value([]), "list")
44 self.assertEqual(_widget_for_value(["a", "b"]), "list")
45
46 def test_string_default(self):
47 self.assertEqual(_widget_for_value("hello"), "string")
48 self.assertEqual(_widget_for_value(None), "string")
49
50
51 class TestParseFrontmatter(unittest.TestCase):
52 def test_parses_yaml_frontmatter(self):
53 with tempfile.NamedTemporaryFile(mode="w", suffix=".md", delete=False) as f:
54 f.write("---\ntitle: Hello\ndate: 2024-01-01\ndraft: false\n---\n\nBody text.\n")
55 path = f.name
56 try:
57 result = _parse_frontmatter(path)
58 self.assertEqual(result["title"], "Hello")
59 self.assertEqual(result["draft"], False)
60 finally:
61 os.unlink(path)
62
63 def test_empty_on_missing_frontmatter(self):
64 with tempfile.NamedTemporaryFile(mode="w", suffix=".md", delete=False) as f:
65 f.write("No frontmatter here.\n")
66 path = f.name
67 try:
68 self.assertEqual(_parse_frontmatter(path), {})
69 finally:
70 os.unlink(path)
71
72 def test_empty_on_missing_file(self):
73 self.assertEqual(_parse_frontmatter("/nonexistent/path.md"), {})
74
75
76 class TestInferFields(unittest.TestCase):
77 def _make_md(self, dirpath, name, frontmatter):
78 path = os.path.join(dirpath, name)
79 with open(path, "w") as f:
80 f.write("---\n")
81 for k, v in frontmatter.items():
82 f.write(f"{k}: {v!r}\n")
83 f.write("---\n\nBody.\n")
84 return path
85
86 def test_folder_fields_include_known_keys(self):
87 with tempfile.TemporaryDirectory() as tmp:
88 self._make_md(tmp, "post1.md", {"title": "Hello", "date": "2024-01-01", "tags": ["a"]})
89 fields = _infer_fields_for_folder(tmp, ["post1.md"])
90 names = [f["name"] for f in fields]
91 self.assertIn("title", names)
92 self.assertIn("date", names)
93 self.assertIn("tags", names)
94 self.assertIn("body", names)
95
96 def test_folder_fields_always_end_with_body(self):
97 with tempfile.TemporaryDirectory() as tmp:
98 self._make_md(tmp, "post.md", {"title": "Test"})
99 fields = _infer_fields_for_folder(tmp, ["post.md"])
100 self.assertEqual(fields[-1]["name"], "body")
101 self.assertEqual(fields[-1]["widget"], "markdown")
102
103 def test_file_fields_include_all_frontmatter_keys(self):
104 with tempfile.NamedTemporaryFile(mode="w", suffix=".md", delete=False) as f:
105 f.write("---\ntitle: About\nsubtitle: Us\n---\n")
106 path = f.name
107 try:
108 fields = _infer_fields_for_file(path)
109 names = [fi["name"] for fi in fields]
110 self.assertIn("title", names)
111 self.assertIn("subtitle", names)
112 self.assertIn("body", names)
113 finally:
114 os.unlink(path)
115
116
117 class TestBuildCollections(unittest.TestCase):
118 def test_folder_collection_from_md_files(self):
119 with tempfile.TemporaryDirectory() as tmp:
120 blog = os.path.join(tmp, "blog")
121 os.makedirs(blog)
122 for i in range(3):
123 with open(os.path.join(blog, f"post{i}.md"), "w") as f:
124 f.write("---\ntitle: Post\n---\n")
125 collections = _build_collections(tmp)
126 self.assertEqual(len(collections), 1)
127 self.assertEqual(collections[0]["name"], "blog")
128 self.assertIn("folder", collections[0])
129
130 def test_file_collection_from_index_only(self):
131 with tempfile.TemporaryDirectory() as tmp:
132 about = os.path.join(tmp, "about")
133 os.makedirs(about)
134 with open(os.path.join(about, "_index.md"), "w") as f:
135 f.write("---\ntitle: About\n---\n")
136 collections = _build_collections(tmp)
137 self.assertEqual(len(collections), 1)
138 self.assertIn("files", collections[0])
139
140 def test_recursive_md_discovery(self):
141 with tempfile.TemporaryDirectory() as tmp:
142 deep = os.path.join(tmp, "blog", "2024")
143 os.makedirs(deep)
144 with open(os.path.join(deep, "post.md"), "w") as f:
145 f.write("---\ntitle: Deep Post\n---\n")
146 collections = _build_collections(tmp)
147 self.assertEqual(len(collections), 1)
148 self.assertEqual(collections[0]["name"], "blog")
149
150 def test_default_collection_when_empty(self):
151 with tempfile.TemporaryDirectory() as tmp:
152 collections = _build_collections(tmp)
153 self.assertEqual(len(collections), 1)
154 self.assertEqual(collections[0]["name"], "pages")
155
156 def test_nonexistent_dir_returns_default(self):
157 collections = _build_collections("/nonexistent/content")
158 self.assertEqual(len(collections), 1)
159 self.assertEqual(collections[0]["name"], "pages")
160
161
162 class TestDecapify(unittest.TestCase):
163 def test_creates_admin_files(self):
164 with tempfile.TemporaryDirectory() as tmp:
165 content = os.path.join(tmp, "content")
166 os.makedirs(content)
167 with open(os.path.join(content, "_index.md"), "w") as f:
168 f.write("---\ntitle: Home\n---\n")
169 result = decapify(tmp)
170 self.assertIn("complete", result.lower())
171 self.assertTrue(os.path.exists(os.path.join(tmp, "static", "admin", "index.html")))
172 self.assertTrue(os.path.exists(os.path.join(tmp, "static", "admin", "config.yml")))
173
174 def test_admin_index_escapes_name(self):
175 with tempfile.TemporaryDirectory() as tmp:
176 decapify(tmp, cms_name='<script>alert("xss")</script>')
177 with open(os.path.join(tmp, "static", "admin", "index.html")) as f:
178 html = f.read()
179 self.assertNotIn("<script>alert", html)
180 self.assertIn("&lt;script&gt;", html)
181
182 def test_invalid_color_falls_back(self):
183 with tempfile.TemporaryDirectory() as tmp:
184 decapify(tmp, cms_color="not-a-color")
185 with open(os.path.join(tmp, "static", "admin", "index.html")) as f:
186 html = f.read()
187 self.assertIn("#2e3748", html)
188
189
190 if __name__ == "__main__":
191 unittest.main()
192
--- tests/test_deploy.py
+++ tests/test_deploy.py
@@ -1,19 +1,18 @@
1
+"""Tests for utils.deploy."""
12
import unittest
2
-from src.utils.deploy import deploy
3
+
4
+from utils.deploy import deploy
5
+
36
47
class TestDeploy(unittest.TestCase):
5
-
6
- def setUp(self):
7
- # Set up any necessary test data
8
- pass
9
-
10
- def tearDown(self):
11
- # Clean up after tests
12
- pass
13
-
14
- def test_deploy(self):
15
- # Placeholder for deploy function test
16
- pass
17
-
18
-if __name__ == '__main__':
19
- unittest.main()
8
+ def test_returns_complete_message(self):
9
+ result = deploy("/some/path", "example.com")
10
+ self.assertIn("complete", result.lower())
11
+
12
+ def test_accepts_path_and_zone(self):
13
+ result = deploy("/tmp/site", "zone-id-123")
14
+ self.assertIsInstance(result, str)
15
+
16
+
17
+if __name__ == "__main__":
18
+ unittest.main()
2019
--- tests/test_deploy.py
+++ tests/test_deploy.py
@@ -1,19 +1,18 @@
 
1 import unittest
2 from src.utils.deploy import deploy
 
 
3
4 class TestDeploy(unittest.TestCase):
5
6 def setUp(self):
7 # Set up any necessary test data
8 pass
9
10 def tearDown(self):
11 # Clean up after tests
12 pass
13
14 def test_deploy(self):
15 # Placeholder for deploy function test
16 pass
17
18 if __name__ == '__main__':
19 unittest.main()
20
--- tests/test_deploy.py
+++ tests/test_deploy.py
@@ -1,19 +1,18 @@
1 """Tests for utils.deploy."""
2 import unittest
3
4 from utils.deploy import deploy
5
6
7 class TestDeploy(unittest.TestCase):
8 def test_returns_complete_message(self):
9 result = deploy("/some/path", "example.com")
10 self.assertIn("complete", result.lower())
11
12 def test_accepts_path_and_zone(self):
13 result = deploy("/tmp/site", "zone-id-123")
14 self.assertIsInstance(result, str)
15
16
17 if __name__ == "__main__":
18 unittest.main()
 
 
 
 
19
--- tests/test_generate_decap_config.py
+++ tests/test_generate_decap_config.py
@@ -1,44 +1,41 @@
1
-import unittest
2
-from src.utils.generate_decap_config import generate_decap_config, analyze_theme, optimize_for_decap, create_config_yaml
1
+"""Tests for utils.generate_decap_config (thin wrapper around decapify)."""
32
import os
3
+import tempfile
4
+import unittest
5
+
6
+from utils.generate_decap_config import generate_decap_config
7
+
48
59
class TestGenerateDecapConfig(unittest.TestCase):
6
-
7
- def setUp(self):
8
- # Set up a temporary directory for testing
9
- self.test_dir = 'test_theme'
10
- os.makedirs(self.test_dir, exist_ok=True)
11
- with open(os.path.join(self.test_dir, 'index.html'), 'w') as f:
12
- f.write('<html><nav>Menu</nav><div class="hero">Welcome</div><footer>Footer</footer></html>')
13
-
14
- def tearDown(self):
15
- # Clean up the temporary directory after tests
16
- for root, dirs, files in os.walk(self.test_dir, topdown=False):
17
- for name in files:
18
- os.remove(os.path.join(root, name))
19
- for name in dirs:
20
- os.rmdir(os.path.join(root, name))
21
- os.rmdir(self.test_dir)
22
-
23
- def test_analyze_theme(self):
24
- elements = analyze_theme(self.test_dir)
25
- self.assertIn('index.html', elements['navigation'])
26
- self.assertIn('index.html', elements['hero'])
27
- self.assertIn('index.html', elements['footer'])
28
-
29
- def test_optimize_for_decap(self):
30
- optimize_for_decap(self.test_dir)
31
- self.assertTrue(os.path.exists(os.path.join(self.test_dir, 'data', 'navigation.yaml')))
32
-
33
- def test_create_config_yaml(self):
34
- config = create_config_yaml(self.test_dir)
35
- self.assertIn('backend', config)
36
- self.assertIn('collections', config)
37
-
38
- def test_generate_decap_config(self):
39
- result = generate_decap_config(self.test_dir)
40
- self.assertEqual(result, "Decap CMS config generation complete")
41
- self.assertTrue(os.path.exists(os.path.join(self.test_dir, 'config.yml')))
42
-
43
-if __name__ == '__main__':
44
- unittest.main()
10
+ def test_creates_admin_directory(self):
11
+ with tempfile.TemporaryDirectory() as tmp:
12
+ generate_decap_config(tmp)
13
+ self.assertTrue(os.path.isdir(os.path.join(tmp, "static", "admin")))
14
+
15
+ def test_creates_index_html(self):
16
+ with tempfile.TemporaryDirectory() as tmp:
17
+ generate_decap_config(tmp)
18
+ self.assertTrue(os.path.exists(os.path.join(tmp, "static", "admin", "index.html")))
19
+
20
+ def test_creates_config_yml(self):
21
+ with tempfile.TemporaryDirectory() as tmp:
22
+ generate_decap_config(tmp)
23
+ self.assertTrue(os.path.exists(os.path.join(tmp, "static", "admin", "config.yml")))
24
+
25
+ def test_returns_status_string(self):
26
+ with tempfile.TemporaryDirectory() as tmp:
27
+ result = generate_decap_config(tmp)
28
+ self.assertIsInstance(result, str)
29
+ self.assertIn("complete", result.lower())
30
+
31
+ def test_config_yml_has_backend(self):
32
+ with tempfile.TemporaryDirectory() as tmp:
33
+ generate_decap_config(tmp)
34
+ with open(os.path.join(tmp, "static", "admin", "config.yml")) as f:
35
+ content = f.read()
36
+ self.assertIn("backend", content)
37
+ self.assertIn("git-gateway", content)
38
+
39
+
40
+if __name__ == "__main__":
41
+ unittest.main()
4542
--- tests/test_generate_decap_config.py
+++ tests/test_generate_decap_config.py
@@ -1,44 +1,41 @@
1 import unittest
2 from src.utils.generate_decap_config import generate_decap_config, analyze_theme, optimize_for_decap, create_config_yaml
3 import os
 
 
 
 
 
4
5 class TestGenerateDecapConfig(unittest.TestCase):
6
7 def setUp(self):
8 # Set up a temporary directory for testing
9 self.test_dir = 'test_theme'
10 os.makedirs(self.test_dir, exist_ok=True)
11 with open(os.path.join(self.test_dir, 'index.html'), 'w') as f:
12 f.write('<html><nav>Menu</nav><div class="hero">Welcome</div><footer>Footer</footer></html>')
13
14 def tearDown(self):
15 # Clean up the temporary directory after tests
16 for root, dirs, files in os.walk(self.test_dir, topdown=False):
17 for name in files:
18 os.remove(os.path.join(root, name))
19 for name in dirs:
20 os.rmdir(os.path.join(root, name))
21 os.rmdir(self.test_dir)
22
23 def test_analyze_theme(self):
24 elements = analyze_theme(self.test_dir)
25 self.assertIn('index.html', elements['navigation'])
26 self.assertIn('index.html', elements['hero'])
27 self.assertIn('index.html', elements['footer'])
28
29 def test_optimize_for_decap(self):
30 optimize_for_decap(self.test_dir)
31 self.assertTrue(os.path.exists(os.path.join(self.test_dir, 'data', 'navigation.yaml')))
32
33 def test_create_config_yaml(self):
34 config = create_config_yaml(self.test_dir)
35 self.assertIn('backend', config)
36 self.assertIn('collections', config)
37
38 def test_generate_decap_config(self):
39 result = generate_decap_config(self.test_dir)
40 self.assertEqual(result, "Decap CMS config generation complete")
41 self.assertTrue(os.path.exists(os.path.join(self.test_dir, 'config.yml')))
42
43 if __name__ == '__main__':
44 unittest.main()
45
--- tests/test_generate_decap_config.py
+++ tests/test_generate_decap_config.py
@@ -1,44 +1,41 @@
1 """Tests for utils.generate_decap_config (thin wrapper around decapify)."""
 
2 import os
3 import tempfile
4 import unittest
5
6 from utils.generate_decap_config import generate_decap_config
7
8
9 class TestGenerateDecapConfig(unittest.TestCase):
10 def test_creates_admin_directory(self):
11 with tempfile.TemporaryDirectory() as tmp:
12 generate_decap_config(tmp)
13 self.assertTrue(os.path.isdir(os.path.join(tmp, "static", "admin")))
14
15 def test_creates_index_html(self):
16 with tempfile.TemporaryDirectory() as tmp:
17 generate_decap_config(tmp)
18 self.assertTrue(os.path.exists(os.path.join(tmp, "static", "admin", "index.html")))
19
20 def test_creates_config_yml(self):
21 with tempfile.TemporaryDirectory() as tmp:
22 generate_decap_config(tmp)
23 self.assertTrue(os.path.exists(os.path.join(tmp, "static", "admin", "config.yml")))
24
25 def test_returns_status_string(self):
26 with tempfile.TemporaryDirectory() as tmp:
27 result = generate_decap_config(tmp)
28 self.assertIsInstance(result, str)
29 self.assertIn("complete", result.lower())
30
31 def test_config_yml_has_backend(self):
32 with tempfile.TemporaryDirectory() as tmp:
33 generate_decap_config(tmp)
34 with open(os.path.join(tmp, "static", "admin", "config.yml")) as f:
35 content = f.read()
36 self.assertIn("backend", content)
37 self.assertIn("git-gateway", content)
38
39
40 if __name__ == "__main__":
41 unittest.main()
 
 
 
 
 
 
 
42
--- tests/test_hugoify.py
+++ tests/test_hugoify.py
@@ -1,19 +1,70 @@
1
+"""Tests for utils.hugoify."""
2
+import os
3
+import tempfile
14
import unittest
2
-from src.utils.hugoify import hugoify
3
-
4
-class TestHugoify(unittest.TestCase):
5
-
6
- def setUp(self):
7
- # Set up any necessary test data
8
- pass
9
-
10
- def tearDown(self):
11
- # Clean up after tests
12
- pass
13
-
14
- def test_hugoify(self):
15
- # Placeholder for hugoify function test
16
- pass
17
-
18
-if __name__ == '__main__':
19
- unittest.main()
5
+
6
+from utils.hugoify import _parse_layout_json, _fallback_baseof, hugoify_dir
7
+
8
+
9
+class TestParseLayoutJson(unittest.TestCase):
10
+ def test_parses_valid_json(self):
11
+ response = '{"_default/baseof.html": "<!doctype html>", "index.html": "{{ define \\"main\\" }}{{ end }}"}'
12
+ result = _parse_layout_json(response)
13
+ self.assertIn("_default/baseof.html", result)
14
+ self.assertEqual(result["_default/baseof.html"], "<!doctype html>")
15
+
16
+ def test_extracts_json_from_prose(self):
17
+ response = 'Here is the converted theme:\n{"_default/baseof.html": "<html></html>"}\nDone.'
18
+ result = _parse_layout_json(response)
19
+ self.assertIn("_default/baseof.html", result)
20
+
21
+ def test_falls_back_on_invalid_json(self):
22
+ result = _parse_layout_json("This is not JSON at all.")
23
+ self.assertIn("_default/baseof.html", result)
24
+ self.assertIn("partials/header.html", result)
25
+ self.assertIn("partials/footer.html", result)
26
+ self.assertIn("index.html", result)
27
+
28
+ def test_fallback_contains_valid_hugo_syntax(self):
29
+ result = _parse_layout_json("not json")
30
+ baseof = result["_default/baseof.html"]
31
+ self.assertIn("block", baseof)
32
+ self.assertIn("partial", baseof)
33
+
34
+
35
+class TestFallbackBaseof(unittest.TestCase):
36
+ def test_contains_required_hugo_blocks(self):
37
+ result = _fallback_baseof()
38
+ self.assertIn('block "main"', result)
39
+ self.assertIn('partial "header.html"', result)
40
+ self.assertIn('partial "footer.html"', result)
41
+ self.assertIn("<!DOCTYPE html>", result)
42
+
43
+ def test_contains_language_code(self):
44
+ result = _fallback_baseof()
45
+ self.assertIn(".Site.LanguageCode", result)
46
+
47
+
48
+class TestHugoifyDir(unittest.TestCase):
49
+ def test_valid_theme_passes(self):
50
+ with tempfile.TemporaryDirectory() as tmp:
51
+ baseof = os.path.join(tmp, "layouts", "_default", "baseof.html")
52
+ os.makedirs(os.path.dirname(baseof))
53
+ open(baseof, "w").close()
54
+ result = hugoify_dir(tmp)
55
+ self.assertIn("Valid", result)
56
+
57
+ def test_missing_layouts_fails(self):
58
+ with tempfile.TemporaryDirectory() as tmp:
59
+ result = hugoify_dir(tmp)
60
+ self.assertIn("failed", result.lower())
61
+
62
+ def test_missing_baseof_reports_issue(self):
63
+ with tempfile.TemporaryDirectory() as tmp:
64
+ os.makedirs(os.path.join(tmp, "layouts", "_default"))
65
+ result = hugoify_dir(tmp)
66
+ self.assertIn("baseof.html", result)
67
+
68
+
69
+if __name__ == "__main__":
70
+ unittest.main()
2071
--- tests/test_hugoify.py
+++ tests/test_hugoify.py
@@ -1,19 +1,70 @@
 
 
 
1 import unittest
2 from src.utils.hugoify import hugoify
3
4 class TestHugoify(unittest.TestCase):
5
6 def setUp(self):
7 # Set up any necessary test data
8 pass
9
10 def tearDown(self):
11 # Clean up after tests
12 pass
13
14 def test_hugoify(self):
15 # Placeholder for hugoify function test
16 pass
17
18 if __name__ == '__main__':
19 unittest.main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
--- tests/test_hugoify.py
+++ tests/test_hugoify.py
@@ -1,19 +1,70 @@
1 """Tests for utils.hugoify."""
2 import os
3 import tempfile
4 import unittest
5
6 from utils.hugoify import _parse_layout_json, _fallback_baseof, hugoify_dir
7
8
9 class TestParseLayoutJson(unittest.TestCase):
10 def test_parses_valid_json(self):
11 response = '{"_default/baseof.html": "<!doctype html>", "index.html": "{{ define \\"main\\" }}{{ end }}"}'
12 result = _parse_layout_json(response)
13 self.assertIn("_default/baseof.html", result)
14 self.assertEqual(result["_default/baseof.html"], "<!doctype html>")
15
16 def test_extracts_json_from_prose(self):
17 response = 'Here is the converted theme:\n{"_default/baseof.html": "<html></html>"}\nDone.'
18 result = _parse_layout_json(response)
19 self.assertIn("_default/baseof.html", result)
20
21 def test_falls_back_on_invalid_json(self):
22 result = _parse_layout_json("This is not JSON at all.")
23 self.assertIn("_default/baseof.html", result)
24 self.assertIn("partials/header.html", result)
25 self.assertIn("partials/footer.html", result)
26 self.assertIn("index.html", result)
27
28 def test_fallback_contains_valid_hugo_syntax(self):
29 result = _parse_layout_json("not json")
30 baseof = result["_default/baseof.html"]
31 self.assertIn("block", baseof)
32 self.assertIn("partial", baseof)
33
34
35 class TestFallbackBaseof(unittest.TestCase):
36 def test_contains_required_hugo_blocks(self):
37 result = _fallback_baseof()
38 self.assertIn('block "main"', result)
39 self.assertIn('partial "header.html"', result)
40 self.assertIn('partial "footer.html"', result)
41 self.assertIn("<!DOCTYPE html>", result)
42
43 def test_contains_language_code(self):
44 result = _fallback_baseof()
45 self.assertIn(".Site.LanguageCode", result)
46
47
48 class TestHugoifyDir(unittest.TestCase):
49 def test_valid_theme_passes(self):
50 with tempfile.TemporaryDirectory() as tmp:
51 baseof = os.path.join(tmp, "layouts", "_default", "baseof.html")
52 os.makedirs(os.path.dirname(baseof))
53 open(baseof, "w").close()
54 result = hugoify_dir(tmp)
55 self.assertIn("Valid", result)
56
57 def test_missing_layouts_fails(self):
58 with tempfile.TemporaryDirectory() as tmp:
59 result = hugoify_dir(tmp)
60 self.assertIn("failed", result.lower())
61
62 def test_missing_baseof_reports_issue(self):
63 with tempfile.TemporaryDirectory() as tmp:
64 os.makedirs(os.path.join(tmp, "layouts", "_default"))
65 result = hugoify_dir(tmp)
66 self.assertIn("baseof.html", result)
67
68
69 if __name__ == "__main__":
70 unittest.main()
71
--- tests/test_parser.py
+++ tests/test_parser.py
@@ -1,19 +1,18 @@
1
-import unittest
2
-from src.utils.parser import parse
3
-
4
-class TestParser(unittest.TestCase):
5
-
6
- def setUp(self):
7
- # Set up any necessary test data
8
- pass
9
-
10
- def tearDown(self):
11
- # Clean up after tests
12
- pass
13
-
14
- def test_parse(self):
15
- # Placeholder for parse function test
16
- pass
17
-
18
-if __name__ == '__main__':
19
- unittest.main()
1
+"""Tests for utils.parser."""
2
+import unittest
3
+
4
+from utils.parser import parse
5
+
6
+
7
+class TestParse(unittest.TestCase):
8
+ def test_returns_complete_message(self):
9
+ result = parse("/some/path")
10
+ self.assertIn("complete", result.lower())
11
+
12
+ def test_accepts_path(self):
13
+ result = parse("/tmp/site")
14
+ self.assertIsInstance(result, str)
15
+
16
+
17
+if __name__ == "__main__":
18
+ unittest.main()
2019
2120
ADDED tests/test_theme_finder.py
2221
ADDED tests/test_theme_patcher.py
--- tests/test_parser.py
+++ tests/test_parser.py
@@ -1,19 +1,18 @@
1 import unittest
2 from src.utils.parser import parse
3
4 class TestParser(unittest.TestCase):
5
6 def setUp(self):
7 # Set up any necessary test data
8 pass
9
10 def tearDown(self):
11 # Clean up after tests
12 pass
13
14 def test_parse(self):
15 # Placeholder for parse function test
16 pass
17
18 if __name__ == '__main__':
19 unittest.main()
20
21 DDED tests/test_theme_finder.py
22 DDED tests/test_theme_patcher.py
--- tests/test_parser.py
+++ tests/test_parser.py
@@ -1,19 +1,18 @@
1 """Tests for utils.parser."""
2 import unittest
3
4 from utils.parser import parse
5
6
7 class TestParse(unittest.TestCase):
8 def test_returns_complete_message(self):
9 result = parse("/some/path")
10 self.assertIn("complete", result.lower())
11
12 def test_accepts_path(self):
13 result = parse("/tmp/site")
14 self.assertIsInstance(result, str)
15
16
17 if __name__ == "__main__":
18 unittest.main()
 
19
20 DDED tests/test_theme_finder.py
21 DDED tests/test_theme_patcher.py
--- a/tests/test_theme_finder.py
+++ b/tests/test_theme_finder.py
@@ -0,0 +1,37 @@
1
+"""Tests for utils.theme_finder."""
2
+import os
3
+import tempfile
4
+import unittest
5
+
6
+from utils.theme_finder import find_hugo_theme, find_raw_html_files
7
+
8
+
9
+def _make_hugo_theme(base_dir, theme_name="test-theme"):
10
+ """Create a minimal Hugo theme structure."""
11
+ layouts = os.path.join(base_dir, theme_name, "layouts", "_default")
12
+ os.makedirs(layouts)
13
+ open(os.path.join(layouts, "baseof.html"), "w").close()
14
+ return os.path.join(base_dir, theme_name)
15
+
16
+
17
+class TestFindHugoTheme(unittest.TestCase):
18
+ def test_finds_theme_with_layouts(self):
19
+ with tempfile.TemporaryDirectory() as tmp:
20
+ theme_path = _make_hugo_theme(tmp)
21
+ result = find_hugo_theme(theme_path)
22
+ self.assertIsNotNone(result)
23
+ self.assertTrue(result["is_hugo_theme"])
24
+ self.assertEqual(result["theme_name"], "test-theme")
25
+
26
+ def test_finds_example_site(self):
27
+ with tempfile.TemporaryDirectory() as tmp:
28
+ theme_path = _make_hugo_theme(tmp)
29
+ example = os.path.join(theme_path, "exampleSite")
30
+ os.makedirs(example)
31
+ result = find_hugo_theme(theme_path)
32
+ self.assertEqual(result["example_site"], example)
33
+
34
+ def test_returns_none_for_non_hugo_dir(self):
35
+ with tempfile.TemporaryDirectory() as tmp:
36
+ os.makedirs(os.path.join(tmp, "css"))
37
+
--- a/tests/test_theme_finder.py
+++ b/tests/test_theme_finder.py
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/tests/test_theme_finder.py
+++ b/tests/test_theme_finder.py
@@ -0,0 +1,37 @@
1 """Tests for utils.theme_finder."""
2 import os
3 import tempfile
4 import unittest
5
6 from utils.theme_finder import find_hugo_theme, find_raw_html_files
7
8
9 def _make_hugo_theme(base_dir, theme_name="test-theme"):
10 """Create a minimal Hugo theme structure."""
11 layouts = os.path.join(base_dir, theme_name, "layouts", "_default")
12 os.makedirs(layouts)
13 open(os.path.join(layouts, "baseof.html"), "w").close()
14 return os.path.join(base_dir, theme_name)
15
16
17 class TestFindHugoTheme(unittest.TestCase):
18 def test_finds_theme_with_layouts(self):
19 with tempfile.TemporaryDirectory() as tmp:
20 theme_path = _make_hugo_theme(tmp)
21 result = find_hugo_theme(theme_path)
22 self.assertIsNotNone(result)
23 self.assertTrue(result["is_hugo_theme"])
24 self.assertEqual(result["theme_name"], "test-theme")
25
26 def test_finds_example_site(self):
27 with tempfile.TemporaryDirectory() as tmp:
28 theme_path = _make_hugo_theme(tmp)
29 example = os.path.join(theme_path, "exampleSite")
30 os.makedirs(example)
31 result = find_hugo_theme(theme_path)
32 self.assertEqual(result["example_site"], example)
33
34 def test_returns_none_for_non_hugo_dir(self):
35 with tempfile.TemporaryDirectory() as tmp:
36 os.makedirs(os.path.join(tmp, "css"))
37
--- a/tests/test_theme_patcher.py
+++ b/tests/test_theme_patcher.py
@@ -0,0 +1,60 @@
1
+"""Tests for utils.theme_patcher."""
2
+import os
3
+import tempfile
4
+import unittest
5
+
6
+from utils.theme_patcher import patch_theme, patch_config
7
+
8
+
9
+class TestPatchtch_theme
10
+
11
+
12
+class TestPatchTheme(unittest.TestCase):
13
+ def _write_layout(self, layouts_dir, name, content):
14
+ path = os.path.join(layouts_dir, name)
15
+ with open(path, "w") as f:
16
+ f.write(content)
17
+ return path
18
+
19
+ def test_patches_disqus_shortname(self):
20
+ with tempfile.TemporaryDirectory() as tmp:
21
+ layouts = os.path.join(tmp, "layouts")
22
+ os.makedirs(layouts)
23
+ self._write_layout(layouts, "single.html", "{{ .Site.DisqusShortname }}")
24
+ patch_theme(tmp)
25
+ with open(os.path.join(layouts, "single.html")) as f:
26
+ result = f.read()
27
+ self.assertIn(".Site.Config.Services.Disqus.Shortname", result)
28
+ self.assertNotIn(".Site.DisqusShortname", result)
29
+
30
+ def test_patches_google_analytics(self):
31
+ with tempfile.TemporaryDirectory() as tmp:
32
+ layouts = os.path.join(tmp, "layouts")
33
+ os.makedirs(layouts)
34
+ self._write_layout(layouts, "head.html", "{{ .Site.GoogleAnalytics }}")
35
+ patch_theme(tmp)
36
+ with open(os.path.join(layouts, "head.html")) as f:
37
+ result = f.read()
38
+ self.assertIn(".Site.Config.Services.GoogleAnalytics.ID", result)
39
+
40
+ def test_no_change_when_already_patched(self):
41
+ with tempfile.TemporaryDirectory() as tmp:
42
+ layouts = os.path.join(tmp, "layouts")
43
+ os.makedirs(layouts)
44
+ content = "{{ .Site.Config.Services.Disqus.Shortname }}"
45
+ self._write_layout(layouts, "single.html", content)
46
+ patch_theme(tmp)
47
+ with open(os.path.join(layouts, "single.html")) as f:
48
+ result = f.read()
49
+ self.assertEqual(result, content)
50
+
51
+ def test_no_layouts_dir_is_safe(self):
52
+ with tempfile.TemporaryDirectory() as tmp:
53
+ # Should not raise even if layouts/ doesn't exist
54
+ patch_theme(tmp)
55
+
56
+
57
+class TestPatchConfig(unittest.TestCase):
58
+ def _write_config(self, path, content):
59
+ with open(path, "w") as f:
60
+
--- a/tests/test_theme_patcher.py
+++ b/tests/test_theme_patcher.py
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/tests/test_theme_patcher.py
+++ b/tests/test_theme_patcher.py
@@ -0,0 +1,60 @@
1 """Tests for utils.theme_patcher."""
2 import os
3 import tempfile
4 import unittest
5
6 from utils.theme_patcher import patch_theme, patch_config
7
8
9 class TestPatchtch_theme
10
11
12 class TestPatchTheme(unittest.TestCase):
13 def _write_layout(self, layouts_dir, name, content):
14 path = os.path.join(layouts_dir, name)
15 with open(path, "w") as f:
16 f.write(content)
17 return path
18
19 def test_patches_disqus_shortname(self):
20 with tempfile.TemporaryDirectory() as tmp:
21 layouts = os.path.join(tmp, "layouts")
22 os.makedirs(layouts)
23 self._write_layout(layouts, "single.html", "{{ .Site.DisqusShortname }}")
24 patch_theme(tmp)
25 with open(os.path.join(layouts, "single.html")) as f:
26 result = f.read()
27 self.assertIn(".Site.Config.Services.Disqus.Shortname", result)
28 self.assertNotIn(".Site.DisqusShortname", result)
29
30 def test_patches_google_analytics(self):
31 with tempfile.TemporaryDirectory() as tmp:
32 layouts = os.path.join(tmp, "layouts")
33 os.makedirs(layouts)
34 self._write_layout(layouts, "head.html", "{{ .Site.GoogleAnalytics }}")
35 patch_theme(tmp)
36 with open(os.path.join(layouts, "head.html")) as f:
37 result = f.read()
38 self.assertIn(".Site.Config.Services.GoogleAnalytics.ID", result)
39
40 def test_no_change_when_already_patched(self):
41 with tempfile.TemporaryDirectory() as tmp:
42 layouts = os.path.join(tmp, "layouts")
43 os.makedirs(layouts)
44 content = "{{ .Site.Config.Services.Disqus.Shortname }}"
45 self._write_layout(layouts, "single.html", content)
46 patch_theme(tmp)
47 with open(os.path.join(layouts, "single.html")) as f:
48 result = f.read()
49 self.assertEqual(result, content)
50
51 def test_no_layouts_dir_is_safe(self):
52 with tempfile.TemporaryDirectory() as tmp:
53 # Should not raise even if layouts/ doesn't exist
54 patch_theme(tmp)
55
56
57 class TestPatchConfig(unittest.TestCase):
58 def _write_config(self, path, content):
59 with open(path, "w") as f:
60
--- tests/test_translate.py
+++ tests/test_translate.py
@@ -1,19 +1,44 @@
1
+"""Tests for utils.translate."""
2
+import os
3
+import tempfile
14
import unittest
2
-from src.utils.translate import translate
5
+from unittest.mock import patch
6
+
37
48
class TestTranslate(unittest.TestCase):
5
-
6
- def setUp(self):
7
- # Set up any necessary test data
8
- pass
9
-
10
- def tearDown(self):
11
- # Clean up after tests
12
- pass
13
-
14
- def test_translate(self):
15
- # Placeholder for translate function test
16
- pass
17
-
18
-if __name__ == '__main__':
19
- unittest.main()
9
+ def test_translates_file_content(self):
10
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".html", delete=False) as f:
11
+ f.write("<p>Hello world</p>")
12
+ path = f.name
13
+ try:
14
+ from utils.translate import translate
15
+ with patch("utils.translate.call_ai", return_value="<p>Hola mundo</p>") as mock_ai:
16
+ result = translate(path, target_language="Spanish")
17
+ self.assertEqual(result, "<p>Hola mundo</p>")
18
+ call_args = mock_ai.call_args[0][0]
19
+ self.assertIn("Spanish", call_args)
20
+ self.assertIn("Hello world", call_args)
21
+ finally:
22
+ os.unlink(path)
23
+
24
+ def test_uses_target_language_param(self):
25
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".html", delete=False) as f:
26
+ f.write("<p>Bonjour</p>")
27
+ path = f.name
28
+ try:
29
+ from utils.translate import translate
30
+ with patch("utils.translate.call_ai", return_value="<p>Hallo</p>") as mock_ai:
31
+ translate(path, target_language="German")
32
+ call_args = mock_ai.call_args[0][0]
33
+ self.assertIn("German", call_args)
34
+ finally:
35
+ os.unlink(path)
36
+
37
+ def test_returns_error_on_missing_file(self):
38
+ from utils.translate import translate
39
+ result = translate("/nonexistent/file.html")
40
+ self.assertIn("failed", result.lower())
41
+
42
+
43
+if __name__ == "__main__":
44
+ unittest.main()
2045
--- tests/test_translate.py
+++ tests/test_translate.py
@@ -1,19 +1,44 @@
 
 
 
1 import unittest
2 from src.utils.translate import translate
 
3
4 class TestTranslate(unittest.TestCase):
5
6 def setUp(self):
7 # Set up any necessary test data
8 pass
9
10 def tearDown(self):
11 # Clean up after tests
12 pass
13
14 def test_translate(self):
15 # Placeholder for translate function test
16 pass
17
18 if __name__ == '__main__':
19 unittest.main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
--- tests/test_translate.py
+++ tests/test_translate.py
@@ -1,19 +1,44 @@
1 """Tests for utils.translate."""
2 import os
3 import tempfile
4 import unittest
5 from unittest.mock import patch
6
7
8 class TestTranslate(unittest.TestCase):
9 def test_translates_file_content(self):
10 with tempfile.NamedTemporaryFile(mode="w", suffix=".html", delete=False) as f:
11 f.write("<p>Hello world</p>")
12 path = f.name
13 try:
14 from utils.translate import translate
15 with patch("utils.translate.call_ai", return_value="<p>Hola mundo</p>") as mock_ai:
16 result = translate(path, target_language="Spanish")
17 self.assertEqual(result, "<p>Hola mundo</p>")
18 call_args = mock_ai.call_args[0][0]
19 self.assertIn("Spanish", call_args)
20 self.assertIn("Hello world", call_args)
21 finally:
22 os.unlink(path)
23
24 def test_uses_target_language_param(self):
25 with tempfile.NamedTemporaryFile(mode="w", suffix=".html", delete=False) as f:
26 f.write("<p>Bonjour</p>")
27 path = f.name
28 try:
29 from utils.translate import translate
30 with patch("utils.translate.call_ai", return_value="<p>Hallo</p>") as mock_ai:
31 translate(path, target_language="German")
32 call_args = mock_ai.call_args[0][0]
33 self.assertIn("German", call_args)
34 finally:
35 os.unlink(path)
36
37 def test_returns_error_on_missing_file(self):
38 from utils.translate import translate
39 result = translate("/nonexistent/file.html")
40 self.assertIn("failed", result.lower())
41
42
43 if __name__ == "__main__":
44 unittest.main()
45

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button