Add self-hosting SX test spec: 81 tests bootstrap to Python + JS
The test framework is written in SX and tests SX — the language proves its own correctness. test.sx defines assertion helpers (assert-equal, assert-true, assert-type, etc.) and 15 test suites covering literals, arithmetic, comparison, strings, lists, dicts, predicates, special forms, lambdas, higher-order forms, components, macros, threading, truthiness, and edge cases. Two bootstrap compilers emit native tests from the same spec: - bootstrap_test.py → pytest (81/81 pass) - bootstrap_test_js.py → Node.js TAP using sx-browser.js (81/81 pass) Also adds missing primitives to spec and Python evaluator: boolean?, string-length, substring, string-contains?, upcase, downcase, reverse, flatten, has-key?. Fixes number? to exclude booleans, append to concatenate lists. Includes testing docs page in SX app at /specs/testing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -192,9 +192,13 @@ def prim_is_zero(n: Any) -> bool:
|
||||
def prim_is_nil(x: Any) -> bool:
|
||||
return x is None or x is NIL
|
||||
|
||||
@register_primitive("boolean?")
|
||||
def prim_is_boolean(x: Any) -> bool:
|
||||
return isinstance(x, bool)
|
||||
|
||||
@register_primitive("number?")
|
||||
def prim_is_number(x: Any) -> bool:
|
||||
return isinstance(x, (int, float))
|
||||
return isinstance(x, (int, float)) and not isinstance(x, bool)
|
||||
|
||||
@register_primitive("string?")
|
||||
def prim_is_string(x: Any) -> bool:
|
||||
@@ -268,13 +272,27 @@ def prim_concat(*colls: Any) -> list:
|
||||
return result
|
||||
|
||||
@register_primitive("upper")
|
||||
@register_primitive("upcase")
|
||||
def prim_upper(s: str) -> str:
|
||||
return s.upper()
|
||||
|
||||
@register_primitive("lower")
|
||||
@register_primitive("downcase")
|
||||
def prim_lower(s: str) -> str:
|
||||
return s.lower()
|
||||
|
||||
@register_primitive("string-length")
|
||||
def prim_string_length(s: str) -> int:
|
||||
return len(s)
|
||||
|
||||
@register_primitive("substring")
|
||||
def prim_substring(s: str, start: int, end: int) -> str:
|
||||
return s[int(start):int(end)]
|
||||
|
||||
@register_primitive("string-contains?")
|
||||
def prim_string_contains(s: str, needle: str) -> bool:
|
||||
return needle in s
|
||||
|
||||
@register_primitive("trim")
|
||||
def prim_trim(s: str) -> str:
|
||||
return s.strip()
|
||||
@@ -384,8 +402,31 @@ def prim_cons(x: Any, coll: Any) -> list:
|
||||
|
||||
@register_primitive("append")
|
||||
def prim_append(coll: Any, x: Any) -> list:
|
||||
if isinstance(x, list):
|
||||
return list(coll) + x if coll else list(x)
|
||||
return list(coll) + [x] if coll else [x]
|
||||
|
||||
@register_primitive("reverse")
|
||||
def prim_reverse(coll: Any) -> list:
|
||||
return list(reversed(coll)) if coll else []
|
||||
|
||||
@register_primitive("flatten")
|
||||
def prim_flatten(coll: Any) -> list:
|
||||
result = []
|
||||
for item in (coll or []):
|
||||
if isinstance(item, list):
|
||||
result.extend(item)
|
||||
else:
|
||||
result.append(item)
|
||||
return result
|
||||
|
||||
@register_primitive("has-key?")
|
||||
def prim_has_key(d: Any, key: Any) -> bool:
|
||||
if not isinstance(d, dict):
|
||||
return False
|
||||
k = key.name if isinstance(key, Keyword) else key
|
||||
return k in d
|
||||
|
||||
@register_primitive("append!")
|
||||
def prim_append_mut(coll: Any, x: Any) -> list:
|
||||
coll.append(x)
|
||||
|
||||
Reference in New Issue
Block a user