Fork me on GitHub
#clojure-spec
<
2016-12-07
>
bfabry00:12:33

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

bbloom00:12:34

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

bbloom00:12:55

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

tetriscodes01:12:31

Can someone tell me if I’m off here?

tetriscodes01:12:34

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

tetriscodes01:12:10

Produces

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

tetriscodes01:12:57

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

alexmiller01:12:00

what is the line that produced the output?

alexmiller01:12:40

what does point-gen do?

tetriscodes01:12:16

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

tetriscodes01:12:57

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

alexmiller01:12:06

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

alexmiller01:12:28

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

alexmiller01:12:10

any source of randomness should come from a generator

alexmiller01:12:34

so something like

tetriscodes01:12:53

Ok, I’ll swap that with double-in

seancorfield01:12:22

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.

seancorfield01:12:49

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

alexmiller01:12:02

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

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

alexmiller01:12:32

something like that

tetriscodes01:12:07

Ok, thank you. I’ll do some refactoring

tetriscodes01:12:19

I’m trying to generate GeoJSON with spec

alexmiller01:12:26

sounds fun :)

tetriscodes01:12:33

I’ll post to it when I’m done

nha10:12:57

@tetriscodes interesting 🙂

mpenet11:12:26

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

mpenet11:12:17

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

mpenet11:12:34

It was useful for gen

vikeri14:12:42

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

alexmiller14:12:23

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

jfntn14:12:55

Don’t understand what’s going on here

vikeri14:12:51

@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.

zane15:12:53

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

alexmiller15:12:36

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

alexmiller15:12:55

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

alexmiller15:12:23

same problem

alexmiller15:12:00

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

jfntn15:12:07

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

tomc16:12:40

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?

alexmiller16:12:11

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

alexmiller16:12:31

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

tomc16:12:15

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

jfntn16:12:13

Makes sense, thank you

tomc16:12:29

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 🙂

alexmiller16:12:25

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

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

tomc16:12:51

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

denik18:12:24

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

denik18:12:48

ah map-of!

bhauman22:12:57

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

bhauman22:12:38

to clarify what I'm talking about it would be nice if this spot fired an event https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/spec/test.cljs#L103

bhauman22:12:54

of some sort

bhauman22:12:05

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

bhauman22:12:16

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

lvh22:12:14

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

dnolen23:12:35

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

dnolen23:12:44

vars exist for a reason 🙂

alexmiller23:12:43

@lvh you will need to dive into gen for that

lvh23:12:54

That’s what I figured, thanks 🙂

lvh23:12:13

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. {}

lvh23:12:21

(I’m running check over the entire ns)

lvh23:12:31

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

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

alexmiller23:12:25

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

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

alexmiller23:12:54

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

alexmiller23:12:12

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

lvh23:12:02

Ah, I see 🙂

lvh23:12:11

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

lvh23:12:30

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

lvh23:12:00

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

alexmiller23:12:42

yeah, I’ve done that too :)

alexmiller23:12:10

it is intentional that it’s lazy

lvh23:12:34

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

alexmiller23:12:15

unlikely we will add that

alexmiller23:12:42

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

alexmiller23:12:13

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

lvh23:12:47

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