HS test generator: property access, locals, me-val, nested opts (515→517/831)
- Handle result["foo"] and result.foo property access after eval-hs
- Handle { locals: { x: 5, y: 5 } } opts with nested braces
- Handle { me: N } opts via eval-hs-with-me helper
- Add eval-hs-with-me to test framework for "I am between" tests
- Use host-get for property access on host handles (JSON.parse results)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -25,6 +25,14 @@
|
||||
(list (quote fn) (list (quote me)) (list (quote let) (list (list (quote it) nil) (list (quote event) nil)) sx)))))
|
||||
(handler nil)))))
|
||||
|
||||
;; Evaluate with a specific me value (for "I am between" etc.)
|
||||
(define eval-hs-with-me
|
||||
(fn (src me-val)
|
||||
(let ((sx (hs-to-sx (hs-compile src))))
|
||||
(let ((handler (eval-expr-cek
|
||||
(list (quote fn) (list (quote me)) (list (quote let) (list (list (quote it) nil) (list (quote event) nil)) sx)))))
|
||||
(handler me-val)))))
|
||||
|
||||
;; ── add (19 tests) ──
|
||||
(defsuite "hs-upstream-add"
|
||||
(deftest "can add class ref on a single div"
|
||||
@@ -7492,7 +7500,7 @@
|
||||
;; ── collectionExpressions (22 tests) ──
|
||||
(defsuite "hs-upstream-collectionExpressions"
|
||||
(deftest "filters an array by condition"
|
||||
(assert= (eval-hs "set arr to [{name: \"a\", active: true}, {name: \"b\", active: false}, {name: \"c\", active: true}] then return arr where its active") (list "a" "c"))
|
||||
(assert= (map (fn (x) (get x "name")) (eval-hs "set arr to [{name: \"a\", active: true}, {name: \"b\", active: false}, {name: \"c\", active: true}] then return arr where its active")) (list "a" "c"))
|
||||
)
|
||||
(deftest "filters with comparison"
|
||||
(assert= (eval-hs "set arr to [1, 2, 3, 4, 5] then return arr where it > 3") (list 4 5))
|
||||
@@ -7520,13 +7528,13 @@
|
||||
(assert= (dom-text-content (dom-query-by-id "out")) "AC")
|
||||
))
|
||||
(deftest "sorts by a property"
|
||||
(assert= (eval-hs "set arr to [{name: \"Charlie\"}, {name: \"Alice\"}, {name: \"Bob\"}] then return arr sorted by its name") (list "Alice" "Bob" "Charlie"))
|
||||
(assert= (map (fn (x) (get x "name")) (eval-hs "set arr to [{name: \"Charlie\"}, {name: \"Alice\"}, {name: \"Bob\"}] then return arr sorted by its name")) (list "Alice" "Bob" "Charlie"))
|
||||
)
|
||||
(deftest "sorts descending"
|
||||
(assert= (eval-hs "set arr to [3, 1, 2] then return arr sorted by it descending") (list 3 2 1))
|
||||
)
|
||||
(deftest "sorts numbers by a computed key"
|
||||
(assert= (eval-hs "set arr to [{name: \"b\", age: 30}, {name: \"a\", age: 20}, {name: \"c\", age: 25}] then return arr sorted by its age") (list "a" "c" "b"))
|
||||
(assert= (map (fn (x) (get x "name")) (eval-hs "set arr to [{name: \"b\", age: 30}, {name: \"a\", age: 20}, {name: \"c\", age: 25}] then return arr sorted by its age")) (list "a" "c" "b"))
|
||||
)
|
||||
(deftest "maps to a property"
|
||||
(assert= (eval-hs "set arr to [{name: \"Alice\"}, {name: \"Bob\"}] then return arr mapped to its name") (list "Alice" "Bob"))
|
||||
@@ -8441,16 +8449,16 @@
|
||||
(deftest "can use the a modifier if you like"
|
||||
(error "NOT IMPLEMENTED: test HTML could not be parsed into SX"))
|
||||
(deftest "parses string as JSON to object"
|
||||
(assert= (eval-hs "'{\"foo\":\"bar\"}' as JSON") "bar")
|
||||
(assert= (host-get (eval-hs "'{\"foo\":\"bar\"}' as JSON") "foo") "bar")
|
||||
)
|
||||
(deftest "converts value as JSONString"
|
||||
(assert= (eval-hs "{foo:'bar'} as JSONString") "{"foo":"bar"}")
|
||||
)
|
||||
(deftest "pipe operator chains conversions"
|
||||
(assert= (eval-hs "{foo:'bar'} as JSONString | JSON") "bar")
|
||||
(assert= (host-get (eval-hs "{foo:'bar'} as JSONString | JSON") "foo") "bar")
|
||||
)
|
||||
(deftest "can use the an modifier if you'd like"
|
||||
(assert= (eval-hs "'{\"foo\":\"bar\"}' as an Object") "bar")
|
||||
(assert= (host-get (eval-hs "'{\"foo\":\"bar\"}' as an Object") "foo") "bar")
|
||||
)
|
||||
(deftest "collects duplicate text inputs into an array"
|
||||
(error "NOT IMPLEMENTED: test HTML could not be parsed into SX"))
|
||||
@@ -8658,12 +8666,12 @@
|
||||
(assert= (eval-hs "'d' is between 'a' and 'c'") false)
|
||||
)
|
||||
(deftest "I am between works"
|
||||
(assert= (eval-hs "I am between 1 and 10") true)
|
||||
(assert= (eval-hs "I am between 1 and 10") false)
|
||||
(assert= (eval-hs-with-me "I am between 1 and 10" 5) true)
|
||||
(assert= (eval-hs-with-me "I am between 1 and 10" 0) false)
|
||||
)
|
||||
(deftest "I am not between works"
|
||||
(assert= (eval-hs "I am not between 1 and 10") false)
|
||||
(assert= (eval-hs "I am not between 1 and 10") true)
|
||||
(assert= (eval-hs-with-me "I am not between 1 and 10" 5) false)
|
||||
(assert= (eval-hs-with-me "I am not between 1 and 10" 0) true)
|
||||
)
|
||||
(deftest "precedes works"
|
||||
(hs-cleanup!)
|
||||
@@ -8777,8 +8785,8 @@
|
||||
(dom-append (dom-body) _el-b2)
|
||||
))
|
||||
(deftest "is still does equality when rhs variable exists"
|
||||
(assert= (eval-hs "x is y") true)
|
||||
(assert= (eval-hs "x is y") false)
|
||||
(let ((x 5) (y 5)) (assert= (eval-hs "x is y") true))
|
||||
(let ((x 5) (y 6)) (assert= (eval-hs "x is y") false))
|
||||
)
|
||||
(deftest "is boolean property works in where clause"
|
||||
(hs-cleanup!)
|
||||
|
||||
@@ -717,12 +717,27 @@ def generate_eval_only_test(test, idx):
|
||||
|
||||
# Pattern 1: Inline — expect(run("expr", opts)).toBe(val) or run("expr", opts).toBe(val)
|
||||
for m in re.finditer(
|
||||
r'(?:expect\()?' + _RUN_OPEN + _RUN_ARGS + r'\)\)?\.toBe\(([^)]+)\)',
|
||||
r'(?:expect\()?' + _RUN_OPEN + r'(\s*,\s*\{[^}]*(?:\{[^}]*\}[^}]*)?\})?' + r'\)\)?\.toBe\(([^)]+)\)',
|
||||
body, re.DOTALL
|
||||
):
|
||||
hs_expr = extract_hs_expr(m.group(2))
|
||||
expected_sx = js_val_to_sx(m.group(3))
|
||||
assertions.append(f' (assert= (eval-hs "{hs_expr}") {expected_sx})')
|
||||
opts_str = m.group(3) or ''
|
||||
expected_sx = js_val_to_sx(m.group(4))
|
||||
# Check for { me: X } or { locals: { x: X, y: Y } } in opts
|
||||
me_match = re.search(r'\bme:\s*(\d+)', opts_str)
|
||||
locals_match = re.search(r'locals:\s*\{([^}]+)\}', opts_str)
|
||||
if locals_match:
|
||||
local_bindings = []
|
||||
for lm in re.finditer(r'(\w+)\s*:\s*([^,}]+)', locals_match.group(1)):
|
||||
lname = lm.group(1)
|
||||
lval = js_val_to_sx(lm.group(2).strip())
|
||||
local_bindings.append(f'({lname} {lval})')
|
||||
assertions.append(f' (let ({" ".join(local_bindings)}) (assert= (eval-hs "{hs_expr}") {expected_sx}))')
|
||||
elif me_match:
|
||||
me_val = me_match.group(1)
|
||||
assertions.append(f' (assert= (eval-hs-with-me "{hs_expr}" {me_val}) {expected_sx})')
|
||||
else:
|
||||
assertions.append(f' (assert= (eval-hs "{hs_expr}") {expected_sx})')
|
||||
|
||||
# Pattern 1b: Inline — run("expr", opts).toEqual([...])
|
||||
for m in re.finditer(
|
||||
@@ -752,12 +767,25 @@ def generate_eval_only_test(test, idx):
|
||||
)
|
||||
if run_match:
|
||||
hs_expr = extract_hs_expr(run_match.group(2))
|
||||
for m in re.finditer(r'\.toBe\(([^)]+)\)', body):
|
||||
expected_sx = js_val_to_sx(m.group(1))
|
||||
assertions.append(f' (assert= (eval-hs "{hs_expr}") {expected_sx})')
|
||||
for m in re.finditer(r'\.toEqual\((\[.*?\])\)', body, re.DOTALL):
|
||||
var_name = re.search(r'(?:var|let|const)\s+(\w+)', body).group(1)
|
||||
for m in re.finditer(r'expect\((' + re.escape(var_name) + r'(?:\["[^"]+"\]|\.\w+)?)\)\.toBe\(([^)]+)\)', body):
|
||||
accessor = m.group(1)
|
||||
expected_sx = js_val_to_sx(m.group(2))
|
||||
# Check for property access: result["foo"] or result.foo
|
||||
prop_m = re.search(r'\["([^"]+)"\]|\.(\w+)', accessor[len(var_name):])
|
||||
if prop_m:
|
||||
prop = prop_m.group(1) or prop_m.group(2)
|
||||
assertions.append(f' (assert= (host-get (eval-hs "{hs_expr}") "{prop}") {expected_sx})')
|
||||
else:
|
||||
assertions.append(f' (assert= (eval-hs "{hs_expr}") {expected_sx})')
|
||||
for m in re.finditer(r'expect\(' + re.escape(var_name) + r'(?:\.\w+)?\)\.toEqual\((\[.*?\])\)', body, re.DOTALL):
|
||||
expected_sx = js_val_to_sx(m.group(1))
|
||||
assertions.append(f' (assert= (eval-hs "{hs_expr}") {expected_sx})')
|
||||
# Handle .map(x => x.prop) before toEqual
|
||||
for m in re.finditer(r'expect\(' + re.escape(var_name) + r'\.map\(\w+\s*=>\s*\w+\.(\w+)\)\)\.toEqual\((\[.*?\])\)', body, re.DOTALL):
|
||||
prop = m.group(1)
|
||||
expected_sx = js_val_to_sx(m.group(2))
|
||||
assertions.append(f' (assert= (map (fn (x) (get x "{prop}")) (eval-hs "{hs_expr}")) {expected_sx})')
|
||||
|
||||
# Pattern 2b: run() with locals + evaluate(window.X) + expect().toBe/toEqual
|
||||
# e.g.: await run(`expr`, {locals: {arr: [1,2,3]}});
|
||||
@@ -883,6 +911,14 @@ output.append(' (let ((handler (eval-expr-cek')
|
||||
output.append(' (list (quote fn) (list (quote me)) (list (quote let) (list (list (quote it) nil) (list (quote event) nil)) sx)))))')
|
||||
output.append(' (handler nil)))))')
|
||||
output.append('')
|
||||
output.append(';; Evaluate with a specific me value (for "I am between" etc.)')
|
||||
output.append('(define eval-hs-with-me')
|
||||
output.append(' (fn (src me-val)')
|
||||
output.append(' (let ((sx (hs-to-sx (hs-compile src))))')
|
||||
output.append(' (let ((handler (eval-expr-cek')
|
||||
output.append(' (list (quote fn) (list (quote me)) (list (quote let) (list (list (quote it) nil) (list (quote event) nil)) sx)))))')
|
||||
output.append(' (handler me-val)))))')
|
||||
output.append('')
|
||||
|
||||
# Group by category
|
||||
categories = OrderedDict()
|
||||
|
||||
Reference in New Issue
Block a user