88 lines
3.5 KiB
Clojure
88 lines
3.5 KiB
Clojure
(ns core.demo
|
|
(:require [clojure.test.check :as tc]
|
|
[clojure.spec.alpha :as spec]
|
|
[clojure.spec.test.alpha :as stest]
|
|
[clojure.test.check.properties :as prop]
|
|
[clojure.test.check.generators :as gen]))
|
|
|
|
;; We can define new specs with spec/def often aliased as s/def, this takes a namespace's keyword and a spec
|
|
;; there are a lot of built in specs like int? pos-int? string? etc you can also use sets
|
|
(spec/def ::id pos-int?)
|
|
(spec/def ::username string?)
|
|
(spec/def ::age (spec/int-in 0 100))
|
|
;; example namespaced version the above is namespaced to core.demo, this is a set of allowed characters
|
|
(spec/def :core/hex-digit #{"0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "A" "B" "C" "D" "E" "F"})
|
|
|
|
;; Check if a value conforms to a spec
|
|
(spec/valid? ::id "ABC-123")
|
|
(spec/valid? ::id 4)
|
|
(spec/valid? ::age 99)
|
|
(spec/valid? ::age 101)
|
|
|
|
;; we can create more custom specs like a html hex colour code, there is no built in so we
|
|
;; need a custom generator in this situation, we create a function that can generate the data
|
|
|
|
(spec/def ::demo (spec/spec string? :gen (fn [] (gen/return "123"))))
|
|
|
|
;; usually nicer to make a custom function, the blow fn create a vector of 6 hex characters
|
|
;; converts it into a string and append # to the beginning
|
|
(defn gen-hex-colour []
|
|
(gen/fmap #(str "#" (apply str %)) (gen/vector (spec/gen :core/hex-digit) 6)))
|
|
|
|
;; define the colour spec it has to pass the regex below, string? would never generate the correct Combination
|
|
;; so we supply a way of generating the data
|
|
(spec/def :core/hex-colour
|
|
(spec/spec
|
|
(spec/and string? #(re-matches #"^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$" %))
|
|
:gen gen-hex-colour))
|
|
|
|
|
|
;; we can also spec out hash maps, this is very useful when dealing with json api's
|
|
;; we can fake a response data set but also validate the real response to catch changes at the edges of our code
|
|
(spec/def ::user
|
|
(spec/keys :req-un [::id ::username]
|
|
:opt-un [::age]))
|
|
|
|
|
|
;; We can also tests functions by defining the inputs and outputs to the functions and using gen/exercise to repeatedly send data.
|
|
;; here we are making sure an integer goes in and an integer always comes out
|
|
;; if nil or some other type is returned stest/check will fail
|
|
(spec/fdef demo-function
|
|
:args (spec/cat :value int?)
|
|
:ret int?)
|
|
|
|
(defn demo-function [value] (+ 5 value))
|
|
|
|
(stest/instrument `demo-function)
|
|
(stest/check `demo-function)
|
|
|
|
;; to generate a single value we use generate we can also use sample to get a list of values
|
|
(gen/generate (spec/gen ::id))
|
|
(gen/generate (spec/gen ::age))
|
|
(gen/generate (spec/gen ::user))
|
|
(gen/sample (spec/gen ::user))
|
|
(gen/sample (spec/gen ::id))
|
|
(gen/sample (spec/gen ::username))
|
|
(gen/sample (spec/gen ::age))
|
|
(gen/sample (spec/gen :core/hex-colour))
|
|
|
|
|
|
;; Bonus simple spec that you can use to insert dummy data into the demo datascript example
|
|
(spec/def :user/name string?)
|
|
(spec/def :room/name string?)
|
|
(spec/def :room/link string?)
|
|
(spec/def :room/description string?)
|
|
(spec/def :datalog/room (spec/keys
|
|
:req [:room/name]
|
|
:opt [:room/link :room/description]))
|
|
(spec/def :user/rooms (spec/coll-of :datalog/room :kind vector?))
|
|
|
|
(spec/def :datalog/user (spec/keys :req [:user/name]
|
|
:opt [:user/rooms]))
|
|
(gen/sample (spec/gen :datalog/user))
|
|
(def datalog-data (gen/sample (spec/gen :datalog/user)))
|
|
|
|
;; we can just generate a sample straight into the datalog transact function like below
|
|
;;(d/transact! conn (gen/sample (spec/gen :datalog/user)))
|
|
|