如何始终为规范中的可选键生成数据?

时间:2018-04-12 20:05:09

标签: clojure clojure.spec test.check

如果我有像

这样的规范
$ cat tca.cql |  cypher-shell -u *** -p ***
  COUNT(*)
  21

$ cat glycolysis.cql |  cypher-shell -u *** -p ***
  COUNT(*)
  22
  node
  (:Metabolism:TCA:Glycolysis {name: "pyruvate"})

$ 

当我做的时候

:Metabolism

有没有办法告诉生成器在为它生成数据时始终考虑可选键?

我知道这可以通过自定义生成器完成,但我想知道是否有可用的功能,或者更简单的方法,不涉及我定义自定义生成器。

2 个答案:

答案 0 :(得分:3)

我认为对你的问题的简短回答是" no"但你可以s/merge使用需要可选键的规范{/ 1}}:

(s/def ::name string?)
(s/def ::age pos-int?)
(s/def ::person (s/keys :req [::name] :opt [::age]))

(gen/sample (s/gen ::person)) ;; ::age not always gen'd
(gen/sample                   ;; ::age always gen'd
  (s/gen (s/merge ::person (s/keys :req [::age]))))

你可以编写一个生成s/keys规范w /生成器的宏来执行此操作。

答案 1 :(得分:0)

我的方法是遍历该规范的表单(使用clojure.spec.alpha/form),如果使用clojure.spec.alpha/keys创建规范,则将可选键合并到必需的键中,最后重新生成规范。

(defn merge-opt-keys
  "Merges optional keys into requried keys (for specs which are created using `clojure.spec.alpha/keys`) using a spec's form/description"
  [fspec]
  (let [keymap (into {} (map (fn [pair] (vec pair)) (partition 2 (rest fspec))))]
    (->> (cond-> {}
           (contains? keymap :opt)
             (assoc :req (vec (concat (keymap :req) (keymap :opt))))
           (contains? keymap :opt-un)
             (assoc :req-un (vec (concat (keymap :req-un) (keymap :opt-un)))))
         (mapcat identity)
         (cons 'clojure.spec.alpha/keys))))

(clojure.spec.alpha/def ::name string?)
(clojure.spec.alpha/def ::desc string?)
(clojure.spec.alpha/def ::book (clojure.spec.alpha/keys :req [::name] :opt [:desc]))

(clojure.spec.gen.alpha/generate (clojure.spec.alpha/gen (eval (merge-opt-keys (clojure.spec.alpha/form ::book)))))