Fork me on GitHub
#clojure-spec
<
2018-04-02
>
avi20:04:27

👋 hi all! I’m having some trouble with a function spec with a :fn predicate… and my Web-searching has turned up nothing. I’m using stest/check like so: (-> (stest/check 'fc4c.core/shrink) first stest/abbrev-result) wherein fc4c.core/shrink is my function that has an attached spec. I always get a failure, but… if I grab the value of :val from the result, and then manually pass it to my predicate, like so: (pred val) then I always get true. So am I missing something? I thought that if the predicate returns true, then the value conforms… I’m confused! Thanks!

seancorfield20:04:47

@aviflax We'll need to see a bit more code in order to help you...

avi20:04:01

yeah? I’m happy to share more code, but I think I’m trying to just confirm an invariant about stest/check and function specs… that if the :fn predicate returns true then the “test case” will be considered to have succeeded… does that make sense? Or am I thinking about this wrong?

taylor20:04:32

are you sure it’s failing due to the :fn spec? could it be failing on the :ret spec?

avi20:04:48

I’m fairly sure but the output of check failures is somewhat overwhelming, even when abbreviated with abbrev-result … I’ll double-check right now

avi20:04:12

Here’s a chunk of the output:

:failure
 {:clojure.spec.alpha/problems
  [{:path [:fn],
    :pred
    (clojure.core/fn

taylor20:04:41

I see one issue that’s not directly related to the spec, but shrink doesn’t return a map when given a map, which looks like an expectation

avi20:04:16

Thanks for the help! I’m a little confused… I don’t see that. If I dig the value of :ret out of the value of :val — I see a map.

avi20:04:42

So it looks like shrink returned a map when check called it?

taylor20:04:02

actually disregard, I copy/pasted your code poorly

avi20:04:13

ah ok no worries! happens to us all!

taylor20:04:08

I was just able to successfully check the function when I replaced the :args and :ret spec:

:args (s/cat :in map?)
        :ret (s/nilable map?)

taylor20:04:36

since the shrink function is more general/doesn’t need to know about your :diagram spec

taylor20:04:05

but… I did try running your :fn spec function against that sample and it does return true, so not sure what’s up with that

avi20:04:18

that makes sense… thanks for the help!

seancorfield20:04:18

@aviflax I notice you're post-walking the tree -- are you aware of the bug in postwalk where MapEntry elements are not preserved?

avi20:04:37

no, I wasn’t aware of that

avi20:04:48

I guess I can search the Web to find more info on that

taylor20:04:14

that doesn’t seem to be the big issue here

avi20:04:38

But I’m not sure how that helps me understand the “contract” of fn predicates… my predicate is returning true so I just don’t understand why a failure is being reported

taylor20:04:11

maybe dumb question, but have you tried restarting your REPL if you’ve been working on this for a while?

avi20:04:30

not dumb!

avi20:04:34

yes, more than a few times

avi20:04:13

:thinking_face: maybe there’s a problem with the name shrink … maybe … that’s somehow confusing check since it internally does shrinking (seems like a long shot)

seancorfield20:04:15

Why not test it with a much simpler :fn predicate that is (constantly true) and see if it still fails?

avi20:04:29

hm ok good idea I’ll try that!

seancorfield20:04:01

If that works (passes) then build the predicate up, piece by piece until you get a failure.

taylor20:04:46

his :fn spec predicate does return true if you manually call it with the map from the check problem output, which is odd

avi20:04:29

yeah that’s precisely what I’m confused by

taylor20:04:59

but I agree w/trying to (re)build up from the simplest working case until it breaks

avi20:04:30

but yeah, since (as I just learned) replacing the predicate with (constantly true) does lead to the check call succeeding… I’ll try rebuilding the predicate to try to debug at what point find a small case wherein I can trigger the confusing behavior

taylor20:04:45

another thing to keep in mind is that it checks out fine if you don’t use his custom keys spec for in/out

avi20:04:43

yeah… my input and output specs (and thus the generated args) are deeply nested colls… not sure why that’d matter but maybe it does

avi21:04:06

anyone know whether/how to use stest/check and have it skip shrinking?

avi21:04:28

ah never mind, I can work with it 😉

avi21:04:45

hmm well I’ve been able to get the predicate to always work as expected by changing (= in-vals ret-vals) to (= (set in-vals) (set ret-vals)) — it appears that the two colls had the same values but in different orders. I’m confused as to why I wasn’t seeing this earlier. I’m very unclear on what I’m doing differently now 😞 … PEBKAC … sorry to have bothered everyone

seancorfield21:04:38

That's cool that you've figured out the problem!

avi21:04:07

but also a bit disorienting that I suddenly can’t reproduce my confusing tangent…

avi22:04:10

my only idea is that earlier I was copy-and-pasting the values as strings and then pasting them into the repl prompt, versus using e.g. (-> *1 :key :key) to get the in-memory values instead… I don’t know why that would matter though.