This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-03-15
Channels
- # announcements (10)
- # asami (5)
- # babashka (49)
- # babashka-sci-dev (8)
- # beginners (25)
- # calva (98)
- # cider (2)
- # clj-kondo (22)
- # clojure (32)
- # clojure-dev (12)
- # clojure-europe (32)
- # clojure-nl (3)
- # clojure-spec (3)
- # clojure-uk (10)
- # clojurescript (12)
- # community-development (1)
- # conjure (71)
- # cursive (7)
- # datalog (6)
- # events (2)
- # figwheel-main (2)
- # fulcro (4)
- # jobs (2)
- # kaocha (3)
- # lsp (43)
- # membrane (12)
- # missionary (9)
- # off-topic (61)
- # pathom (7)
- # polylith (2)
- # reagent (38)
- # remote-jobs (4)
- # shadow-cljs (17)
- # specter (1)
- # tools-deps (38)
- # vim (51)
- # web-security (5)
Hello all. Using clojure.spec a lot now, and also using for generative testing. Working really well, but in one domain I need to generate 'unique' [obv only in that test run] integer identifiers. Unfortunately, they also need to match a specific pattern and have a Verhoeff check digit. My spec and a custom generator is:
(defn gen-identifier
"A generator of identifiers of the specified type.
Parameters:
- t : one of :info.snomed/Concept :info.snomed.Description or
:info.snomed/Relationship."
[t]
(gen/fmap #(let [partition (rand-nth (seq (partitions-for-type t)))]
(Long/parseLong (verhoeff/append (str % partition))))
(s/gen (s/int-in 100000 Long/MAX_VALUE))))
https://github.com/wardle/hermes/blob/46cfee5b8005ffe8e26d86dcbbb239ba7b8ef01a/src/com/eldrix/hermes/rf2spec.clj#L18
I can do this for some by simply filtering out duplicates if I'm generating a single batch, but there are other times when that is not possible. I guess I could fallback to an incrementing counter and forego using a generator, or map through generated entities and override with an autoincrementing integer generator from an atom, but is there something in spec I'm missing? I've seen the list-distinct-by but that appears to offer guarantees only within the list obviously. I was thinking about something that starts with something based on time but then increments to satisfy the other generative predicates. Then it starts to feel a bit tricky! Anyone else faced this issue, or have any suggestions? I am missing something obvious? All suggestions welcomed. Thank you
When using test.check I’ve generated these using an atom as a counter in the past. Then it’s a matter of using gen/fmap
where it’s generator is all the different things that should be related, and the transform function assigns the ids to be consistent. The generator looks like this:
(def counter (atom 0))
(def gen-unique
(gen/no-shrink (gen/fmap (fn [_] (str (swap! counter inc))) (gen/return nil))))
Interested though if other people have different ways to do this. I don’t know if it’s a downside, but it’s extra coordination at the gen/fmap
to “reconcile” the parts (but I’ve found this necessary at some level for almost all generators i’ve written).Oh that looks really good thank you. I shall give that a try. Hadn't used gen/no-shrink either before! Thanks again.