Files
rose-ash/lib/prolog/tests/query_api.sx
giles 25a4ce4a05
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
prolog-query SX API: pl-load + pl-query-all + pl-query-one + pl-query (+16 tests)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 09:58:56 +00:00

128 lines
3.2 KiB
Plaintext

;; lib/prolog/tests/query_api.sx — tests for pl-load/pl-query-all/pl-query-one/pl-query
(define pl-qa-test-count 0)
(define pl-qa-test-pass 0)
(define pl-qa-test-fail 0)
(define pl-qa-test-failures (list))
(define
pl-qa-test!
(fn
(name got expected)
(begin
(set! pl-qa-test-count (+ pl-qa-test-count 1))
(if
(= got expected)
(set! pl-qa-test-pass (+ pl-qa-test-pass 1))
(begin
(set! pl-qa-test-fail (+ pl-qa-test-fail 1))
(append!
pl-qa-test-failures
(str name "\n expected: " expected "\n got: " got)))))))
(define
pl-qa-src
"parent(tom, bob). parent(tom, liz). parent(bob, ann). ancestor(X, Y) :- parent(X, Y). ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).")
(define pl-qa-db (pl-load pl-qa-src))
;; ── pl-load ──
(pl-qa-test!
"pl-load returns a usable DB (pl-query-all non-nil)"
(not (nil? pl-qa-db))
true)
;; ── pl-query-all: basic fact lookup ──
(pl-qa-test!
"query-all parent(tom, X): 2 solutions"
(len (pl-query-all pl-qa-db "parent(tom, X)"))
2)
(pl-qa-test!
"query-all parent(tom, X): first solution X=bob"
(dict-get (first (pl-query-all pl-qa-db "parent(tom, X)")) "X")
"bob")
(pl-qa-test!
"query-all parent(tom, X): second solution X=liz"
(dict-get (nth (pl-query-all pl-qa-db "parent(tom, X)") 1) "X")
"liz")
;; ── pl-query-all: no solutions ──
(pl-qa-test!
"query-all no solutions returns empty list"
(pl-query-all pl-qa-db "parent(liz, X)")
(list))
;; ── pl-query-all: boolean query (no vars) ──
(pl-qa-test!
"boolean success: 1 solution (empty dict)"
(len (pl-query-all pl-qa-db "parent(tom, bob)"))
1)
(pl-qa-test!
"boolean success: solution has no bindings"
(empty? (keys (first (pl-query-all pl-qa-db "parent(tom, bob)"))))
true)
(pl-qa-test!
"boolean fail: 0 solutions"
(len (pl-query-all pl-qa-db "parent(bob, tom)"))
0)
;; ── pl-query-all: multi-var ──
(pl-qa-test!
"query-all parent(X, Y): 3 solutions total"
(len (pl-query-all pl-qa-db "parent(X, Y)"))
3)
;; ── pl-query-all: rule-based (ancestor/2) ──
(pl-qa-test!
"query-all ancestor(tom, X): 3 descendants (bob, liz, ann)"
(len (pl-query-all pl-qa-db "ancestor(tom, X)"))
3)
;; ── pl-query-all: built-in in query ──
(pl-qa-test!
"query with is/2 built-in"
(dict-get (first (pl-query-all pl-qa-db "X is 2 + 3")) "X")
"5")
;; ── pl-query-one ──
(pl-qa-test!
"query-one returns first solution"
(dict-get (pl-query-one pl-qa-db "parent(tom, X)") "X")
"bob")
(pl-qa-test!
"query-one returns nil for no solutions"
(pl-query-one pl-qa-db "parent(liz, X)")
nil)
;; ── pl-query convenience ──
(pl-qa-test!
"pl-query convenience: count solutions"
(len (pl-query "likes(alice, bob). likes(alice, carol)." "likes(alice, X)"))
2)
(pl-qa-test!
"pl-query convenience: first solution"
(dict-get (first (pl-query "likes(alice, bob). likes(alice, carol)." "likes(alice, X)")) "X")
"bob")
(pl-qa-test!
"pl-query with empty source (built-ins only)"
(dict-get (first (pl-query "" "X is 6 * 7")) "X")
"42")
(define pl-query-api-tests-run! (fn () {:failed pl-qa-test-fail :passed pl-qa-test-pass :total pl-qa-test-count :failures pl-qa-test-failures}))