Start test.check
tests on vector instructions
This is a start on using `test.check` to write tests for the vector instructions. We currently have tests for: * `vector/_emptyvector` * `vector/_indexof` * `vector/_subvec` There are _lots_ of other functions still to be tested. This did reveal errors in `vector/_subvec`, which will be addressed in the next commit. We used macros to make it easy to generate tests for each of the four vector types; this should be extensible to additional vector types in the future if needed.
This commit is contained in:
parent
a6e195eb0e
commit
d1e863a23a
@ -4,6 +4,7 @@
|
||||
:license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
|
||||
:url "https://www.eclipse.org/legal/epl-2.0/"}
|
||||
:dependencies [[org.clojure/clojure "1.10.0"]
|
||||
[org.clojure/clojurescript "1.9.946"]]
|
||||
[org.clojure/clojurescript "1.9.946"]
|
||||
[org.clojure/test.check "1.1.0"]]
|
||||
:main ^:skip-aot propeller.core
|
||||
:repl-options {:init-ns propeller.core})
|
||||
|
112
test/propeller/push/instructions/vector_spec.clj
Normal file
112
test/propeller/push/instructions/vector_spec.clj
Normal file
@ -0,0 +1,112 @@
|
||||
(ns propeller.push.instructions.vector-spec
|
||||
(:require
|
||||
[clojure.test.check.generators :as gen]
|
||||
[clojure.test.check.properties :as prop]
|
||||
[clojure.test.check.clojure-test :as ct :refer [defspec]]
|
||||
[propeller.push.state :as state]
|
||||
[propeller.push.instructions.vector :as vector]))
|
||||
|
||||
(defn check-empty-vector
|
||||
[generator value-type]
|
||||
(let [stack-type (keyword (str "vector_" value-type))]
|
||||
(prop/for-all [vect (gen/vector generator)]
|
||||
(let [start-state (state/push-to-stack state/empty-state
|
||||
stack-type
|
||||
vect)
|
||||
end-state (vector/_emptyvector stack-type start-state)]
|
||||
(= (empty? vect)
|
||||
(state/peek-stack end-state :boolean))))))
|
||||
|
||||
(defmacro empty-vector-spec
|
||||
[generator value-type]
|
||||
`(defspec ~(symbol (str "empty-vector-spec-" value-type))
|
||||
100
|
||||
(check-empty-vector ~generator ~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")
|
||||
|
||||
(defn check-expected-index
|
||||
"Creates an otherwise empty Push state with the given vector on the
|
||||
appropriate vector stack (assumed to be :vector_<value-type>), and
|
||||
the given value on the appropriate stack (determined by value-type).
|
||||
It then runs the vector/_indexof instruction, and confirms that the
|
||||
result (on the :integer stack) is the expected value."
|
||||
[vect value value-type]
|
||||
(let [stack-type (keyword (str "vector_" value-type))
|
||||
start-state (state/push-to-stack
|
||||
(state/push-to-stack state/empty-state
|
||||
stack-type
|
||||
vect)
|
||||
(keyword value-type) value)
|
||||
end-state (vector/_indexof stack-type start-state)
|
||||
expected-index (.indexOf vect value)]
|
||||
(= expected-index
|
||||
(state/peek-stack end-state :integer))))
|
||||
|
||||
(defmacro indexof-spec
|
||||
[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")
|
||||
|
||||
(defn clean-subvec-bounds
|
||||
[start stop vect-size]
|
||||
(let [start (max 0 start)
|
||||
stop (max 0 stop)
|
||||
start (min start vect-size)
|
||||
stop (min stop vect-size)
|
||||
stop (max start stop)]
|
||||
[start stop]))
|
||||
|
||||
(defn check-subvec
|
||||
"Creates an otherwise empty Push state with the given vector on the
|
||||
appropriate vector stack (assumed to be :vector_<value-type>), and
|
||||
the given values on the integer stack.
|
||||
It then runs the vector/_subvec instruction, and confirms that the
|
||||
result (on the :vector_<value-type> stack) is the expected value."
|
||||
[vect start stop value-type]
|
||||
(let [stack-type (keyword (str "vector_" value-type))
|
||||
start-state (state/push-to-stack
|
||||
(state/push-to-stack
|
||||
(state/push-to-stack state/empty-state
|
||||
stack-type
|
||||
vect)
|
||||
:integer start)
|
||||
:integer stop)
|
||||
end-state (vector/_subvec stack-type start-state)
|
||||
[cleaned-start cleaned-stop] (clean-subvec-bounds start stop (count vect))
|
||||
expected-subvec (subvec vect cleaned-start cleaned-stop)]
|
||||
(= expected-subvec
|
||||
(state/peek-stack end-state stack-type))))
|
||||
|
||||
(defmacro subvec-spec
|
||||
[generator value-type]
|
||||
`(defspec ~(symbol (str "subvec-spec-" value-type))
|
||||
(prop/for-all [vect# (gen/vector ~generator)
|
||||
start# gen/small-integer
|
||||
stop# gen/small-integer]
|
||||
(check-subvec vect# start# stop# ~value-type))))
|
||||
|
||||
(subvec-spec gen/small-integer "integer")
|
||||
(subvec-spec gen/double "float")
|
||||
(subvec-spec gen/boolean "boolean")
|
||||
(subvec-spec gen/string "string")
|
Loading…
x
Reference in New Issue
Block a user