|
Java example source code file (spec.clj)
The spec.clj Java example source code
(ns clojure.test-clojure.spec
(:require [clojure.spec :as s]
[clojure.spec.gen :as gen]
[clojure.spec.test :as stest]
[clojure.test :refer :all]))
(set! *warn-on-reflection* true)
(defmacro result-or-ex [x]
`(try
~x
(catch Throwable t#
(.getName (class t#)))))
(def even-count? #(even? (count %)))
(defn submap?
"Is m1 a subset of m2?"
[m1 m2]
(if (and (map? m1) (map? m2))
(every? (fn [[k v]] (and (contains? m2 k)
(submap? v (get m2 k))))
m1)
(= m1 m2)))
(deftest conform-explain
(let [a (s/and #(> % 5) #(< % 10))
o (s/or :s string? :k keyword?)
c (s/cat :a string? :b keyword?)
either (s/alt :a string? :b keyword?)
star (s/* keyword?)
plus (s/+ keyword?)
opt (s/? keyword?)
andre (s/& (s/* keyword?) even-count?)
m (s/map-of keyword? string?)
coll (s/coll-of keyword? [])
lrange (s/int-in 7 42)
drange (s/double-in :infinite? false :NaN? false :min 3.1 :max 3.2)
irange (s/inst-in #inst "1939" #inst "1946")
]
(are [spec x conformed ed]
(let [co (result-or-ex (s/conform spec x))
e (result-or-ex (::s/problems (s/explain-data spec x)))]
(when (not= conformed co) (println "conform fail\n\texpect=" conformed "\n\tactual=" co))
(when (not (submap? ed e)) (println "explain fail\n\texpect=" ed "\n\tactual=" e))
(and (= conformed co) (submap? ed e)))
lrange 7 7 nil
lrange 8 8 nil
lrange 42 ::s/invalid {[] {:pred '(int-in-range? 7 42 %), :val 42, :via [], :in []}}
irange #inst "1938" ::s/invalid {[] {:pred '(inst-in-range? #inst "1939-01-01T00:00:00.000-00:00" #inst "1946-01-01T00:00:00.000-00:00" %), :val #inst "1938", :via [], :in []}}
irange #inst "1942" #inst "1942" nil
irange #inst "1946" ::s/invalid {[] {:pred '(inst-in-range? #inst "1939-01-01T00:00:00.000-00:00" #inst "1946-01-01T00:00:00.000-00:00" %), :val #inst "1946", :via [], :in []}}
drange 3.0 ::s/invalid {[] {:pred '(<= 3.1 %), :val 3.0, :via [], :in []}}
drange 3.1 3.1 nil
drange 3.2 3.2 nil
drange Double/POSITIVE_INFINITY ::s/invalid {[] {:pred '(not (isInfinite %)), :val Double/POSITIVE_INFINITY, :via [], :in []}}
;; can't use equality-based test for Double/NaN
;; drange Double/NaN ::s/invalid {[] {:pred '(not (isNaN %)), :val Double/NaN, :via [], :in []}}
keyword? :k :k nil
keyword? nil ::s/invalid {[] {:pred ::s/unknown :val nil :via []}}
keyword? "abc" ::s/invalid {[] {:pred ::s/unknown :val "abc" :via []}}
a 6 6 nil
a 3 ::s/invalid '{[] {:pred (> % 5), :val 3 :via []}}
a 20 ::s/invalid '{[] {:pred (< % 10), :val 20 :via []}}
a nil "java.lang.NullPointerException" "java.lang.NullPointerException"
a :k "java.lang.ClassCastException" "java.lang.ClassCastException"
o "a" [:s "a"] nil
o :a [:k :a] nil
o 'a ::s/invalid '{[:s] {:pred string?, :val a :via []}, [:k] {:pred keyword?, :val a :via []}}
c nil ::s/invalid '{[:a] {:reason "Insufficient input", :pred string?, :val (), :via []}}
c [] ::s/invalid '{[:a] {:reason "Insufficient input", :pred string?, :val (), :via []}}
c [:a] ::s/invalid '{[:a] {:pred string?, :val :a, :via []}}
c ["a"] ::s/invalid '{[:b] {:reason "Insufficient input", :pred keyword?, :val (), :via []}}
c ["s" :k] '{:a "s" :b :k} nil
c ["s" :k 5] ::s/invalid '{[] {:reason "Extra input", :pred (cat :a string? :b keyword?), :val (5), :via []}}
(s/cat) nil {} nil
(s/cat) [5] ::s/invalid '{[] {:reason "Extra input", :pred (cat), :val (5), :via [], :in [0]}}
either nil ::s/invalid '{[] {:reason "Insufficient input", :pred (alt :a string? :b keyword?), :val () :via []}}
either [] ::s/invalid '{[] {:reason "Insufficient input", :pred (alt :a string? :b keyword?), :val () :via []}}
either [:k] [:b :k] nil
either ["s"] [:a "s"] nil
either [:b "s"] ::s/invalid '{[] {:reason "Extra input", :pred (alt :a string? :b keyword?), :val ("s") :via []}}
star nil [] nil
star [] [] nil
star [:k] [:k] nil
star [:k1 :k2] [:k1 :k2] nil
star [:k1 :k2 "x"] ::s/invalid '{[] {:pred keyword?, :val "x" :via []}}
star ["a"] ::s/invalid {[] '{:pred keyword?, :val "a" :via []}}
plus nil ::s/invalid '{[] {:reason "Insufficient input", :pred keyword?, :val () :via []}}
plus [] ::s/invalid '{[] {:reason "Insufficient input", :pred keyword?, :val () :via []}}
plus [:k] [:k] nil
plus [:k1 :k2] [:k1 :k2] nil
plus [:k1 :k2 "x"] ::s/invalid '{[] {:pred keyword?, :val "x", :via [], :in [2]}}
plus ["a"] ::s/invalid '{[] {:pred keyword?, :val "a" :via []}}
opt nil nil nil
opt [] nil nil
opt :k ::s/invalid '{[] {:pred (? keyword?), :val :k, :via []}}
opt [:k] :k nil
opt [:k1 :k2] ::s/invalid '{[] {:reason "Extra input", :pred (? keyword?), :val (:k2), :via []}}
opt [:k1 :k2 "x"] ::s/invalid '{[] {:reason "Extra input", :pred (? keyword?), :val (:k2 "x"), :via []}}
opt ["a"] ::s/invalid '{[] {:pred keyword?, :val "a", :via []}}
andre nil nil nil
andre [] nil nil
andre :k :clojure.spec/invalid '{[] {:pred (& (* keyword?) even-count?), :val :k, :via []}}
andre [:k] ::s/invalid '{[] {:pred even-count?, :val [:k], :via []}}
andre [:j :k] [:j :k] nil
m nil ::s/invalid '{[] {:pred map?, :val nil, :via []}}
m {} {} nil
m {:a "b"} {:a "b"} nil
coll nil nil nil
coll [] [] nil
coll [:a] [:a] nil
coll [:a :b] [:a :b] nil
;;coll [:a "b"] ::s/invalid '{[] {:pred (coll-checker keyword?), :val [:a b], :via []}}
)))
(s/fdef flip-nums
:args (s/cat :arg1 integer? :arg2 integer?)
:ret vector?
:fn (fn [{:keys [args ret]}]
(= ret [(:arg2 args) (:arg1 args)])))
(def ^:dynamic *break-flip-nums* false)
(defn flip-nums
"Set *break-flip-nums* to break this fns compatibility with
its spec for test purposes."
[a b]
(if *break-flip-nums*
(when-not (= a b)
(vec (sort [a b])))
[b a]))
(defmacro get-ex-data
[x]
`(try
~x
nil
(catch Throwable t#
(ex-data t#))))
;; Note the the complicated equality comparisons below are exactly the
;; kind of thing that spec helps you avoid, used here only because we
;; are near the bottom, testing spec itself.
(deftest test-instrument-flip-nums
(when-not (= "true" (System/getProperty "clojure.compiler.direct-linking"))
(binding [*break-flip-nums* true]
(try
(= [1 2] (flip-nums 2 1))
(= [:a :b] (flip-nums :a :b))
(= [1 2] (flip-nums 1 2))
(is (nil? (flip-nums 1 1)))
(s/instrument `flip-nums)
(is (= [1 2] (flip-nums 2 1)))
(is (submap? '{:clojure.spec/problems {[:args :arg1] {:pred integer?, :val :a, :via []}}, :clojure.spec/args (:a :b)}
(get-ex-data (flip-nums :a :b))))
(is (submap? '{:clojure.spec/problems {[:fn] {:pred (fn [{:keys [args ret]}] (= ret [(:arg2 args) (:arg1 args)])), :val {:args {:arg1 1, :arg2 2}, :ret [1 2]}, :via []}}, :clojure.spec/args (1 2)}
(get-ex-data (flip-nums 1 2))))
(is (submap? '{:clojure.spec/problems {[:ret] {:pred vector?, :val nil, :via []}}, :clojure.spec/args (1 1)}
(get-ex-data (flip-nums 1 1))))
(s/unstrument `flip-nums)
(= [1 2] (flip-nums 2 1))
(= [:a :b] (flip-nums :a :b))
(= [1 2] (flip-nums 1 2))
(is (nil? (flip-nums 1 1)))
(s/unstrument `flip-nums)))))
(def core-pred-syms
(into #{}
(comp (map first) (filter (fn [s] (.endsWith (name s) "?"))))
(ns-publics 'clojure.core)))
(def generatable-core-pred-syms
(into #{}
(filter #(gen/gen-for-pred @ (resolve %)))
core-pred-syms))
(s/fdef generate-from-core-pred
:args (s/cat :s generatable-core-pred-syms)
:ret ::s/any
:fn (fn [{:keys [args ret]}]
(@(resolve (:s args)) ret)))
(defn generate-from-core-pred
[s]
(gen/generate (gen/gen-for-pred @(resolve s))))
(comment
(require '[clojure.test :refer (run-tests)])
(in-ns 'clojure.test-clojure.spec)
(run-tests)
(stest/run-all-tests)
(stest/check-var #'generate-from-core-pred :num-tests 10000)
)
Other Java examples (source code examples)Here is a short list of links related to this Java spec.clj source code file: |
| ... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.