-
Notifications
You must be signed in to change notification settings - Fork 223
Fix :map-of :min and unreachable generator, explain such-that failures #1029
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
fa56647
to
4540b39
Compare
4540b39
to
9e947ff
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, comment about throwing & errors.
src/malli/generator.cljc
Outdated
(gen/return (f [])) | ||
(-never-gen options)) | ||
(gen/fmap f (gen/vector-distinct gen {:min-elements min, :max-elements max, :max-tries 100 | ||
:ex-fn #(ex-info (str "Could not generate enough distinct elements for schema " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Malli follow a "fail fast with data, pretty errors in dev-mode" philosophy. This enables both smaller bundle sizes on ClojureScript and fast runtime in prod (things like pr-str
are really slow).
e.g.
(m/schema :enum)
fails with just enough data, while:
((requiring-resolve 'malli.dev/start!))
(m/schema :enum)
pretty prints the proper text of what happened.
Would it be possible to do same here? Currently, the malli.dev/start!
hi-jacks actual throwing of error, I guess you can't control that here, just generating the exception, to be throwed by test.check
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the feedback.
I think it's just a matter of calling m/-exception
, I'll look into it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you take another look?
@@ -412,11 +427,21 @@ | |||
(defmethod -schema-generator :< [schema options] (-double-gen {:max (-> schema (m/children options) first dec)})) | |||
(defmethod -schema-generator :<= [schema options] (-double-gen {:max (-> schema (m/children options) first)})) | |||
(defmethod -schema-generator := [schema options] (gen/return (first (m/children schema options)))) | |||
(defmethod -schema-generator :not= [schema options] (gen/such-that #(not= % (-> schema (m/children options) first)) gen/any-printable 100)) | |||
(defmethod -schema-generator :not= [schema options] (gen/such-that #(not= % (-> schema (m/children options) first)) gen/any-printable | |||
{:max-tries 100 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some of these have :max-tries
, but not all, is there a reason for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My best guess is that the ones without :max-tries
always succeed in practice.
Thanks! Calling the |
The
:map-of
generator should use(gen/vector-distinct-by first ..)
in order to satisfy:min
, otherwise it can generate less than the minimum number of entries by generating the same key multiple times with different vals.such-that
and functions built on it accept a custom error message on generation failures. It's very helpful to have the precise schema that failed in the error message.The unreachable elements case for
:map-of
disallows generating the empty map if:max
was non-zero. It's perfectly fine to generate empty regardless of:max
. Other collection generators almost made this mistake by checking(<= (or min 0) 0 (or max 0))
, which is technically correct but simplifiable to(= 0 (or min 0))
.coll-distinct-gen
nested generators incorrectly in the unreachable elements case. We want(-never-gen options)
, not(gen/fmap f (-never-gen options))
which defeats our simplification logic of checking for-never-gen
's metadata.