;; 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}))