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.py202
1 files changed, 202 insertions, 0 deletions
diff --git a/scripts/theme-studio/test_generate.py b/scripts/theme-studio/test_generate.py
index 974fca68a..3bc78bdf8 100644
--- a/scripts/theme-studio/test_generate.py
+++ b/scripts/theme-studio/test_generate.py
@@ -18,6 +18,39 @@ from collections import Counter, defaultdict
from contextlib import redirect_stdout
import generate # importable without side effects: the file write is __main__-guarded
+import face_coverage
+from unittest import mock
+
+
+class ClassifyBucket(unittest.TestCase):
+ """Characterization of face_coverage.classify's core/general/package decision,
+ locking each branch before the named-locals rewrite. bucket_of_source is mocked
+ to identity, so the src dict maps each face straight to its bucket name."""
+
+ def _classify(self, src, pkgfaces=(), name="x"):
+ with mock.patch.object(face_coverage, "bucket_of_source", lambda s: s):
+ return face_coverage.classify(name, list(src), src, set(pkgfaces))
+
+ def test_emacs_core_short_circuits_to_core(self):
+ self.assertEqual(face_coverage.classify("emacs-core", [], {}, set()), "core")
+
+ def test_nothing_loaded_with_a_package_face_is_package(self):
+ self.assertEqual(self._classify({"a": "unloaded", "b": "unloaded"}, pkgfaces={"b"}), "package")
+
+ def test_nothing_loaded_without_a_package_face_is_general(self):
+ self.assertEqual(self._classify({"a": "unloaded"}), "general")
+
+ def test_elpa_plurality_is_package(self):
+ self.assertEqual(self._classify({"a": "elpa", "b": "elpa", "c": "builtin"}), "package")
+
+ def test_elpa_tied_with_builtin_is_package(self):
+ self.assertEqual(self._classify({"a": "elpa", "b": "builtin"}), "package")
+
+ def test_other_beats_builtin_and_ties_elpa_is_package(self):
+ self.assertEqual(self._classify({"a": "other", "b": "other", "c": "elpa", "d": "builtin"}), "package")
+
+ def test_builtin_plurality_is_general(self):
+ self.assertEqual(self._classify({"a": "builtin", "b": "builtin", "c": "elpa"}), "general")
from app_inventory import face_rows
from default_faces import DefaultFaces, changed_summary
from face_specs import face_spec, package_face_spec, ui_face_spec
@@ -597,5 +630,174 @@ class GeneratedDefaults(unittest.TestCase):
self.assertEqual(generate.SYNTAX["str"]["slant"], "italic")
+class NerdIconsLegend(unittest.TestCase):
+ """The committed nerd-icons-legend.json artifact and the loader fallback."""
+
+ def _write(self, content):
+ path = os.path.join(tempfile.mkdtemp(), "nerd-icons-legend.json")
+ with open(path, "w") as out:
+ out.write(content)
+ return path
+
+ def test_committed_artifact_has_valid_rows(self):
+ rows = generate.load_nerd_icons_legend()
+ self.assertIsNotNone(rows, "committed nerd-icons-legend.json should load")
+ self.assertTrue(rows)
+ for row in rows:
+ for field in generate.NERD_ICONS_LEGEND_FIELDS:
+ self.assertIsInstance(row.get(field), str)
+ self.assertTrue(row[field])
+ self.assertTrue(row["face"].startswith("nerd-icons-"))
+ self.assertIn(row["category"], ("extension", "dir", "command", "buffer"))
+
+ def test_absent_artifact_falls_back_to_none(self):
+ with redirect_stdout(io.StringIO()) as out:
+ self.assertIsNone(generate.load_nerd_icons_legend("/no/such/legend.json"))
+ self.assertIn("absent", out.getvalue())
+
+ def test_malformed_artifact_falls_back_to_none(self):
+ path = self._write("{not json")
+ with redirect_stdout(io.StringIO()) as out:
+ self.assertIsNone(generate.load_nerd_icons_legend(path))
+ self.assertIn("malformed", out.getvalue())
+
+ def test_empty_artifact_falls_back_to_none(self):
+ path = self._write("[]")
+ with redirect_stdout(io.StringIO()) as out:
+ self.assertIsNone(generate.load_nerd_icons_legend(path))
+ self.assertIn("empty", out.getvalue())
+
+ def test_row_missing_a_field_falls_back_to_none(self):
+ path = self._write(json.dumps([{"key": "ext:el", "label": "init.el",
+ "face": "nerd-icons-purple", "category": "extension"}]))
+ with redirect_stdout(io.StringIO()) as out:
+ self.assertIsNone(generate.load_nerd_icons_legend(path))
+ self.assertIn("invalid", out.getvalue())
+
+ def test_nerd_icons_registered_as_bespoke_legend_app(self):
+ app = generate.APPS.get("nerd-icons")
+ self.assertIsNotNone(app, "nerd-icons should be a bespoke app with the legend present")
+ self.assertEqual(app["preview"], "nerdicons")
+ self.assertTrue(app.get("legend"))
+ self.assertGreaterEqual(len(app["faces"]), 30)
+ # The dir-completion face is a different package and keeps its own app.
+ self.assertIn("nerd-icons-completion", generate.APPS)
+
+ def test_nerd_icons_app_faces_are_seeded_with_native_colors(self):
+ # apply_default_face_seeds fills the editable rows from emacs-default-faces.json.
+ rows = {r[0]: r[2] for r in generate.APPS["nerd-icons"]["faces"]}
+ self.assertIn("nerd-icons-blue", rows)
+ self.assertTrue(rows["nerd-icons-blue"], "nerd-icons-blue should carry a native seed")
+
+ def test_legend_loads_from_object_shaped_artifact(self):
+ # The committed artifact is now an object {legend, gallery}; the legend
+ # loader must read the "legend" key, not assume a bare array.
+ path = self._write(json.dumps({"legend": [
+ {"key": "ext:el", "label": "init.el", "face": "nerd-icons-purple",
+ "category": "extension", "glyph": "x"}], "gallery": []}))
+ rows = generate.load_nerd_icons_legend(path)
+ self.assertEqual(len(rows), 1)
+ self.assertEqual(rows[0]["face"], "nerd-icons-purple")
+
+
+class NerdIconsGallery(unittest.TestCase):
+ """The committed gallery (full colored catalog) and its loader fallback."""
+
+ def _write(self, content):
+ path = os.path.join(tempfile.mkdtemp(), "nerd-icons-legend.json")
+ with open(path, "w") as out:
+ out.write(content)
+ return path
+
+ def test_committed_artifact_has_valid_groups(self):
+ groups = generate.load_nerd_icons_gallery()
+ self.assertIsNotNone(groups, "committed gallery should load")
+ self.assertTrue(groups)
+ for g in groups:
+ self.assertTrue(g["face"].startswith("nerd-icons-"))
+ self.assertIsInstance(g["hue"], (int, float))
+ self.assertTrue(g["glyphs"])
+ for e in g["glyphs"]:
+ for field in generate.NERD_ICONS_GALLERY_GLYPH_FIELDS:
+ self.assertIsInstance(e.get(field), str)
+ self.assertTrue(e[field])
+
+ def test_groups_are_ordered_by_hue(self):
+ groups = generate.load_nerd_icons_gallery()
+ hues = [g["hue"] for g in groups]
+ self.assertEqual(hues, sorted(hues), "color rows cluster by hue (ascending)")
+
+ def test_icons_are_deduplicated_within_a_group(self):
+ for g in generate.load_nerd_icons_gallery():
+ names = [e["name"] for e in g["glyphs"]]
+ self.assertEqual(len(names), len(set(names)), f"{g['face']} repeats an icon name")
+
+ def test_absent_artifact_falls_back_to_none(self):
+ with redirect_stdout(io.StringIO()):
+ self.assertIsNone(generate.load_nerd_icons_gallery("/no/such/legend.json"))
+
+ def test_malformed_artifact_falls_back_to_none(self):
+ path = self._write("{not json")
+ with redirect_stdout(io.StringIO()):
+ self.assertIsNone(generate.load_nerd_icons_gallery(path))
+
+ def test_legacy_array_only_artifact_has_no_gallery(self):
+ # A v1-era bare-array file carries a legend but no gallery -> None, no crash.
+ path = self._write(json.dumps([{"key": "ext:el"}]))
+ with redirect_stdout(io.StringIO()):
+ self.assertIsNone(generate.load_nerd_icons_gallery(path))
+
+ def test_group_missing_a_field_falls_back_to_none(self):
+ # Missing hue and glyphs -> invalid.
+ path = self._write(json.dumps({"legend": [], "gallery": [{"face": "nerd-icons-blue"}]}))
+ with redirect_stdout(io.StringIO()) as out:
+ self.assertIsNone(generate.load_nerd_icons_gallery(path))
+ self.assertIn("invalid", out.getvalue())
+
+ def test_glyph_entry_missing_a_field_falls_back_to_none(self):
+ path = self._write(json.dumps({"gallery": [
+ {"face": "nerd-icons-blue", "hue": 212, "glyphs": [{"glyph": "x"}]}]}))
+ with redirect_stdout(io.StringIO()) as out:
+ self.assertIsNone(generate.load_nerd_icons_gallery(path))
+ self.assertIn("invalid", out.getvalue())
+
+ def test_group_with_empty_glyphs_falls_back_to_none(self):
+ path = self._write(json.dumps({"gallery": [
+ {"face": "nerd-icons-blue", "hue": 212, "glyphs": []}]}))
+ with redirect_stdout(io.StringIO()) as out:
+ self.assertIsNone(generate.load_nerd_icons_gallery(path))
+ self.assertIn("invalid", out.getvalue())
+
+ def test_group_with_a_foreign_face_falls_back_to_none(self):
+ path = self._write(json.dumps({"gallery": [
+ {"face": "rainbow-delimiters-depth-1", "hue": 212,
+ "glyphs": [{"glyph": "x", "name": "nf-x"}]}]}))
+ with redirect_stdout(io.StringIO()) as out:
+ self.assertIsNone(generate.load_nerd_icons_gallery(path))
+ self.assertIn("invalid", out.getvalue())
+
+ def test_group_with_a_non_numeric_hue_falls_back_to_none(self):
+ path = self._write(json.dumps({"gallery": [
+ {"face": "nerd-icons-blue", "hue": "212",
+ "glyphs": [{"glyph": "x", "name": "nf-x"}]}]}))
+ with redirect_stdout(io.StringIO()) as out:
+ self.assertIsNone(generate.load_nerd_icons_gallery(path))
+ self.assertIn("invalid", out.getvalue())
+
+ def test_non_dict_glyph_entry_falls_back_to_none(self):
+ path = self._write(json.dumps({"gallery": [
+ {"face": "nerd-icons-blue", "hue": 212, "glyphs": ["not-a-dict"]}]}))
+ with redirect_stdout(io.StringIO()) as out:
+ self.assertIsNone(generate.load_nerd_icons_gallery(path))
+ self.assertIn("invalid", out.getvalue())
+
+ def test_nerd_icons_app_carries_the_gallery(self):
+ app = generate.APPS.get("nerd-icons")
+ self.assertIsNotNone(app)
+ self.assertTrue(app.get("gallery"), "nerd-icons app should carry the gallery groups")
+ faces = {g["face"] for g in app["gallery"]}
+ self.assertIn("nerd-icons-blue", faces)
+
+
if __name__ == "__main__":
unittest.main()