Fork me on GitHub

@bbloom I fully expect someone will write a dev lib that provides an overinstrument or whatever shortly after 1.9 is released


it’s not a big deal - it was just 1) surprising and 2) not convincingly justified, despite being unsurprisingly/welcomely accompanied by a rationale


gave me feedback, for whatever that’s worth, and moved back on to writing code 🙂


Can someone tell me if I’m off here?


(s/def :gj/coordinates (s/with-gen
                         #(s/gen #{(point-gen)})))
(s/def :gjpt/type (s/with-gen string? #(s/gen #{"Point"})))
(s/def :gjls/coordinates (s/coll-of :gj/coordinates))



[-7.4052159604840995, 12.824879014110294, -195933.59674337224],
			[-7.4052159604840995, 12.824879014110294, -195933.59674337224],
			[-7.4052159604840995, 12.824879014110294, -195933.59674337224]


I would think that coll-of would call a spec multiple times that has a generator and would produce unique values each time

Alex Miller (Clojure team)01:12:00

what is the line that produced the output?

Alex Miller (Clojure team)01:12:40

what does point-gen do?


(defn point-gen
  "Generates a valid SRID:4326 point"
  [(- (rand 360) 180)
   (- (rand 180) 90)
   (- (rand 200000) 200000)])


(s/def :gj/linestring (s/keys :req-un [:gjls/type :gjls/coordinates]))

Alex Miller (Clojure team)01:12:06

you should never use a random-generating thing in your generator

Alex Miller (Clojure team)01:12:28

when you do that, you rob test.check from being able to a) make reproducible results and b) shrink on error

Alex Miller (Clojure team)01:12:10

any source of randomness should come from a generator


Ok, I’ll swap that with double-in


also with-gen is only going to call the function once to get the generator, right? so this gets a generator for #{(point-gen)} so it calls point-gen just once and gets #{[some, random, values]} and then just generates coords from that single-valued set.


or does the function argument get called every time it needs a generator?

Alex Miller (Clojure team)01:12:02

yeah, you really want to use gen/fmap or gen/bind to do this kind of thing

Alex Miller (Clojure team)01:12:27

your point-gen could be (s/gen (s/tuple (s/int-in -180 180) (s/int-in -90 90) (s/int-in -20000 0)))


Ok, thank you. I’ll do some refactoring


I’m trying to generate GeoJSON with spec


I’ll post to it when I’m done


@tetriscodes interesting 🙂


@tetriscodes I have done something similar as part of one of our internal projects (just for the subset used by twitter)


I you need (rev)geocoding data check mpenet/sextant on github


It was useful for gen


I guess I’m missing something about how cat should be nested, or why does that fail?

Alex Miller (Clojure team)14:12:23

If you need to nest regexs, wrap the inner in s/spec to start a new nested sequential context


Don’t understand what’s going on here


@alexmiller Ok, if I don’t need regexes, is there some other way I could spec a vector of one or possibly two different elements? (s/tuple boolean? (s/? map?)) did not work.


@vikeri: (s/or :one-element (s/tuple boolean?) :two-elements (s/tuple boolean? map?))

Alex Miller (Clojure team)15:12:36

@jfntn the ::foo inside the map is not valid according to the spec you have defined for ::foo

Alex Miller (Clojure team)15:12:55

(also, identity is not a valid retag function - you’d hit that with gen if you tried it)

Alex Miller (Clojure team)15:12:00

the ::foo in the map is not a valid value for the ::foo multispec


ok so the problem is that the kw that registers the mspec is also present in the map, correct?


I've got the same spec returning false for s/valid? and "Success" for s/explain-str, for the same data, which I didn't expect to be possible. Is there an obvious reason this is occurring? Can someone point me to something in the docs?

Alex Miller (Clojure team)16:12:11

@tomc shouldn’t ever happen. can’t say more without more info

Alex Miller (Clojure team)16:12:31

@jfntn yes - s/keys will validate specs for all keys in the map


@alexmiller ok, let me verify it's not something on my end (which it almost certainly is) and if I can't figure it out I'll give you more info here. Thanks!


Makes sense, thank you


Turns out I had a call to s/keys that didn't conform to s/key's api. If only there were some way to prevent that type of thing 🙂

Alex Miller (Clojure team)16:12:25

I have created specs for spec, but it’s somewhat problematic to actually use it without encountering an infinite loop of checking

Alex Miller (Clojure team)16:12:46

that said, I’d be happy to see a jira for whatever problem you had as that’s something we could prevent in the code


Probably not worth it. I'm doing some whacky metaprogramming for reasons not worth getting into, and it resulted in me evaluating code like (s/keys :req-un [nil])


how do I spec a hash-map where the keys are integers?


ah map-of!


Thinking about a spec api so that tooling can register listeners for fn spec failures.


to clarify what I'm talking about it would be nice if this spot fired an event


of some sort


I would need something like this to reliably report spec errors in tooling like figwheel


in JS especially because its extremely difficult and fairly invasive to get any sort of reliable top level Exception handling


Is there an efficient way to ask for a string of specific length range? The obvious (s/def ::layout-row (s/and string? #(<= 8 (count %) 11))) breaks such-that generation


@bhauman another thing to consider is there’s really no harm in patching that for custom tooling


vars exist for a reason 🙂

Alex Miller (Clojure team)23:12:43

@lvh you will need to dive into gen for that


That’s what I figured, thanks 🙂


Is there a way to figure out which spec failed to generate when I see:

java.util.concurrent.ExecutionException: clojure.lang.ExceptionInfo: Couldn't satisfy such-that predicate after 100 tries. {}


(I’m running check over the entire ns)


Is that gonna change, or is there a deep reason for that

Alex Miller (Clojure team)23:12:57

the problem here is that test.check doesn’t have a way to do so (or doesn’t in the version used by spec at least)

Alex Miller (Clojure team)23:12:25

basically, spec builds a big composite generator and says gimme and gets back either a sample or a failure

Alex Miller (Clojure team)23:12:41

I know Gary has been making some changes to make this better in test.check but I haven’t had time to look at them yet

Alex Miller (Clojure team)23:12:54

and it’s possible that we can do better if we leveraged that

Alex Miller (Clojure team)23:12:12

there is certainly no desire for that to be information free :)


Ah, I see 🙂


Yeah, so I’ve made the same mistake several times now


in that I forget how to write a clojure.,test test that is actually doing stest/check


And just do (t/is …) and forget it’s lazy, and then only way later discover that the checks were just not running and I’ve had a bug all along

Alex Miller (Clojure team)23:12:42

yeah, I’ve done that too :)

Alex Miller (Clojure team)23:12:10

it is intentional that it’s lazy


Yeah, it makes sense. It’d be fine if there was an stest/deftest IMO

Alex Miller (Clojure team)23:12:15

unlikely we will add that

Alex Miller (Clojure team)23:12:42

in general, the lifecycle and use of generative or check-based tests is much different than example-based clojure.test tests

Alex Miller (Clojure team)23:12:13

I’m dubious that combining them in a single suite makes sense


Hm; I’ve been doing that by having lein test filter for me based on tags