179 lines
6.8 KiB
Clojure
179 lines
6.8 KiB
Clojure
|
|
(ns clojure.test-clojure.instr
|
||
|
|
(:require [clojure.spec.alpha :as s]
|
||
|
|
[clojure.spec.gen.alpha :as gen]
|
||
|
|
[clojure.spec.test.alpha :as stest]
|
||
|
|
[clojure.test :refer :all]))
|
||
|
|
|
||
|
|
(set! *warn-on-reflection* true)
|
||
|
|
|
||
|
|
;; utils
|
||
|
|
|
||
|
|
(defmacro with-feature [feature & body]
|
||
|
|
`(try ~feature
|
||
|
|
~@body
|
||
|
|
(catch Exception ex#)))
|
||
|
|
|
||
|
|
;; instrument tests
|
||
|
|
|
||
|
|
(defn kwargs-fn
|
||
|
|
([opts] opts)
|
||
|
|
([a b] [a b])
|
||
|
|
([a b & {:as m}] [a b m]))
|
||
|
|
|
||
|
|
(defn no-kwargs-fn
|
||
|
|
([opts] opts)
|
||
|
|
([a b] [a b])
|
||
|
|
([args inner & opts] [args inner opts]))
|
||
|
|
|
||
|
|
(defn no-kwargs-destruct-fn
|
||
|
|
([opts] opts)
|
||
|
|
([{:as a} b] [a b])
|
||
|
|
([{:as args} inner & opts] [args inner opts]))
|
||
|
|
|
||
|
|
(defn just-varargs [& args]
|
||
|
|
(apply + args))
|
||
|
|
|
||
|
|
(defn add10 [n]
|
||
|
|
(+ 10 n))
|
||
|
|
|
||
|
|
(alter-meta! #'add10 dissoc :arglists)
|
||
|
|
|
||
|
|
;;; Specs
|
||
|
|
|
||
|
|
(s/def ::a any?)
|
||
|
|
(s/def ::b number?)
|
||
|
|
(s/def ::c any?)
|
||
|
|
(s/def ::m map?)
|
||
|
|
|
||
|
|
(s/fdef kwargs-fn
|
||
|
|
:args (s/alt :unary (s/cat :a ::a)
|
||
|
|
:binary (s/cat :a ::a :b ::b)
|
||
|
|
:variadic (s/cat :a ::a
|
||
|
|
:b ::b
|
||
|
|
:kwargs (s/keys* :opt-un [::a ::b ::c]))))
|
||
|
|
|
||
|
|
(s/fdef no-kwargs-fn
|
||
|
|
:args (s/alt :unary (s/cat :a ::a)
|
||
|
|
:binary (s/cat :a ::a :b ::b)
|
||
|
|
:variadic (s/cat :a ::a
|
||
|
|
:b ::b
|
||
|
|
:varargs (s/cat :numbers (s/* number?)))))
|
||
|
|
|
||
|
|
(s/fdef no-kwargs-destruct-fn
|
||
|
|
:args (s/alt :unary (s/cat :a ::a)
|
||
|
|
:binary (s/cat :a ::a :m ::m)
|
||
|
|
:variadic (s/cat :a ::a
|
||
|
|
:b ::b
|
||
|
|
:varargs (s/cat :numbers (s/* number?)))))
|
||
|
|
|
||
|
|
(s/fdef just-varargs
|
||
|
|
:args (s/cat :numbers (s/* number?))
|
||
|
|
:ret number?)
|
||
|
|
|
||
|
|
(s/fdef add10
|
||
|
|
:args (s/cat :arg ::b)
|
||
|
|
:ret number?)
|
||
|
|
|
||
|
|
(defn- fail-no-kwargs [& args] (apply no-kwargs-fn args))
|
||
|
|
(defn- fail-kwargs [& args] (apply kwargs-fn args))
|
||
|
|
|
||
|
|
(with-feature (kwargs-fn 1 2 {:a 1 :b 2})
|
||
|
|
(deftest test-instrument
|
||
|
|
(testing "that a function taking fixed args and varargs is spec'd and checked at runtime"
|
||
|
|
(letfn [(test-varargs-raw []
|
||
|
|
(are [x y] (= x y)
|
||
|
|
1 (no-kwargs-fn 1)
|
||
|
|
[1 2] (no-kwargs-fn 1 2)
|
||
|
|
[1 2 [3 4 5]] (no-kwargs-fn 1 2 3 4 5)))]
|
||
|
|
(testing "that the raw kwargs function operates as expected"
|
||
|
|
(test-varargs-raw))
|
||
|
|
|
||
|
|
(testing "that the instrumented kwargs function operates as expected"
|
||
|
|
(stest/instrument `no-kwargs-fn {})
|
||
|
|
|
||
|
|
(test-varargs-raw)
|
||
|
|
(is (thrown-with-msg? clojure.lang.ExceptionInfo #"did not conform to spec" (no-kwargs-fn 1 :not-num)))
|
||
|
|
(is (thrown-with-msg? clojure.lang.ExceptionInfo #"did not conform to spec" (no-kwargs-fn 1 2 :not-num 3)))
|
||
|
|
|
||
|
|
#_(testing "that the ex-info data looks correct"
|
||
|
|
(try (fail-no-kwargs 1 :not-num)
|
||
|
|
(catch Exception ei
|
||
|
|
(is (= 'clojure.test-clojure.instr/fail-no-kwargs (-> ei ex-data :clojure.spec.test.alpha/caller :var-scope)))))
|
||
|
|
|
||
|
|
(try (fail-no-kwargs 1 2 :not-num 3)
|
||
|
|
(catch Exception ei
|
||
|
|
(is (= 'clojure.test-clojure.instr/fail-no-kwargs (-> ei ex-data :clojure.spec.test.alpha/caller :var-scope)))))))
|
||
|
|
|
||
|
|
(testing "that the uninstrumented kwargs function operates as the raw function"
|
||
|
|
(stest/unstrument `no-kwargs-fn)
|
||
|
|
(test-varargs-raw))))
|
||
|
|
|
||
|
|
(testing "that a function taking only varargs is spec'd and checked at runtime"
|
||
|
|
(letfn [(test-varargs-raw []
|
||
|
|
(are [x y] (= x y)
|
||
|
|
1 (just-varargs 1)
|
||
|
|
3 (just-varargs 1 2)
|
||
|
|
15 (just-varargs 1 2 3 4 5)))]
|
||
|
|
(testing "that the raw varargs function operates as expected"
|
||
|
|
(test-varargs-raw))
|
||
|
|
|
||
|
|
(testing "that the instrumented varargs function operates as expected"
|
||
|
|
(stest/instrument `just-varargs {})
|
||
|
|
|
||
|
|
(test-varargs-raw)
|
||
|
|
(is (thrown-with-msg? clojure.lang.ExceptionInfo #"did not conform to spec" (just-varargs 1 :not-num)))
|
||
|
|
(is (thrown-with-msg? clojure.lang.ExceptionInfo #"did not conform to spec" (just-varargs 1 2 :not-num 3))))
|
||
|
|
|
||
|
|
(testing "that the uninstrumented kwargs function operates as the raw function"
|
||
|
|
(stest/unstrument `just-varargs)
|
||
|
|
(test-varargs-raw))))
|
||
|
|
|
||
|
|
(testing "that a function taking keyword args is spec'd and checked at runtime"
|
||
|
|
(letfn [(test-kwargs-baseline []
|
||
|
|
(are [x y] (= x y)
|
||
|
|
1 (kwargs-fn 1)
|
||
|
|
[1 2] (kwargs-fn 1 2)
|
||
|
|
[1 2 {:a 1}] (kwargs-fn 1 2 :a 1)
|
||
|
|
[1 2 {:a 1}] (kwargs-fn 1 2 {:a 1})
|
||
|
|
[1 2 {:a 1 :b 2}] (kwargs-fn 1 2 :a 1 {:b 2})))
|
||
|
|
(test-kwargs-extended []
|
||
|
|
(are [x y] (= x y)
|
||
|
|
[1 :not-num] (kwargs-fn 1 :not-num)
|
||
|
|
[1 2 {:a 1 :b :not-num}] (kwargs-fn 1 2 :a 1 {:b :not-num})))]
|
||
|
|
(testing "that the raw kwargs function operates as expected"
|
||
|
|
(test-kwargs-baseline)
|
||
|
|
(test-kwargs-extended))
|
||
|
|
|
||
|
|
(testing "that the instrumented kwargs function operates as expected"
|
||
|
|
(stest/instrument `kwargs-fn {})
|
||
|
|
|
||
|
|
(test-kwargs-baseline)
|
||
|
|
(is (thrown-with-msg? clojure.lang.ExceptionInfo #"did not conform to spec" (kwargs-fn 1 :not-num)))
|
||
|
|
(is (thrown-with-msg? clojure.lang.ExceptionInfo #"did not conform to spec" (kwargs-fn 1 2 :a 1 {:b :not-num})))
|
||
|
|
|
||
|
|
#_(testing "that the ex-info data looks correct"
|
||
|
|
(try (fail-kwargs 1 :not-num)
|
||
|
|
(catch Exception ei
|
||
|
|
(is (= 'clojure.test-clojure.instr/fail-kwargs (-> ei ex-data :clojure.spec.test.alpha/caller :var-scope)))))
|
||
|
|
|
||
|
|
(try (fail-kwargs 1 2 :a 1 {:b :not-num})
|
||
|
|
(catch Exception ei
|
||
|
|
(is (= 'clojure.test-clojure.instr/fail-kwargs (-> ei ex-data :clojure.spec.test.alpha/caller :var-scope)))))))
|
||
|
|
|
||
|
|
(testing "that the uninstrumented kwargs function operates as the raw function"
|
||
|
|
(stest/unstrument `kwargs-fn)
|
||
|
|
(test-kwargs-baseline)
|
||
|
|
(test-kwargs-extended))))
|
||
|
|
|
||
|
|
(testing "that a var with no arglists meta is spec'd and checked at runtime"
|
||
|
|
(stest/instrument `add10 {})
|
||
|
|
(is (= 11 (add10 1)))
|
||
|
|
(is (thrown-with-msg? clojure.lang.ExceptionInfo #"did not conform to spec" (add10 :not-num)))
|
||
|
|
(is (= 11 (add10 1))))
|
||
|
|
|
||
|
|
(testing "that a function with positional destructuring in its parameter list is spec'd and checked at runtime"
|
||
|
|
(stest/instrument `no-kwargs-destruct-fn {})
|
||
|
|
|
||
|
|
(is (= [{:a 1} {}] (no-kwargs-destruct-fn {:a 1} {})))
|
||
|
|
(is (= [{:a 1} 2 [3 4 5]] (no-kwargs-destruct-fn {:a 1} 2 3 4 5))))))
|