Fork me on GitHub

👋 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!


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


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?


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


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


Here’s a chunk of the output:

  [{:path [:fn],


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


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.


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


actually disregard, I copy/pasted your code poorly


ah ok no worries! happens to us all!


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?)


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


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


that makes sense… thanks for the help!


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


no, I wasn’t aware of that


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


that doesn’t seem to be the big issue here


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


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


not dumb!


yes, more than a few times


: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)


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


hm ok good idea I’ll try that!


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


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


yeah that’s precisely what I’m confused by


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


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


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


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


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


ah never mind, I can work with it 😉


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


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


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


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.