;; lib/relations/tests/direct.sx — Phase 1: schema + direct relations. (define relations-dt-pass 0) (define relations-dt-fail 0) (define relations-dt-failures (list)) (define relations-dt-check! (fn (name got expected) (if (= got expected) (set! relations-dt-pass (+ relations-dt-pass 1)) (do (set! relations-dt-fail (+ relations-dt-fail 1)) (append! relations-dt-failures (str name "\n expected: " expected "\n got: " got)))))) ;; Order-insensitive membership: every x in xs is in ys. (define relations-dt-subset? (fn (xs ys) (cond ((= (len xs) 0) true) ((relations-member? (first xs) ys) (relations-dt-subset? (rest xs) ys)) (else false)))) (define relations-dt-set=? (fn (xs ys) (and (= (len xs) (len ys)) (relations-dt-subset? xs ys) (relations-dt-subset? ys xs)))) ;; Fixture: a small forest with two kinds. ;; parent: a -> b, a -> c, b -> d ;; reply: p -> q (define relations-dt-fixture (fn () (relations-build-db (list (relations-rel (quote a) (quote b) (quote parent)) (relations-rel (quote a) (quote c) (quote parent)) (relations-rel (quote b) (quote d) (quote parent)) (relations-rel (quote p) (quote q) (quote reply)))))) (define relations-dt-run-all! (fn () (let ((db (relations-dt-fixture))) (do (relations-dt-check! "direct children of a" (relations-dt-set=? (relations-children-of db (quote a) (quote parent)) (list (quote b) (quote c))) true) (relations-dt-check! "direct children of b" (relations-dt-set=? (relations-children-of db (quote b) (quote parent)) (list (quote d))) true) (relations-dt-check! "leaf has no children" (relations-children-of db (quote d) (quote parent)) (list)) (relations-dt-check! "direct parents of b" (relations-dt-set=? (relations-parents-of db (quote b) (quote parent)) (list (quote a))) true) (relations-dt-check! "root has no parents" (relations-parents-of db (quote a) (quote parent)) (list)) (relations-dt-check! "related is both directions" (relations-dt-set=? (relations-related db (quote b) (quote parent)) (list (quote d) (quote a))) true) (relations-dt-check! "kind isolation: parent query skips reply edge" (relations-children-of db (quote p) (quote parent)) (list)) (relations-dt-check! "reply children of p" (relations-dt-set=? (relations-children-of db (quote p) (quote reply)) (list (quote q))) true) (relations-dt-check! "unknown node -> empty" (relations-children-of db (quote zzz) (quote parent)) (list)) (let ((db2 (relations-build-db (list (relations-rel (quote x) (quote y) (quote parent)))))) (do (relations-dt-check! "before retract: y is a child of x" (relations-dt-set=? (relations-children-of db2 (quote x) (quote parent)) (list (quote y))) true) (dl-retract! db2 (relations-rel (quote x) (quote y) (quote parent))) (relations-dt-check! "after retract: x has no children" (relations-children-of db2 (quote x) (quote parent)) (list)))) (do (relations/load! (list)) (relations/relate (quote o1) (quote li1) (quote member)) (relations/relate (quote o1) (quote li2) (quote member)) (relations-dt-check! "api relate then children" (relations-dt-set=? (relations/children (quote o1) (quote member)) (list (quote li1) (quote li2))) true) (relations-dt-check! "api parents" (relations-dt-set=? (relations/parents (quote li1) (quote member)) (list (quote o1))) true) (relations/unrelate (quote o1) (quote li1) (quote member)) (relations-dt-check! "api unrelate removes one child" (relations-dt-set=? (relations/children (quote o1) (quote member)) (list (quote li2))) true) (relations/load! (list)) (relations-dt-check! "api reload clears prior facts" (relations/children (quote o1) (quote member)) (list))) (relations-dt-check! "rel constructor shape" (relations-rel (quote s) (quote d) (quote parent)) (list (quote rel) (quote s) (quote d) (quote parent))) (relations-dt-check! "fact valid" (relations-fact-valid? (relations-rel (quote s) (quote d) (quote parent))) true) (relations-dt-check! "fact bad arity invalid" (relations-fact-valid? (list (quote rel) (quote s))) false) (relations-dt-check! "fact wrong head invalid" (relations-fact-valid? (list (quote edge) (quote s) (quote d) (quote parent))) false) (relations-dt-check! "known kind" (relations-known-kind? (quote parent)) true) (relations-dt-check! "unknown kind" (relations-known-kind? (quote frobnicate)) false) (relations-dt-check! "accessors" (list (relations-rel-src (relations-rel (quote s) (quote d) (quote k))) (relations-rel-dst (relations-rel (quote s) (quote d) (quote k))) (relations-rel-kind (relations-rel (quote s) (quote d) (quote k)))) (list (quote s) (quote d) (quote k))))))) (define relations-direct-tests-run! (fn () (do (set! relations-dt-pass 0) (set! relations-dt-fail 0) (set! relations-dt-failures (list)) (relations-dt-run-all!) {:failures relations-dt-failures :total (+ relations-dt-pass relations-dt-fail) :passed relations-dt-pass :failed relations-dt-fail})))