|
| 1 | +;; See also `malli.generator-ast` for viewing generators as data |
| 2 | +;; Note: use `::mg/foo` instead of `::foo` in this namespace |
| 3 | +;; to assist in generating `malli.generator-ast`. |
1 | 4 | (ns malli.generator |
2 | 5 | (:require [clojure.spec.gen.alpha :as ga] |
3 | 6 | [clojure.string :as str] |
|
8 | 11 | [clojure.test.check.rose-tree :as rose] |
9 | 12 | [malli.core :as m] |
10 | 13 | [malli.registry :as mr] |
| 14 | + [malli.generator :as-alias mg] |
11 | 15 | #?(:clj [borkdude.dynaload :as dynaload]))) |
12 | 16 |
|
13 | 17 | (declare generator generate -create) |
|
48 | 52 |
|
49 | 53 | (defn -never-gen |
50 | 54 | "Return a generator of no values that is compatible with -unreachable-gen?." |
51 | | - [{::keys [original-generator-schema] :as _options}] |
| 55 | + [{::mg/keys [original-generator-schema] :as _options}] |
52 | 56 | (with-meta (gen/such-that (fn [_] |
53 | 57 | (throw (ex-info |
54 | 58 | (str "Cannot generate values due to infinitely expanding schema: " |
|
58 | 62 | (cond-> {} |
59 | 63 | original-generator-schema (assoc :schema (m/form original-generator-schema)))))) |
60 | 64 | gen/any) |
61 | | - {::never-gen true |
62 | | - ::original-generator-schema original-generator-schema})) |
| 65 | + {::mg/never-gen true |
| 66 | + ::mg/original-generator-schema original-generator-schema})) |
63 | 67 |
|
64 | 68 | (defn -unreachable-gen? |
65 | 69 | "Returns true iff generator g generators no values." |
66 | | - [g] (-> (meta g) ::never-gen boolean)) |
| 70 | + [g] (-> (meta g) ::mg/never-gen boolean)) |
67 | 71 |
|
68 | 72 | (defn -not-unreachable [g] (when-not (-unreachable-gen? g) g)) |
69 | 73 |
|
|
80 | 84 | (defn -min-max [schema options] |
81 | 85 | (let [{:keys [min max] gen-min :gen/min gen-max :gen/max} (m/properties schema options)] |
82 | 86 | (when (and min gen-min (< gen-min min)) |
83 | | - (m/-fail! ::invalid-property {:key :gen/min, :value gen-min, :min min})) |
| 87 | + (m/-fail! ::mg/invalid-property {:key :gen/min, :value gen-min, :min min})) |
84 | 88 | (when (and max gen-max (> gen-max max)) |
85 | | - (m/-fail! ::invalid-property {:key :gen/max, :value gen-min, :max min})) |
| 89 | + (m/-fail! ::mg/invalid-property {:key :gen/max, :value gen-min, :max min})) |
86 | 90 | {:min (or gen-min min) |
87 | 91 | :max (or gen-max max)})) |
88 | 92 |
|
|
286 | 290 |
|
287 | 291 | (defn -ref-gen [schema options] |
288 | 292 | (let [ref-id (-identify-ref-schema schema)] |
289 | | - (or (force (get-in options [::rec-gen ref-id])) |
| 293 | + (or (force (get-in options [::mg/rec-gen ref-id])) |
290 | 294 | (let [scalar-ref-gen (delay (-never-gen options)) |
291 | 295 | dschema (m/deref schema)] |
292 | | - (cond->> (generator dschema (assoc-in options [::rec-gen ref-id] scalar-ref-gen)) |
| 296 | + (cond->> (generator dschema (assoc-in options [::mg/rec-gen ref-id] scalar-ref-gen)) |
293 | 297 | (realized? scalar-ref-gen) (gen/recursive-gen |
294 | | - #(generator dschema (assoc-in options [::rec-gen ref-id] %)))))))) |
| 298 | + #(generator dschema (assoc-in options [::mg/rec-gen ref-id] %)))))))) |
295 | 299 |
|
296 | 300 | (defn -=>-gen [schema options] |
297 | 301 | (let [output-generator (generator (:output (m/-function-info schema)) options)] |
|
334 | 338 | (gen/return ())))) |
335 | 339 |
|
336 | 340 | (defn -*-gen [schema options] |
337 | | - (let [child (m/-get schema 0 nil)] |
| 341 | + (let [child (m/-get schema 0 nil) |
| 342 | + mode (::mg/-*-gen-mode options :*) |
| 343 | + options (dissoc options ::mg/-*-gen-mode)] |
338 | 344 | (if-some [g (-not-unreachable (generator child options))] |
339 | 345 | (cond->> (gen/vector g) |
340 | 346 | (m/-regex-op? child) |
341 | 347 | (gen/fmap #(apply concat %))) |
342 | | - (gen/return ())))) |
| 348 | + (case mode |
| 349 | + :* (gen/return ()) |
| 350 | + :+ (-never-gen options))))) |
| 351 | + |
| 352 | +(defn -+-gen [schema options] |
| 353 | + (let [g (-*-gen schema (assoc options ::mg/-*-gen-mode :+))] |
| 354 | + (cond-> g |
| 355 | + (-not-unreachable g) gen/not-empty))) |
343 | 356 |
|
344 | 357 | (defn -repeat-gen [schema options] |
345 | 358 | (let [child (m/-get schema 0 nil)] |
|
360 | 373 | (defn -qualified-symbol-gen [schema] |
361 | 374 | (-qualified-ident-gen schema symbol gen/symbol qualified-symbol? gen/symbol-ns)) |
362 | 375 |
|
363 | | -(defmulti -schema-generator (fn [schema options] (m/type schema options)) :default ::default) |
| 376 | +(defmulti -schema-generator (fn [schema options] (m/type schema options)) :default ::mg/default) |
364 | 377 |
|
365 | | -(defmethod -schema-generator ::default [schema options] (ga/gen-for-pred (m/validator schema options))) |
| 378 | +(defmethod -schema-generator ::mg/default [schema options] (ga/gen-for-pred (m/validator schema options))) |
366 | 379 |
|
367 | 380 | (defmethod -schema-generator :> [schema options] (-double-gen {:min (-> schema (m/children options) first inc)})) |
368 | 381 | (defmethod -schema-generator :>= [schema options] (-double-gen {:min (-> schema (m/children options) first)})) |
|
432 | 445 |
|
433 | 446 | (defmethod -schema-generator :? [schema options] (-?-gen schema options)) |
434 | 447 | (defmethod -schema-generator :* [schema options] (-*-gen schema options)) |
435 | | -(defmethod -schema-generator :+ [schema options] (gen/not-empty (-*-gen schema options))) |
| 448 | +(defmethod -schema-generator :+ [schema options] (-+-gen schema options)) |
436 | 449 | (defmethod -schema-generator :repeat [schema options] (-repeat-gen schema options)) |
437 | 450 |
|
438 | 451 | ;; |
|
448 | 461 | (when-not (:gen/elements props) |
449 | 462 | (if (satisfies? Generator schema) |
450 | 463 | (-generator schema options) |
451 | | - (-schema-generator schema (assoc options ::original-generator-schema schema)))))) |
| 464 | + (-schema-generator schema (assoc options ::mg/original-generator-schema schema)))))) |
452 | 465 |
|
453 | 466 | (defn- -create-from-schema [props options] |
454 | 467 | (some-> (:gen/schema props) (generator options))) |
|
468 | 481 | (-create-from-elements props) |
469 | 482 | (-create-from-schema props options) |
470 | 483 | (-create-from-gen props schema options) |
471 | | - (m/-fail! ::no-generator {:options options |
472 | | - :schema schema})))) |
| 484 | + (m/-fail! ::mg/no-generator {:options options |
| 485 | + :schema schema})))) |
473 | 486 |
|
474 | 487 | ;; |
475 | 488 | ;; public api |
|
479 | 492 | ([?schema] |
480 | 493 | (generator ?schema nil)) |
481 | 494 | ([?schema options] |
482 | | - (if (::rec-gen options) |
| 495 | + (if (::mg/rec-gen options) |
483 | 496 | ;; disable cache while calculating recursive schemas. caches don't distinguish options. |
484 | 497 | (-create (m/schema ?schema options) options) |
485 | 498 | (m/-cached (m/schema ?schema options) :generator #(-create % options))))) |
|
507 | 520 |
|
508 | 521 | (defn function-checker |
509 | 522 | ([?schema] (function-checker ?schema nil)) |
510 | | - ([?schema {::keys [=>iterations] :or {=>iterations 100} :as options}] |
| 523 | + ([?schema {::mg/keys [=>iterations] :or {=>iterations 100} :as options}] |
511 | 524 | (let [schema (m/schema ?schema options) |
512 | 525 | check (fn [schema] |
513 | 526 | (let [{:keys [input output]} (m/-function-info schema) |
|
524 | 537 | (try (apply f smallest) (catch #?(:clj Exception, :cljs js/Error) e e))) |
525 | 538 | explain-output (when-not explain-input (m/explain output response))] |
526 | 539 | (cond-> shrunk |
527 | | - explain-input (assoc ::explain-input explain-input) |
528 | | - explain-output (assoc ::explain-output explain-output) |
| 540 | + explain-input (assoc ::mg/explain-input explain-input) |
| 541 | + explain-output (assoc ::mg/explain-output explain-output) |
529 | 542 | (ex-message result) (-> (update :result ex-message) |
530 | 543 | (dissoc :result-data)))))))))] |
531 | 544 | (condp = (m/type schema) |
532 | 545 | :=> (check schema) |
533 | 546 | :function (let [checkers (map #(function-checker % options) (m/-children schema))] |
534 | 547 | (fn [x] (->> checkers (keep #(% x)) (seq)))) |
535 | | - (m/-fail! ::invalid-function-schema {:type (m/-type schema)}))))) |
| 548 | + (m/-fail! ::mg/invalid-function-schema {:type (m/-type schema)}))))) |
536 | 549 |
|
537 | 550 | (defn check |
538 | 551 | ([?schema f] (check ?schema f nil)) |
|
0 commit comments