Skip to content

Commit

Permalink
Add specs for clojure.set #70 (#152)
Browse files Browse the repository at this point in the history
  • Loading branch information
eerohele authored and borkdude committed Dec 1, 2018
1 parent 5179b3e commit 009ab61
Show file tree
Hide file tree
Showing 6 changed files with 285 additions and 5 deletions.
16 changes: 15 additions & 1 deletion src/speculative/instrument.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
instrument and unstruments specs provided by speculative. Alpha,
subject to change."
(:require
[clojure.set :as set]
[clojure.string :as str]
[speculative.core]
[speculative.set]
Expand Down Expand Up @@ -45,7 +46,20 @@
;; clojure.string
str/starts-with?
str/ends-with?
])

;; clojure.set
set/union
set/intersection
set/difference
set/select
set/project
set/rename-keys
set/rename
set/index
set/map-invert
set/join
set/subset?
set/superset?])

(deftime

Expand Down
102 changes: 100 additions & 2 deletions src/speculative/set.cljc
Original file line number Diff line number Diff line change
@@ -1,4 +1,102 @@
(ns speculative.set
(:require [speculative.specs :as ss]))
(:require [clojure.set :as set]
[clojure.spec.alpha :as s]
[speculative.specs :as ss]))

;; TODO
(s/def ::nilable-set
(s/nilable ::ss/set))

(s/def ::nilable-map
(s/nilable ::ss/map))

(s/def ::rel
(s/nilable (s/coll-of ::nilable-map)))

(s/def ::rel*
(s/nilable (s/coll-of ::ss/seqable-of-map-entry)))

(s/def ::seqable-of-pairs
(s/coll-of (s/or :map-entry ::ss/map-entry
:pair (s/coll-of ::ss/any :count 2))
:kind seqable?))

(s/def ::nullary
(s/cat))

(s/def ::unary
(s/cat :s1 ::nilable-set))

(s/def ::binary
(s/cat :s1 ::nilable-set
:s2 ::nilable-set))

(s/def ::variadic
(s/cat :s1 ::nilable-set
:s2 ::nilable-set
:sets (s/* ::nilable-set)))

(s/fdef set/union
:args (s/alt :nullary ::nullary
:unary ::unary
:binary ::binary
:variadic ::variadic)
:ret ::nilable-set)

(s/fdef set/intersection
:args (s/alt :unary ::unary
:binary ::binary
:variadic ::variadic)
:ret ::nilable-set)

(s/fdef set/difference
:args (s/alt :unary ::unary
:binary ::binary
:variadic ::variadic)
:ret ::nilable-set)

(s/fdef set/select
:args (s/cat :pred ::ss/predicate
:xset ::nilable-set)
:ret ::nilable-set)

(s/fdef set/project
:args (s/cat :xrel ::rel*
:ks ::ss/sequential)
:ret ::ss/set)

(s/fdef set/rename-keys
:args (s/cat :map ::nilable-map
:kmap ::nilable-map)
:ret ::nilable-map)

(s/fdef set/rename
:args (s/cat :xrel ::rel
:kmap ::nilable-map)
:ret ::ss/set)

(s/fdef set/index
:args (s/cat :xrel ::rel*
:ks ::ss/sequential)
:ret ::ss/map)

(s/fdef set/map-invert
:args (s/cat :m (s/nilable ::seqable-of-pairs))
:ret ::ss/map)

(s/fdef set/join
:args (s/alt :binary (s/cat :xrel ::rel
:yrel ::rel*)
:ternary (s/cat :xrel ::rel
:yrel ::rel*
:km ::nilable-map))
:ret ::ss/set)

(s/fdef set/subset?
:args (s/cat :set1 ::nilable-set
:set2 ::nilable-set)
:ret ::ss/boolean)

(s/fdef set/superset?
:args (s/cat :set1 ::nilable-set
:set2 ::nilable-set)
:ret ::ss/boolean)
2 changes: 2 additions & 0 deletions src/speculative/specs.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,12 @@
(fn []
(gen/fmap first
(s/gen (s/and ::map seq))))))
(s/def ::set set?)
(s/def ::nil nil?)
(s/def ::number number?)
(s/def ::reducible reducible?)
(s/def ::seqable seqable?)
(s/def ::sequential sequential?)
(s/def ::some some?)
(s/def ::string string?)
#?(:clj (s/def ::char-sequence
Expand Down
2 changes: 1 addition & 1 deletion test/speculative/core_test.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

(deftest instrument-test
(testing "speculative specs should be instrumentable and unstrumentable"
(let [spec-count #?(:clj 29 :cljs 26)
(let [spec-count #?(:clj 41 :cljs 38)
instrumented (speculative.instrument/instrument)
unstrumented (speculative.instrument/unstrument)]
(is (= spec-count (count instrumented)))
Expand Down
164 changes: 164 additions & 0 deletions test/speculative/set_test.cljc
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
(ns speculative.set-test
(:require [clojure.set :as set]
[clojure.test :refer [are deftest is]]
[speculative.set]
[speculative.test :refer [with-instrumentation
with-unstrumentation
throws
check-call]]))

(deftest union
(is (= #{1 2 3} (check-call `set/union [#{1 2} #{3}])))
(is (= #{1 2} (check-call `set/union [#{1 2} nil])))
(is (= nil (check-call `set/union [nil nil])))
(with-instrumentation `set/union
(throws `set/union (set/union #{1 2} [3]))
(throws `set/union (set/union [1 2] #{3}))
(throws `set/union (set/union {1 2} #{3}))))

(deftest intersection
(is (= #{1} (check-call `set/intersection [#{1 2} #{1}])))
(is (= nil (check-call `set/intersection [nil #{1}])))
(is (= nil (check-call `set/intersection [nil nil])))
(with-instrumentation `set/intersection
(throws `set/intersection (set/intersection #{1 2} [1]))
(throws `set/intersection (set/intersection [1 2] #{1}))
(throws `set/intersection (set/intersection {1 2} #{1}))))

(deftest difference
(is (= #{2} (check-call `set/difference [#{1 2} #{1}])))
(is (= nil (check-call `set/difference [nil #{1}])))
(is (= #{1 2} (check-call `set/difference [#{1 2} nil])))
(is (= nil (check-call `set/difference [nil nil])))
(with-instrumentation `set/difference
(throws `set/difference (set/difference #{1 2} [1]))
(throws `set/difference (set/difference [1 2] #{1}))
(throws `set/difference (set/difference {1 2} [1]))))

(deftest select
(is (= #{1 2} (check-call `set/select [int? #{1 2 :a}])))
(is (= nil (check-call `set/select [int? nil])))
(with-instrumentation `set/select
(throws `set/select (set/select int? [1 2 :a]))
(throws `set/select (set/select int? {:a 1}))))

(deftest project
(is (= #{{:a 1}} (check-call `set/project [[{:a 1 :b 2}] [:a]])))
(is (= #{{:a 1}} (check-call `set/project [[{:a 1 :b 2}] '(:a)])))
#?(:clj (is (= #{{:a 1}} (check-call `set/project [#{(java.util.HashMap. {:a 1 :b 2})} [:a]]))))
(is (= #{{:a 1}} (check-call `set/project [#{{:a 1 :b 2}} [:a]])))
(is (= #{} (check-call `set/project [nil [:a]])))
(is (= #{{}} (check-call `set/project [#{nil} [:a]])))
(with-instrumentation `set/project
(throws `set/project (set/project nil nil))
(throws `set/project (set/project #{[:a 1 :b 2]} {:a nil}))
(throws `set/project (set/project {:a 1 :b 2} [:a]))))

(deftest rename-keys
(is (= {:c 1 :d 2} (check-call `set/rename-keys [{:a 1 :b 2} {:a :c :b :d}])))
(is (= nil (check-call `set/rename-keys [nil {:a :c :b :d}])))
(is (= {:a 1 :b 2} (check-call `set/rename-keys [{:a 1 :b 2} nil])))
(with-instrumentation `set/rename-keys
(throws `set/rename-keys (set/rename-keys [:a 1 :b 2] {:a :c :b :d}))
(throws `set/rename-keys (set/rename-keys {:a 1 :b 2} [:a :c :b :d]))
#?(:clj (throws `set/rename-keys (set/rename-keys (java.util.HashMap. {:a 1 :b 2}) {:a :c :b :d})))))

(deftest rename
(is (= #{{:b 1 :c 1} {:b 2 :c 2}} (check-call `set/rename [#{{:a 1 :b 1} {:a 2 :b 2}} {:a :c}])))
(is (= #{{:b 1 :c 1} {:b 2 :c 2}} (check-call `set/rename [[{:a 1 :b 1} {:a 2 :b 2}] {:a :c}])))
(is (= #{} (check-call `set/rename [nil {:a :c}])))
(is (= #{nil} (check-call `set/rename [[nil] {:a :c}])))
(is (= #{} (check-call `set/rename [nil nil])))
(is (= #{nil} (check-call `set/rename [[nil] nil])))
(with-instrumentation `set/rename
(throws `set/rename (set/rename [[:a 1 :b 1]] {:a :c}))
(throws `set/rename (set/rename [{:a 1 :b 1}] [:a :c]))
#?(:clj (throws `set/rename (set/rename [(java.util.HashMap. {:a 1 :b 1})] [:a :c])))))

(deftest index
(is (= {{:a 1} #{{:a 1 :b 2}}} (check-call `set/index [#{{:a 1 :b 2}} [:a]])))
(is (= {{:a 1} #{{:a 1 :b 2}}} (check-call `set/index [#{{:a 1 :b 2}} '(:a)])))
(is (= {{:a 1} #{{:a 1 :b 2}}} (check-call `set/index [[{:a 1 :b 2}] [:a]])))
#?(:clj (is (= {{:a 1} #{(java.util.HashMap. {:a 1 :b 2})}}
(check-call `set/index [#{(java.util.HashMap. {:a 1 :b 2})} [:a]]))))
(is (= {} (check-call `set/index [nil [:a]])))
(is (= {{} #{nil}} (check-call `set/index [[nil] [:a]])))
(with-instrumentation `set/index
(throws `set/index (set/index [[:a 1 :b 2]] [:a]))
(throws `set/index (set/index [{:a 1 :b 2}] :a))))

(deftest map-invert
(is (= {:b :a} (check-call `set/map-invert [{:a :b}])))
(is (= {1 :a 2 :b} (check-call `set/map-invert ['([:a 1] [:b 2])])))
(is (= {1 :a 2 :b} (check-call `set/map-invert [[[:a 1] [:b 2]]])))
(is (= {} (check-call `set/map-invert [nil])))
#?(:clj (is (= {1 :a 2 :b} (check-call `set/map-invert [(java.util.HashMap. {:a 1 :b 2})]))))
(with-instrumentation `set/map-invert
(throws `set/map-invert (set/map-invert [[:a :b :c]]))
(throws `set/map-invert (set/map-invert [:a :b]))
(throws `set/map-invert (set/map-invert #{:a :b}))))

(deftest join
(are [x y] (= x y)
#{{:a 1 :b 1} {:a 2 :b 2}}
(check-call `set/join [#{{:a 1} {:a 2}} #{{:a 1 :b 1} {:a 2 :b 2}}])

#{{:a 1 :b 1} {:a 2 :b 2}}
(check-call `set/join [#{{:a 1} {:a 2}} [{:a 1 :b 1} {:a 2 :b 2}]])

#{{:a 1 :b 1} {:a 2 :b 2}}
(check-call `set/join [[{:a 1} {:a 2}] #{{:a 1 :b 1} {:a 2 :b 2}}])

#{{:a 1 :b 1} {:a 2 :b 2}}
(check-call `set/join [[{:a 1} {:a 2}] [{:a 1 :b 1} {:a 2 :b 2}]])

#{{:a 1 :b 1} {:a 2 :b 2}}
(check-call `set/join [#{{:a 1} {:a 2}} #{{:b 1} {:b 2}} {:a :b}])

#{{:a 1 :b 1} {:a 2 :b 2}}
(check-call `set/join [#{{:a 1} {:a 2}} [{:b 1} {:b 2}] {:a :b}])

#{{:a 1 :b 1} {:a 2 :b 2}}
(check-call `set/join [[{:a 1} {:a 2}] #{{:b 1} {:b 2}} {:a :b}])

#{{:a 1 :b 1} {:a 2 :b 2}}
(check-call `set/join [[{:a 1} {:a 2}] [{:b 1} {:b 2}] {:a :b}])

#{}
(check-call `set/join [nil [{:b 1} {:b 2}] {:a :b}])

#{}
(check-call `set/join [[{:a 1} {:a 2}] nil {:a :b}])

#{}
(check-call `set/join [[{:a 1} {:a 2}] nil nil])

#{nil}
(check-call `set/join [[nil] [nil] nil]))

#?(:clj (is (= #{{:a 1 :b 1} {:a 2 :b 2}}
(check-call `set/join [[{:a 1} {:a 2}] [(java.util.HashMap. {:b 1}) {:b 2}] {:a :b}]))))

(with-instrumentation `set/join
(throws `set/join (set/join [{:a 1}] [{:b 2}] [:a :b]))
(throws `set/join (set/join [[:a 1]] [{:b 2}] {:a :b}))
(throws `set/join (set/join [{:a 1}] [[:b 2]] {:a :b}))
#?(:clj (throws `set/join (set/join [(java.util.HashMap. {:a 1})] [{:b 2}] {:a :b})))))

(deftest subset?
(is (true? (check-call `set/subset? [#{:a} #{:a :b}])))
(is (true? (check-call `set/subset? [nil #{:a :b}])))
(is (false? (check-call `set/subset? [#{:a} nil])))
(with-instrumentation `set/subset?
(throws `set/subset? (set/subset? #{:a} [:a :b]))
(throws `set/subset? (set/subset? [:a] #{:a :b}))
(throws `set/subset? (set/subset? [:a] [:a :b]))))

(deftest superset?
(is (true? (check-call `set/superset? [#{:a :b} #{:a}])))
(is (false? (check-call `set/superset? [nil #{:a}])))
(is (true? (check-call `set/superset? [#{:a :b} nil])))
(with-instrumentation `set/superset?
(throws `set/superset? (set/superset? [:a :b] #{:a}))
(throws `set/superset? (set/superset? #{:a :b} [:a]))
(throws `set/superset? (set/superset? [:a :b] [:a]))))
4 changes: 3 additions & 1 deletion test/speculative/test_runner.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
[clojure.test :as t :refer [run-tests]]
[clojure.test]
[speculative.core-test]
[speculative.set-test]
[speculative.string-test]
[speculative.test :refer [planck-env?]]
[speculative.test-test]))
Expand Down Expand Up @@ -52,6 +53,7 @@
(defn -main [& args]
(run-tests 'speculative.test-test
'speculative.core-test
'speculative.string-test))
'speculative.string-test
'speculative.set-test))

#?(:cljs (set! *main-cli-fn* -main))

0 comments on commit 009ab61

Please sign in to comment.