aboutsummaryrefslogtreecommitdiff
path: root/scripts/theme-studio/test_generate.py
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-06-09 07:45:18 -0500
committerCraig Jennings <c@cjennings.net>2026-06-09 07:45:18 -0500
commit092a2312a1d2fa1364b1d5cb9c2d71a8aefaeb8e (patch)
treee2d1f2a58e4b5af1cfe2c6fec8379b61ac80bb6a /scripts/theme-studio/test_generate.py
parentec3d767435390cebedee8e3ca504d4b20d52f735 (diff)
downloaddotemacs-092a2312a1d2fa1364b1d5cb9c2d71a8aefaeb8e.tar.gz
dotemacs-092a2312a1d2fa1364b1d5cb9c2d71a8aefaeb8e.zip
test(theme-studio): extract color/slug helpers to importable modules and cover them
The pure helpers that were still stranded in app.js — normHex, ratingColor, textOn, and the filename-slug logic — had no unit tests because app.js can't be imported (it runs its bootstrap and references the data placeholders at load). Moved them into importable modules so they can be tested directly: a new app-util.js holds the color/UI-boundary trio, and slugify joins app-core.js. app.js keeps thin wrappers, so no call site changed and the built DOM is byte-identical. textOn needs rl from colormath, so generate.py's inline strip now drops import lines as well as export lines — app-util.js imports rl for its tests, and the import is stripped on inline where rl is already in the page. _faces in generate.py also gets direct tests for its prefix-strip and label derivation. New: 12 node tests (normHex, ratingColor, textOn, slugify) and 7 python tests (_faces, app-util integrity, the import strip). Coverage: app-util.js 100/100/100, app-core.js 100/94.9/100, colormath.js 100/96/100 (line/branch/func); generate.py 89% lines (the rest is the __main__ writer and the optional seed-env branch). No bugs surfaced — the logic was correct, just untested.
Diffstat (limited to 'scripts/theme-studio/test_generate.py')
-rw-r--r--scripts/theme-studio/test_generate.py42
1 files changed, 41 insertions, 1 deletions
diff --git a/scripts/theme-studio/test_generate.py b/scripts/theme-studio/test_generate.py
index 077382e4..ee13f8de 100644
--- a/scripts/theme-studio/test_generate.py
+++ b/scripts/theme-studio/test_generate.py
@@ -30,6 +30,12 @@ class StripExports(unittest.TestCase):
src = "export const a=1;\ncode();\nexport { a };"
self.assertEqual(generate.strip_exports(src), "code();")
+ def test_removes_import_lines_too(self):
+ # A pure module may import a peer for its own tests; the import must be
+ # stripped on inline (the peer is already in the page).
+ src = "import { rl } from './colormath.js';\nfunction f(){return rl();}"
+ self.assertEqual(generate.strip_exports(src), "function f(){return rl();}")
+
def test_matches_the_js_side_strip_so_integrity_holds(self):
# test-colormath.mjs strips with the same rule: drop lines starting with
# 'export', then trim trailing whitespace. Keep the two in lockstep.
@@ -62,7 +68,7 @@ class ColormathInlining(unittest.TestCase):
class AssembledPage(unittest.TestCase):
PLACEHOLDERS = [
- "STYLES_CSS", "APP_JS", "APP_CORE_J",
+ "STYLES_CSS", "APP_JS", "APP_CORE_J", "APP_UTIL_J",
"COLORMATH_J", "SAMPLES_J", "PALETTE_J", "CATS_J",
"UIFACES_J", "UIMAP_J", "APPS_J", "BOLD_J", "MAP_J",
]
@@ -81,6 +87,15 @@ class AssembledPage(unittest.TestCase):
# and the unit-tested module cannot drift.
self.assertIn(generate.APP_CORE_BODY, generate.HTML)
+ def test_page_carries_the_app_util_body_verbatim(self):
+ # app-util.js inlines verbatim after its import line is stripped.
+ self.assertIn(generate.APP_UTIL_BODY, generate.HTML)
+
+ def test_app_util_inlined_body_has_no_import_line(self):
+ # The `import rl` line must be gone, or the page <script> is invalid.
+ for line in generate.APP_UTIL_BODY.splitlines():
+ self.assertFalse(line.startswith("import"), f"import survived: {line!r}")
+
def test_page_carries_the_stylesheet_verbatim(self):
# styles.css has no placeholders, so it inlines verbatim: the inlined copy
# and the source file cannot drift.
@@ -97,5 +112,30 @@ class AssembledPage(unittest.TestCase):
self.assertEqual(generate.HTML.count("</script>"), 1)
+class FacesHelper(unittest.TestCase):
+ def test_strips_prefix_and_derives_label_and_merges_seed(self):
+ # Normal: the prefix comes off the label, and the per-face seed is attached.
+ rows = generate._faces(["org-todo", "org-done"], "org-", {"org-todo": {"fg": "gold"}})
+ self.assertEqual(rows, [
+ ["org-todo", "todo", {"fg": "gold"}],
+ ["org-done", "done", {}],
+ ])
+
+ def test_label_drops_face_suffix_and_spaces_remaining_dashes(self):
+ # Boundary: "-face" is removed and the rest of the dashes become spaces.
+ rows = generate._faces(["lsp-rename-placeholder-face"], "lsp-", {})
+ self.assertEqual(rows[0][1], "rename placeholder")
+
+ def test_name_without_the_prefix_is_left_intact(self):
+ # Boundary: a name that doesn't start with the prefix keeps its full text
+ # (only "-face" removal and dash-spacing apply).
+ rows = generate._faces(["shr-text"], "org-", {})
+ self.assertEqual(rows[0], ["shr-text", "shr text", {}])
+
+ def test_empty_names_gives_empty_list(self):
+ # Error/Boundary: nothing in, nothing out.
+ self.assertEqual(generate._faces([], "org-", {"org-todo": {"fg": "gold"}}), [])
+
+
if __name__ == "__main__":
unittest.main()