aboutsummaryrefslogtreecommitdiff
path: root/scripts/theme-studio/test_generate.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/theme-studio/test_generate.py')
-rw-r--r--scripts/theme-studio/test_generate.py179
1 files changed, 128 insertions, 51 deletions
diff --git a/scripts/theme-studio/test_generate.py b/scripts/theme-studio/test_generate.py
index ed2ce74ba..974fca68a 100644
--- a/scripts/theme-studio/test_generate.py
+++ b/scripts/theme-studio/test_generate.py
@@ -10,6 +10,7 @@ Run: python3 -m unittest test_generate (from scripts/theme-studio/)
"""
import os
import io
+import json
import tempfile
import runpy
import unittest
@@ -82,38 +83,36 @@ class AssembledPage(unittest.TestCase):
"PALETTE_ACTIONS_J", "BROWSER_GATES_J",
"COLORMATH_J", "SAMPLES_J", "PALETTE_J", "CATS_J",
"UIFACES_J", "UIMAP_J", "APPS_J", "SYNTAX_J", "MAP_J",
- "COLOR_NAMES_J",
+ "COLOR_NAMES_J", "FACE_DOCS_J", "SYNTAX_DOCS_J",
]
def test_every_placeholder_is_substituted(self):
for token in self.PLACEHOLDERS:
self.assertNotIn(token, generate.HTML, f"{token} left unsubstituted")
- def test_page_carries_the_colormath_body_verbatim(self):
- # Python-side inline-integrity: the same guarantee the JS test asserts, but
- # checked at the point the page is built rather than after a round-trip.
- self.assertIn(generate.COLORMATH_BODY, generate.HTML)
-
- def test_page_carries_the_app_core_body_verbatim(self):
- # app-core.js inlines verbatim (no data placeholders), so the inlined copy
- # 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_page_carries_palette_generator_core_verbatim(self):
- self.assertIn(generate.PALETTE_GENERATOR_CORE_BODY, generate.HTML)
-
- def test_page_carries_palette_generator_ui_verbatim(self):
- self.assertIn(generate.PALETTE_GENERATOR_UI_BODY, generate.HTML)
-
- def test_page_carries_palette_actions_verbatim(self):
- self.assertIn(generate.PALETTE_ACTIONS_BODY, generate.HTML)
-
- def test_page_carries_browser_gates_verbatim(self):
- self.assertIn(generate.BROWSER_GATES_BODY, generate.HTML)
+ def test_face_docs_maps_embed_a_known_docstring(self):
+ # The face/syntax docstring maps inline so element hovers can show them.
+ # default is always present; its first line is stable across Emacs builds.
+ self.assertIn("Basic default face.", generate.FACE_DOCS["default"])
+ self.assertIn(json.dumps(generate.FACE_DOCS), generate.HTML)
+
+ def test_syntax_docs_resolve_categories_to_face_docstrings(self):
+ # The syntax table is keyed by category (kw, doc, ...); each resolves to
+ # its font-lock face's docstring via build-theme's canonical map.
+ self.assertIn("keyword", generate.SYNTAX_DOCS["kw"].lower())
+ self.assertIn(json.dumps(generate.SYNTAX_DOCS), generate.HTML)
+
+ def test_page_carries_each_inlined_body_verbatim(self):
+ # Python-side inline-integrity: every verbatim-inlined module (no data
+ # placeholders, exports/imports stripped) must appear in the page byte for
+ # byte, so the inlined copy and the unit-tested module cannot drift. Checked
+ # at build time rather than after a round-trip. app-util.js's import line is
+ # already stripped in APP_UTIL_BODY.
+ for name in ("COLORMATH_BODY", "APP_CORE_BODY", "APP_UTIL_BODY",
+ "PALETTE_GENERATOR_CORE_BODY", "PALETTE_GENERATOR_UI_BODY",
+ "PALETTE_ACTIONS_BODY", "BROWSER_GATES_BODY"):
+ with self.subTest(body=name):
+ self.assertIn(getattr(generate, name), 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.
@@ -164,6 +163,20 @@ class LanguageSamples(unittest.TestCase):
self.assertIn("@import", text)
self.assertIn("error.MissingColor", text)
+ def test_expanded_language_set_is_registered_and_renders(self):
+ # Every added language is selectable and renders a non-trivial sample that
+ # exercises keywords and carries a comment.
+ added = ["Racket", "Scheme", "Haskell", "OCaml", "Scala", "Kotlin",
+ "Swift", "Lua", "Ruby", "Perl", "R", "Erlang", "SQL", "PHP",
+ "Ada", "Fortran", "MATLAB", "Assembly"]
+ for lang in added:
+ self.assertIn(lang, generate.SAMPLES, f"{lang} not in the language selector")
+ tokens = self._tokens(lang)
+ cats = {k for k, _ in tokens}
+ self.assertGreater(len(tokens), 40, f"{lang} sample is too short")
+ self.assertIn("kw", cats, f"{lang} sample has no keywords")
+ self.assertIn("cmd", cats, f"{lang} sample has no comment")
+
class FacesHelper(unittest.TestCase):
def test_strips_prefix_and_derives_label_and_merges_seed(self):
@@ -192,27 +205,54 @@ class FacesHelper(unittest.TestCase):
class FaceSpecDefaults(unittest.TestCase):
def test_ui_face_spec_fills_style_fields(self):
+ # The legacy "bold" migrates to weight "bold" through face_spec.
self.assertEqual(ui_face_spec({"bg": "#ffffff", "bold": True}), {
"fg": None,
"bg": "#ffffff",
- "bold": True,
- "italic": False,
- "underline": False,
- "strike": False,
+ "distant-fg": None,
+ "family": None,
+ "weight": "bold",
+ "slant": None,
+ "underline": None,
+ "strike": None,
+ "overline": None,
"box": None,
+ "inverse": False,
+ "extend": False,
+ "inherit": None,
+ "height": None,
})
+ def test_ui_face_spec_carries_inherit_and_height(self):
+ # inherit/height are no longer package-only; a ui face can set them.
+ spec = ui_face_spec({"inherit": "shadow", "height": 1.3})
+ self.assertEqual(spec["inherit"], "shadow")
+ self.assertEqual(spec["height"], 1.3)
+
+ def test_face_spec_migrates_legacy_style_booleans(self):
+ spec = ui_face_spec({"italic": True, "underline": True, "strike": True})
+ self.assertEqual(spec["slant"], "italic")
+ self.assertEqual(spec["underline"], {"style": "line", "color": None})
+ self.assertEqual(spec["strike"], {"color": None})
+ self.assertNotIn("bold", spec)
+ self.assertNotIn("italic", spec)
+
def test_package_face_spec_fills_structure_fields(self):
self.assertEqual(package_face_spec({"inherit": "base", "height": 1.2}), {
"fg": None,
"bg": None,
- "bold": False,
- "italic": False,
- "underline": False,
- "strike": False,
+ "distant-fg": None,
+ "family": None,
+ "weight": None,
+ "slant": None,
+ "underline": None,
+ "strike": None,
+ "overline": None,
+ "box": None,
+ "inverse": False,
+ "extend": False,
"inherit": "base",
"height": 1.2,
- "box": None,
})
def test_generated_color_names_are_base_columns_when_legacy(self):
@@ -240,6 +280,19 @@ class GeneratorStateHelpers(unittest.TestCase):
self.assertTrue(uimap["link"]["underline"])
self.assertEqual(uimap["mode-line"]["box"], {"style": "released", "width": 1, "color": None})
+ def test_mode_line_highlight_defaults_to_raised_box(self):
+ # The face is absent from the snapshot, so it must get the raised box in
+ # both the with-snapshot and no-snapshot branches.
+ raised = {"style": "released", "width": 1, "color": None}
+ self.assertEqual(generate.UIMAP["mode-line-highlight"]["box"], raised)
+ no_snapshot = generate.build_uimap(generate.UI_FACES, DefaultFaces(None))
+ self.assertEqual(no_snapshot["mode-line-highlight"]["box"], raised)
+
+ def test_hover_box_default_yields_to_existing_box(self):
+ uimap = {"mode-line-highlight": ui_face_spec({"box": {"style": "line", "width": 2, "color": "#abcdef"}})}
+ generate.apply_hover_box_default(uimap)
+ self.assertEqual(uimap["mode-line-highlight"]["box"], {"style": "line", "width": 2, "color": "#abcdef"})
+
def test_build_syntax_uses_map_and_style_fallbacks_without_defaults_snapshot(self):
syntax = generate.build_syntax(
{"kw": [None, True]},
@@ -249,8 +302,8 @@ class GeneratorStateHelpers(unittest.TestCase):
DefaultFaces(None),
)
self.assertEqual(syntax["kw"]["fg"], "#d3d3d3")
- self.assertTrue(syntax["kw"]["bold"])
- self.assertFalse(syntax["kw"]["italic"])
+ self.assertEqual(syntax["kw"]["weight"], "bold")
+ self.assertIsNone(syntax["kw"]["slant"])
def test_builtin_fallback_styles_fill_known_emacs_styles(self):
uimap = {
@@ -262,12 +315,13 @@ class GeneratorStateHelpers(unittest.TestCase):
)
}
generate.apply_builtin_fallback_styles(uimap)
- self.assertTrue(uimap["link"]["underline"])
- self.assertTrue(uimap["lazy-highlight"]["underline"])
- self.assertTrue(uimap["show-paren-match"]["underline"])
- self.assertTrue(uimap["error"]["bold"])
- self.assertTrue(uimap["warning"]["bold"])
- self.assertTrue(uimap["success"]["bold"])
+ line_underline = {"style": "line", "color": None}
+ self.assertEqual(uimap["link"]["underline"], line_underline)
+ self.assertEqual(uimap["lazy-highlight"]["underline"], line_underline)
+ self.assertEqual(uimap["show-paren-match"]["underline"], line_underline)
+ self.assertEqual(uimap["error"]["weight"], "bold")
+ self.assertEqual(uimap["warning"]["weight"], "bold")
+ self.assertEqual(uimap["success"]["weight"], "bold")
self.assertEqual(uimap["mode-line"]["box"], {"style": "released", "width": 1, "color": None})
self.assertEqual(uimap["mode-line-inactive"]["box"], {"style": "released", "width": 1, "color": None})
@@ -303,7 +357,7 @@ class GeneratorStateHelpers(unittest.TestCase):
}
}, syntax, color_map)
self.assertEqual(syntax["kw"]["fg"], "#222222")
- self.assertTrue(syntax["kw"]["bold"])
+ self.assertEqual(syntax["kw"]["weight"], "bold")
self.assertEqual(color_map["kw"], "#222222")
self.assertNotIn("unknown", syntax)
@@ -380,6 +434,16 @@ class DefaultFaceAdapter(unittest.TestCase):
},
"effectiveGuiLight": {},
},
+ "rich": {
+ "chosenGuiLight": {
+ "distantForeground": "black",
+ "distantForegroundHex": "#000000",
+ "overline": "t",
+ "inverseVideo": "t",
+ "extend": "t",
+ },
+ "effectiveGuiLight": {},
+ },
}
})
@@ -387,13 +451,26 @@ class DefaultFaceAdapter(unittest.TestCase):
self.assertEqual(self.defaults.seed("sample", effective=False), {
"fg": "#333333",
"bg": "#ffffff",
- "bold": True,
- "italic": True,
- "underline": True,
+ "weight": "bold",
+ "slant": "italic",
+ "underline": {"style": "line", "color": None},
"inherit": "parent",
"box": {"style": "released", "width": 2, "color": None},
})
+ def test_seed_emits_the_additive_attrs_when_the_snapshot_has_them(self):
+ self.assertEqual(self.defaults.seed("rich", effective=False), {
+ "distant-fg": "#000000",
+ "overline": {"color": None},
+ "inverse": True,
+ "extend": True,
+ })
+
+ def test_seed_omits_additive_attrs_when_the_snapshot_lacks_them(self):
+ seeded = self.defaults.seed("sample", effective=False)
+ for key in ("distant-fg", "overline", "inverse", "extend"):
+ self.assertNotIn(key, seeded)
+
def test_color_reads_effective_hex_by_default(self):
self.assertEqual(self.defaults.color("sample"), "#000000")
@@ -513,11 +590,11 @@ class GeneratedDefaults(unittest.TestCase):
def test_syntax_defaults_capture_font_lock_styles(self):
self.assertEqual(generate.MAP["kw"], "#d3d3d3")
- self.assertTrue(generate.SYNTAX["kw"]["bold"])
- self.assertFalse(generate.SYNTAX["kw"]["italic"])
+ self.assertEqual(generate.SYNTAX["kw"]["weight"], "bold")
+ self.assertIsNone(generate.SYNTAX["kw"]["slant"])
self.assertEqual(generate.MAP["str"], "#696969")
- self.assertFalse(generate.SYNTAX["str"]["bold"])
- self.assertTrue(generate.SYNTAX["str"]["italic"])
+ self.assertIsNone(generate.SYNTAX["str"]["weight"])
+ self.assertEqual(generate.SYNTAX["str"]["slant"], "italic")
if __name__ == "__main__":