This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-10-07
Channels
- # beginners (153)
- # cider (2)
- # cljs-dev (1)
- # cljsjs (11)
- # cljsrn (4)
- # clojure (21)
- # clojure-austin (2)
- # clojure-greece (1)
- # clojure-italy (8)
- # clojure-russia (12)
- # clojure-spec (68)
- # clojurescript (35)
- # cursive (4)
- # datomic (2)
- # fulcro (15)
- # off-topic (1)
- # om (1)
- # portkey (35)
- # protorepl (6)
- # re-frame (28)
- # shadow-cljs (13)
- # specter (10)
- # uncomplicate (3)
- # unrepl (7)
Since instrument does not check the return value, it would seem to me that a :post condition is still quite useful.
with :post
at least, you don’t have to let
your fn’s return value so you can assert it before you return it
i know that instrument only looks at args, but i haven’t tried out how valid? works on it. will try that when i get home.
@guy no it doesn't. Are you sure? Check the docs. Only args are supported for instrument, though you can specify ret and fn for other purposes.
The spec guide itself, in instrument section. Why do you think libraries like Orchestra exist?
So then, is fdef
orthogonal in some way. Its doc string says: “Once registered, function specs are included in doc, checked by
instrument, tested by the runner clojure.spec.test/run-tests, and (if a macro) used to explain errors during macroexpansion.”
Other than tests, I gather there's really no way to perform validation on the entirety of a function's signature, including its return value, and also validating that the entire fn received in a higher order function, is what is expected, is that right?
stest/check
is the only thing in spec that validates :ret and :fn specs
I’m not sure I fully understand the question re hof
I’m trying to write a spec for a collection where I need the first item to conform to another spec. s/cat
works great, but when I fdef
and check
an unary function of that collection it looks like test.check is apply
ing the collection to the function, and so I get arity exceptions. Should I change the function to take varargs?
are you using s/cat
to express the whole arglist or just the first arg?
I think to use a regex for a single arg you'll need to wrap in s/spec
, maybe that's what you're missing
(s/cat :first-arg (s/spec (s/cat ...)))
something like that
I don't know then. You certainly should be able to spec that.
actually it does work when I wrap with s/spec
, but I think I need to limit the test cases because it’s running forever
yeah 😞 the Big Problem of spec/test.check
Other than tests, I gather there's really no way to perform validation on the entirety of a function's signature, including its return value, and also validating that the entire fn received in a higher order function, is what is expected, is that right?
(binding [clojure.spec.alpha/*recursion-limit* 1]
(stest/check `clause-str {:num-tests 1}))
or I could read the docs… https://clojure.github.io/clojure/branch-master/clojure.spec-api.html#clojure.spec/*recursion-limit*
I think so. what's it default to?
The depth of spec checking is somewhat limited by the JVM stack size, that keeps the generators from blowing the stack. Without it, you’d get a stack overflow from almost any recursive structure.
@tbaldridge you're saying *recursion-limit*
refers to checking rather than generation?
It only refers to generation. Checking is assumed to be bounded by the depth of the input
okay. I think there could be a more automatic approach to handling the recursion, but I'm not sure.
I have to come up with something for the vanilla test.check collection generators, so whatever works there might apply to how spec assembles generators
There probably could be. That dynamic var got added in one of the pre-alpha builds when I tried to build a recursive spec and it would stack overflow on the first structure generated.
Checking is fine since that's GIGO, so it's on the user not to check data that's millions of levels deep.
@gfredericks any insight in the past year about shrinking recursive generators?
They currently shrink by width (and a b) -> (and a), but not by depth: (and (and (and a))) -> (and a). I know we discussed this once, not sure if anything has changed in the past year
I don't think I have any thoughts that I didn't put on the ticket
@U3DAE8HMG important to note here that spec doesn't use recursive-gen
But spec's approach has the same problem, but even worse
the unfortunate part is that after generating a collection, test.check can't (in general) tell what parts the children are
and you'd need their shrink-trees in any case, not just the data
oh ummmm
I was thinking that there's an unsound approach where you wrap the child generator in an observer that keeps track of how it was called and use that to add shrinking info I thought it was unsound because you can't tell just because the generator was called, that the result actually appears in the final structure but I just realized that that probably doesn't matter. anything generated by the child generator should be a valid value from the final generator, so even if it doesn't appear in the actual data, it's not an invalid thing to shrink to in the strict sense
so now the worst thing about this approach is that it's a bit messy
but I think everything still ends up being deterministic
I'll go comment on the ticket. I don't have time to work on it until at least thursday
Well maybe not worse....
ah right, I forgot about that. Spec's stack overflow happened during the creation of the generator
ah yeah
the thing about spec's approach is that it's committing to a particular depth in the generator rather than describing the recursion the way the spec itself does
it might be making other commitments in the process, I'm not sure
I'm not sure this is a significant problem, it just complicates things