clojureclojure.spectest.check

Clojure spec - s/or single branch generator


Is it possible to override a default spec generator so that data is always generated only for a single branch of the s/or composite spec?

(s/def ::x
  (s/or :x-a nat-int?
        :x-b string?))

(gen/sample (s/gen ::x))
;; generate strings only

Solution

  • You can use s/with-gen to supply a custom generator:

    (s/def ::x
      (s/with-gen
        (s/or :x-a nat-int?
              :x-b string?)
        #(s/gen string?)))
    
    (gen/sample (s/gen ::x))
    => ("" "j" "e" "Jmi" "" "d" "bc" "ul" "H65P0ni" "OEDK")
    

    You could also use it only where you're sampling, without modifying the base ::x spec:

    (gen/sample (s/gen (s/with-gen ::x #(s/gen string?))))
    

    There are other spec functions that accept a map of overrides for the same purpose, e.g. s/exercise:

    (s/exercise ::x 10 {::x #(s/gen string?)})
    =>
    (["" [:x-b ""]]
     ["" [:x-b ""]]
     ["" [:x-b ""]]
     ["" [:x-b ""]]
     ["13R0" [:x-b "13R0"]]
     ["7cT30" [:x-b "7cT30"]]
     ["uia0b" [:x-b "uia0b"]]
     ["" [:x-b ""]]
     ["bP" [:x-b "bP"]]
     ["4k2t6bW" [:x-b "4k2t6bW"]])