aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-07-25 15:00:56 -0500
committerCraig Jennings <c@cjennings.net>2026-07-25 15:00:56 -0500
commit2c416f5361ed10cd73eb72eb5062261b2e73c18f (patch)
tree5c84c09deb2c8392544020d432ffcd0fccde79f2 /tests
parentd52da959bc416e09bc0f3e54994563bd80e19c64 (diff)
downloadarchsetup-2c416f5361ed10cd73eb72eb5062261b2e73c18f.tar.gz
archsetup-2c416f5361ed10cd73eb72eb5062261b2e73c18f.zip
refactor(prototypes): merge casting widgets into Dupre kit
Diffstat (limited to 'tests')
-rw-r--r--tests/gallery-probes/probe.mjs2
-rw-r--r--tests/gallery-probes/test_dupre_merge.py53
-rw-r--r--tests/gallery-tokens/test_gen_tokens.py22
-rw-r--r--tests/gallery-widgets/test-gallery-widget.el20
4 files changed, 96 insertions, 1 deletions
diff --git a/tests/gallery-probes/probe.mjs b/tests/gallery-probes/probe.mjs
index 5f56f46..9d230c0 100644
--- a/tests/gallery-probes/probe.mjs
+++ b/tests/gallery-probes/probe.mjs
@@ -97,7 +97,7 @@ try {
// 1. card count (the instruments/row default is checked in 1h)
const cards = await evl(`document.querySelectorAll('.card').length`);
- ok('111 cards', cards === 111, `got ${cards}`);
+ ok('112 cards', cards === 112, `got ${cards}`);
// 1b. Every card carries a spec sheet. R58 shipped without one and nothing
// noticed — the sheet is the card's actual specification, so a card without
diff --git a/tests/gallery-probes/test_dupre_merge.py b/tests/gallery-probes/test_dupre_merge.py
new file mode 100644
index 0000000..891b789
--- /dev/null
+++ b/tests/gallery-probes/test_dupre_merge.py
@@ -0,0 +1,53 @@
+"""The settings-casting widget candidates live in the canonical Dupre kit."""
+
+import os
+import unittest
+
+
+ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
+
+
+def source(name):
+ with open(os.path.join(ROOT, "docs", "prototypes", name)) as handle:
+ return handle.read()
+
+
+class DupreMergeTests(unittest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ cls.widgets = source("widgets.js")
+ cls.additions = source("dupre-kit-additions.js")
+ cls.gallery = source("panel-widget-gallery.html")
+
+ def test_three_candidates_are_owned_only_by_the_canonical_kit(self):
+ for name in ("detentFader", "drumRoller", "guardedToggle"):
+ declaration = f"DUPRE.{name} = function"
+ self.assertEqual(self.widgets.count(declaration), 1, name)
+ self.assertNotIn(declaration, self.additions, name)
+
+ def test_detent_fader_brings_its_styles_and_policy(self):
+ self.assertIn(".dupre-dfader{", self.widgets)
+ self.assertIn("DUPRE.detentFader.POLICY", self.widgets)
+
+ def test_drum_supports_any_channel_count_and_configurable_range(self):
+ for fragment in (
+ "opts.min !== undefined",
+ "opts.max !== undefined",
+ "opts.height !== undefined",
+ "chans.forEach((c, i) => set(i, c.v))",
+ ):
+ self.assertIn(fragment, self.widgets)
+
+ def test_guarded_toggle_throws_through_the_viewer_plane(self):
+ self.assertIn("lever.style.transformBox = 'view-box'", self.widgets)
+ self.assertIn("'rotateX(180deg)'", self.widgets)
+
+ def test_gallery_specifies_detent_and_multichannel_drum(self):
+ self.assertIn("card(C,'A1','Detent fader'", self.gallery)
+ self.assertIn("channels:[{name:'HIGH'", self.gallery)
+ self.assertIn("{name:'MID'", self.gallery)
+ self.assertIn("{name:'LOW'", self.gallery)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/gallery-tokens/test_gen_tokens.py b/tests/gallery-tokens/test_gen_tokens.py
index 2968119..afd9db1 100644
--- a/tests/gallery-tokens/test_gen_tokens.py
+++ b/tests/gallery-tokens/test_gen_tokens.py
@@ -95,6 +95,28 @@ class ResolveColor(unittest.TestCase):
gt.resolve_color(FIXTURE, "nonexistent")
+class IterSectionItems(unittest.TestCase):
+ def test_preserves_section_and_item_order(self):
+ self.assertEqual(
+ list(gt.iter_section_items(FIXTURE, ("amber", "palette"))),
+ [
+ ("gold", "#e2a038"),
+ ("gold-hi", "#ffbe54"),
+ ("amber-grad-top", "#f2c76a"),
+ ("ground", "#151311"),
+ ("wash", "#2c2f32"),
+ ("slate-hi", "#54677d"),
+ ],
+ )
+
+ def test_missing_and_empty_sections_contribute_no_items(self):
+ tokens = {"palette": {}, "amber": {"gold": "#e2a038"}}
+ self.assertEqual(
+ list(gt.iter_section_items(tokens, ("missing", "palette", "amber"))),
+ [("gold", "#e2a038")],
+ )
+
+
class EmitWebCss(unittest.TestCase):
def setUp(self):
self.css = gt.emit_web_css(FIXTURE)
diff --git a/tests/gallery-widgets/test-gallery-widget.el b/tests/gallery-widgets/test-gallery-widget.el
index c0d38b4..9a3c29f 100644
--- a/tests/gallery-widgets/test-gallery-widget.el
+++ b/tests/gallery-widgets/test-gallery-widget.el
@@ -54,6 +54,26 @@
(should-error (gallery-widget--needle-angle "fifty"))
(should-error (gallery-widget--needle-angle nil)))
+;;; --- shared SVG geometry ---
+
+(ert-deftest gallery-widget-semicircle-path-normal ()
+ "A semicircle path is derived from center and radius, not copied literals."
+ (should (equal (gallery-widget--semicircle-path 48 48 47)
+ "M 1 48 A 47 47 0 0 1 95 48")))
+
+(ert-deftest gallery-widget-semicircle-path-can-close-a-hub ()
+ "The same geometry helper closes the smaller half-dome hub."
+ (should (equal (gallery-widget--semicircle-path 48 48 4 t)
+ "M 44 48 A 4 4 0 0 1 52 48 Z")))
+
+(ert-deftest gallery-widget-source-uses-only-public-dom-append ()
+ "The renderer must not depend on svg.el's private `svg--append' API."
+ (with-temp-buffer
+ (insert-file-contents
+ (expand-file-name "docs/prototypes/gallery-widget.el"
+ test-gallery-widget--root))
+ (should-not (search-forward "svg--append" nil t))))
+
;;; --- rendered SVG structure ---
(defun test-gallery-widget--svg-string (value)