Hope I’m not spamming people, but I would love to get some feedback on a tool we made to help with creating spec generators: https://git.sr.ht/~jomco/proof-specs proof-specs can be run as a leiningen alias or from the repl and will exercise all data specs (keyword specs) in a set of namespaces and report on any errors. We’re using it ourselves as part of our test suite to ensure we always write generating specs and to make it easier to find out which part of complex specs are broken.
Thanks for any feedback :-)
Main reason we wrote the thing is that sometimes spec generators just error out with very little context making it hard to figure out which specs even work. proof-specs will at very least give you a list of every spec that won’t generate which helps a lot in figuring out what’s going on.
This might be a silly question but is there a s-exp spec that can be applied recursively?
But I guess you’re free to make a function that does recursive stuff and use it in a spec? 🙂
yes, also specs can be applied recursively even if it's silly 👺
@raymcdermott What are you looking for? Something like tree-seq + spec? This is what grasp basically does: https://github.com/borkdude/grasp
ok - thanks, I remember talking about it with you but I've never looked at the code 👀
to be more straightforward: I'm looking to conform all of Clojure. That's what I'm really looking to do.
@borkdude one small thing I noticed in your reify spec is that you use (s/cat :reify #{'reify} ... why do you use a set rather than just the symbol 'reify? Cos that's what I do and it works but maybe set gets you something else that I'm missing?
Because of how spec works?
user=> (require '[clojure.spec.alpha :as s])
nil
user=> (s/valid? 'foo 'foo)
Execution error at user/eval154 (REPL:1).
Unable to resolve spec: foo
user=> (s/valid? (s/cat :foo 'foo) ['foo])
Execution error at user/eval156 (REPL:1).
Unable to resolve spec: foo
user=> (s/valid? #{'foo} 'foo)
true
user=> (s/valid? (s/cat :foo #{'foo}) ['foo])
trueI.e. I want to match the literal symbol 'reify
yes ... actually it's neater than #(= 'reify %)which is the ugly thing I have 🙇🏼
I use sets for comparison all the time. it's great!
yeah, seems a ton more elegant and more transparent than a function
oh but it is a function ;)
ho ho
Sometimes it can make sense to make it a var as well. Like
(def valid-foo? #{:x :y :z})
(valid-foo? :x) ;=> :xNo, and I think you can quickly come up with many reasons why
Sure. Like I said, was a silly question. I just wanted to make sure I hadn't missed anything before moving on other options.
Eg (s/cat symbol? s/+ any?) but recurring
You can give it a name, then recur to this name:
(s/def ::foo
(s/cat :k keyword?
:v map?
:others (s/? ::foo)))
=> :user/foo
(s/valid? ::foo
[:a {} :b {} :c {}])
=> true
(s/valid? ::foo
[:a {} :b {} :c])
=> false
(s/valid? ::foo
[:a {} :b {} :c []])
=> false
ha, yes - actually that's what we ended up doing! 🙂
thank you @souenzzo
[on the phone so syntax ain't great]