Use new gen-specs
macro for other test cases
This moved the new `gen-specs` macro to the top of the file, and uses it to simplify the generation for the existing specifications. This allowed us to remove quite a lot of code. We also had to change the order of arguments for all the "old" check functions so that `value-type` comes first. We renamed a few check functions so the naming is more consistent.
This commit is contained in:
parent
d30f7c195e
commit
957af4fc06
@ -12,15 +12,45 @@
|
|||||||
['gen/boolean "boolean"]
|
['gen/boolean "boolean"]
|
||||||
['gen/string "string"]])
|
['gen/string "string"]])
|
||||||
|
|
||||||
|
(defn generator-for-arg-type
|
||||||
|
[arg-type generator]
|
||||||
|
(case arg-type
|
||||||
|
:boolean 'gen/boolean
|
||||||
|
:integer 'gen/small-integer
|
||||||
|
:float 'gen/double
|
||||||
|
:string 'gen/string
|
||||||
|
; This is for "generic" vectors where the element is provided by
|
||||||
|
; the `generator` argument.
|
||||||
|
:vector `(gen/vector ~generator)
|
||||||
|
:item generator
|
||||||
|
:vector_boolean '(gen/vector gen/boolean)
|
||||||
|
:vector_integer '(gen/vector gen/small-integer)
|
||||||
|
:vector_float '(gen/vector gen/double)
|
||||||
|
:vector_string '(gen/vector gen/string)))
|
||||||
|
|
||||||
|
(defmacro gen-specs
|
||||||
|
[spec-name check-fn & arg-types]
|
||||||
|
(let [symbol-names (repeatedly (count arg-types) gensym)]
|
||||||
|
`(do ~@(for [[generator value-type] gen-type-pairs
|
||||||
|
:let [name (symbol (str spec-name "-spec-" value-type))]]
|
||||||
|
`(defspec ~name
|
||||||
|
(prop/for-all
|
||||||
|
[~@(mapcat
|
||||||
|
(fn [symbol-name arg-type]
|
||||||
|
[symbol-name (generator-for-arg-type arg-type generator)])
|
||||||
|
symbol-names
|
||||||
|
arg-types)]
|
||||||
|
(~check-fn ~value-type ~@symbol-names)))))))
|
||||||
|
|
||||||
;;; vector/_contains
|
;;; vector/_contains
|
||||||
|
|
||||||
(defn check-expected-contains
|
(defn check-contains
|
||||||
"Creates an otherwise empty Push state with the given vector on the
|
"Creates an otherwise empty Push state with the given vector on the
|
||||||
appropriate vector stack (assumed to be :vector_<value-type>), and
|
appropriate vector stack (assumed to be :vector_<value-type>), and
|
||||||
the given value on the appropriate stack (determined by value-type).
|
the given value on the appropriate stack (determined by value-type).
|
||||||
It then runs the vector/_contains instruction, and confirms that the
|
It then runs the vector/_contains instruction, and confirms that the
|
||||||
result (on the :boolean stack) is the expected value."
|
result (on the :boolean stack) is the expected value."
|
||||||
[vect value value-type]
|
[value-type vect value]
|
||||||
(let [stack-type (keyword (str "vector_" value-type))
|
(let [stack-type (keyword (str "vector_" value-type))
|
||||||
start-state (state/push-to-stack
|
start-state (state/push-to-stack
|
||||||
(state/push-to-stack state/empty-state
|
(state/push-to-stack state/empty-state
|
||||||
@ -28,36 +58,16 @@
|
|||||||
vect)
|
vect)
|
||||||
(keyword value-type) value)
|
(keyword value-type) value)
|
||||||
end-state (vector/_contains stack-type start-state)
|
end-state (vector/_contains stack-type start-state)
|
||||||
expected-result (not (= (.indexOf vect value) -1))]
|
expected-result (not= (.indexOf vect value) -1)]
|
||||||
(= expected-result
|
(= expected-result
|
||||||
(state/peek-stack end-state :boolean))))
|
(state/peek-stack end-state :boolean))))
|
||||||
|
|
||||||
(defmacro contains-vector-spec
|
(gen-specs "contains" check-contains :vector :item)
|
||||||
[generator value-type]
|
|
||||||
`(do
|
|
||||||
(defspec ~(symbol (str "contains-vector-spec-" value-type))
|
|
||||||
; Should this be smaller for booleans? (Ditto for below.)
|
|
||||||
100
|
|
||||||
(prop/for-all [vect# (gen/vector ~generator)
|
|
||||||
value# ~generator]
|
|
||||||
(check-expected-contains vect# value# ~value-type)))
|
|
||||||
; For float and string vectors, it's rather rare to actually have a random value that
|
|
||||||
; appears in the vector, so we don't consistently test the case where it should
|
|
||||||
; return TRUE. So maybe we do need a separate test for those?
|
|
||||||
(defspec ~(symbol (str "contains-vector-spec-has-value-" value-type))
|
|
||||||
100
|
|
||||||
(prop/for-all [vect# (gen/not-empty (gen/vector ~generator))]
|
|
||||||
(check-expected-contains vect# (rand-nth vect#) ~value-type)))))
|
|
||||||
|
|
||||||
(contains-vector-spec gen/small-integer "integer")
|
|
||||||
(contains-vector-spec gen/double "float")
|
|
||||||
(contains-vector-spec gen/boolean "boolean")
|
|
||||||
(contains-vector-spec gen/string "string")
|
|
||||||
|
|
||||||
;;; vector/_emptyvector
|
;;; vector/_emptyvector
|
||||||
|
|
||||||
(defn check-empty-vector
|
(defn check-empty-vector
|
||||||
[vect value-type]
|
[value-type vect]
|
||||||
(let [stack-type (keyword (str "vector_" value-type))
|
(let [stack-type (keyword (str "vector_" value-type))
|
||||||
start-state (state/push-to-stack state/empty-state
|
start-state (state/push-to-stack state/empty-state
|
||||||
stack-type
|
stack-type
|
||||||
@ -66,22 +76,12 @@
|
|||||||
(= (empty? vect)
|
(= (empty? vect)
|
||||||
(state/peek-stack end-state :boolean))))
|
(state/peek-stack end-state :boolean))))
|
||||||
|
|
||||||
(defmacro empty-vector-spec
|
(gen-specs "empty-vector" check-empty-vector :vector)
|
||||||
[generator value-type]
|
|
||||||
`(defspec ~(symbol (str "empty-vector-spec-" value-type))
|
|
||||||
100
|
|
||||||
(prop/for-all [vect# (gen/vector ~generator)]
|
|
||||||
(check-empty-vector vect# ~value-type))))
|
|
||||||
|
|
||||||
(empty-vector-spec gen/small-integer "integer")
|
|
||||||
(empty-vector-spec gen/double "float")
|
|
||||||
(empty-vector-spec gen/boolean "boolean")
|
|
||||||
(empty-vector-spec gen/string "string")
|
|
||||||
|
|
||||||
;;; vector/_first
|
;;; vector/_first
|
||||||
|
|
||||||
(defn check-first
|
(defn check-first
|
||||||
[vect value-type]
|
[value-type vect]
|
||||||
(let [stack-type (keyword (str "vector_" value-type))
|
(let [stack-type (keyword (str "vector_" value-type))
|
||||||
start-state (state/push-to-stack state/empty-state
|
start-state (state/push-to-stack state/empty-state
|
||||||
stack-type
|
stack-type
|
||||||
@ -96,22 +96,12 @@
|
|||||||
(state/peek-stack end-state (keyword value-type)))
|
(state/peek-stack end-state (keyword value-type)))
|
||||||
(state/empty-stack? end-state stack-type)))))
|
(state/empty-stack? end-state stack-type)))))
|
||||||
|
|
||||||
(defmacro first-spec
|
(gen-specs "first" check-first :vector)
|
||||||
[generator value-type]
|
|
||||||
`(defspec ~(symbol (str "first-spec-" value-type))
|
|
||||||
100
|
|
||||||
(prop/for-all [vect# (gen/vector ~generator)]
|
|
||||||
(check-first vect# ~value-type))))
|
|
||||||
|
|
||||||
(first-spec gen/small-integer "integer")
|
|
||||||
(first-spec gen/double "float")
|
|
||||||
(first-spec gen/boolean "boolean")
|
|
||||||
(first-spec gen/string "string")
|
|
||||||
|
|
||||||
;;; vector/_last
|
;;; vector/_last
|
||||||
|
|
||||||
(defn check-last
|
(defn check-last
|
||||||
[vect value-type]
|
[value-type vect]
|
||||||
(let [stack-type (keyword (str "vector_" value-type))
|
(let [stack-type (keyword (str "vector_" value-type))
|
||||||
start-state (state/push-to-stack state/empty-state
|
start-state (state/push-to-stack state/empty-state
|
||||||
stack-type
|
stack-type
|
||||||
@ -126,27 +116,17 @@
|
|||||||
(state/peek-stack end-state (keyword value-type)))
|
(state/peek-stack end-state (keyword value-type)))
|
||||||
(state/empty-stack? end-state stack-type)))))
|
(state/empty-stack? end-state stack-type)))))
|
||||||
|
|
||||||
(defmacro last-spec
|
(gen-specs "last" check-last :vector)
|
||||||
[generator value-type]
|
|
||||||
`(defspec ~(symbol (str "last-spec-" value-type))
|
|
||||||
100
|
|
||||||
(prop/for-all [vect# (gen/vector ~generator)]
|
|
||||||
(check-last vect# ~value-type))))
|
|
||||||
|
|
||||||
(last-spec gen/small-integer "integer")
|
|
||||||
(last-spec gen/double "float")
|
|
||||||
(last-spec gen/boolean "boolean")
|
|
||||||
(last-spec gen/string "string")
|
|
||||||
|
|
||||||
;;; vector/_indexof
|
;;; vector/_indexof
|
||||||
|
|
||||||
(defn check-expected-index
|
(defn check-indexof
|
||||||
"Creates an otherwise empty Push state with the given vector on the
|
"Creates an otherwise empty Push state with the given vector on the
|
||||||
appropriate vector stack (assumed to be :vector_<value-type>), and
|
appropriate vector stack (assumed to be :vector_<value-type>), and
|
||||||
the given value on the appropriate stack (determined by value-type).
|
the given value on the appropriate stack (determined by value-type).
|
||||||
It then runs the vector/_indexof instruction, and confirms that the
|
It then runs the vector/_indexof instruction, and confirms that the
|
||||||
result (on the :integer stack) is the expected value."
|
result (on the :integer stack) is the expected value."
|
||||||
[vect value value-type]
|
[value-type vect value]
|
||||||
(let [stack-type (keyword (str "vector_" value-type))
|
(let [stack-type (keyword (str "vector_" value-type))
|
||||||
start-state (state/push-to-stack
|
start-state (state/push-to-stack
|
||||||
(state/push-to-stack state/empty-state
|
(state/push-to-stack state/empty-state
|
||||||
@ -158,27 +138,7 @@
|
|||||||
(= expected-index
|
(= expected-index
|
||||||
(state/peek-stack end-state :integer))))
|
(state/peek-stack end-state :integer))))
|
||||||
|
|
||||||
(defmacro indexof-spec
|
(gen-specs "indexof" check-indexof :vector :item)
|
||||||
[generator value-type]
|
|
||||||
`(do
|
|
||||||
(defspec ~(symbol (str "indexof-spec-" value-type))
|
|
||||||
; Should this be smaller for booleans? (Ditto for below.)
|
|
||||||
100
|
|
||||||
(prop/for-all [vect# (gen/vector ~generator)
|
|
||||||
value# ~generator]
|
|
||||||
(check-expected-index vect# value# ~value-type)))
|
|
||||||
; For float and string vectors, it's rather rare to actually have a random value that
|
|
||||||
; appears in the vector, so we don't consistently test the case where it should
|
|
||||||
; return -1. So maybe we do need a separate test for those?
|
|
||||||
(defspec ~(symbol (str "indexof-spec-has-value-" value-type))
|
|
||||||
100
|
|
||||||
(prop/for-all [vect# (gen/not-empty (gen/vector ~generator))]
|
|
||||||
(check-expected-index vect# (rand-nth vect#) ~value-type)))))
|
|
||||||
|
|
||||||
(indexof-spec gen/small-integer "integer")
|
|
||||||
(indexof-spec gen/double "float")
|
|
||||||
(indexof-spec gen/boolean "boolean")
|
|
||||||
(indexof-spec gen/string "string")
|
|
||||||
|
|
||||||
;;; vector/_concat
|
;;; vector/_concat
|
||||||
|
|
||||||
@ -201,16 +161,7 @@
|
|||||||
(= (concat second-vect first-vect)
|
(= (concat second-vect first-vect)
|
||||||
(state/peek-stack end-state stack-type))))
|
(state/peek-stack end-state stack-type))))
|
||||||
|
|
||||||
(defmacro concat-spec
|
(gen-specs "concat" check-concat :vector :vector)
|
||||||
[]
|
|
||||||
`(do ~@(for [[generator value-type] gen-type-pairs
|
|
||||||
:let [name (symbol (str "concat-spec-" value-type))]]
|
|
||||||
`(defspec ~name
|
|
||||||
(prop/for-all [first-vect# (gen/vector ~generator)
|
|
||||||
second-vect# (gen/vector ~generator)]
|
|
||||||
(check-concat first-vect# second-vect# ~value-type))))))
|
|
||||||
|
|
||||||
; (concat-spec)
|
|
||||||
|
|
||||||
;;; vector/_subvec
|
;;; vector/_subvec
|
||||||
|
|
||||||
@ -244,47 +195,4 @@
|
|||||||
(= expected-subvec
|
(= expected-subvec
|
||||||
(state/peek-stack end-state stack-type))))
|
(state/peek-stack end-state stack-type))))
|
||||||
|
|
||||||
(defmacro subvec-spec
|
|
||||||
[]
|
|
||||||
`(do ~@(for [[generator value-type] gen-type-pairs
|
|
||||||
:let [name (symbol (str "subvec-spec-" value-type))]]
|
|
||||||
`(defspec ~name
|
|
||||||
(prop/for-all [vect# (gen/vector ~generator)
|
|
||||||
start# gen/small-integer
|
|
||||||
stop# gen/small-integer]
|
|
||||||
(check-subvec vect# start# stop# ~value-type))))))
|
|
||||||
|
|
||||||
; (subvec-spec)
|
|
||||||
|
|
||||||
(defn generator-for-arg-type
|
|
||||||
[arg-type generator]
|
|
||||||
(case arg-type
|
|
||||||
:boolean 'gen/boolean
|
|
||||||
:integer 'gen/small-integer
|
|
||||||
:float 'gen/double
|
|
||||||
:string 'gen/string
|
|
||||||
; This is for "generic" vectors where the element is provided by
|
|
||||||
; the `generator` argument.
|
|
||||||
:vector `(gen/vector ~generator)
|
|
||||||
:vector_boolean '(gen/vector gen/boolean)
|
|
||||||
:vector_integer '(gen/vector gen/small-integer)
|
|
||||||
:vector_float '(gen/vector gen/double)
|
|
||||||
:vector_string '(gen/vector gen/string)
|
|
||||||
))
|
|
||||||
|
|
||||||
(defmacro gen-specs
|
|
||||||
[spec-name check-fn & arg-types]
|
|
||||||
(let [symbol-names (repeatedly (count arg-types) gensym)]
|
|
||||||
`(do ~@(for [[generator value-type] gen-type-pairs
|
|
||||||
:let [name (symbol (str spec-name "-spec-" value-type))]]
|
|
||||||
`(defspec ~name
|
|
||||||
(prop/for-all
|
|
||||||
[~@(mapcat
|
|
||||||
(fn [symbol-name arg-type]
|
|
||||||
[symbol-name (generator-for-arg-type arg-type generator)])
|
|
||||||
symbol-names
|
|
||||||
arg-types) ]
|
|
||||||
(~check-fn ~value-type ~@symbol-names)))))))
|
|
||||||
|
|
||||||
(gen-specs "concat" check-concat :vector :vector)
|
|
||||||
(gen-specs "subvec" check-subvec :vector :integer :integer)
|
(gen-specs "subvec" check-subvec :vector :integer :integer)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user