Fork me on GitHub
#clojure-spec
<
2019-01-22
>
kenny01:01:15

Is there any way to get more info about why a spec generator is failing? This is the error message:

clojure.lang.ExceptionInfo: Couldn't satisfy such-that predicate after 100 tries. {:pred #object[clojure.spec.alpha$gensub$fn__1876 0x7230d43f "[email protected]"], :gen #clojure.test.check.generators.Generator{:gen #object[clojure.test.check.generators$such_that$fn__45785 0x2ea879fb "[email protected]"]}, :max-tries 100}
Nothing in the stacktrace points to my code. I guess I could go through and individually test all my specs for which failed but in this case the spec is huge and that would be very time consuming.

gfredericks01:01:23

@kenny not an answer to your direct question, but that particular failure is usually caused by an s/and, where one of the non-initial predicates is not likely to happen by chance

gfredericks01:01:36

(or all of them together, more accurately)

kenny01:01:39

Right. There's a lot of those 😞

gfredericks01:01:47

it's a long outstanding issue between spec and test.check; test.check's alphas have a feature in such-that that would let spec report what spec is causing it

gfredericks01:01:59

but spec doesn't use that feature yet afaik

seancorfield01:01:26

It doesn't help you now @kenny but when I'm writing specs, I pretty much always have a (comment ..) form with calls to s/exercise for each of my specs, and I make sure they generate as I'm writing them... for exactly this reason.

kenny01:01:57

I have some decent guesses for the ones that fail but the feature @gfredericks mentioned would significantly improve this experience. Then you could get rid of all those comment blocks @seancorfield😉

kenny01:01:44

Any idea if there's a jira issue for this?

seancorfield01:01:08

I have a lot of Rich Comment Forms in my code 🙂

seancorfield01:01:13

I find they're a good way to keep notes about my thinking as I develop, as well as containing expressions that produce test data and show usage of functions -- and specs 🙂

lmergen13:01:10

what would be the recommend way to do a multi-spec dispatch for some nested map variable ? e.g. let's say that i have this

{:entity/type :user
 :entity/data 
 {:user/id 1234}}
and i want to multi-spec the :entity/data based on the :entity/type ... this seems pretty tricky ?

lmergen13:01:41

because this is not possible, although it's something that i would want:

(s/def :entity/data (s/multi-spec entity-data :entity/type))
(s/def :entity (s/keys :req [:entity/type :entity/data]))

lmergen13:01:35

now i could repeat :entity/type as a property of :entity/data again, but that seems redundant

jeroenvandijk13:01:06

If you really have to, you can use multispec with the dispatch on type. Repeat this for all the different types:

(s/def :your/data any?)


(s/valid?
 (s/coll-of (s/or :type (s/tuple #{:entity/type} #{:user})
                  :data (s/tuple #{:entity/data}
                                 :your/data))
            :kind map?)
 {:entity/type :user
  :entity/data :foo})

jeroenvandijk13:01:36

If you control the design of the data, but i guess you dont, there is probably a better way more in line with clojure.spec

lmergen14:01:26

🤔 not sure whether this is brilliant or evil

lmergen14:01:33

it works though

lmergen14:01:08

how would you redesign the data ? lift the data inside :entity/data into the parent map so that multispec works ?

lmergen14:01:08

how would you redesign the data ? lift the data inside :entity/data into the parent map so that multispec works ?

jeroenvandijk21:01:14

yeah sorry for giving the evil hack 🙂 Changing the data will make it much cleaner. And using multispec for example gives you very nice specific validation errors e.g. when using it with expound

lmergen22:01:00

yes thanks a lot, your comment was helpful!

jeroenvandijk23:01:47

btw, not using a namespaced keyword, so :data instead of :entity/data could also be used as a fix instead of lifting the data inside. You would use s/keys with :req-un instead of :req

lmergen14:01:01

actually that makes a lot of sense

misha19:01:07

qualified keywords allow you to have a mix of "unrelated" keys in a flat map

lmergen20:01:31

yes, it is obvious that I was doing this wrong

lmergen20:01:44

makes a lot of sense