(str (js/Date.))
              
	    

Open this presentation in your computer for a collaborative live coding session: http://slides.klipse.tech/clojure-spec-cr17/part1.html#slide-3
(It works also on mobile)
The interactive code snippets are powered by KLIPSE. 🤗
	    (map inc [1 2 3])
	 
      For the upcoming parts, we need to require two additional namespaces
(ns my.playground
  (:require [clojure.test.check :as tc ]
            [clojure.test.check.generators]
            [clojure.test.check.properties :as prop :include-macros true]
            [clojure.spec.alpha :as s]
            [clojure.spec.test.alpha :as stest]
            [clojure.spec.gen.alpha :as gen])) 
	
	We can generate data samples out of our specs:
	    (s/def ::big-integer (s/and integer?
            #(> % 1000000)))
	    (s/def ::short-string (s/and string?
            #(< (count %) 5)))
		(s/def ::big-integer-or-short-string (s/or :int ::big-integer
		:str ::short-string))
		
	Either with gen/sample:
	      (gen/sample (s/gen ::big-integer) 5)
	  
	Or with s/exercise:
	      (s/exercise ::big-integer-or-short-string 5)
	  
	Why do we need to specify optional keys in a map?
	      (gen/sample (s/gen (s/keys :req [::big-integer])) 5)
	  
	
	      (gen/sample (s/gen (s/keys :req [::big-integer] :opt [::short-string])) 5)
	  
	You can describe the shape of the args and return value of your functions
Let's imagine we have an addition function where the result is bounded:
	(defn bounded-addition [a b {:keys [upper lower]}]
  (cond-> (+ a b)
    lower (max lower)
    upper (min upper)))
    Here are the initial specifications of our function:
	  (s/def ::upper number?)
	  (s/def ::lower number?)
	  (s/fdef bounded-addition
          :args (s/cat :a number? :b number? :boundaries (s/keys :req-un [::upper ::lower])))
      
    What happens when one passes the wrong arguments?
	  (stest/instrument `bounded-addition)
	  (bounded-addition 1 2 {})
      
     You can instrument and unstrument:
	  (stest/unstrument `bounded-addition)
	  (bounded-addition 1 2 {})
      
    What is the default - instrument or unstrument?
    
Let's check how our function behaves with valid random arguments
	  (s/exercise-fn bounded-addition)
      
    We can also specify:
Let's imagine we have a multiplication function where the result is bounded:
	    (defn bounded-multiplication [a b {:keys [upper lower]}]
	    (-> (* a b)
	    #_(max lower)
	    #_(min upper)))
	
      Here are the full specifications of our function:
	    (s/def ::upper number?)
	    (s/def ::lower number?)
	    (s/fdef bounded-multiplication
            :args (s/and (s/cat :a number? :b number? :boundaries (s/keys :req-un [::upper ::lower]))
            #(>= (-> % :boundaries :upper) (-> % :boundaries :lower)))
            :ret number?
            :fn #(<= (-> % :args :boundaries :lower) (:ret %) (-> % :args :boundaries :upper)))
	
      Let's test our function (Test generation for free!):
(-> (stest/check `bounded-multiplication {::tc/opts {:num-tests 10}})   
  first
  stest/abbrev-result)  
	
      What do you think about this amazing stuff?

      powered by KLIPSE /