This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-02-07
Channels
- # announcements (35)
- # beginners (80)
- # boot (1)
- # calva (4)
- # cider (33)
- # cljdoc (40)
- # clojars (3)
- # clojure (95)
- # clojure-berlin (2)
- # clojure-europe (4)
- # clojure-italy (28)
- # clojure-nl (2)
- # clojure-seattle (1)
- # clojure-serbia (1)
- # clojure-spec (74)
- # clojure-uk (71)
- # clojurescript (29)
- # core-async (1)
- # cursive (80)
- # data-science (4)
- # datomic (17)
- # duct (75)
- # emacs (4)
- # figwheel-main (5)
- # fulcro (3)
- # jackdaw (1)
- # java (1)
- # jobs-discuss (20)
- # off-topic (32)
- # parinfer (2)
- # pathom (23)
- # re-frame (26)
- # reagent (25)
- # rum (6)
- # shadow-cljs (122)
- # speculative (4)
- # sql (17)
- # testing (7)
- # yada (8)
I thought I had to make upgrading existing spec libraries less painful is to have something like a reader conditional that can dispatch on the version of spec. E.g.:
#?(:spec2 (:require [clojure.spec-alpha2] :as s) :default (:require [clojure.spec.alpha :as s]))
#?(:spec2 (s/def …) :default (s/def …))
This way a library can maintain compatibility with both versions of spec(try
(require '[clojure.spec-alpha2 :as s])
(catch Exception e
(require '[clojure.spec.alpha :as s])))
No? 😄we could use a goog-define for it in CLJS, but then still you cannot do anything on the namespace declaration level
it's a shame that it doesn't work in cljs given the work that was done to make require
work there.
anyway, it would be nice to have a way have libraries support both versions. I bet it will be 2 branches and versions with “-spec2” suffixes for a while
you could use a macro, and perform the require
voodoo at the clojure level perhaps :thinking_face:
oh right, I think I saw someone “abuse” a data reader for that recently. Maybe it was @U050PJ2EU?
it would work in shadow-cljs, which has the ability to specify custom :keywords which run
no worries
good catches
can anyone point out something i may have missed… if i try to generate from a s/keys spec un-req
i get all blank maps… but if i use the same with req
i can generate data. Do you need a custom generator for anything un-req
?
do you mean req-un ?
user=> (require '[clojure.spec.alpha :as s])
nil
user=> (s/def ::a int?)
:user/a
user=> (s/def ::b string?)
:user/b
user=> (s/exercise (s/keys :req-un [::a ::b]))
([{:a -1, :b ""} {:a -1, :b ""}] [{:a 0, :b ""} {:a 0, :b ""}] [{:a -1, :b "75"} {:a -1, :b "75"}] [{:a 0, :b "zW7"} {:a 0, :b "zW7"}] [{:a -3, :b ""} {:a -3, :b ""}] [{:a -2, :b "Hlf"} {:a -2, :b "Hlf"}] [{:a 11, :b "M8r"} {:a 11, :b "M8r"}] [{:a -4, :b "K9Dn"} {:a -4, :b "K9Dn"}] [{:a 44, :b "o2rAl"} {:a 44, :b "o2rAl"}] [{:a -4, :b "SzHY1pTSN"} {:a -4, :b "SzHY1pTSN"}])
user=>
attention to detail is important. thanks.
clojure
(s/def :my-test/name (s/and string? #(not= "" %)))
(s/def :my-test/developer (s/keys :req [:my-test/name ]))
(s/exercise :my-test/developer 2)
([#:my-test{:name "W"} #:my-test{:name "W"}] [#:my-test{:name "7"} #:my-test{:name "7"}])
;; d'oh `un-req` not a thing.
(s/def :my-test/developer (s/keys :un-req [:my-test/name ]))
(s/exercise :my-test/developer 2)
([{} {}] [{} {}])
I'm a bit surprised s/keys
doesn't complain that all its known options are missing
user=> (s/exercise (s/keys))
([{} {}] [{} {}] [{} {}] [{} {}] [{} {}] [{} {}] [{} {}] [{} {}] [{} {}] [{} {}])
user=>
s/keys is a valid spec that will validate all registered keys in the map
yeah i guess i did come across in the guide the mention of (s/keys) was valid and i guess the rule to fn’s are “extra keys no-big-deal”
but of course it doesn’t know how to gen
just use this mnemonic … “I req-un the map should have a key like this”
whats the idiomatic way to mandate presence of keys? related: whats also the idiomatic way to mandate the lack of extraneous / undefined keys?
mandate the presence of keys: req-un
not allow extra keys: this is not according to the philosophy of spec/Clojure I think
there are some code snippets around for disallowing "extra" keys though @ben.borders even though it's counter to the design philosophy
right, i figured.. seems like i should probably try to allign more with the philosophy
well, this covers a lot of other stuff, but there is a section in here: https://github.com/matthiasn/talk-transcripts/blob/master/Hickey_Rich/Spec_ulation.md
grep for “code for growth”
I think one of the metaphors is "if you're expecting a truck to deliver your TV, you shouldn't care what else is on the truck" or something like that
There have been some conversations about what spec is and isn’t suited for. E.g. it isn’t designed for coercion or “closed world” assumptions (not allowing extra keys), e.g. using it as API boundary protection
I think the greater point is actually that you shouldn’t design your systems that way, and if you don’t, spec will mesh well :)
right.. we don’t now.. we allow our maps to have whatever values they have, and we grab the ones we care about
well, sometimes I don’t want to have crap in my jsonb field, but there’s always select-keys, etc.
and you might be interested in the new stuff coming in spec 2 around that https://github.com/matthiasn/talk-transcripts/blob/master/Hickey_Rich/MaybeNot.md
> I think the greater point is actually that you shouldn’t design your systems that way, and if you don’t, spec will mesh well :) It's fine for a (REST) API to be passed a bunch of parameters it doesn't care about. It can just ignore them. Then spec works well for parameter validation.
I started to use REST API with compojure-api 2.0.0 that can coerce data with spec and generate swagger docs from it. I thought it would be the trend for specs, but reading this conversation maybe not. It's better to use compojure-api with schema to follow the clojure philosophy in REST?
I don't understand your question : what do you mean "clojure philosophy in REST"?
> well, sometimes I don’t want to have crap in my jsonb field, but there’s always select-keys, etc. And you can pull the "known" keys out of a spec fairly easily (usually!) so that you can narrow your set of fields down to just what's in the spec (we do this around database insertion where we have a spec for the row representation of data).
how would a spec look for the output (https://github.com/clojure/clojure/blob/master/src/clj/clojure/xml.clj#L78) from clojure.xml\parse
look?
Below is what i’m guessing at so far, but the ::content references ::element and vice versa… not sure how to handle this. (I’m not worried about namespaces at the moment):
I think its tricky for me because it’s a hierarchy.
(s/def ::tag keyword?)
(s/def ::attrs (s/map-of keyword? string?
:conform-keys true))
(s/def ::content-strings (s/coll-of string?))
(s/def ::content-maps (s/coll-of ::element?))
(s/def ::content
(s/or :content-map ::content-maps
:content-string ::content-strings ))
(s/def ::element (s/keys :req-un [::tag]
:opt-un [::content ::attrs]))
(gen/sample (s/gen string?) 10000)
...only gives me alphanumeric, for 10,000 iterations. Why is that?
No symbols / unicode
That's probably all the string?
generator is coded to produce.
test.chuck
has a regex string generator that can produce a much wider range of character values, if you need to test that.
Hmmm. I was trying to follow this blog post: https://lispcast.com/testing-stateful-and-concurrent-systems-using-test-check/
For example, here are some generated "email" strings, using that generator:
(["脀@Z.Gp" "脀@Z.Gp"] ["@OG.lr" "@OG.lr"] ["\"\"@z.DtS.K.Qpu" "\"\"@z.DtS.K.Qpu"] [".@2N8.SuYn.FY.zBf" ".@2N8.SuYn.FY.zBf"] ["@3.QBB" "@3.QBB"] ["䱝...𣩷.쑆.@[3.61.526.313]" "䱝...𣩷.쑆.@[3.61.526.313]"] ["\"𰄖\"@[78.35.80.6]" "\"𰄖\"@[78.35.80.6]"] ["\"\"@[00.5.0.8]" "\"\"@[00.5.0.8]"] ["\"\"@-Npu4W.unVx6R.DdNnk.4.A6tM.y.EJFHfw92N.ecYbisymo" "\"\"@-Npu4W.unVx6R.DdNnk.4.A6tM.y.EJFHfw92N.ecYbisymo"] ["\"𫐊\"@[0.881.6.929]" "\"𫐊\"@[0.881.6.929]"])
(my editor does not render them all correctly 😞)
... scrolling down to "Lets set up some Generators", he uses gen/string
instead of string?
and it produces the full range
Ah, there you go!
Would be nice not to have to override all my string?
specs with gen/string
however 🙂
I guess it depends on how important it is that you exercise your code with more exotic strings?
Yeah, I guess so. It just surprised me. Testing against exotic strings strikes me as exactly within generative testing's wheelhouse
Well... it is but this is a case where you need to opt into it.
It really depends on what parts of your data processing you need to stress test. If you only pass a string through your system and into the DB, you don't really care whether it's alphanumeric or all poop emojis.
If you have specific string processing that does some sort of parsing, it might well be useful to stress test it with really exotic strings.
Not everything is important to test to the same level.
It might be more useful, for example, to use a string generator that only ever produces an empty string, a short readable string, or a giant long string.
I started to use REST API with compojure-api 2.0.0 that can coerce data with spec and generate swagger docs from it. I thought it would be the trend for specs, but reading this conversation maybe not. It's better to use compojure-api with schema to follow the clojure philosophy in REST?