alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (spec.clj)

This example Java source code file (spec.clj) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

double/nan, double/positive_infinity, extra, insufficient, note, set, system/getproperty, throwable

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

 

new blog posts

 

Copyright 1998-2021 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.