Sandbox conformance runner: 147/214 passing (69%)
New file: spec/tests/test-hyperscript-conformance-sandbox.sx - 214 fixtures extracted from official _hyperscript 0.9.14 test suite - Runs via: sx_playwright mode=sandbox stack=hs files=[this] expr=(do (hs-conf-run-all) (hs-conf-report)) - Uses cek-eval (full env) — no runtime let-binding hacks - try-call error handling per fixture Up from 62/109 (57%) in OCaml runner to 147/214 (69%) in sandbox. +85 tests unlocked by real eval context. 67 remaining failures: - 11 coercion types (Fixed, JSON, Object, Values, custom) - 9 cookies (DOM) - 8 template strings (parser needed) - 6 string postfix (1em, 1px) - 5 window globals (foo, value) - 4 block literals (parser needed) - 4 I am in (me binding in cek-eval) - 4 in operator (array intersection semantics) - 4 typecheck colon syntax (: String) - 3 object literals - 3 DOM selectors - 2 logical short-circuit (func1/func2) - 2 float/nan edge cases - 1 no .class (DOM) - 1 its foo (window global) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
271
spec/tests/test-hyperscript-conformance-sandbox.sx
Normal file
271
spec/tests/test-hyperscript-conformance-sandbox.sx
Normal file
@@ -0,0 +1,271 @@
|
||||
;; _hyperscript conformance — 222 tests from v0.9.14
|
||||
;;
|
||||
;; OCaml: loaded by run_tests.exe, uses eval-expr-cek
|
||||
;; Sandbox: sx_playwright mode=sandbox stack=hs files=[this]
|
||||
;; expr=(do (hs-conf-run-all) (hs-conf-report))
|
||||
|
||||
;; ── Counters ────────────────────────────────────────────────────
|
||||
(define hs-conf-pass 0)
|
||||
(define hs-conf-fail 0)
|
||||
(define hs-conf-fails (list))
|
||||
|
||||
;; ── eval-hs: sandbox version uses cek-eval ──────────────────────
|
||||
(define eval-hs
|
||||
(fn (src &rest opts)
|
||||
(let ((sx (hs-to-sx (hs-compile src)))
|
||||
(ctx (if (> (len opts) 0) (first opts) nil)))
|
||||
(let ((bindings (list
|
||||
(list (quote me) nil)
|
||||
(list (quote it) nil)
|
||||
(list (quote result) nil))))
|
||||
(do
|
||||
(when ctx
|
||||
(do
|
||||
(when (get ctx "me")
|
||||
(set! bindings (cons (list (quote me) (get ctx "me")) bindings)))
|
||||
(when (get ctx "locals")
|
||||
(for-each
|
||||
(fn (k) (set! bindings (cons (list (make-symbol k) (get (get ctx "locals") k)) bindings)))
|
||||
(keys (get ctx "locals"))))))
|
||||
(cek-eval (list (quote let) bindings sx)))))))
|
||||
|
||||
;; ── Fixture runner ──────────────────────────────────────────────
|
||||
(define hs-conf-run-fixture
|
||||
(fn (f)
|
||||
(let ((src (get f "src"))
|
||||
(expected (get f "expected"))
|
||||
(ctx (if (or (get f "locals") (get f "me"))
|
||||
{"locals" (get f "locals") "me" (get f "me")} nil)))
|
||||
(let ((ok (try-call (fn ()
|
||||
(let ((result (if ctx (eval-hs src ctx) (eval-hs src))))
|
||||
(if (= result expected)
|
||||
(set! hs-conf-pass (+ hs-conf-pass 1))
|
||||
(do (set! hs-conf-fail (+ hs-conf-fail 1))
|
||||
(append! hs-conf-fails (str src " => " result " exp " expected)))))))))
|
||||
(when (not (get ok "ok"))
|
||||
(do (set! hs-conf-fail (+ hs-conf-fail 1))
|
||||
(append! hs-conf-fails (str "ERR: " src))))))))
|
||||
|
||||
(define hs-conf-run-all
|
||||
(fn () (for-each hs-conf-run-fixture hs-conf-all-fixtures)))
|
||||
|
||||
(define hs-conf-report
|
||||
(fn () (str hs-conf-pass "/" (+ hs-conf-pass hs-conf-fail) " pass, " hs-conf-fail " fail")))
|
||||
|
||||
;; ── Fixtures ────────────────────────────────────────────────────
|
||||
(define hs-conf-all-fixtures (list
|
||||
{:src "[1, 2, 3]" :expected (list 1 2 3)}
|
||||
{:src "[]" :expected (list)}
|
||||
{:src "[true]" :expected (list true)}
|
||||
{:src "[true, false]" :expected (list true false)}
|
||||
{:src "10 as String" :expected "10"}
|
||||
{:src "true as String" :expected "true"}
|
||||
{:src "'10' as Int" :expected 10}
|
||||
{:src "'10.4' as Int" :expected 10}
|
||||
{:src "'10' as Float" :expected 10}
|
||||
{:src "'10.4' as Float" :expected 10.4}
|
||||
{:src "'10.4' as Fixed" :expected "10"}
|
||||
{:src "'10.4899' as Fixed:2" :expected "10.49"}
|
||||
{:src "'10' as Number" :expected 10}
|
||||
{:src "'10.4' as Number" :expected 10.4}
|
||||
{:src "{foo:'bar'} as JSON" :expected "{\"foo\":\"bar\"}"}
|
||||
{:src "'{\"foo\":\"bar\"}' as Object" :expected "bar"}
|
||||
{:src "'{\"foo\":\"bar\"}' as an Object" :expected "bar"}
|
||||
{:src "x as Object" :expected "bar"}
|
||||
{:src "x as Values" :expected "John"}
|
||||
{:src "value as HTML" :expected "123"}
|
||||
{:src "value as Fragment" :expected 1}
|
||||
{:src "1 as Foo" :expected "foo1"}
|
||||
{:src "1 as Foo:Bar" :expected "Bar1"}
|
||||
{:src "\\\\-> true" :expected true}
|
||||
{:src "\\\\ x -> x" :expected true}
|
||||
{:src "\\\\ x, y -> y" :expected true}
|
||||
{:src "['a', 'ab', 'abc'].map(\\\\ s -> s.length )" :expected (list 1 2 3)}
|
||||
{:src "true" :expected true}
|
||||
{:src "false" :expected false}
|
||||
{:src ".badClassThatDoesNotHaveAnyElements" :expected 0}
|
||||
{:src "1 < 2" :expected true}
|
||||
{:src "2 < 1" :expected false}
|
||||
{:src "2 < 2" :expected false}
|
||||
{:src "1 <= 2" :expected true}
|
||||
{:src "2 <= 1" :expected false}
|
||||
{:src "2 <= 2" :expected true}
|
||||
{:src "1 > 2" :expected false}
|
||||
{:src "2 > 1" :expected true}
|
||||
{:src "2 > 2" :expected false}
|
||||
{:src "1 >= 2" :expected false}
|
||||
{:src "2 >= 1" :expected true}
|
||||
{:src "2 >= 2" :expected true}
|
||||
{:src "1 == 2" :expected false}
|
||||
{:src "2 == 1" :expected false}
|
||||
{:src "2 == 2" :expected true}
|
||||
{:src "1 === 2" :expected false}
|
||||
{:src "2 === 1" :expected false}
|
||||
{:src "2 === 2" :expected true}
|
||||
{:src "1 != 2" :expected true}
|
||||
{:src "2 != 1" :expected true}
|
||||
{:src "2 != 2" :expected false}
|
||||
{:src "1 !== 2" :expected true}
|
||||
{:src "2 !== 1" :expected true}
|
||||
{:src "2 !== 2" :expected false}
|
||||
{:src "1 is 2" :expected false}
|
||||
{:src "2 is 1" :expected false}
|
||||
{:src "2 is 2" :expected true}
|
||||
{:src "1 equals 2" :expected false}
|
||||
{:src "2 equals 1" :expected false}
|
||||
{:src "2 equals 2" :expected true}
|
||||
{:src "1 is equal to 2" :expected false}
|
||||
{:src "2 is equal to 1" :expected false}
|
||||
{:src "2 is equal to 2" :expected true}
|
||||
{:src "1 is really equal to 2" :expected false}
|
||||
{:src "2 is really equal to 1" :expected false}
|
||||
{:src "2 is really equal to '2'" :expected false}
|
||||
{:src "2 is really equal to 2" :expected true}
|
||||
{:src "1 really equals 2" :expected false}
|
||||
{:src "2 really equals 1" :expected false}
|
||||
{:src "2 really equals 2" :expected true}
|
||||
{:src "1 is not 2" :expected true}
|
||||
{:src "2 is not 1" :expected true}
|
||||
{:src "2 is not 2" :expected false}
|
||||
{:src "1 is not equal to 2" :expected true}
|
||||
{:src "2 is not equal to 1" :expected true}
|
||||
{:src "2 is not equal to 2" :expected false}
|
||||
{:src "1 is not really equal to 2" :expected true}
|
||||
{:src "2 is not really equal to 1" :expected true}
|
||||
{:src "2 is not really equal to '2'" :expected true}
|
||||
{:src "2 is not really equal to 2" :expected false}
|
||||
{:src "1 is in [1, 2]" :expected true}
|
||||
{:src "2 is in [1, 2]" :expected true}
|
||||
{:src "3 is in [1, 2]" :expected false}
|
||||
{:src "3 is in null" :expected false}
|
||||
{:src "1 is not in [1, 2]" :expected false}
|
||||
{:src "2 is not in [1, 2]" :expected false}
|
||||
{:src "3 is not in [1, 2]" :expected true}
|
||||
{:src "3 is not in null" :expected true}
|
||||
{:src "I am in [1, 2]" :me 1 :expected true}
|
||||
{:src "I am in [1, 2]" :me 2 :expected true}
|
||||
{:src "I am in [1, 2]" :me 3 :expected false}
|
||||
{:src "I am in null" :expected false}
|
||||
{:src "I am not in [1, 2]" :me 1 :expected false}
|
||||
{:src "I am not in [1, 2]" :me 2 :expected false}
|
||||
{:src "I am not in [1, 2]" :me 3 :expected true}
|
||||
{:src "I am not in null" :expected true}
|
||||
{:src "'a' matches '.*'" :expected true}
|
||||
{:src "'a' matches 'b'" :expected false}
|
||||
{:src "'a' does not match '.*'" :expected false}
|
||||
{:src "'a' does not match 'b'" :expected true}
|
||||
{:src "undefined is empty" :expected true}
|
||||
{:src "'' is empty" :expected true}
|
||||
{:src "[] is empty" :expected true}
|
||||
{:src "'not empty' is empty" :expected false}
|
||||
{:src "1000 is empty" :expected false}
|
||||
{:src "[1,2,3] is empty" :expected false}
|
||||
{:src "undefined is not empty" :expected false}
|
||||
{:src "'' is not empty" :expected false}
|
||||
{:src "[] is not empty" :expected false}
|
||||
{:src "'not empty' is not empty" :expected true}
|
||||
{:src "1000 is not empty" :expected true}
|
||||
{:src "[1,2,3] is not empty" :expected true}
|
||||
{:src "null is a String" :expected true}
|
||||
{:src "null is a String!" :expected false}
|
||||
{:src "'' is a String!" :expected true}
|
||||
{:src "null is not a String" :expected false}
|
||||
{:src "null is not a String!" :expected true}
|
||||
{:src "'' is not a String!" :expected false}
|
||||
{:src "null is an String" :expected true}
|
||||
{:src "null is an String!" :expected false}
|
||||
{:src "'' is an String!" :expected true}
|
||||
{:src "null is not an String" :expected false}
|
||||
{:src "null is not an String!" :expected true}
|
||||
{:src "'' is not an String!" :expected false}
|
||||
{:src "1 is less than 2" :expected true}
|
||||
{:src "2 is less than 1" :expected false}
|
||||
{:src "2 is less than 2" :expected false}
|
||||
{:src "1 is less than or equal to 2" :expected true}
|
||||
{:src "2 is less than or equal to 1" :expected false}
|
||||
{:src "2 is less than or equal to 2" :expected true}
|
||||
{:src "1 is greater than 2" :expected false}
|
||||
{:src "2 is greater than 1" :expected true}
|
||||
{:src "2 is greater than 2" :expected false}
|
||||
{:src "1 is greater than or equal to 2" :expected false}
|
||||
{:src "2 is greater than or equal to 1" :expected true}
|
||||
{:src "2 is greater than or equal to 2" :expected true}
|
||||
{:src "undefined does not exist" :expected true}
|
||||
{:src "null does not exist" :expected true}
|
||||
{:src "cookies.foo" :expected "bar"}
|
||||
{:src "set cookies.foo to 'bar'" :expected "bar"}
|
||||
{:src "cookies.foo" :expected "bar"}
|
||||
{:src "set cookies.foo to 'bar'" :expected "bar"}
|
||||
{:src "cookies.foo" :expected "bar"}
|
||||
{:src "set cookies.foo to 'doh'" :expected "doh"}
|
||||
{:src "cookies.foo" :expected "doh"}
|
||||
{:src "set cookies.foo to 'bar'" :expected true}
|
||||
{:src "for x in cookies me.push(x.name) then you.push(x.value) end" :expected true}
|
||||
{:src "1 in [1, 2, 3]" :expected (list 1)}
|
||||
{:src "[1, 3] in [1, 2, 3]" :expected (list 1 3)}
|
||||
{:src "[1, 3, 4] in [1, 2, 3]" :expected (list 1 3)}
|
||||
{:src "[4, 5, 6] in [1, 2, 3]" :expected (list)}
|
||||
{:src "func1() and func2()" :expected false}
|
||||
{:src "func1() or func2()" :expected true}
|
||||
{:src "1 + 1" :expected 2}
|
||||
{:src "'a' + 'b'" :expected "ab"}
|
||||
{:src "1 - 1" :expected 0}
|
||||
{:src "1 * 2" :expected 2}
|
||||
{:src "1 / 2" :expected 0.5}
|
||||
{:src "3 mod 2" :expected 1}
|
||||
{:src "1 + 2 + 3" :expected 6}
|
||||
{:src "1 + (2 * 3)" :expected 7}
|
||||
{:src "no null" :expected true}
|
||||
{:src "no 'thing'" :expected false}
|
||||
{:src "no ['thing']" :expected false}
|
||||
{:src "no []" :expected true}
|
||||
{:src "no .aClassThatDoesNotExist" :expected true}
|
||||
{:src "not true" :expected false}
|
||||
{:src "not false" :expected true}
|
||||
{:src "not not true" :expected true}
|
||||
{:src "-1" :expected -1}
|
||||
{:src "1" :expected 1}
|
||||
{:src "1.1" :expected 1.1}
|
||||
{:src "1234567890.1234567890" :expected 1234570000}
|
||||
{:src "{}" :expected {}}
|
||||
{:src "{-foo:true, bar-baz:false}" :expected {:bar-baz false :-foo true}}
|
||||
{:src "{foo:true, bar-baz:false,}" :expected {:bar-baz false :foo true}}
|
||||
{:src "the first of [1, 2, 3]" :expected 1}
|
||||
{:src "the last of [1, 2, 3]" :expected 3}
|
||||
{:src "foo's foo" :expected "foo"}
|
||||
{:src "its foo" :expected "foo"}
|
||||
{:src "foo.foo" :expected "foo"}
|
||||
{:src "foo of foo" :expected "foo"}
|
||||
{:src "bar.doh of foo" :expected "foo"}
|
||||
{:src "doh of foo.bar" :expected "foo"}
|
||||
{:src "<.badClassThatDoesNotHaveAnyElements/>" :expected 0}
|
||||
{:src "some null" :expected false}
|
||||
{:src "some 'thing'" :expected true}
|
||||
{:src "some []" :expected false}
|
||||
{:src "some .aClassThatDoesNotExist" :expected false}
|
||||
{:src "some <html/>" :expected true}
|
||||
{:src "some ['thing']" :expected true}
|
||||
{:src "1em" :expected "1em"}
|
||||
{:src "1px" :expected "1px"}
|
||||
{:src "-1px" :expected "-1px"}
|
||||
{:src "100%" :expected "100%"}
|
||||
{:src "1 em" :expected "1em"}
|
||||
{:src "1 px" :expected "1px"}
|
||||
{:src "100 %" :expected "100%"}
|
||||
{:src "\"foo\"" :expected "foo"}
|
||||
{:src "\"fo'o\"" :expected "fo'o"}
|
||||
{:src "'foo'" :expected "foo"}
|
||||
{:src "`$1`" :expected "1"}
|
||||
{:src "`${1 + 2}`" :expected "3"}
|
||||
{:src "` ${1 + 2} ${1 + 2} `" :expected " 3 3 "}
|
||||
{:src "`${1 + 2} ${1 + 2} `" :expected "3 3 "}
|
||||
{:src "`${1 + 2}${1 + 2} `" :expected "33 "}
|
||||
{:src "`${1 + 2} ${1 + 2}`" :expected "3 3"}
|
||||
{:src "`<div age=\"${record.age}\" style=\"color:${record.favouriteColour}\">${record.name}</div>`" :expected "<div age=\"21\" style=\"color:bleaux\">John Connor</div>"}
|
||||
{:src "`https://${foo}`" :locals {:foo "bar"} :expected "https://bar"}
|
||||
{:src "foo" :locals {:foo 42} :expected 42}
|
||||
{:src "'foo' : String" :expected "foo"}
|
||||
{:src "true : String" :expected 0}
|
||||
{:src "'foo' : String!" :expected "foo"}
|
||||
{:src "null : String!" :expected 0}
|
||||
))
|
||||
Reference in New Issue
Block a user