Add some additional libraries to test

Also improved docs around add-libtest
Close #1137
Close #1128
This commit is contained in:
Gabriel Horner 2022-01-11 23:39:10 -05:00
parent 2f6d363ee8
commit 744c5d0732
18 changed files with 1943 additions and 5 deletions

View file

@ -114,7 +114,13 @@
clojure-term-colors/clojure-term-colors {:mvn/version "0.1.0"} clojure-term-colors/clojure-term-colors {:mvn/version "0.1.0"}
io.aviso/pretty {:mvn/version "1.1.1"} io.aviso/pretty {:mvn/version "1.1.1"}
progrock/progrock {:mvn/version "0.1.2"} progrock/progrock {:mvn/version "0.1.2"}
djblue/portal {:mvn/version "0.19.0"}} djblue/portal {:mvn/version "0.19.0"}
com.wsscode/cljc-misc {:mvn/version "2021.10.16"}
edn-query-language/eql {:mvn/version "2021.07.18"}
town.lilac/pyramid {:mvn/version "3.2.0"}
meta-merge/meta-merge {:mvn/version "1.0.0"}
com.exoscale/lingo {:mvn/version "1.0.0-alpha14"}
io.github.swirrl/dogstatsd {:mvn/version "0.1.39"}}
:classpath-overrides {org.clojure/clojure nil :classpath-overrides {org.clojure/clojure nil
org.clojure/spec.alpha nil}} org.clojure/spec.alpha nil}}
:clj-nvd :clj-nvd

View file

@ -81,9 +81,19 @@ Test the native version:
## Tests for Libraries ## Tests for Libraries
Babashka runs tests of libraries that are compatible with it through Babashka runs tests of libraries that are compatible with it through
`script/run_lib_tests`. To add tests for a new library that has a git repository `script/run_lib_tests`. The script `add-libtest.clj` makes adding new libraries
and run them, use the script `add-libtest.clj` e.g. `script/add-libtest.clj fairly easy. Some examples:
'{listora/again {:mvn/version "1.0.0"}}' https://github.com/liwp/again --test`.
```sh
# To add tests for a new library on clojars
script/add-libtest.clj com.exoscale/lingo -t
# To add tests for a new library that is git based only
script/add-libtest.clj '{borkdude/carve {:git/url "https://github.com/borkdude/carve" :sha "df552797a198b6701fb2d92390fce7c59205ea77"}}' -t
# There are a number of options for specifying how to copy tests
script/add-libtest.clj -h
```
If the library you want to add doesn't work automatically, you can manually do the following: If the library you want to add doesn't work automatically, you can manually do the following:

View file

@ -12,10 +12,12 @@ clj-commons/clj-yaml,https://github.com/clj-commons/clj-yaml
clj-commons/multigrep,https://github.com/clj-commons/multigrep clj-commons/multigrep,https://github.com/clj-commons/multigrep
clojure-csv/clojure-csv,https://github.com/davidsantiago/clojure-csv clojure-csv/clojure-csv,https://github.com/davidsantiago/clojure-csv
clojure-term-colors/clojure-term-colors,https://github.com/trhura/clojure-term-colors clojure-term-colors/clojure-term-colors,https://github.com/trhura/clojure-term-colors
com.exoscale/lingo,https://github.com/exoscale/lingo
com.github.seancorfield/honeysql,https://github.com/seancorfield/honeysql com.github.seancorfield/honeysql,https://github.com/seancorfield/honeysql
com.grammarly/omniconf,https://github.com/grammarly/omniconf com.grammarly/omniconf,https://github.com/grammarly/omniconf
com.stuartsierra/component,https://github.com/stuartsierra/component com.stuartsierra/component,https://github.com/stuartsierra/component
com.stuartsierra/dependency,https://github.com/stuartsierra/dependency com.stuartsierra/dependency,https://github.com/stuartsierra/dependency
com.wsscode/cljc-misc,https://github.com/wilkerlucio/cljc-misc
comb/comb,https://github.com/weavejester/comb comb/comb,https://github.com/weavejester/comb
cprop/cprop,https://github.com/tolitius/cprop cprop/cprop,https://github.com/tolitius/cprop
crispin/crispin,https://github.com/dunaj-project/crispin crispin/crispin,https://github.com/dunaj-project/crispin
@ -23,6 +25,7 @@ dev.nubank/docopt,https://github.com/nubank/docopt.clj
djblue/portal,https://github.com/djblue/portal djblue/portal,https://github.com/djblue/portal
doric/doric,https://github.com/joegallo/doric doric/doric,https://github.com/joegallo/doric
douglass/clj-psql,https://github.com/DarinDouglass/clj-psql douglass/clj-psql,https://github.com/DarinDouglass/clj-psql
edn-query-language/eql,https://github.com/edn-query-language/eql
environ/environ,https://github.com/weavejester/environ environ/environ,https://github.com/weavejester/environ
exoscale/coax,https://github.com/exoscale/coax exoscale/coax,https://github.com/exoscale/coax
expound/expound,https://github.com/bhb/expound expound/expound,https://github.com/bhb/expound
@ -34,8 +37,10 @@ henryw374/cljc.java-time,https://github.com/henryw374/cljc.java-time
hiccup/hiccup,http://github.com/weavejester/hiccup hiccup/hiccup,http://github.com/weavejester/hiccup
honeysql/honeysql,https://github.com/seancorfield/honeysql honeysql/honeysql,https://github.com/seancorfield/honeysql
http-kit/http-kit,https://github.com/http-kit/http-kit http-kit/http-kit,https://github.com/http-kit/http-kit
integrant/integrant,https://github.com/weavejester/integrant
io.aviso/pretty,https://github.com/AvisoNovate/pretty io.aviso/pretty,https://github.com/AvisoNovate/pretty
io.github.cognitect-labs/test-runner,https://github.com/cognitect-labs/test-runner io.github.cognitect-labs/test-runner,https://github.com/cognitect-labs/test-runner
io.github.swirrl/dogstatsd,https://github.com/swirrl/dogstatsd
io.github.technomancy/limit-break,https://github.com/technomancy/limit-break io.github.technomancy/limit-break,https://github.com/technomancy/limit-break
io.helins/binf,https://github.com/helins/binf.cljc io.helins/binf,https://github.com/helins/binf.cljc
io.replikativ/hasch,https://github.com/replikativ/hasch io.replikativ/hasch,https://github.com/replikativ/hasch
@ -44,6 +49,7 @@ lambdaisland/regal,https://github.com/lambdaisland/regal
listora/again,https://github.com/liwp/again listora/again,https://github.com/liwp/again
markdown-clj/markdown-clj,https://github.com/yogthos/markdown-clj markdown-clj/markdown-clj,https://github.com/yogthos/markdown-clj
medley/medley,https://github.com/weavejester/medley medley/medley,https://github.com/weavejester/medley
meta-merge/meta-merge,https://github.com/weavejester/meta-merge
minimallist/minimallist,https://github.com/green-coder/minimallist minimallist/minimallist,https://github.com/green-coder/minimallist
mvxcvi/arrangement,https://github.com/greglook/clj-arrangement mvxcvi/arrangement,https://github.com/greglook/clj-arrangement
orchestra/orchestra,https://github.com/jeaye/orchestra orchestra/orchestra,https://github.com/jeaye/orchestra
@ -69,4 +75,5 @@ selmer/selmer,https://github.com/yogthos/Selmer
slingshot/slingshot,https://github.com/scgilardi/slingshot slingshot/slingshot,https://github.com/scgilardi/slingshot
table/table,https://github.com/cldwalker/table table/table,https://github.com/cldwalker/table
testdoc/testdoc,https://github.com/liquidz/testdoc testdoc/testdoc,https://github.com/liquidz/testdoc
town.lilac/pyramid,https://github.com/lilactown/pyramid
version-clj/version-clj,https://github.com/xsc/version-clj version-clj/version-clj,https://github.com/xsc/version-clj

1 maven-name git-url
12 clj-commons/multigrep https://github.com/clj-commons/multigrep
13 clojure-csv/clojure-csv https://github.com/davidsantiago/clojure-csv
14 clojure-term-colors/clojure-term-colors https://github.com/trhura/clojure-term-colors
15 com.exoscale/lingo https://github.com/exoscale/lingo
16 com.github.seancorfield/honeysql https://github.com/seancorfield/honeysql
17 com.grammarly/omniconf https://github.com/grammarly/omniconf
18 com.stuartsierra/component https://github.com/stuartsierra/component
19 com.stuartsierra/dependency https://github.com/stuartsierra/dependency
20 com.wsscode/cljc-misc https://github.com/wilkerlucio/cljc-misc
21 comb/comb https://github.com/weavejester/comb
22 cprop/cprop https://github.com/tolitius/cprop
23 crispin/crispin https://github.com/dunaj-project/crispin
25 djblue/portal https://github.com/djblue/portal
26 doric/doric https://github.com/joegallo/doric
27 douglass/clj-psql https://github.com/DarinDouglass/clj-psql
28 edn-query-language/eql https://github.com/edn-query-language/eql
29 environ/environ https://github.com/weavejester/environ
30 exoscale/coax https://github.com/exoscale/coax
31 expound/expound https://github.com/bhb/expound
37 hiccup/hiccup http://github.com/weavejester/hiccup
38 honeysql/honeysql https://github.com/seancorfield/honeysql
39 http-kit/http-kit https://github.com/http-kit/http-kit
40 integrant/integrant https://github.com/weavejester/integrant
41 io.aviso/pretty https://github.com/AvisoNovate/pretty
42 io.github.cognitect-labs/test-runner https://github.com/cognitect-labs/test-runner
43 io.github.swirrl/dogstatsd https://github.com/swirrl/dogstatsd
44 io.github.technomancy/limit-break https://github.com/technomancy/limit-break
45 io.helins/binf https://github.com/helins/binf.cljc
46 io.replikativ/hasch https://github.com/replikativ/hasch
49 listora/again https://github.com/liwp/again
50 markdown-clj/markdown-clj https://github.com/yogthos/markdown-clj
51 medley/medley https://github.com/weavejester/medley
52 meta-merge/meta-merge https://github.com/weavejester/meta-merge
53 minimallist/minimallist https://github.com/green-coder/minimallist
54 mvxcvi/arrangement https://github.com/greglook/clj-arrangement
55 orchestra/orchestra https://github.com/jeaye/orchestra
75 slingshot/slingshot https://github.com/scgilardi/slingshot
76 table/table https://github.com/cldwalker/table
77 testdoc/testdoc https://github.com/liquidz/testdoc
78 town.lilac/pyramid https://github.com/lilactown/pyramid
79 version-clj/version-clj https://github.com/xsc/version-clj

View file

@ -96,4 +96,11 @@
io.aviso/pretty {:git-url "https://github.com/AvisoNovate/pretty", :test-namespaces (io.aviso.binary-test), :git-sha "155926f991f94addaf6f5c8621748924ab144988" :skip-windows true} io.aviso/pretty {:git-url "https://github.com/AvisoNovate/pretty", :test-namespaces (io.aviso.binary-test), :git-sha "155926f991f94addaf6f5c8621748924ab144988" :skip-windows true}
progrock/progrock {:git-url "https://github.com/weavejester/progrock", :test-namespaces (progrock.core-test), :git-sha "9c277a3244c52bfde19c21add327d6e20b94fdf5"} progrock/progrock {:git-url "https://github.com/weavejester/progrock", :test-namespaces (progrock.core-test), :git-sha "9c277a3244c52bfde19c21add327d6e20b94fdf5"}
;; Don't run portal.jvm-test as it depends on headless chrome ;; Don't run portal.jvm-test as it depends on headless chrome
djblue/portal {:git-url "https://github.com/djblue/portal", :test-namespaces (portal.test-runner portal.runtime.cson-test portal.runtime.fs-test portal.e2e portal.bench), :git-sha "64e4624bcf3bee2dd47e3d8e47982c709738eb11"}} djblue/portal {:git-url "https://github.com/djblue/portal", :test-namespaces (portal.test-runner portal.runtime.cson-test portal.runtime.fs-test portal.e2e portal.bench), :git-sha "64e4624bcf3bee2dd47e3d8e47982c709738eb11"}
integrant/integrant {:git-url "https://github.com/weavejester/integrant", :test-namespaces (integrant.test.foo integrant.test.quz integrant.test.bar integrant.test.baz integrant.core-test), :git-sha "32a46f5dca8a6b563a6dddf88bec887be3201b08"}
com.wsscode/cljc-misc {:git-url "https://github.com/wilkerlucio/cljc-misc", :test-namespaces (com.wsscode.misc.uuid-test com.wsscode.misc.macros-test com.wsscode.misc.math-test com.wsscode.misc.coll-test com.wsscode.misc.refs-test), :git-sha "dc8e31a200f9cacf86af10b63e40fcb448c259f4"}
edn-query-language/eql {:git-url "https://github.com/edn-query-language/eql", :test-namespaces (edn-query-language.core-test), :git-sha "0d4f9745d98c3d20b81bb4bdce3e8e15db7fd094"}
town.lilac/pyramid {:git-url "https://github.com/lilactown/pyramid", :test-namespaces (pyramid.pull-test pyramid.query-test pyramid.core-test), :git-sha "3862d64bc78e789739515191b70a1f6591fd1b68"}
meta-merge/meta-merge {:git-url "https://github.com/weavejester/meta-merge", :test-namespaces (meta-merge.core-test), :git-sha "c968c38baccd4219fe0ba592d89af37ea8e426bf"}
com.exoscale/lingo {:git-url "https://github.com/exoscale/lingo", :test-namespaces (exoscale.lingo.test.core-test), :git-sha "30b5084fab28d24c99ec683e21535366910d9f2f"}
io.github.swirrl/dogstatsd {:git-url "https://github.com/swirrl/dogstatsd", :test-namespaces (swirrl.dogstatsd-test), :git-sha "e110caae452cd1185e65e389a359b69502076d61"}}

View file

@ -0,0 +1,257 @@
(ns com.wsscode.misc.coll-test
(:require
[clojure.test :refer [deftest is are run-tests testing]]
[com.wsscode.misc.coll :as coll]))
(deftest distinct-by-test
(is (= (coll/distinct-by :id
[{:id 1
:name "foo"}
{:id 2
:name "bar"}
{:id 1
:name "other"}])
[{:id 1
:name "foo"}
{:id 2
:name "bar"}])))
(deftest dedupe-by-test
(is (= (coll/dedupe-by :id
[{:id 1
:name "foo"}
{:id 1
:name "dedup-me"}
{:id 2
:name "bar"}
{:id 1
:name "other"}])
[{:id 1
:name "foo"}
{:id 2
:name "bar"}
{:id 1
:name "other"}])))
(deftest index-by-test
(is (= (coll/index-by :id
[{:id 1
:name "foo"}
{:id 1
:name "dedup-me"}
{:id 2
:name "bar"}
{:id 1
:name "other"}])
{1 {:id 1, :name "other"}, 2 {:id 2, :name "bar"}})))
(deftest find-first-test
(is (= (coll/find-first even? [1 2 3 4])
2)))
(deftest sconj-test
(is (= (coll/sconj nil 42) #{42}))
(is (set? (coll/sconj nil 42))))
(deftest vconj-test
(is (= (coll/vconj nil 42) [42]))
(is (vector? (coll/vconj nil 42))))
(deftest queue-test
(let [queue (-> (coll/queue)
(conj 1 2))]
(is (= queue [1 2]))
(is (= (peek queue) 1))
(is (= (pop queue) [2])))
(let [queue (coll/queue [1 2])]
(is (= queue [1 2]))
(is (= (peek queue) 1))
(is (= (pop queue) [2]))))
(deftest map-keys-test
(is (= (coll/map-keys inc {1 :a 2 :b})
{2 :a 3 :b})))
(deftest filter-keys-test
(is (= (coll/filter-keys simple-keyword? {1 :a 2 :b "foo" 3 :bar 4})
{:bar 4})))
(deftest filter-vals-test
(is (= (coll/filter-vals simple-keyword? {1 :a 2 :b "foo" 3 :bar 4})
{1 :a 2 :b})))
(deftest remove-keys-test
(is (= (coll/remove-keys number? {1 :a 2 :b "foo" 3 :bar 4})
{"foo" 3 :bar 4})))
(deftest remove-vals-test
(is (= (coll/remove-vals number? {1 :a 2 :b "foo" 3 :bar 4})
{1 :a 2 :b})))
(deftest map-vals-test
(is (= (coll/map-vals inc {:a 1 :b 2})
{:a 2 :b 3})))
(deftest keys-set-test
(is (= (coll/keys-set {:a 1 :b 2}) #{:a :b}))
(is (= (coll/keys-set 5) nil)))
(deftest merge-grow-test
(is (= (coll/merge-grow) {}))
(is (= (coll/merge-grow {:foo "bar"}) {:foo "bar"}))
(testing "merge sets by union"
(is (= (coll/merge-grow {:foo #{:a}} {:foo #{:b}})
{:foo #{:a :b}})))
(testing "merge maps"
(is (= (coll/merge-grow {:foo {:a 1}} {:foo {:b 2}})
{:foo {:a 1 :b 2}})))
(testing "keep left value if right one is nil"
(is (= (coll/merge-grow {:foo {:a 1}} {:foo {:a nil}})
{:foo {:a 1}}))))
(deftest merge-defaults-test
(is (= (coll/merge-defaults {:a 1} {:b 2})
{:a 1 :b 2}))
(is (= (coll/merge-defaults {:a 1} {:a 2})
{:a 1})))
(deftest assoc-if-test
(is (= (coll/assoc-if {} :foo "bar")
{:foo "bar"}))
(is (= (coll/assoc-if {} :foo nil)
{}))
(is (= (coll/assoc-if {} :foo false)
{}))
(is (= (coll/assoc-if {} :foo false :bar 30)
{:bar 30}))
(is (= (coll/assoc-if {} :foo false :bar 30 :baz false)
{:bar 30})))
(deftest update-contained-test
(is (= (coll/update-contained {:foo 3} :foo inc)
{:foo 4}))
(is (= (coll/update-contained {:foo nil} :foo #(str % " bla"))
{:foo " bla"}))
(is (= (coll/update-contained {} :foo inc)
{})))
(deftest update-if-test
(is (= (coll/update-if {:foo 3} :foo inc)
{:foo 4}))
(is (= (coll/update-if {:foo nil} :foo inc)
{:foo nil}))
(is (= (coll/update-if {} :foo inc)
{})))
(defrecord CustomRecord [])
(deftest native-map?-test
(is (= true (coll/native-map? {})))
(is (= true (coll/native-map? {:foo "bar"})))
(is (= true (coll/native-map? (zipmap (range 50) (range 50)))))
(is (= false (coll/native-map? (->CustomRecord)))))
(deftest restore-order-test
(is (= (coll/restore-order
[{:my.entity/id 1} {:my.entity/id 2}]
:my.entity/id
[{:my.entity/id 2
:my.entity/color :my.entity.color/green}
{:my.entity/id 1
:my.entity/color :my.entity.color/purple}])
[{:my.entity/id 1
:my.entity/color :my.entity.color/purple}
{:my.entity/id 2
:my.entity/color :my.entity.color/green}]))
(is (= (coll/restore-order
[{:my.entity/id 1}
{:my.entity/id 2}
{:my.entity/id 3}]
:my.entity/id
[{:my.entity/id 3
:my.entity/color :my.entity.color/green}
{:my.entity/id 1
:my.entity/color :my.entity.color/purple}])
[{:my.entity/id 1
:my.entity/color :my.entity.color/purple}
{:my.entity/id 2}
{:my.entity/id 3
:my.entity/color :my.entity.color/green}]))
(is (= (coll/restore-order [{:my.entity/id 1}
{:my.entity/id 2}
{:my.entity/id 3}]
:my.entity/id
[{:my.entity/id 3
:my.entity/color :my.entity.color/green}
{:my.entity/id 1
:my.entity/color :my.entity.color/purple}]
(fn [x] (assoc x :my.entity/color nil)))
[{:my.entity/id 1
:my.entity/color :my.entity.color/purple}
{:my.entity/id 2
:my.entity/color nil}
{:my.entity/id 3
:my.entity/color :my.entity.color/green}])))
(deftest conj-at-index-test
(is (= (coll/conj-at-index [:a :b] 0 :c)
[:c :a :b]))
(is (= (coll/conj-at-index [:a :b] 1 :c)
[:a :c :b]))
(is (= (coll/conj-at-index [:a :b] 2 :c)
[:a :b :c])))
(deftest index-of-test
(is (= (coll/index-of [:a {:id :b} :c] :not-here)
nil))
(is (= (coll/index-of [:a {:id :b} :c] :a)
0))
(is (= (coll/index-of [:a {:id :b} :c] {:id :b})
1)))
(deftest coll-append-ahead?-test
(is (true? (coll/coll-append-at-head? (list "foo"))))
(is (true? (coll/coll-append-at-head? (map identity ["foo"]))))
(is (false? (coll/coll-append-at-head? ["foo"])))
(is (false? (coll/coll-append-at-head? #{"foo"}))))
(deftest collection?-test
(is (true? (coll/collection? [])))
(is (true? (coll/collection? '())))
(is (true? (coll/collection? #{})))
(is (true? (coll/collection? (map identity []))))
(is (false? (coll/collection? {}))))
(deftest vector-compare-test
(is (= (coll/vector-compare [0] [1])
-1))
(is (= (coll/vector-compare [1] [0])
1))
(is (= (coll/vector-compare [1] [1])
0))
(is (= (coll/vector-compare [2 0] [2 1])
-1))
(is (= (coll/vector-compare [2 0 0] [2 1])
-1)))
(deftest iterate-while-test
(is (= (coll/iterate-while :n {:x 1 :n {:x 2 :n {:x 3}}})
[{:x 1, :n {:x 2, :n {:x 3}}} {:x 2, :n {:x 3}} {:x 3}])))
(deftest deep-merge-test
(is (= (coll/deep-merge {:a 1} {:b 2})
{:a 1 :b 2}))
(is (= (coll/deep-merge {:a {:x 1 :foo "bar"}} {:a {:baz "f" :foo "2"}})
{:a {:baz "f" :foo "2" :x 1}}))
(is (= (coll/deep-merge {:a [{:a 1}]} {:a [{:b 2}]})
{:a [{:b 2}]})))

View file

@ -0,0 +1,14 @@
(ns com.wsscode.misc.macros-test
(:require
[clojure.test :refer [deftest is are run-tests testing]]
[com.wsscode.misc.macros :as macros]))
(deftest full-symbol-test
(is (= (macros/full-symbol
'known/foo
"bar")
'known/foo))
(is (= (macros/full-symbol
'foo
"bar")
'bar/foo)))

View file

@ -0,0 +1,28 @@
(ns com.wsscode.misc.math-test
(:require
[clojure.test :refer [deftest is are run-tests testing]]
[com.wsscode.misc.math :as math]))
(deftest floor-test
(is (= (math/floor 30.2) 30))
(is (= (math/floor 30.9) 30)))
(deftest round-test
(is (= (math/round 30.2) 30))
(is (= (math/round 30.6) 31)))
(deftest ceil-test
(is (= (math/ceil 30.2) 31))
(is (= (math/ceil 30.9) 31)))
(deftest divmod-test
(is (= (math/divmod 10 3)
[3 1])))
(deftest parse-long-test
(is (= (math/parse-long "21")
21)))
(deftest parse-double-test
(is (= (math/parse-double "21.3")
21.3)))

View file

@ -0,0 +1,36 @@
(ns com.wsscode.misc.refs-test
(:require
[clojure.test :refer [deftest is are run-tests testing]]
[com.wsscode.misc.refs :refer [atom?] :as refs]))
(deftest kw-identical?-test
(is (not (refs/kw-identical? :foo :bar)))
(is (not (refs/kw-identical? :foo "foo")))
(is (refs/kw-identical? :foo :foo))
(is (refs/kw-identical? :foo (keyword "foo"))))
(deftest atom?-test
(is (true? (atom? (atom "x"))))
(is (false? (atom? "x"))))
(deftest greset!-test
(let [x (atom nil)]
(refs/greset! x "val")
(is (= @x "val")))
(let [x (volatile! nil)]
(refs/greset! x "val")
(is (= @x "val"))))
(deftest gswap!-test
(let [x (atom 10)]
(refs/gswap! x inc)
(is (= @x 11)))
(let [x (volatile! 10)]
(refs/gswap! x inc)
(is (= @x 11)))
(let [x (volatile! 10)]
(refs/gswap! x + 1 2 3 4 5)
(is (= @x 25))))

View file

@ -0,0 +1,7 @@
(ns com.wsscode.misc.uuid-test
(:require
[clojure.test :refer [deftest is are run-tests testing]]
[com.wsscode.misc.uuid :as uuid]))
(deftest cljc-random-uuid-test
(is (uuid? (uuid/cljc-random-uuid))))

View file

@ -0,0 +1,386 @@
(ns edn-query-language.core-test
(:require [clojure.spec.alpha :as s]
[clojure.spec.test.alpha :as s.test]
[clojure.test :refer [deftest is testing]]
[clojure.test.check :as tc]
[clojure.test.check.clojure-test :as test]
[clojure.test.check.generators :as gen]
[clojure.test.check.properties :as props]
[edn-query-language.core :as eql]
[edn-query-language.gen :as eql-gen]))
(s.test/instrument)
;; spec tests
(defn valid-queries-props []
(props/for-all [query (eql-gen/make-gen {} ::eql-gen/gen-query)]
(s/valid? ::eql/query query)))
(test/defspec generator-makes-valid-queries {:max-size 12 :num-tests 50} (valid-queries-props))
(comment
(tc/quick-check 50 (valid-queries-props) :max-size 12))
;; lib tests
(defn remove-meta [x]
(eql/transduce-children (map #(dissoc % :meta)) x))
(defn tquery->ast [query]
(remove-meta (eql/query->ast query)))
(deftest test-query->ast
(testing "empty query"
(is (= (tquery->ast [])
{:type :root, :children []})))
(testing "single property"
(is (= (tquery->ast [:a])
{:type :root, :children [{:type :prop, :dispatch-key :a, :key :a}]})))
(testing "multiple properties"
(is (= (tquery->ast [:a :b])
{:type :root,
:children [{:type :prop, :dispatch-key :a, :key :a}
{:type :prop, :dispatch-key :b, :key :b}]})))
(testing "blank join"
(is (= (tquery->ast [{:a []}])
{:type :root,
:children [{:type :join, :dispatch-key :a, :key :a, :query [], :children []}]})))
(testing "simple join"
(is (= (tquery->ast [{:a [:b]}])
{:type :root,
:children [{:type :join,
:dispatch-key :a,
:key :a,
:query [:b],
:children [{:type :prop, :dispatch-key :b, :key :b}]}]})))
(testing "param expression"
(is (= (tquery->ast ['(:a {:foo "bar"})])
{:type :root,
:children [{:type :prop,
:dispatch-key :a,
:key :a,
:params {:foo "bar"},}]})))
(testing "param join"
(is (= (tquery->ast ['({:a [:sub]} {:foo "bar"})])
{:type :root,
:children [{:type :join,
:dispatch-key :a,
:key :a,
:query [:sub],
:children [{:type :prop, :dispatch-key :sub, :key :sub}],
:params {:foo "bar"},}]})))
(testing "param join 2"
(is (= (tquery->ast [{'(:a {:foo "bar"}) [:sub]}])
{:type :root
:children [{:children [{:dispatch-key :sub
:key :sub
:type :prop}]
:dispatch-key :a
:key :a
:params {:foo "bar"}
:query [:sub]
:type :join}]})))
(testing "union query"
(is (= (tquery->ast [{:foo {:a [:b]
:c [:d]}}])
{:type :root,
:children [{:type :join,
:dispatch-key :foo,
:key :foo,
:query {:a [:b], :c [:d]},
:children [{:type :union,
:query {:a [:b], :c [:d]},
:children [{:type :union-entry,
:union-key :a,
:query [:b],
:children [{:type :prop, :dispatch-key :b, :key :b}]}
{:type :union-entry,
:union-key :c,
:query [:d],
:children [{:type :prop, :dispatch-key :d, :key :d}]}]}]}]})))
(testing "unbounded recursion"
(is (= (tquery->ast '[{:item [:a :b {:parent ...}]}])
'{:type :root,
:children [{:type :join,
:dispatch-key :item,
:key :item,
:query [:a :b {:parent ...}],
:children [{:type :prop, :dispatch-key :a, :key :a}
{:type :prop, :dispatch-key :b, :key :b}
{:type :join, :dispatch-key :parent, :key :parent, :query ...}]}]})))
(testing "bounded recursion"
(is (= (tquery->ast '[{:item [:a :b {:parent 5}]}])
'{:type :root,
:children [{:type :join,
:dispatch-key :item,
:key :item,
:query [:a :b {:parent 5}],
:children [{:type :prop, :dispatch-key :a, :key :a}
{:type :prop, :dispatch-key :b, :key :b}
{:type :join, :dispatch-key :parent, :key :parent, :query 5}]}]})))
(testing "mutation expression"
(is (= (tquery->ast ['(a {})])
'{:type :root,
:children [{:dispatch-key a,
:key a,
:params {},
:type :call}]})))
(testing "mutation join expression"
(is (= (tquery->ast [{'(a {}) [:sub-query]}])
'{:type :root,
:children [{:dispatch-key a,
:key a,
:params {},
:type :call,
:query [:sub-query],
:children [{:type :prop, :dispatch-key :sub-query, :key :sub-query}]}]}))))
(defn query<->ast-props []
(props/for-all [query (eql-gen/make-gen {::eql-gen/gen-params
(fn [_]
(gen/map gen/keyword gen/string-alphanumeric))}
::eql-gen/gen-query)]
(let [ast (-> query
eql/query->ast
eql/ast->query
eql/query->ast)]
(= ast (-> ast
eql/ast->query
eql/query->ast)))))
(test/defspec query-ast-roundtrip {:max-size 12 :num-tests 100} (query<->ast-props))
(comment
(tc/quick-check 100 (query<->ast-props) :max-size 12))
(deftest test-ast->query
(is (= (eql/ast->query {:type :prop
:key :foo
:dispatch-key :foo})
[:foo]))
(is (= (eql/ast->query {:type :root
:children [{:type :prop
:dispatch-key :foo
:key :foo}]})
[:foo])))
(deftest test-focus-subquery
(is (= (eql/focus-subquery [] [])
[]))
(is (= (eql/focus-subquery [:a :b :c] [])
[]))
(is (= (eql/focus-subquery [:a :b :c] [:d])
[]))
(is (= (eql/focus-subquery [:a :b :c] [:a])
[:a]))
(is (= (eql/focus-subquery [:a :b :c] [:a :b])
[:a :b]))
(is (= (eql/focus-subquery [:a {:b [:d]}] [:a :b])
[:a {:b [:d]}]))
(is (= (eql/focus-subquery [:a {:b [:c :d]}] [:a {:b [:c]}])
[:a {:b [:c]}]))
(is (= (eql/focus-subquery [:a '({:b [:c :d]} {:param "value"})] [:a {:b [:c]}])
[:a '({:b [:c]} {:param "value"})]))
; in union case, keys absent from focus will be pulled anyway, given ones will focus
(is (= (eql/focus-subquery [:a {:b {:c [:d :e]
:f [:g :h]}}]
[:a {:b {:f [:g]}}])
[:a {:b {:c [:d :e] :f [:g]}}])))
(defn transduce-query [xform query]
(->> query eql/query->ast
(eql/transduce-children xform)
eql/ast->query))
(deftest test-tranduce-children
(is (= (transduce-query
(comp (filter (comp #{:a :c} :key))
(map #(assoc % :params {:n 42})))
[:a :b :c :d])
'[(:a {:n 42}) (:c {:n 42})])))
(deftest test-merge-queries
(is (= (eql/merge-queries nil nil)
[]))
(is (= (eql/merge-queries [:a] nil)
[:a]))
(is (= (eql/merge-queries [] [])
[]))
(is (= (eql/merge-queries [:a] [])
[:a]))
(is (= (eql/merge-queries [:a] [:a])
[:a]))
(is (= (eql/merge-queries [:a] [:b])
[:a :b]))
(is (= (eql/merge-queries [:a] [:b :c :d])
[:a :b :c :d]))
(is (= (eql/merge-queries [[:u/id 1]] [[:u/id 2]])
[[:u/id 1] [:u/id 2]]))
(is (= (eql/merge-queries [{:user [:name]}] [{:user [:email]}])
[{:user [:name :email]}]))
(is (= (eql/merge-queries [:a] [{:a [:x]}])
[{:a [:x]}]))
(is (= (eql/merge-queries [{:a [:x]}] [:a])
[{:a [:x]}]))
(testing "don't merge queries with different params"
(is (= (eql/merge-queries ['({:user [:name]} {:login "u1"})]
['({:user [:email]} {:login "u2"})])
nil)))
(testing "don't merge queries with different params"
(is (= (eql/merge-queries ['(:user {:login "u1"})]
['(:user {:login "u2"})])
nil)))
(testing "merge when params are same"
(is (= (eql/merge-queries ['({:user [:name]} {:login "u1"})]
['({:user [:email]} {:login "u1"})])
['({:user [:name :email]} {:login "u1"})])))
(testing "calls can't be merged when same name occurs"
(is (= (eql/merge-queries ['(hello {:login "u1"})]
['(hello {:bla "2"})])
nil)))
(testing "even when parameters are the same"
(is (= (eql/merge-queries ['(hello {:login "u1"})]
['(hello {:login "u1"})])
nil))))
(deftest test-update-child
(is (= (eql/update-child {:children [{:dispatch-key :id :key :id :type :prop}
{:dispatch-key :parent :key :parent :query 3 :type :join}]
:type :root}
:parent update :query dec)
{:children [{:dispatch-key :id :key :id :type :prop}
{:dispatch-key :parent :key :parent :query 2 :type :join}]
:type :root})))
(deftest update-recursive-depth-test
(is (= (eql/update-recursive-depth
{:children [{:dispatch-key :id :key :id :type :prop}
{:dispatch-key :parent :key :parent :query 3 :type :join}]
:type :root}
:parent dec)
{:children [{:dispatch-key :id :key :id :type :prop}
{:dispatch-key :parent :key :parent :query 2 :type :join}]
:type :root})))
(deftest test-mask-query
(is (= (eql/mask-query [] [])
[]))
(is (= (eql/mask-query [:foo :bar] [])
[]))
(is (= (eql/mask-query [:foo :bar] [:foo])
[:foo]))
(is (= (eql/mask-query [:bar :foo] [:foo])
[:foo]))
(is (= (eql/mask-query [:foo {:bar [:inside]}] [:foo])
[:foo]))
(is (= (eql/mask-query ['(:foo {:bla "meh"}) :bar] [:foo])
['(:foo {:bla "meh"})]))
(is (= (eql/mask-query [:foo {:bar [:inside :more]}] [:foo :bar])
[:foo {:bar [:inside :more]}]))
(is (= (eql/mask-query [:foo {:bar [:inside :more]}] [:foo {:bar [:inside]}])
[:foo {:bar [:inside]}])))
(deftest test-normalize-query-variables
(testing "blank query"
(is (= (eql/normalize-query-variables [])
[])))
(testing "simple query"
(is (= (eql/normalize-query-variables [:a :b :c])
[:a :b :c])))
(testing "normalize ident values"
(is (= (eql/normalize-query-variables [[:foo "bar"]])
[[:foo ::eql/var]])))
(testing "normalize params"
(is (= (eql/normalize-query-variables ['(:foo {:x 1 :y 2})])
['(:foo {:x ::eql/var :y ::eql/var})])))
(testing "all together"
(is (= (eql/normalize-query-variables '[:a :b {[:join "val"] [{(:c {:page 10}) [:d]}]}])
'[:a :b
{[:join ::eql/var]
[({:c [:d]}
{:page ::eql/var})]}]))))
(deftest test-query-id
(is (= (eql/query-id '[:a :b {[:join "val"] [{(:c {:page 10}) [:d]}]}])
-61421281)))
(deftest shallow-conversion
(testing "requesting shallow conversion will only convert the first layer of a query"
(let [ast (eql/query->shallow-ast [:x
{:y [{:z [:a]}]}
{[:table 1] [:z {:other [:m :n]}]}
{:ujoin {:u1 [:x] :u2 [:y]}}])]
(is (= {:type :root,
:children [{:type :prop, :dispatch-key :x, :key :x}
;; BB-TEST-PATCH: bb returns {} for some meta calls that clojure doesn't
{:type :join, :dispatch-key :y, :key :y, :query [{:z [:a]}] :meta {}}
{:type :join, :dispatch-key :table, :key [:table 1], :query [:z {:other [:m :n]}] :meta {}}
{:type :join, :dispatch-key :ujoin, :key :ujoin, :query {:u1 [:x], :u2 [:y]} :meta {}}]}
ast)))))
(deftest merge-asts-as-reduce-function
(testing
"init - when called with arity zero, it returns an empty ast"
(is (= {:type :root
:children []}
(transduce (map identity)
eql/merge-asts
[]))))
(testing
"completion - when called with arity one, it should return its argument"
(is (= {:children [{:dispatch-key :a
:key :a
:type :prop}]
:type :root}
(transduce (map identity)
eql/merge-asts
[(eql/query->ast [:a])]))))
(testing
"step - the old arity 2. Should compose both nodes into a new node"
(is (= {:children [{:dispatch-key :a
:key :a
:type :prop}
{:dispatch-key :b
:key :b
:type :prop}]
:type :root}
(transduce (map identity)
eql/merge-asts
[(eql/query->ast [:a])
(eql/query->ast [:b])])))))

View file

@ -0,0 +1,385 @@
(ns exoscale.lingo.test.core-test
(:require [clojure.test :refer [are deftest is]]
[exoscale.lingo :as l]
[exoscale.lingo.impl :as impl]
[exoscale.lingo.highlight :as u]
[clojure.spec.alpha :as s]))
(defn f2? [_] false)
(defn f3? [_] false)
(l/set-spec-error! `exoscale.lingo.test.core-test/f2? "yolo")
(l/set-spec-error! `f3? "should match Something")
(-> (s/def ::thing #(string? %))
(l/set-spec-error! "should be a string with bla bla bla"))
(s/def ::things (s/coll-of ::thing))
(s/def :foo/name string?)
(s/def :foo/names (s/coll-of :foo/name))
(s/def :foo/person (s/keys :req-un [:foo/names]))
(s/def :foo/age int?)
(s/def :foo/agent (s/keys :req-un [:foo/person :foo/age]))
(s/def :foo/agent2 (s/keys :req-un [:foo/person :foo/age]))
(def ^:dynamic *opts* {:highlight? false
:group-missing-keys? false
:group-or-problems? false
:header? false})
(deftest test-outputs
(are [spec val output] (= (l/explain-str spec val *opts*)
output)
::thing
1
"1 is an invalid :exoscale.lingo.test.core-test/thing - should be a string with bla bla bla\n"
(s/coll-of ::thing)
[1]
"1 in `[0]` is an invalid :exoscale.lingo.test.core-test/thing - should be a string with bla bla bla\n"
::things
[1]
"1 in `[0]` is an invalid :exoscale.lingo.test.core-test/thing - should be a string with bla bla bla\n"
;; test traversing
(s/def ::things2 ::things)
[1]
"1 in `[0]` is an invalid :exoscale.lingo.test.core-test/thing - should be a string with bla bla bla\n"
::things
1
"1 is an invalid :exoscale.lingo.test.core-test/things - should be a Collection\n"
(s/and string? #(> (count %) 3))
""
"\"\" is invalid - should contain more than 3 elements\n"
(s/def ::cnt #(> (count %) 3))
""
"\"\" is an invalid :exoscale.lingo.test.core-test/cnt - should contain more than 3 elements\n"
;; test the original unchanged msg
(s/and string? #(pos? (count %)))
""
"\"\" is invalid - (pos? (count %))\n"
;; with a custom pred matcher
(do
(l/set-pred-error! #{'(pos? (count %))} (constantly "should be non blank"))
(s/and string? #(pos? (count %))))
""
"\"\" is invalid - should be non blank\n"
#{:a :b :c}
"b"
"\"b\" is invalid - should be one of :a, :b, :c\n"
;; (s/and string? #(xss/string-of* % {:blank? false :min-length 3 :max-length 10}))
;; ""
;; "\"\" is invalid - should be a String non blank, at least 3 characters in length, at most 10 characters in length\n"
(s/def :exoscale.lingo/c1 (s/map-of int? int? :count 3))
{"a" "b"}
"{\"a\" \"b\"} is an invalid :exoscale.lingo/c1 - should contain exactly 3 elements\n"
(s/and any? #(= 1 (count %)))
[]
"[] is invalid - should contain exactly 1 element\n"
(s/and any? #(= (count %) 1))
[]
"[] is invalid - should contain exactly 1 element\n"
(s/and any? #(= 42 (count %)))
[]
"[] is invalid - should contain exactly 42 elements\n"
(s/and any? #(= (count %) 42))
[]
"[] is invalid - should contain exactly 42 elements\n"
(s/and any? #(>= (count %) 42))
[]
"[] is invalid - should contain at least 42 elements\n"
(s/and any? #(<= (count %) 1))
[1 1]
"[1 1] is invalid - should contain at most 1 element\n"
(s/and any? #(<= % 1))
10
"10 is invalid - should be at most 1\n"
(s/and any? #(< % 1))
10
"10 is invalid - should be less than 1\n"
(s/and any? #(>= % 1))
0
"0 is invalid - should be at least 1\n"
(s/and any? #(> % 1))
0
"0 is invalid - should be greater than 1\n"
(s/and any? #(= % "yolo"))
0
"0 is invalid - should be equal to yolo\n"
(s/and any? #(= "yolo" %))
0
"0 is invalid - should be equal to yolo\n"
(s/int-in 0 10)
-1
"-1 is invalid - should be an Integer between 0 10\n"
(s/and number? #(<= 0 % 10))
-1
"-1 is invalid - should be an Integer between 0 10\n"
(s/double-in :min 0 :max 10)
(double 11)
"11.0 is invalid - should be at most 10\n"
(s/coll-of any? :min-count 3)
[1]
"[1] is invalid - should contain at least 3 elements\n"
(s/coll-of any? :max-count 3)
[1 1 1 1]
"[1 1 1 1] is invalid - should contain between 0 3 elements\n"
(s/coll-of any? :max-count 3 :min-count 1)
[1 1 1 1]
"[1 1 1 1] is invalid - should contain between 1 3 elements\n"
(s/coll-of any? :count 3)
[1 1 1 1]
"[1 1 1 1] is invalid - should contain exactly 3 elements\n"
(s/coll-of any? :count 1)
[1 1 1 1]
"[1 1 1 1] is invalid - should contain exactly 1 element\n"
(s/coll-of any? :kind set?)
[1]
"[1] is invalid - should be a Set\n"
(s/map-of any? any? :count 1)
{:a 1 :b 2}
"{:a 1, :b 2} is invalid - should contain exactly 1 element\n"
neg-int?
[1]
"[1] is invalid - should be a Negative Integer\n"
(s/def :foo/agent (s/keys :req-un [:foo/person :foo/age]))
{:age 10}
"{:age 10} is an invalid :foo/agent - missing key :person\n"
(s/def :foo/agent (s/keys :req [:foo/person :foo/age]))
{:foo/age 10}
"#:foo{:age 10} is an invalid :foo/agent - missing key :foo/person\n"
(do
(alter-var-root #'*opts* assoc :hide-keyword-namespaces? true)
(s/def :foo/agent (s/keys :req [:foo/person :foo/age])))
{:foo/age 10}
"#:foo{:age 10} is an invalid :foo/agent - missing key :person\n"
(do
(alter-var-root #'*opts* dissoc :hide-keyword-namespaces?)
(s/def :foo/agent (s/keys :req-un [:foo/person :foo/age])))
{:age 10 :person {:names [1]}}
"1 in `person.names[0]` is an invalid :foo/name - should be a String\n"
(-> (s/def :foo/agent2 (s/keys :req-un [:foo/person :foo/age]))
;; (xs/with-meta! {:exoscale.lingo/name "Agent"})
)
{:age ""}
"\"\" in `age` is an invalid :foo/age - should be an Integer\n{:age \"\"} is an invalid :foo/agent2 - missing key :person\n"
(s/def :foo/animal #{:a :b :c})
1
"1 is an invalid :foo/animal - should be one of :a, :b, :c\n"
:foo/person
{:names [1 :yolo]}
"1 in `names[0]` is an invalid :foo/name - should be a String\n:yolo in `names[1]` is an invalid :foo/name - should be a String\n"
nil?
1
"1 is invalid - should be nil\n"
(s/nilable string?)
1
"1 is invalid - should be a String\n1 is invalid - should be nil\n"
;; BB-TEST-PATCH: bb returns sci details instead of string
#_f2?
#_1
#_"1 is invalid - yolo\n"
;; BB-TEST-PATCH: bb returns sci details instead of string
#_f3?
#_1
#_"1 is invalid - should match Something\n"))
(deftest focus-test
(let [_ '_]
(is (= [_ _ _] (u/focus [3 2 1] nil)))
(is (= _ (u/focus 1 nil)))
(is (= 1 (u/focus 1 [])))
(is (= [_ _ 1] (u/focus [3 2 1] [2])))
(is (= [3 _ _] (u/focus [3 2 1] [0])))
(is (= {:a 1} (u/focus {:a 1} [:a])))
(is (= {:a _} (u/focus {:a 1} [:b])))
(is (= {:a _ :c 1} (u/focus {:a {:b 1} :c 1} [:c])))
(is (= {:a {:b [_ {:c {:d #{:b :a}, :e _}}]}}
(u/focus {:a {:b [1 {:c {:d #{:a :b} :e :foo}}]}}
[:a :b 1 :c :d]
{:descend-mismatching-nodes? true})))
(is (= {:a {:b [1 {:c {:d #{_}, :e _}}]}}
(u/focus {:a {:b [1 {:c {:d #{:a :b} :e :foo}}]}}
[:a :b 0]
{:descend-mismatching-nodes? true})))
(is (= {:a {:b [_ {:c {:d #{_}, :e _}}]}}
(u/focus {:a {:b [1 {:c {:d #{:a :b} :e :foo}}]}}
nil
{:descend-mismatching-nodes? true})))
(is (= {:a {:b [1 _]}}
(u/focus {:a {:b [1 {:c {:d #{:a :b} :e :foo}}]}}
[:a :b 0])))
(is (= {:a {:b [_ {:c {:d #{:b :a} :e _}}]}}
(u/focus {:a {:b [1 {:c {:d #{:b :a} :e {:f 1}}}]}}
[:a :b 1 :c :d])))))
(deftest highlight-test
(are [input path output]
(= (u/highlight input path {:focus? true})
output)
[3 2 1] {:in [2] :val 1} "[_ _ 1]\n ^"
[3 2 1] {:in [0] :val 3} "[3 _ _]\n ^"
{:a 1} {:in [:a] :val 1} "{:a 1}\n ^"
{:a {:b 1} :c 1} {:in [:c] :val 1} "{:a _, :c 1}\n ^"
{:a {:b [1 {:c {:d #{:a :b} :e :foo}}]}}
{:in [:a :b 1 :c :d] :val #{:a :b}}
"{:a {:b [_ {:c {:d #{:b :a}, :e _}}]}}\n ^^^^^^^^"
{:a {:b [1 {:c {:d #{:a :b} :e :foo}}]}}
{:in [:a :b 0] :val 1}
"{:a {:b [1 _]}}\n ^"
{:a {:b [1 {:c {:d #{:a :b} :e :foo}}]}}
{:in [:a :b 0] :val 1}
"{:a {:b [1 _]}}\n ^"
{:a {:b [1 {:c {:d #{:b :a} :e {:f 1}}}]}}
{:in [:a :b 1 :c :d] :val #{:b :a}}
"{:a {:b [_ {:c {:d #{:b :a}, :e _}}]}}\n ^^^^^^^^"
;; single line hl
{:a {:bar 255555 :c 3 :d 4 :e 5}}
{:in [:a :bar] :val 255555}
"{:a {:bar 255555, :c _, :d _, :e _}}\n ^^^^^^"
;; ;; multiline hl output
{:aaaaaaaaaaaaa
{:bbbbbbbbbbbbbbbbbdddddddddddddddddddddddddddddddddddddd 2 :c 33333 :d 4 :e 5}}
{:in [:aaaaaaaaaaaaa :c] :val 33333}
"{:aaaaaaaaaaaaa\n {:bbbbbbbbbbbbbbbbbdddddddddddddddddddddddddddddddddddddd _,\n :c 33333,\n ^^^^^\n :d _,\n :e _}}")
(is (= ["[1]\n ^ should be a string with bla bla bla"]
(->> (l/explain-data ::things [1])
:clojure.spec.alpha/problems
(map :exoscale.lingo.explain/highlight)))))
(deftest test-group-map-keys
(is (= "missing keys :age, :person"
(-> (l/explain-data :foo/agent2 {} {:group-missing-keys? true})
:clojure.spec.alpha/problems
first
:exoscale.lingo.explain/message)))
(is (= #{"missing keys :age, :person"
"missing keys :names"}
(->> (l/explain-data (s/tuple :foo/agent2 :foo/person)
[{} {}]
{:group-missing-keys? true})
:clojure.spec.alpha/problems
(map :exoscale.lingo.explain/message)
set))))
(deftest test-group-or-keys
(s/def ::test-group-or-keys (s/nilable string?))
(s/def ::test-group-or-keys2 (s/or :str string? :int int?))
(is (= #{"should be a String OR should be nil"}
(->> (l/explain-data ::test-group-or-keys
1
{:group-or-problems? true
:group-missing-keys? true})
:clojure.spec.alpha/problems
(map :exoscale.lingo.explain/message)
set)))
(is (= #{"should be a String OR should be an Integer"}
(->> (l/explain-data ::test-group-or-keys2
:kw
{:group-or-problems? true
:group-missing-keys? true})
:clojure.spec.alpha/problems
(map :exoscale.lingo.explain/message)
set)))
(is (= #{"should be a String OR should be nil"}
(->> (l/explain-data (s/coll-of (s/or :_ ::test-group-or-keys
:_ string?))
["" 1]
{:group-or-problems? true
:group-missing-keys? true})
:clojure.spec.alpha/problems
(map :exoscale.lingo.explain/message)
set))
"ensure there is no duplication of messages in the final pb string")
(s/def ::test-group-or-keys3 int?)
(is (= #{"should be a String OR should be nil"
"should be a String OR should be an Integer"
"should be an Integer"}
(->> (l/explain-data (s/keys :req-un [::test-group-or-keys])
{:test-group-or-keys 1
::test-group-or-keys2 :boom
::test-group-or-keys3 ""}
{:group-or-problems? true
:group-missing-keys? true})
:clojure.spec.alpha/problems
(map :exoscale.lingo.explain/message)
set))
"grouping does not alter the other problems"))
(deftest fix-map-path-test
(is (= [] (impl/fix-map-path [] [])))
(is (= [] (impl/fix-map-path {} [])))
(is (= [:a] (impl/fix-map-path {:a 1} [:a 1])))
(is (= [:a :b :c] (impl/fix-map-path {:a {:b {:c 1}}} [:a 1 :b 1 :c 1])))
(is (= [:a :b :c 0] (impl/fix-map-path {:a {:b {:c [1]}}}
[:a 1 :b 1 :c 1 0])))
(is (= [:a :b :c 1 :d]
(impl/fix-map-path {:a {:b {:c [{} {:d 1}]}}} [:a 1 :b 1 :c 1 1 :d 1]))))

View file

@ -98,6 +98,7 @@
"{:foo/a #test/var clojure.core/+}") "{:foo/a #test/var clojure.core/+}")
{:foo/a #'+})))) {:foo/a #'+}))))
;; BB-TEST-PATCH: No *loaded-libs* in bb
#?(:bb :TODO :clj #?(:bb :TODO :clj
(defn- remove-lib [lib] (defn- remove-lib [lib]
(remove-ns lib) (remove-ns lib)
@ -105,6 +106,7 @@
(derive :integrant.test-child/foo :integrant.test/foo) (derive :integrant.test-child/foo :integrant.test/foo)
;; BB-TEST-PATCH: No *loaded-libs* in bb
#?(:bb :TODO #?(:bb :TODO
:clj :clj
(deftest load-namespaces-test (deftest load-namespaces-test

View file

@ -0,0 +1,57 @@
(ns meta-merge.core-test
(:require #?(:clj [clojure.test :refer :all]
:cljs [cljs.test :refer-macros [deftest is testing]])
[meta-merge.core :refer [meta-merge]]))
(deftest test-meta-merge
(testing "simple merge"
(is (= (meta-merge {:a 1 :b 2} {:b 3 :c 4})
{:a 1 :b 3 :c 4})))
(testing "inner map merge"
(is (= (meta-merge {:a {:b 1 :c 2}} {:a {:c 3}})
{:a {:b 1 :c 3}})))
(testing "inner set merge"
(is (= (meta-merge {:a #{:b :c}} {:a #{:c :d}})
{:a #{:b :c :d}})))
(testing "inner vector merge"
(is (= (meta-merge {:a [:b :c]} {:a [:d]})
{:a [:b :c :d]})))
(testing "meta replace"
(is (= (meta-merge {:a [:b :c]} {:a ^:replace [:d]})
{:a [:d]})))
(testing "meta displace"
(is (= (meta-merge {:a [:b :c]} {:a ^:displace [:d]})
{:a [:b :c]})))
(testing "meta prepend"
(is (= (meta-merge {:a [:b :c]} {:a ^:prepend [:d]})
{:a [:d :b :c]})))
(testing "deep inner merge"
(is (= (meta-merge {:a {:b {:c [:d]}}} {:a {:b {:c [:e] :f :g}}})
{:a {:b {:c [:d :e] :f :g}}})))
(testing "collection type remains the same"
(is (map? (meta-merge {:a :b} {:c :d})))
(is (vector? (meta-merge [:a :b] [:c])))
(is (set? (meta-merge #{:a :b} #{:c})))
(is (list? (meta-merge '(:a :b) '(:c)))))
(testing "nil displace"
(is (= (meta-merge {:b :c} {:a ^:displace [:d]})
{:a [:d] :b :c})))
(testing "varargs"
(is (= (meta-merge)
{}))
(is (= (meta-merge {:a :b})
{:a :b}))
(is (= (meta-merge {:a :b :x 1} {:a :c :y 2} {:a :d})
{:a :d :x 1 :y 2}))
(is (= (meta-merge {:a :b :x 1} {:a :c :y 2} {:a :d} {:y 4 :z 3})
{:a :d :x 1 :y 4 :z 3}))))

View file

@ -0,0 +1,5 @@
(ns meta-merge.test-runner
(:require [doo.runner :refer-macros [doo-tests]]
[meta-merge.core-test]))
(doo-tests 'meta-merge.core-test)

View file

@ -0,0 +1,574 @@
(ns pyramid.core-test
(:require
[pyramid.core :as p]
[pyramid.ident :as ident]
[clojure.test :as t]))
(t/deftest normalization
(t/is (= {:person/id {0 {:person/id 0}}}
(p/db [{:person/id 0}]))
"a single entity")
(t/is (= {:person/id {0 {:person/id 0
:person/name "asdf"}
1 {:person/id 1
:person/name "jkl"}}}
(p/db [{:person/id 0
:person/name "asdf"}
{:person/id 1
:person/name "jkl"}]))
"multiple entities with attributes")
(t/is (= {:person/id {0 {:person/id 0
:person/name "asdf"}
1 {:person/id 1
:person/name "jkl"}}
:people [[:person/id 0]
[:person/id 1]]}
(p/db [{:people [{:person/id 0
:person/name "asdf"}
{:person/id 1
:person/name "jkl"}]}]))
"nested under a key")
(t/is (= {:person/id {0 {:person/id 0
:some-data {1 "hello"
3 "world"}}}}
(p/db [{:person/id 0
:some-data {1 "hello"
3 "world"}}]))
"Map with numbers as keys")
(t/is (= {:a/id {1 {:a/id 1
:b [{:c [:d/id 1]}]}}
:d/id {1 {:d/id 1
:d/txt "a"}}}
(p/db [{:a/id 1
:b [{:c {:d/id 1
:d/txt "a"}}]}]))
"Collections of non-entities still get normalized")
(t/is (= {:person/id
{123
{:person/id 123,
:person/name "Will",
:contact {:phone "000-000-0001"},
:best-friend [:person/id 456],
:friends
[[:person/id 9001]
[:person/id 456]
[:person/id 789]
[:person/id 1000]]},
456
{:person/id 456,
:person/name "Jose",
:account/email "asdf@jkl",
:best-friend [:person/id 123]},
9001 #:person{:id 9001, :name "Georgia"},
789 #:person{:id 789, :name "Frank"},
1000 #:person{:id 1000, :name "Robert"}}}
(p/db [{:person/id 123
:person/name "Will"
:contact {:phone "000-000-0001"}
:best-friend
{:person/id 456
:person/name "Jose"
:account/email "asdf@jkl"}
:friends
[{:person/id 9001
:person/name "Georgia"}
{:person/id 456
:person/name "Jose"}
{:person/id 789
:person/name "Frank"}
{:person/id 1000
:person/name "Robert"}]}
{:person/id 456
:best-friend {:person/id 123}}]))
"refs"))
(t/deftest non-entities
(t/is (= {:foo ["bar"]} (p/db [{:foo ["bar"]}])))
(t/is (= {:person/id {0 {:person/id 0
:foo ["bar"]}}}
(p/db [{:person/id 0
:foo ["bar"]}]))))
(t/deftest custom-schema
(t/is (= {:color {"red" {:color "red" :hex "#ff0000"}}}
(p/db [{:color "red" :hex "#ff0000"}]
(ident/by-keys :color)))
"ident/by-keys")
(t/is (= {:color {"red" {:color "red" :hex "#ff0000"}}}
(p/db [^{:db/ident :color}
{:color "red" :hex "#ff0000"}]))
"local schema")
(t/testing "complex schema"
(let [db (p/db [{:type "person"
:id "1234"
:purchases [{:type "item"
:id "1234"}]}
{:type "item"
:id "5678"}
{:type "foo"}
{:id "bar"}]
(fn [entity]
(let [{:keys [type id]} entity]
(when (and (some? type) (some? id))
[(keyword type "id") id]))))]
(t/is (= {:person/id
{"1234" {:type "person", :id "1234", :purchases [[:item/id "1234"]]}},
:item/id
{"1234" {:type "item", :id "1234"}, "5678" {:type "item", :id "5678"}},
:type "foo",
:id "bar"}
db)
"correctly identifies entities")
(t/is (= {[:person/id "1234"]
{:type "person", :id "1234", :purchases [{:type "item", :id "1234"}]}}
(p/pull db [{[:person/id "1234"] [:type :id {:purchases [:type :id]}]}]))
"pull"))))
(t/deftest add
(t/is (= {:person/id {0 {:person/id 0}}}
(p/add {} {:person/id 0})))
(t/is (= {:person/id {0 {:person/id 0 :person/name "Gill"}
1 {:person/id 1}}}
(p/add
{}
{:person/id 0}
{:person/id 1}
{:person/id 0 :person/name "Gill"}))))
(t/deftest add-report
(t/is (= {:db {:person/id {0 {:person/id 0}}}
:entities #{[:person/id 0]}}
(p/add-report {} {:person/id 0})))
(t/is (= {:db {:person/id {0 {:person/id 0
:person/name "Gill"
:best-friend [:person/id 1]}
1 {:person/id 1
:person/name "Uma"}}
:me [:person/id 0]}
:entities #{[:person/id 0]
[:person/id 1]}}
(p/add-report {} {:me {:person/id 0
:person/name "Gill"
:best-friend {:person/id 1
:person/name "Uma"}}})))
#_(t/is (= {:db {:person/id {0 {:person/id 0 :person/name "Gill"}
1 {:person/id 1}}}
:entities #{{:person/id 0 :person/name "Gill"}
{:person/id 1}}}
(p/add-report
{}
{:person/id 0}
{:person/id 1}
{:person/id 0 :person/name "Gill"}))))
(def data
{:people/all [{:person/id 0
:person/name "Alice"
:person/age 25
:best-friend {:person/id 1}
:person/favorites
{:favorite/ice-cream "vanilla"}}
{:person/id 1
:person/name "Bob"
:person/age 23}]})
(def db
(p/db [data]))
(t/deftest pull
(t/is (= #:people{:all [{:person/id 0} {:person/id 1}]}
(p/pull db [:people/all]))
"simple key")
(t/is (= {:people/all [{:person/name "Alice"
:person/id 0}
{:person/name "Bob"
:person/id 1}]}
(p/pull db [{:people/all [:person/name :person/id]}]))
"basic join + prop")
(t/is (= #:people{:all [{:person/name "Alice"
:person/id 0
:best-friend #:person{:name "Bob", :id 1 :age 23}}
#:person{:name "Bob", :id 1}]}
(p/pull db [#:people{:all [:person/name :person/id :best-friend]}]))
"join + prop + join ref lookup")
(t/is (= #:people{:all [{:person/name "Alice"
:person/id 0
:best-friend #:person{:name "Bob"}}
#:person{:name "Bob", :id 1}]}
(p/pull db [#:people{:all [:person/name
:person/id
{:best-friend [:person/name]}]}]))
"join + prop, ref as prop resolver")
(t/is (= {[:person/id 1] #:person{:id 1, :name "Bob", :age 23}}
(p/pull db [[:person/id 1]]))
"ident acts as ref lookup")
(t/is (= {[:person/id 0] {:person/id 0
:person/name "Alice"
:person/age 25
:best-friend {:person/id 1}
:person/favorites #:favorite{:ice-cream "vanilla"}}}
(p/pull db [[:person/id 0]]))
"ident does not resolve nested refs")
(t/is (= {[:person/id 0] #:person{:id 0
:name "Alice"
:favorites #:favorite{:ice-cream "vanilla"}}}
(p/pull db [{[:person/id 0] [:person/id
:person/name
:person/favorites]}]))
"join on ident")
(t/is (= {:people/all [{:person/name "Alice"
:person/id 0
:best-friend #:person{:name "Bob", :id 1 :age 23}}
#:person{:name "Bob", :id 1}]
[:person/id 1] #:person{:age 23}}
(p/pull db [{:people/all [:person/name :person/id :best-friend]}
{[:person/id 1] [:person/age]}]))
"multiple joins")
(t/testing "includes params"
(t/is (= #:people{:all [#:person{:name "Bob", :id 1}]}
(p/pull (-> db
(p/add {'(:people/all {:with "params"}) [[:person/id 1]]}))
'[{(:people/all {:with "params"})
[:person/name :person/id]}])))
(t/is (= '{:person/foo {:person/id 1
:person/name "Bob"}}
(p/pull (-> db
(p/add {'(:person/foo {:person/id 2})
{:person/id 1}}))
'[{(:person/foo {:person/id 2})
[:person/name :person/id]}]))
"params that include an entity-looking thing should not be normalized")
(t/is (= {}
(p/pull db '[([:person/id 1] {:with "params"})])))
(t/is (= {}
(p/pull db '[{(:people/all {:with "params"})
[:person/name :person/id]}]))))
(t/testing "union"
(let [data {:chat/entries
[{:message/id 0
:message/text "foo"
:chat.entry/timestamp "1234"}
{:message/id 1
:message/text "bar"
:chat.entry/timestamp "1235"}
{:audio/id 0
:audio/url "audio://asdf.jkl"
:audio/duration 1234
:chat.entry/timestamp "4567"}
{:photo/id 0
:photo/url "photo://asdf_10x10.jkl"
:photo/height 10
:photo/width 10
:chat.entry/timestamp "7890"}]}
db1 (p/db [data])
query [{:chat/entries
{:message/id
[:message/id :message/text :chat.entry/timestamp]
:audio/id
[:audio/id :audio/url :audio/duration :chat.entry/timestamp]
:photo/id
[:photo/id :photo/url :photo/width :photo/height :chat.entry/timestamp]
:asdf/jkl [:asdf/jkl]}}]]
(t/is (= #:chat{:entries [{:message/id 0
:message/text "foo"
:chat.entry/timestamp "1234"}
{:message/id 1
:message/text "bar"
:chat.entry/timestamp "1235"}
{:audio/id 0
:audio/url "audio://asdf.jkl"
:audio/duration 1234
:chat.entry/timestamp "4567"}
{:photo/id 0
:photo/url "photo://asdf_10x10.jkl"
:photo/width 10
:photo/height 10
:chat.entry/timestamp "7890"}]}
(p/pull db1 query)))))
(t/testing "not found"
(t/is (= {} (p/pull {} [:foo])))
(t/is (= {} (p/pull {} [:foo :bar :baz])))
(t/is (= {} (p/pull {} [:foo {:bar [:asdf]} :baz])))
(t/is (= {:foo "bar"}
(p/pull {:foo "bar"} [:foo {:bar [:asdf]} :baz])))
(t/is (= {:bar {:asdf 123}}
(p/pull
{:bar {:asdf 123}}
[:foo {:bar [:asdf :jkl]} :baz])))
(t/is (= {:bar {}}
(p/pull
(p/db [{:bar {:bar/id 0}}
{:bar/id 0
:qwerty 1234}])
[:foo {:bar [:asdf :jkl]} :baz])))
(t/is (= {:bar {:asdf "jkl"}}
(p/pull
(p/db [{:bar {:bar/id 0}}
{:bar/id 0
:asdf "jkl"}])
[:foo {:bar [:asdf :jkl]} :baz])))
(t/is (= {:bar {}}
(p/pull
(p/db [{:bar {:bar/id 0}}
{:bar/id 1
:asdf "jkl"}])
[:foo {:bar [:asdf :jkl]} :baz])))
(t/is (= {:foo [{:bar/id 1
:bar/name "asdf"}
{:baz/id 1
:baz/name "jkl"}]}
(p/pull
(p/db [{:foo [{:bar/id 1
:bar/name "asdf"}
{:baz/id 1
:baz/name "jkl"}]}])
[{:foo {:bar/id [:bar/id :bar/name]
:baz/id [:baz/id :baz/name]}}])))
(t/is (= {:foo [{:bar/id 1
:bar/name "asdf"}
{:bar/id 2}
{:baz/id 1
:baz/name "jkl"}]}
(p/pull
(p/db [{:foo [{:bar/id 1
:bar/name "asdf"}
{:bar/id 2}
{:baz/id 1
:baz/name "jkl"}]}])
[{:foo {:bar/id [:bar/id :bar/name]
:baz/id [:baz/id :baz/name]}}]))))
(t/testing "bounded recursion"
(let [data {:entries
{:entry/id "foo"
:entry/folders
[{:entry/id "bar"}
{:entry/id "baz"
:entry/folders
[{:entry/id "asdf"
:entry/folders
[{:entry/id "qwerty"}]}
{:entry/id "jkl"
:entry/folders
[{:entry/id "uiop"}]}]}]}}
db (p/db [data])]
(t/is (= {:entries
{:entry/id "foo"
:entry/folders
[]}}
(p/pull db '[{:entries [:entry/id
{:entry/folders 0}]}])))
(t/is (= {:entries
{:entry/id "foo"
:entry/folders
[{:entry/id "bar"}
{:entry/id "baz"
:entry/folders []}]}}
(p/pull db '[{:entries [:entry/id
{:entry/folders 1}]}])))
(t/is (= {:entries
{:entry/id "foo"
:entry/folders
[{:entry/id "bar"}
{:entry/id "baz"
:entry/folders
[{:entry/id "asdf"
:entry/folders []}
{:entry/id "jkl"
:entry/folders []}]}]}}
(p/pull db '[{:entries [:entry/id
{:entry/folders 2}]}])))
(t/is (= {:entries
{:entry/id "foo"
:entry/folders
[{:entry/id "bar"}
{:entry/id "baz"
:entry/folders
[{:entry/id "asdf"
:entry/folders
[{:entry/id "qwerty"}]}
{:entry/id "jkl"
:entry/folders
[{:entry/id "uiop"}]}]}]}}
(p/pull db '[{:entries [:entry/id
{:entry/folders 3}]}])))
(t/is (= {:entries
{:entry/id "foo"
:entry/folders
[{:entry/id "bar"}
{:entry/id "baz"
:entry/folders
[{:entry/id "asdf"
:entry/folders
[{:entry/id "qwerty"}]}
{:entry/id "jkl"
:entry/folders
[{:entry/id "uiop"}]}]}]}}
(p/pull db '[{:entries [:entry/id
{:entry/folders 10}]}])))))
(t/testing "infinite recursion"
(let [data {:entries
{:entry/id "foo"
:entry/folders
[{:entry/id "bar"}
{:entry/id "baz"
:entry/folders
[{:entry/id "asdf"
:entry/folders
[{:entry/id "qwerty"}]}
{:entry/id "jkl"
:entry/folders
[{:entry/id "uiop"}]}]}]}}
db (p/db [data])]
(t/is (= data
(p/pull db '[{:entries [:entry/id
{:entry/folders ...}]}])))))
(t/testing "query metadata"
(t/is (-> db
(p/pull ^:foo [])
(meta)
(:foo))
"root")
(t/is (-> db
(p/pull [^:foo {[:person/id 0] [:person/name]}])
(get [:person/id 0])
(meta)
(:foo))
"join")
(let [data {:chat/entries
[{:message/id 0
:message/text "foo"
:chat.entry/timestamp "1234"}
{:message/id 1
:message/text "bar"
:chat.entry/timestamp "1235"}
{:audio/id 0
:audio/url "audio://asdf.jkl"
:audio/duration 1234
:chat.entry/timestamp "4567"}
{:photo/id 0
:photo/url "photo://asdf_10x10.jkl"
:photo/height 10
:photo/width 10
:chat.entry/timestamp "7890"}]}
db1 (p/db [data])
query ^:foo [^:bar
{:chat/entries
{:message/id
[:message/id :message/text :chat.entry/timestamp]
:audio/id
[:audio/id :audio/url :audio/duration :chat.entry/timestamp]
:photo/id
[:photo/id :photo/url :photo/width :photo/height :chat.entry/timestamp]
:asdf/jkl [:asdf/jkl]}}]
result (p/pull db1 query)]
(t/is (= #:chat{:entries [{:message/id 0
:message/text "foo"
:chat.entry/timestamp "1234"}
{:message/id 1
:message/text "bar"
:chat.entry/timestamp "1235"}
{:audio/id 0
:audio/url "audio://asdf.jkl"
:audio/duration 1234
:chat.entry/timestamp "4567"}
{:photo/id 0
:photo/url "photo://asdf_10x10.jkl"
:photo/width 10
:photo/height 10
:chat.entry/timestamp "7890"}]}
result))
(t/is (-> result meta :foo))
(t/is (every? #(:bar (meta %)) (get result :chat/entries)))))
(t/testing "dangling entities"
(t/is (= {[:id 0] {:friends [{:id 1} {:id 2}]}}
(p/pull
{:id {0 {:id 0 :name "asdf" :friends [[:id 1] [:id 2]]}
1 {:id 1 :name "jkl"}}}
[{[:id 0] [:friends]}]))
"dangling entity shows up in queries that do not select any props")
;; BB-TEST-PATCH: NullPointerException: Cannot invoke "clojure.lang.IObj.withMeta(clojure.lang.IPersistentMap)"
#_(t/is (= {[:id 0] {:friends [{:id 1, :name "jkl"} {:id 2}]}}
(p/pull
{:id {0 {:id 0 :name "asdf" :friends [[:id 1] [:id 2]]}
1 {:id 1 :name "jkl"}}}
[{[:id 0] [{:friends [:id :name]}]}]))
"dangling entity shows up in queries that include ID")
;; BB-TEST-PATCH: NullPointerException: Cannot invoke "clojure.lang.IObj.withMeta(clojure.lang.IPersistentMap)"
#_(t/is (= {[:id 0] {:friends [{:name "jkl"}]}}
(p/pull
{:id {0 {:id 0 :name "asdf" :friends [[:id 1] [:id 2]]}
1 {:id 1 :name "jkl"}}}
[{[:id 0] [{:friends [:name]}]}]))
"dangling entity does not show up in queries that do not include ID")))
(t/deftest pull-report
(t/is (= {:data {:people/all [{:person/name "Alice"}
{:person/name "Bob"}]}
:entities #{[:person/id 0] [:person/id 1]}}
(p/pull-report db [{:people/all [:person/name]}]))
"basic join + prop")
(t/is (= {:data #:people{:all [{:person/name "Alice"
:best-friend #:person{:name "Bob", :id 1 :age 23}}
#:person{:name "Bob"}]}
:entities #{[:person/id 0] [:person/id 1]}}
(p/pull-report db [#:people{:all [:person/name :best-friend]}]))
"join + prop + join ref lookup")
(t/is (= {:data {[:person/id 1] #:person{:id 1, :name "Bob", :age 23}}
:entities #{[:person/id 1]}}
(p/pull-report db [[:person/id 1]]))
"ident acts as ref lookup")
(t/is (= {:data {[:person/id 0] {:person/id 0
:person/name "Alice"
:person/age 25
:best-friend {:person/id 1}
:person/favorites #:favorite{:ice-cream "vanilla"}}}
:entities #{[:person/id 0]}}
(p/pull-report db [[:person/id 0]]))
"ident does not resolve nested refs"))
(t/deftest delete
(t/is (= {:people/all [[:person/id 0]]
:person/id {0 {:person/id 0
:person/name "Alice"
:person/age 25
:person/favorites #:favorite{:ice-cream "vanilla"}}}}
(p/delete db [:person/id 1]))))
(t/deftest data->query
(t/is (= [:a]
(p/data->query {:a 42})))
(t/is (= [{:a [:b]}]
(p/data->query {:a {:b 42}})))
(t/is (= [{:a [:b :c]}]
(p/data->query {:a [{:b 42} {:c :d}]})))
(t/is (= [{[:a 42] [:b]}]
(p/data->query {[:a 42] {:b 33}}))))
(comment
(t/run-tests))

View file

@ -0,0 +1,23 @@
(ns pyramid.pull-test
(:require
[clojure.test :as t]
[pyramid.pull :as p]))
(def entities
(for [i (range 1000)]
[:id i]))
(t/deftest many-entities
(t/is (= (set entities)
(:entities
(p/pull-report
{:id (into
{}
(map #(vector
(second %)
(hash-map (first %) (second %))))
entities)
:all (vec entities)}
[{:all [:id]}])))))

View file

@ -0,0 +1,112 @@
(ns pyramid.query-test
(:require
[pyramid.query :as p.q :refer [q]]
[clojure.test :as t]))
(def db {:person/id {"123" {:person/id "123"
:person/name "foo"
:person/best-friend [:person/id "789"]
:person/friends [[:person/id "456"]
[:person/id "789"]]}
"456" {:person/id "456"
:person/name "bar"
:person/friends [[:person/id "123"]
[:person/id "789"]]}
"789" {:person/id "789"
:person/name "baz"
:person/friends [[:person/id "123"]
[:person/id "456"]]}
"1011" {:person/id "1011"}}
:person {:bar "baz"}
:asdf "jkl"})
(t/deftest joins
(t/is (= '(["123"] ["456"] ["789"] ["1011"])
(q '[:find ?id
:where
[?e :person/id ?id]]
db)))
(t/is (= '(["123" "foo"] ["456" "bar"] ["789" "baz"])
(q '[:find ?id ?name
:where
[?e :person/id ?id]
[?e :person/name ?name]]
db)))
(t/is (= '(["123" "foo" [:person/id "789"]])
(q '[:find ?id ?name ?friend
:where
[?e :person/id ?id]
[?e :person/name ?name]
[?e :person/best-friend ?friend]]
db)))
(t/is (= '(["foo" "baz"])
(q '[:find ?name ?friend-name
:where
[?e :person/name ?name]
[?e :person/best-friend ?friend]
[?friend :person/name ?friend-name]]
db)))
(t/is (= '()
(q '[:find ?id
:where
[?e :person/name "asdf"]
[?e :person/id ?id]]
db))
"not found")
(t/is (= '(["123" "foo"])
(q '[:find ?id ?name
:in $ ?name
:where
[?e :person/name ?name]
[?e :person/id ?id]]
db
"foo"))
"join on :in")
(t/is (= '(["foo" "bar"]
["foo" "baz"]
["bar" "foo"]
["bar" "baz"]
["baz" "foo"]
["baz" "bar"])
(q '[:find ?name ?friend-name
:where
[?e :person/name ?name]
[?e :person/friends ^:many ?friend]
[?friend :person/name ?friend-name]]
db))
"multiple cardinality value")
(t/is (= '(["123" "foo"]
["456" "bar"])
(q '[:find ?id ?name
:in $ ^:many ?name
:where
[?e :person/name ?name]
[?e :person/id ?id]]
db
["foo" "bar"]))
"multi cardinality join on :in")
(t/is (= '(["foo" "foo"]
["foo" "bar"]
["foo" "baz"]
["bar" "foo"]
["bar" "bar"]
["bar" "baz"]
["baz" "foo"]
["baz" "bar"]
["baz" "baz"])
(q '[:find ?name1 ?name2
:where
[?e1 :person/name ?name1]
[?e2 :person/name ?name2]]
db))
"cross product"))

View file

@ -0,0 +1,22 @@
(ns swirrl.dogstatsd-test
(:require [swirrl.dogstatsd :as sut]
[swirrl.dogstatsd.specs]
[clojure.test :refer [deftest is testing]]
[clojure.spec.test.alpha :as st]))
(st/instrument)
(deftest basic-invocation-tests
(testing "Basic metric procedure calls run without error"
(let [client (sut/configure {:endpoint "localhost:8111"})]
(sut/increment! client ::increment)
(sut/increment! client ::increment 10)
(sut/decrement! client ::decrement)
(sut/histogram! client ::histogram 10)
(sut/distribution! client ::distribution 10)
(sut/set! client ::set "a-value")
(sut/event! client "event title" "some text here" {})
(is true))))