Hyperscript conformance: 222 test fixtures from _hyperscript 0.9.14
Extract pure expression tests from the official _hyperscript test suite and implement parser/compiler/runtime extensions to pass them. Test infrastructure: - 222 fixtures extracted from evalHyperScript calls (no DOM dependency) - SX data format with eval-hs bridge and run-hs-fixture runner - 24 suites covering expressions, comparisons, coercion, logic, etc. Parser extensions (parser.sx): - mod as infix arithmetic operator - English comparison phrases (is less than, is greater than or equal to) - is a/an Type typecheck syntax - === / !== strict equality operators - I as me synonym, am as is for comparisons - does not exist/match/contain postfix - some/every ... with quantifier expressions - undefined keyword → nil Compiler updates (compiler.sx): - + emits hs-add (type-dispatching: string concat or numeric add) - no emits hs-falsy? (HS truthiness: empty string is falsy) - matches? emits hs-matches? (string regex in non-DOM context) - New cases: not-in?, in?, type-check, strict-eq, some, every Runtime additions (runtime.sx): - hs-coerce: Int/Integer truncation via floor - hs-add: string concat when either operand is string - hs-falsy?: HS-compatible truthiness (nil, false, "" are falsy) - hs-matches?: string pattern matching - hs-type-check/hs-type-check!: lenient/strict type checking - hs-strict-eq: type + value equality Tokenizer (tokenizer.sx): - Added keywords: I, am, does, some, mod, equal, equals, really, include, includes, contain, undefined, exist Scorecard: 47/112 test groups passing. 0 non-HS regressions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -57,10 +57,10 @@
|
||||
(deftest
|
||||
"addition passes through"
|
||||
(let
|
||||
((sx (hs-to-sx-from-source "set x to 1 + 2")))
|
||||
((sx (hs-to-sx-from-source "1 + 2")))
|
||||
(let
|
||||
((val (nth sx 2)))
|
||||
(assert= (quote +) (first val))
|
||||
((val (first sx)))
|
||||
(assert= (quote hs-add) (first val))
|
||||
(assert= 1 (nth val 1))
|
||||
(assert= 2 (nth val 2)))))
|
||||
(deftest
|
||||
@@ -287,4 +287,61 @@
|
||||
"decrement attribute"
|
||||
(let
|
||||
((sx (hs-to-sx-from-source "decrement @count")))
|
||||
(assert= (quote dom-set-attr) (first sx)))))
|
||||
(assert= (quote dom-set-attr) (first sx)))))
|
||||
|
||||
(defsuite
|
||||
"hs-live-demo-toggle"
|
||||
(deftest
|
||||
"toggle class on me compiles to single hs-on"
|
||||
(let
|
||||
((sx (hs-to-sx-from-source "on click toggle .bg-violet-600 on me then toggle .text-white on me")))
|
||||
(assert= (quote hs-on) (first sx))
|
||||
(assert= "click" (nth sx 2))
|
||||
(let
|
||||
((body (nth (nth sx 3) 2)))
|
||||
(assert= (quote do) (first body))
|
||||
(assert= 2 (len (rest body))))))
|
||||
(deftest
|
||||
"bounce: then chains wait and remove in same handler"
|
||||
(let
|
||||
((sx (hs-to-sx-from-source "on click add .animate-bounce to me then wait 1s then remove .animate-bounce from me")))
|
||||
(assert= (quote hs-on) (first sx))
|
||||
(assert= "click" (nth sx 2))
|
||||
(let
|
||||
((body (nth (nth sx 3) 2)))
|
||||
(assert= (quote do) (first body))
|
||||
(assert= 3 (len (rest body)))
|
||||
(assert= (quote hs-wait) (first (nth body 2)))
|
||||
(assert= 1000 (nth (nth body 2) 1)))))
|
||||
(deftest
|
||||
"count clicks: then chains increment and set in same handler"
|
||||
(let
|
||||
((sx (hs-to-sx-from-source "on click increment @data-count on me then set #click-counter's innerHTML to my @data-count")))
|
||||
(assert= (quote hs-on) (first sx))
|
||||
(assert= "click" (nth sx 2))
|
||||
(let
|
||||
((body (nth (nth sx 3) 2)))
|
||||
(assert= (quote do) (first body))
|
||||
(assert= 2 (len (rest body)))))))
|
||||
|
||||
(defsuite
|
||||
"hs-wait-suspension"
|
||||
(deftest
|
||||
"wait in then chain keeps hs-wait (platform handles suspension)"
|
||||
(let
|
||||
((sx (hs-to-sx-from-source "on click add .bounce to me then wait 1s then remove .bounce from me")))
|
||||
(assert= (quote hs-on) (first sx))
|
||||
(let
|
||||
((body (nth (nth sx 3) 2)))
|
||||
(assert= (quote do) (first body))
|
||||
(assert= 3 (len (rest body)))
|
||||
(assert= (quote hs-wait) (first (nth body 2)))
|
||||
(assert= 1000 (nth (nth body 2) 1)))))
|
||||
(deftest
|
||||
"wait preserves ms value in handler"
|
||||
(let
|
||||
((sx (hs-to-sx-from-source "on click add .a then wait 2s then add .b")))
|
||||
(let
|
||||
((body (nth (nth sx 3) 2)))
|
||||
(assert= (quote hs-wait) (first (nth body 2)))
|
||||
(assert= 2000 (nth (nth body 2) 1))))))
|
||||
826
spec/tests/test-hyperscript-conformance.sx
Normal file
826
spec/tests/test-hyperscript-conformance.sx
Normal file
@@ -0,0 +1,826 @@
|
||||
;; _hyperscript conformance test fixtures
|
||||
;; Auto-extracted from https://github.com/bigskysoftware/_hyperscript (v0.9.14)
|
||||
;; 222 pure expression tests (no DOM dependency)
|
||||
;; Generated: 2026-04-08T17:44:00.716Z
|
||||
|
||||
;; ── eval-hs: compile + evaluate hyperscript source ──────────────────
|
||||
(define
|
||||
eval-hs
|
||||
(fn
|
||||
(src &rest opts)
|
||||
(let
|
||||
((sx (hs-to-sx (hs-compile src)))
|
||||
(ctx (if (> (len opts) 0) (first opts) nil)))
|
||||
(if
|
||||
(nil? ctx)
|
||||
(eval-expr-cek
|
||||
(list
|
||||
(quote let)
|
||||
(list
|
||||
(list (quote me) nil)
|
||||
(list (quote it) nil)
|
||||
(list (quote result) nil))
|
||||
sx))
|
||||
(let
|
||||
((defaults (list (list (quote me) nil) (list (quote it) nil) (list (quote result) nil)))
|
||||
(overrides (list)))
|
||||
(do
|
||||
(when
|
||||
(get ctx "me")
|
||||
(set!
|
||||
overrides
|
||||
(cons (list (quote me) (get ctx "me")) overrides)))
|
||||
(when
|
||||
(get ctx "locals")
|
||||
(for-each
|
||||
(fn
|
||||
(k)
|
||||
(set!
|
||||
overrides
|
||||
(cons
|
||||
(list (make-symbol k) (get (get ctx "locals") k))
|
||||
overrides)))
|
||||
(keys (get ctx "locals"))))
|
||||
(eval-expr-cek
|
||||
(list (quote let) defaults (list (quote let) overrides sx)))))))))
|
||||
|
||||
;; ── run-hs-fixture: evaluate one test case ────────────────────────────
|
||||
(define run-hs-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 ((result (if ctx (eval-hs src ctx) (eval-hs src))))
|
||||
(assert= result expected src)))))
|
||||
|
||||
;; ── arrayIndex (1 fixtures) ──────────────────────────────
|
||||
(defsuite "hs-compat-arrayIndex"
|
||||
(deftest "can-create-an-array-literal"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "[1, 2, 3]" "expected" (list 1 2 3)}
|
||||
)))
|
||||
)
|
||||
|
||||
;; ── arrayLiteral (3 fixtures) ──────────────────────────────
|
||||
(defsuite "hs-compat-arrayLiteral"
|
||||
(deftest "empty-array-literals-work"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "[]" "expected" (list)}
|
||||
)))
|
||||
(deftest "one-element-array-literal-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "[true]" "expected" (list true)}
|
||||
)))
|
||||
(deftest "multi-element-array-literal-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "[true, false]" "expected" (list true false)}
|
||||
)))
|
||||
)
|
||||
|
||||
;; ── asExpression (19 fixtures) ──────────────────────────────
|
||||
(defsuite "hs-compat-asExpression"
|
||||
(deftest "converts-value-as-string"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "10 as String" "expected" "10"}
|
||||
{"src" "true as String" "expected" "true"}
|
||||
)))
|
||||
(deftest "converts-value-as-int"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "'10' as Int" "expected" 10}
|
||||
{"src" "'10.4' as Int" "expected" 10}
|
||||
)))
|
||||
(deftest "converts-value-as-float"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "'10' as Float" "expected" 10}
|
||||
{"src" "'10.4' as Float" "expected" 10.4}
|
||||
)))
|
||||
(deftest "converts-value-as-fixed"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "'10.4' as Fixed" "expected" "10"}
|
||||
{"src" "'10.4899' as Fixed:2" "expected" "10.49"}
|
||||
)))
|
||||
(deftest "converts-value-as-number"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "'10' as Number" "expected" 10}
|
||||
{"src" "'10.4' as Number" "expected" 10.4}
|
||||
)))
|
||||
(deftest "converts-value-as-json"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "{foo:'bar'} as JSON" "expected" "{\"foo\":\"bar\"}"}
|
||||
)))
|
||||
(deftest "converts-string-as-object"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "'{\"foo\":\"bar\"}' as Object" "expected" "bar"}
|
||||
)))
|
||||
(deftest "can-use-the-an-modifier-if-you"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "'{\"foo\":\"bar\"}' as an Object" "expected" "bar"}
|
||||
)))
|
||||
(deftest "converts-value-as-object"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "x as Object" "expected" "bar"}
|
||||
)))
|
||||
(deftest "converts-a-complete-form-into-values"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "x as Values" "expected" "John"}
|
||||
)))
|
||||
(deftest "converts-numbers-things-"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "value as HTML" "expected" "123"}
|
||||
)))
|
||||
(deftest "converts-strings-into-fragments"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "value as Fragment" "expected" 1}
|
||||
)))
|
||||
(deftest "can-accept-custom-conversions"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1 as Foo" "expected" "foo1"}
|
||||
)))
|
||||
(deftest "-"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1 as Foo:Bar" "expected" "Bar1"}
|
||||
)))
|
||||
)
|
||||
|
||||
;; ── blockLiteral (4 fixtures) ──────────────────────────────
|
||||
(defsuite "hs-compat-blockLiteral"
|
||||
(deftest "basic-block-literals-work"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "\\\\-> true" "expected" true}
|
||||
)))
|
||||
(deftest "basic-identity-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "\\\\ x -> x" "expected" true}
|
||||
)))
|
||||
(deftest "basic-two-arg-identity-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "\\\\ x, y -> y" "expected" true}
|
||||
)))
|
||||
(deftest "can-map-an-array"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "['a', 'ab', 'abc'].map(\\\\ s -> s.length )" "expected" (list 1 2 3)}
|
||||
)))
|
||||
)
|
||||
|
||||
;; ── boolean (2 fixtures) ──────────────────────────────
|
||||
(defsuite "hs-compat-boolean"
|
||||
(deftest "true-boolean-literals-work"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "true" "expected" true}
|
||||
)))
|
||||
(deftest "false-boolean-literals-work"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "false" "expected" false}
|
||||
)))
|
||||
)
|
||||
|
||||
;; ── classRef (1 fixtures) ──────────────────────────────
|
||||
(defsuite "hs-compat-classRef"
|
||||
(deftest "basic-classref-works-w-no-match"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" ".badClassThatDoesNotHaveAnyElements" "expected" 0}
|
||||
)))
|
||||
)
|
||||
|
||||
;; ── comparisonOperator (113 fixtures) ──────────────────────────────
|
||||
(defsuite "hs-compat-comparisonOperator"
|
||||
(deftest "less-than-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1 < 2" "expected" true}
|
||||
{"src" "2 < 1" "expected" false}
|
||||
{"src" "2 < 2" "expected" false}
|
||||
)))
|
||||
(deftest "less-than-or-equal-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1 <= 2" "expected" true}
|
||||
{"src" "2 <= 1" "expected" false}
|
||||
{"src" "2 <= 2" "expected" true}
|
||||
)))
|
||||
(deftest "greater-than-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1 > 2" "expected" false}
|
||||
{"src" "2 > 1" "expected" true}
|
||||
{"src" "2 > 2" "expected" false}
|
||||
)))
|
||||
(deftest "greater-than-or-equal-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1 >= 2" "expected" false}
|
||||
{"src" "2 >= 1" "expected" true}
|
||||
{"src" "2 >= 2" "expected" true}
|
||||
)))
|
||||
(deftest "equal-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1 == 2" "expected" false}
|
||||
{"src" "2 == 1" "expected" false}
|
||||
{"src" "2 == 2" "expected" true}
|
||||
)))
|
||||
(deftest "triple-equal-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1 === 2" "expected" false}
|
||||
{"src" "2 === 1" "expected" false}
|
||||
{"src" "2 === 2" "expected" true}
|
||||
)))
|
||||
(deftest "not-equal-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1 != 2" "expected" true}
|
||||
{"src" "2 != 1" "expected" true}
|
||||
{"src" "2 != 2" "expected" false}
|
||||
)))
|
||||
(deftest "triple-not-equal-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1 !== 2" "expected" true}
|
||||
{"src" "2 !== 1" "expected" true}
|
||||
{"src" "2 !== 2" "expected" false}
|
||||
)))
|
||||
(deftest "is-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1 is 2" "expected" false}
|
||||
{"src" "2 is 1" "expected" false}
|
||||
{"src" "2 is 2" "expected" true}
|
||||
)))
|
||||
(deftest "equals-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1 equals 2" "expected" false}
|
||||
{"src" "2 equals 1" "expected" false}
|
||||
{"src" "2 equals 2" "expected" true}
|
||||
)))
|
||||
(deftest "is-equal-to-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1 is equal to 2" "expected" false}
|
||||
{"src" "2 is equal to 1" "expected" false}
|
||||
{"src" "2 is equal to 2" "expected" true}
|
||||
)))
|
||||
(deftest "is-really-equal-to-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"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}
|
||||
)))
|
||||
(deftest "really-equals-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1 really equals 2" "expected" false}
|
||||
{"src" "2 really equals 1" "expected" false}
|
||||
{"src" "2 really equals 2" "expected" true}
|
||||
)))
|
||||
(deftest "is-not-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1 is not 2" "expected" true}
|
||||
{"src" "2 is not 1" "expected" true}
|
||||
{"src" "2 is not 2" "expected" false}
|
||||
)))
|
||||
(deftest "is-not-equal-to-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"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}
|
||||
)))
|
||||
(deftest "is-not-really-equal-to-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"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}
|
||||
)))
|
||||
(deftest "is-in-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"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}
|
||||
)))
|
||||
(deftest "is-not-in-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"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}
|
||||
)))
|
||||
(deftest "i-am-in-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "I am in [1, 2]" "expected" true "me" 1}
|
||||
{"src" "I am in [1, 2]" "expected" true "me" 2}
|
||||
{"src" "I am in [1, 2]" "expected" false "me" 3}
|
||||
{"src" "I am in null" "expected" false}
|
||||
)))
|
||||
(deftest "i-am-not-in-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "I am not in [1, 2]" "expected" false "me" 1}
|
||||
{"src" "I am not in [1, 2]" "expected" false "me" 2}
|
||||
{"src" "I am not in [1, 2]" "expected" true "me" 3}
|
||||
{"src" "I am not in null" "expected" true}
|
||||
)))
|
||||
(deftest "match-works-w-strings"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "'a' matches '.*'" "expected" true}
|
||||
{"src" "'a' matches 'b'" "expected" false}
|
||||
)))
|
||||
(deftest "does-not-match-works-w-strings"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "'a' does not match '.*'" "expected" false}
|
||||
{"src" "'a' does not match 'b'" "expected" true}
|
||||
)))
|
||||
(deftest "is-empty-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"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" ".aClassThatDoesNotExist is empty" "expected" true}
|
||||
)))
|
||||
(deftest "is-not-empty-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"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}
|
||||
)))
|
||||
(deftest "is-a-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "null is a String" "expected" true}
|
||||
{"src" "null is a String!" "expected" false}
|
||||
{"src" "'' is a String!" "expected" true}
|
||||
)))
|
||||
(deftest "is-not-a-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "null is not a String" "expected" false}
|
||||
{"src" "null is not a String!" "expected" true}
|
||||
{"src" "'' is not a String!" "expected" false}
|
||||
)))
|
||||
(deftest "is-an-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "null is an String" "expected" true}
|
||||
{"src" "null is an String!" "expected" false}
|
||||
{"src" "'' is an String!" "expected" true}
|
||||
)))
|
||||
(deftest "is-not-an-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "null is not an String" "expected" false}
|
||||
{"src" "null is not an String!" "expected" true}
|
||||
{"src" "'' is not an String!" "expected" false}
|
||||
)))
|
||||
(deftest "english-less-than-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1 is less than 2" "expected" true}
|
||||
{"src" "2 is less than 1" "expected" false}
|
||||
{"src" "2 is less than 2" "expected" false}
|
||||
)))
|
||||
(deftest "english-less-than-or-equal-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"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}
|
||||
)))
|
||||
(deftest "english-greater-than-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1 is greater than 2" "expected" false}
|
||||
{"src" "2 is greater than 1" "expected" true}
|
||||
{"src" "2 is greater than 2" "expected" false}
|
||||
)))
|
||||
(deftest "english-greater-than-or-equal-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"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}
|
||||
)))
|
||||
(deftest "does-not-exist-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "undefined does not exist" "expected" true}
|
||||
{"src" "null does not exist" "expected" true}
|
||||
{"src" "#doesNotExist does not exist" "expected" true}
|
||||
{"src" ".aClassThatDoesNotExist does not exist" "expected" true}
|
||||
{"src" "<.aClassThatDoesNotExist/> does not exist" "expected" true}
|
||||
{"src" "<body/> does not exist" "expected" false}
|
||||
)))
|
||||
)
|
||||
|
||||
;; ── cookies (9 fixtures) ──────────────────────────────
|
||||
(defsuite "hs-compat-cookies"
|
||||
(deftest "basic-set-cookie-values-work"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "cookies.foo" "expected" "bar"}
|
||||
{"src" "set cookies.foo to 'bar'" "expected" "bar"}
|
||||
{"src" "cookies.foo" "expected" "bar"}
|
||||
)))
|
||||
(deftest "update-cookie-values-work"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"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"}
|
||||
)))
|
||||
(deftest "iterate-cookies-values-work"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"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}
|
||||
)))
|
||||
)
|
||||
|
||||
;; ── in (4 fixtures) ──────────────────────────────
|
||||
(defsuite "hs-compat-in"
|
||||
(deftest "basic-no-query-return-values"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"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)}
|
||||
)))
|
||||
)
|
||||
|
||||
;; ── logicalOperator (2 fixtures) ──────────────────────────────
|
||||
(defsuite "hs-compat-logicalOperator"
|
||||
(deftest "should-short-circuit-with-and-expression"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "func1() and func2()" "expected" false}
|
||||
)))
|
||||
(deftest "should-short-circuit-with-or-expression"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "func1() or func2()" "expected" true}
|
||||
)))
|
||||
)
|
||||
|
||||
;; ── mathOperator (8 fixtures) ──────────────────────────────
|
||||
(defsuite "hs-compat-mathOperator"
|
||||
(deftest "addition-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1 + 1" "expected" 2}
|
||||
)))
|
||||
(deftest "string-concat-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "'a' + 'b'" "expected" "ab"}
|
||||
)))
|
||||
(deftest "subtraction-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1 - 1" "expected" 0}
|
||||
)))
|
||||
(deftest "multiplication-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1 * 2" "expected" 2}
|
||||
)))
|
||||
(deftest "division-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1 / 2" "expected" 0.5}
|
||||
)))
|
||||
(deftest "mod-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "3 mod 2" "expected" 1}
|
||||
)))
|
||||
(deftest "addition-works-w-more-than-one-value"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1 + 2 + 3" "expected" 6}
|
||||
)))
|
||||
(deftest "parenthesized-expressions-with-multiple-operators-work"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1 + (2 * 3)" "expected" 7}
|
||||
)))
|
||||
)
|
||||
|
||||
;; ── no (5 fixtures) ──────────────────────────────
|
||||
(defsuite "hs-compat-no"
|
||||
(deftest "no-returns-true-for-null"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "no null" "expected" true}
|
||||
)))
|
||||
(deftest "no-returns-false-for-non-null"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "no 'thing'" "expected" false}
|
||||
{"src" "no ['thing']" "expected" false}
|
||||
)))
|
||||
(deftest "no-returns-true-for-empty-array"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "no []" "expected" true}
|
||||
)))
|
||||
(deftest "no-returns-true-for-empty-selector"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "no .aClassThatDoesNotExist" "expected" true}
|
||||
)))
|
||||
)
|
||||
|
||||
;; ── not (3 fixtures) ──────────────────────────────
|
||||
(defsuite "hs-compat-not"
|
||||
(deftest "not-inverts-true"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "not true" "expected" false}
|
||||
)))
|
||||
(deftest "not-inverts-false"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "not false" "expected" true}
|
||||
)))
|
||||
(deftest "two-nots-make-a-true"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "not not true" "expected" true}
|
||||
)))
|
||||
)
|
||||
|
||||
;; ── numbers (4 fixtures) ──────────────────────────────
|
||||
(defsuite "hs-compat-numbers"
|
||||
(deftest "handles-numbers-properly"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "-1" "expected" -1}
|
||||
{"src" "1" "expected" 1}
|
||||
{"src" "1.1" "expected" 1.1}
|
||||
{"src" "1234567890.1234567890" "expected" 1234567890.1234567}
|
||||
)))
|
||||
)
|
||||
|
||||
;; ── objectLiteral (3 fixtures) ──────────────────────────────
|
||||
(defsuite "hs-compat-objectLiteral"
|
||||
(deftest "empty-object-literals-work"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "{}" "expected" {}}
|
||||
)))
|
||||
(deftest "hyphens-work-in-object-literal-field-names"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "{-foo:true, bar-baz:false}" "expected" {"-foo" true "bar-baz" false}}
|
||||
)))
|
||||
(deftest "allows-trailing-commans"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "{foo:true, bar-baz:false,}" "expected" {"foo" true "bar-baz" false}}
|
||||
)))
|
||||
)
|
||||
|
||||
;; ── positionalExpression (2 fixtures) ──────────────────────────────
|
||||
(defsuite "hs-compat-positionalExpression"
|
||||
(deftest "first-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "the first of [1, 2, 3]" "expected" 1}
|
||||
)))
|
||||
(deftest "last-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "the last of [1, 2, 3]" "expected" 3}
|
||||
)))
|
||||
)
|
||||
|
||||
;; ── possessiveExpression (2 fixtures) ──────────────────────────────
|
||||
(defsuite "hs-compat-possessiveExpression"
|
||||
(deftest "can-access-basic-properties"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "foo's foo" "expected" "foo"}
|
||||
)))
|
||||
(deftest "can-access-its-properties"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "its foo" "expected" "foo"}
|
||||
)))
|
||||
)
|
||||
|
||||
;; ── propertyAccess (4 fixtures) ──────────────────────────────
|
||||
(defsuite "hs-compat-propertyAccess"
|
||||
(deftest "can-access-basic-properties"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "foo.foo" "expected" "foo"}
|
||||
)))
|
||||
(deftest "of-form-works"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "foo of foo" "expected" "foo"}
|
||||
)))
|
||||
(deftest "of-form-works-w-complex-left-side"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "bar.doh of foo" "expected" "foo"}
|
||||
)))
|
||||
(deftest "of-form-works-w-complex-right-side"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "doh of foo.bar" "expected" "foo"}
|
||||
)))
|
||||
)
|
||||
|
||||
;; ── queryRef (1 fixtures) ──────────────────────────────
|
||||
(defsuite "hs-compat-queryRef"
|
||||
(deftest "basic-queryref-works-w-no-match"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "<.badClassThatDoesNotHaveAnyElements/>" "expected" 0}
|
||||
)))
|
||||
)
|
||||
|
||||
;; ── some (6 fixtures) ──────────────────────────────
|
||||
(defsuite "hs-compat-some"
|
||||
(deftest "some-returns-false-for-null"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "some null" "expected" false}
|
||||
)))
|
||||
(deftest "some-returns-true-for-non-null"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "some 'thing'" "expected" true}
|
||||
)))
|
||||
(deftest "some-returns-false-for-empty-array"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "some []" "expected" false}
|
||||
)))
|
||||
(deftest "some-returns-false-for-empty-selector"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "some .aClassThatDoesNotExist" "expected" false}
|
||||
)))
|
||||
(deftest "some-returns-true-for-nonempty-selector"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "some <html/>" "expected" true}
|
||||
)))
|
||||
(deftest "some-returns-true-for-filled-array"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "some ['thing']" "expected" true}
|
||||
)))
|
||||
)
|
||||
|
||||
;; ── stringPostfix (10 fixtures) ──────────────────────────────
|
||||
(defsuite "hs-compat-stringPostfix"
|
||||
(deftest "handles-basic-postfix-strings-properly"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1em" "expected" "1em"}
|
||||
{"src" "1px" "expected" "1px"}
|
||||
{"src" "-1px" "expected" "-1px"}
|
||||
{"src" "100%" "expected" "100%"}
|
||||
)))
|
||||
(deftest "handles-basic-postfix-strings-with-spaces-properly"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "1 em" "expected" "1em"}
|
||||
{"src" "1 px" "expected" "1px"}
|
||||
{"src" "100 %" "expected" "100%"}
|
||||
)))
|
||||
(deftest "handles-expression-roots-properly"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "(0 + 1) em" "expected" "1em"}
|
||||
{"src" "(0 + 1) px" "expected" "1px"}
|
||||
{"src" "(100 + 0) %" "expected" "100%"}
|
||||
)))
|
||||
)
|
||||
|
||||
;; ── strings (11 fixtures) ──────────────────────────────
|
||||
(defsuite "hs-compat-strings"
|
||||
(deftest "handles-strings-properly"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "\"foo\"" "expected" "foo"}
|
||||
{"src" "\"fo'o\"" "expected" "fo'o"}
|
||||
{"src" "'foo'" "expected" "foo"}
|
||||
)))
|
||||
(deftest "string-templates-work-properly"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "`$1`" "expected" "1"}
|
||||
)))
|
||||
(deftest "string-templates-work-properly-w-braces"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "`${1 + 2}`" "expected" "3"}
|
||||
)))
|
||||
(deftest "string-templates-preserve-white-space"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"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"}
|
||||
)))
|
||||
(deftest "should-handle-strings-with-tags-and-quotes"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "`<div age=\"${record.age}\" style=\"color:${record.favouriteColour}\">${record.name}</div>`" "expected" "<div age=\"21\" style=\"color:bleaux\">John Connor</div>"}
|
||||
)))
|
||||
(deftest "should-handle-back-slashes-in-non-template-content"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "`https://${foo}`" "expected" "https://bar" "locals" {"foo" "bar"}}
|
||||
)))
|
||||
)
|
||||
|
||||
;; ── symbol (1 fixtures) ──────────────────────────────
|
||||
(defsuite "hs-compat-symbol"
|
||||
(deftest "resolves-local-context-properly"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "foo" "expected" 42 "locals" {"foo" 42}}
|
||||
)))
|
||||
)
|
||||
|
||||
;; ── typecheck (4 fixtures) ──────────────────────────────
|
||||
(defsuite "hs-compat-typecheck"
|
||||
(deftest "can-do-basic-string-typecheck"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "'foo' : String" "expected" "foo"}
|
||||
)))
|
||||
(deftest "can-do-basic-non-string-typecheck-failure"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "true : String" "expected" 0}
|
||||
)))
|
||||
(deftest "can-do-basic-string-non-null-typecheck"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "'foo' : String!" "expected" "foo"}
|
||||
)))
|
||||
(deftest "null-causes-null-safe-string-check-to-fail"
|
||||
(for-each run-hs-fixture
|
||||
(list
|
||||
{"src" "null : String!" "expected" 0}
|
||||
)))
|
||||
)
|
||||
|
||||
;; ── Summary ──────────────────────────────────────────────────────────
|
||||
;; 24 suites, 112 tests, 222 fixtures
|
||||
|
||||
Reference in New Issue
Block a user