clojure-spec

About: http://clojure.org/about/spec Guide: http://clojure.org/guides/spec API: https://clojure.github.io/spec.alpha/clojure.spec.alpha-api.html
Aron 2020-08-26T08:43:36.067200Z

What's the proper way to generate random emails for testing?

dharrigan 2020-08-26T08:46:11.067500Z

If you're using spec you could use a generator

dharrigan 2020-08-26T08:46:30.067700Z

<https://medium.com/appsflyer/clojure-automated-property-based-tests-for-complicated-inputs-786de23de8f0> shows one such approach

dharrigan 2020-08-26T08:47:03.067900Z

<https://gist.github.com/conan/2edca210999b96ad26d38c1ee96dfe40> another

Aron 2020-08-26T08:51:24.068400Z

Yes, I am trying to learn spec to use it : ) Would be a stretch that I am using it now : )

Aron 2020-08-26T08:53:14.069400Z

I see, so these are valid emails but they only generate a relatively small subset of possible email formats

Joe Lane 2020-08-26T13:49:18.071800Z

@ashnur Check out https://github.com/miner/strgen , ignoring that it still uses clojure.spec in it's examples, I think everything else should work.

👀 1
Aron 2020-08-26T13:50:02.072300Z

I was just about to try test.chuck

plexus 2020-08-26T14:48:37.072700Z

or (shameless plug): Regal https://lambdaisland.github.io/regal-playground/

Aron 2020-08-27T17:53:33.101100Z

I tried out regal, and I like it, but I am not entirely sure I understand what is happening.I tried out regal, and I like it, but I am not entirely sure I understand what is happening.

Aron 2020-08-26T15:14:03.072900Z

that link is broken 😞

Aron 2020-08-26T15:15:27.074300Z

I am having an extremely frustrating experience while trying out test chuck. Even though the namespace is included, the example code doesn't work, methods like string-from-regexp are nil. I am not even sure in this situation where should I go to ask for help, probably #beginners ?

alexmiller 2020-08-26T15:30:42.074800Z

here's probably fine - can you share a snippet of what you're doing?

alexmiller 2020-08-26T15:31:56.075Z

https://lambdaisland.github.io/land-of-regal/ looks to be the right link

alexmiller 2020-08-26T15:37:47.075500Z

% clj -Sdeps '{:deps {com.gfredericks/test.chuck {:mvn/version "0.2.10"}}}'
Clojure 1.10.1
user=&gt; (require '[com.gfredericks.test.chuck.generators :as gen'])
nil
user=&gt; (require '[clojure.test.check.generators :as gen])
nil
user=&gt; (gen/sample (gen'/string-from-regex #"([☃-♥]{3}|B(A|OO)M)*"))
("" "" "BAMBOOM" "♛♜☖☐♢☴♏♡♍" "☹♍♈☈☠♇BOOM" "BAMBAM♥♞☬♗☒☄" "" "BOOM" "♤☺☵☗☃☻BAM☨♥♗♕♥☈BOOMBOOM♊♅♝" "☪☓☉☠☓☔BOOM")

Aron 2020-08-26T15:47:57.075900Z

so this only works with java I am guessing

Aron 2020-08-26T15:53:46.077100Z

Probably because java regex is not the same as js regex. But then I am probably better off with one of the other options that were mentioned.

alexmiller 2020-08-26T15:56:52.077300Z

it should work with both

alexmiller 2020-08-26T15:57:07.077600Z

did you (require '[clojure.test.check.generators :as gen]) ?

alexmiller 2020-08-26T15:57:53.078300Z

test.chuck builds on top of test.check, so you need to include both of the generator namespaces

Aron 2020-08-26T15:58:43.079Z

hmm

Aron 2020-08-26T15:58:49.079300Z

I did, but this gives me an idea

alexmiller 2020-08-26T16:00:02.080100Z

it seems from those errors that you have issues with both the gen and gen' namespaces

hadils 2020-08-26T16:12:38.082100Z

I need help with multi-spec:

(def a #{1 2 3})
(def b #{4 5 6})
(s/def ::type #{:foo :bar})
;;; This is pseudocode
(if (= ::type :foo)
   ; I want ::new-sym to be defined as a
  else (= ::type :bar)
    ; I want ::new-sym to be defined as b
; ::type and ::new-sym appear in the same map
I am pretty sure this is done with multi-spec but I am stumped as to how to make it work...

2020-08-26T16:23:12.083Z

test.chuck's regex generator is jvm-only

1
alexmiller 2020-08-26T16:36:28.083200Z

ah, sorry

alexmiller 2020-08-26T16:38:29.084200Z

@hadilsabbagh18 s/multi-spec is for the case where you can look at the data and return different specs based on the data

alexmiller 2020-08-26T16:38:35.084500Z

what is your actual data?

alexmiller 2020-08-26T16:40:14.086Z

in general, spec is designed primarily for the case where attributes always have the same spec so you are probably going against that grain a bit.

alexmiller 2020-08-26T16:41:22.087100Z

if the attribute is in a map, you could create (s/and (s/keys :req-un [::new-sym]) arbitrary-condition)) to tighten a more general spec

alexmiller 2020-08-26T16:41:49.087600Z

and then use an s/multi-spec to choose which of those applies

hadils 2020-08-26T16:50:30.087900Z

Thank you @alexmiller! Here is the actual snippet:

(s/def :budget-item/main-category #{"Household" "Personal" "Savings" "Investments" "Other"})

(defn budget-categories
  [main-category]
  (into #{}
    (mapv first
      (d/q '[:find ?cat :in $ ?main :where
             [?e :expense/budget-category ?main]
             [?e :expense/categories ?cat]] (db) main-category))))

(defmulti ordered-categories :budget-item/main-category)
(defmethod ordered-categories "Household" [_]
  (budget-categories "Household"))
(defmethod ordered-categories "Personal" [_]
  (budget-categories "Personal"))
(defmethod ordered-categories "Savings" [_]
  (budget-categories "Savings"))
(defmethod ordered-categories "Investments" [_]
  (budget-categories "Investments"))
(defmethod ordered-categories "Other" [_]
  (budget-categories "Other"))
(s/def :budget-item/ordered-categories (s/multi-spec ordered-categories ,,,))
I want to make :budget-item/ordered-categories dependent on what :budget-item/main-category is set to. They will be in a map together...

alexmiller 2020-08-26T17:12:24.088200Z

yeah, I don't think you should do this in a spec

alexmiller 2020-08-26T17:13:27.088700Z

or just make it a valid-category? predicate

alexmiller 2020-08-26T17:15:15.090300Z

just spec ordered-categories as a string? or keyword? or whatever, then s/and the whole map predicate with a custom predicate that validates that extracts ordered-categories and main-category, and validates that one is valid according to the other

hadils 2020-08-26T17:15:55.090900Z

Ok, I'll do that. Thanks a lot for your help @alexmiller! I am really grateful.

alexmiller 2020-08-26T17:16:41.091700Z

dependent stuff is hard to do well - it's easiest to just specify that constraint at the level that contains all of the data