UP | HOME

Clojure Spec with Expectations.
Expectations와 Clojure Spec.

I use clojure.spec to verify the read data. and I test the spec using Expectations as following: (latest version: https://gitlab.com/snippets/1638290)

(ns expectations.ext
  (:require #?(:cljs [cljs.js :as cljs])
	    #?(:clj  [clojure.spec :as s]
	       :cljs [cljs.spec :as s])
	    [clojure.string :as str]
	    [expectations :refer [CustomPred]]))

#?(:cljs
   (defn eval
     [form]
     (let [ret   (atom nil)
	   state (cljs/empty-state)
	   opt   {:eval cljs/js-eval :context :expr}]
       (cljs/eval state form opt #(reset! ret (:value %)))
       @ret)))

(defrecord SpecPred [ret-fn spec]
  CustomPred
  (expect-fn [_ arg]
    (ret-fn (s/valid? spec arg)))

  (expected-message [_ arg _ _])
  (actual-message   [_ arg _ _])
  (message [_ arg _ _]
    (->> (for [edata (::s/problems (s/explain-data spec arg))]
	   (let [pred    (:pred edata)
		 pred-fn
		 (cond-> pred
		   (seq? pred)
		   (->> (list)
			(concat (->> pred
				     (filter #(and (symbol? %)
						   (str/starts-with? (name %) "%")))
				     (vec)
				     (list 'fn)))
			(eval)))
		 val (:val edata)]
	     (str "Invalid spec: " (:via edata) ", "
		  "(" (cond->> (pr-str pred) (seq? pred) (str "#"))
		  " " (pr-str val) ")"
		  " => " (pr-str (pred-fn val)))))
	 (interpose "\n\n           ")
	 (apply str))))

(defn spec
  [spec]
  (->SpecPred identity spec))

(defn spec:failure
  [spec]
  (->SpecPred complement spec))

<2017-03-02 Thu>: udpate.