Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
128 lines
3.2 KiB
Plaintext
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}))
|