Files
rose-ash/shared/sx/ref/test-engine.sx
giles 917a487195 Add deps and engine test specs, bootstrap engine to Python
New test specs (test-deps.sx: 33 tests, test-engine.sx: 37 tests) covering
component dependency analysis and engine pure functions. All 6 spec modules
now have formal SX tests: eval (81), parser (39), router (18), render (23),
deps (33), engine (37) = 231 total.

- Add engine as spec module in bootstrap_py.py (alongside deps)
- Add primitive aliases (trim, replace, parse_int, upper) for engine functions
- Fix parse-int to match JS parseInt semantics (strip trailing non-digits)
- Regenerate sx_ref.py with --spec-modules deps,engine
- Update all three test runners (run.js, run.py, sx-test-runner.js)
- Add Dependencies and Engine nav items and testing page entries
- Wire deps-source/engine-source through testing overview UI

Node.js: 231/231 pass. Python: 226/231 (5 pre-existing parser/router gaps).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 18:01:33 +00:00

213 lines
7.6 KiB
Plaintext

;; ==========================================================================
;; test-engine.sx — Tests for SxEngine pure logic (engine.sx)
;;
;; Requires: test-framework.sx loaded first.
;; Platform functions: parse-time, parse-trigger-spec, default-trigger,
;; parse-swap-spec, parse-retry-spec, next-retry-ms, filter-params
;; (loaded from bootstrapped output by test runners)
;; ==========================================================================
;; --------------------------------------------------------------------------
;; 1. parse-time — time string parsing
;; --------------------------------------------------------------------------
(defsuite "parse-time"
(deftest "seconds to ms"
(assert-equal 2000 (parse-time "2s")))
(deftest "milliseconds"
(assert-equal 500 (parse-time "500ms")))
(deftest "nil returns 0"
(assert-equal 0 (parse-time nil)))
(deftest "plain number string"
(assert-equal 100 (parse-time "100")))
(deftest "one second"
(assert-equal 1000 (parse-time "1s")))
(deftest "large seconds"
(assert-equal 30000 (parse-time "30s"))))
;; --------------------------------------------------------------------------
;; 2. parse-trigger-spec — trigger attribute parsing
;; --------------------------------------------------------------------------
(defsuite "parse-trigger-spec"
(deftest "nil returns nil"
(assert-nil (parse-trigger-spec nil)))
(deftest "single event"
(let ((triggers (parse-trigger-spec "click")))
(assert-equal 1 (len triggers))
(assert-equal "click" (get (first triggers) "event"))))
(deftest "event with once modifier"
(let ((triggers (parse-trigger-spec "click once")))
(assert-equal 1 (len triggers))
(assert-equal "click" (get (first triggers) "event"))
(assert-true (get (get (first triggers) "modifiers") "once"))))
(deftest "event with delay modifier"
(let ((triggers (parse-trigger-spec "click delay:500ms")))
(assert-equal 1 (len triggers))
(assert-equal 500 (get (get (first triggers) "modifiers") "delay"))))
(deftest "multiple triggers comma-separated"
(let ((triggers (parse-trigger-spec "click,change")))
(assert-equal 2 (len triggers))
(assert-equal "click" (get (first triggers) "event"))
(assert-equal "change" (get (nth triggers 1) "event"))))
(deftest "polling trigger"
(let ((triggers (parse-trigger-spec "every 3s")))
(assert-equal 1 (len triggers))
(assert-equal "every" (get (first triggers) "event"))
(assert-equal 3000 (get (get (first triggers) "modifiers") "interval"))))
(deftest "event with from modifier"
(let ((triggers (parse-trigger-spec "click from:body")))
(assert-equal "body" (get (get (first triggers) "modifiers") "from"))))
(deftest "event with changed modifier"
(let ((triggers (parse-trigger-spec "keyup changed")))
(assert-equal "keyup" (get (first triggers) "event"))
(assert-true (get (get (first triggers) "modifiers") "changed")))))
;; --------------------------------------------------------------------------
;; 3. default-trigger — default trigger by element tag
;; --------------------------------------------------------------------------
(defsuite "default-trigger"
(deftest "form submits"
(let ((triggers (default-trigger "FORM")))
(assert-equal "submit" (get (first triggers) "event"))))
(deftest "input changes"
(let ((triggers (default-trigger "INPUT")))
(assert-equal "change" (get (first triggers) "event"))))
(deftest "select changes"
(let ((triggers (default-trigger "SELECT")))
(assert-equal "change" (get (first triggers) "event"))))
(deftest "textarea changes"
(let ((triggers (default-trigger "TEXTAREA")))
(assert-equal "change" (get (first triggers) "event"))))
(deftest "div clicks"
(let ((triggers (default-trigger "DIV")))
(assert-equal "click" (get (first triggers) "event"))))
(deftest "button clicks"
(let ((triggers (default-trigger "BUTTON")))
(assert-equal "click" (get (first triggers) "event")))))
;; --------------------------------------------------------------------------
;; 4. parse-swap-spec — swap specification parsing
;; --------------------------------------------------------------------------
(defsuite "parse-swap-spec"
(deftest "default swap"
(let ((spec (parse-swap-spec nil false)))
(assert-equal "outerHTML" (get spec "style"))
(assert-false (get spec "transition"))))
(deftest "innerHTML"
(let ((spec (parse-swap-spec "innerHTML" false)))
(assert-equal "innerHTML" (get spec "style"))))
(deftest "with transition true"
(let ((spec (parse-swap-spec "innerHTML transition:true" false)))
(assert-equal "innerHTML" (get spec "style"))
(assert-true (get spec "transition"))))
(deftest "transition false overrides global"
(let ((spec (parse-swap-spec "outerHTML transition:false" true)))
(assert-equal "outerHTML" (get spec "style"))
(assert-false (get spec "transition"))))
(deftest "global transition when not overridden"
(let ((spec (parse-swap-spec "innerHTML" true)))
(assert-equal "innerHTML" (get spec "style"))
(assert-true (get spec "transition")))))
;; --------------------------------------------------------------------------
;; 5. parse-retry-spec — retry specification parsing
;; --------------------------------------------------------------------------
(defsuite "parse-retry-spec"
(deftest "nil returns nil"
(assert-nil (parse-retry-spec nil)))
(deftest "exponential backoff"
(let ((spec (parse-retry-spec "exponential:1000:30000")))
(assert-equal "exponential" (get spec "strategy"))
(assert-equal 1000 (get spec "start-ms"))
(assert-equal 30000 (get spec "cap-ms"))))
(deftest "linear strategy"
(let ((spec (parse-retry-spec "linear:2000:60000")))
(assert-equal "linear" (get spec "strategy"))
(assert-equal 2000 (get spec "start-ms"))
(assert-equal 60000 (get spec "cap-ms")))))
;; --------------------------------------------------------------------------
;; 6. next-retry-ms — exponential backoff calculation
;; --------------------------------------------------------------------------
(defsuite "next-retry-ms"
(deftest "doubles current"
(assert-equal 2000 (next-retry-ms 1000 30000)))
(deftest "caps at maximum"
(assert-equal 30000 (next-retry-ms 20000 30000)))
(deftest "exact cap"
(assert-equal 30000 (next-retry-ms 15000 30000)))
(deftest "small initial"
(assert-equal 200 (next-retry-ms 100 30000))))
;; --------------------------------------------------------------------------
;; 7. filter-params — form parameter filtering
;; --------------------------------------------------------------------------
(defsuite "filter-params"
(deftest "nil passes all through"
(let ((params (list (list "a" "1") (list "b" "2"))))
(assert-equal 2 (len (filter-params nil params)))))
(deftest "none returns empty"
(let ((params (list (list "a" "1") (list "b" "2"))))
(assert-equal 0 (len (filter-params "none" params)))))
(deftest "star passes all"
(let ((params (list (list "a" "1") (list "b" "2"))))
(assert-equal 2 (len (filter-params "*" params)))))
(deftest "whitelist"
(let ((params (list (list "name" "Jo") (list "age" "30") (list "secret" "x"))))
(let ((filtered (filter-params "name,age" params)))
(assert-equal 2 (len filtered)))))
(deftest "blacklist with not"
(let ((params (list (list "name" "Jo") (list "csrf" "tok") (list "age" "30"))))
(let ((filtered (filter-params "not csrf" params)))
(assert-equal 2 (len filtered))))))