(require '[clojure.test.check.generators :as gen])
(def ACTIONS
{:create-new-user #{}
:edit-user #{:create-new-user}
:create-new-board #{:create-new-user}
:edit-board #{:create-new-board}
:create-new-anonymous-comment #{:create-new-board}
:create-new-signed-comment #{:create-new-board}
:edit-comment-text #{:create-new-anonymous-comment :create-new-signed-comment}
:edit-comment-text-and-flip-anonymity #{:create-new-anonymous-comment :create-new-signed-comment}
:flip-anonymity #{:create-new-anonymous-comment :create-new-signed-comment}
:vote-comment-up #{:create-new-anonymous-comment :create-new-signed-comment}
:vote-comment-down #{:create-new-anonymous-comment :create-new-signed-comment}})
(def actions (-> ACTIONS keys vec gen/elements gen/vector))
(defn filter-actions-into-logical-order [as]
(let [seen (atom #{})]
(filter
(fn [v]
(let [required (get ACTIONS v)
valid? (or (some? (some required @seen))
(and (empty? @seen) (= v :create-new-user)))]
(when valid?
(swap! seen conj v)
true)))
as)))
(def ordered-actions (gen/fmap #(-> % filter-actions-into-logical-order vec) actions))以这两个生成器为例:
# (last (gen/sample actions 100))
[:edit-user :vote-comment-down :flip-anonymity :vote-comment-down :vote-comment-down :vote-comment-up :edit-user :create-new-anonymous-comment :edit-board :create-new-signed-comment :vote-comment-up :edit-comment-text-and-flip-anonymity :edit-user :create-new-signed-comment :edit-user :edit-user :vote-comment-down :edit-user :vote-comment-down :create-new-user :vote-comment-down :create-new-user :create-new-user :edit-comment-text-and-flip-anonymity :create-new-user :edit-comment-text-and-flip-anonymity :create-new-anonymous-comment :edit-comment-text :create-new-board :vote-comment-down :flip-anonymity :create-new-signed-comment :vote-comment-up :create-new-user :create-new-signed-comment :edit-user :create-new-user :create-new-board :vote-comment-down :create-new-board :create-new-board :create-new-board :edit-board :edit-comment-text-and-flip-anonymity :edit-user :edit-comment-text :create-new-signed-comment :vote-comment-up :edit-comment-text-and-flip-anonymity :flip-anonymity :create-new-anonymous-comment :create-new-anonymous-comment :edit-board :create-new-signed-comment :edit-comment-text-and-flip-anonymity :edit-board :vote-comment-up :edit-comment-text :create-new-board :edit-comment-text-and-flip-anonymity :create-new-board :vote-comment-down :edit-comment-text-and-flip-anonymity :vote-comment-up :create-new-user :vote-comment-up :edit-comment-text :edit-board :edit-comment-text-and-flip-anonymity :flip-anonymity :edit-board :create-new-anonymous-comment :flip-anonymity :create-new-signed-comment :edit-user :edit-comment-text-and-flip-anonymity :edit-comment-text :edit-comment-text :create-new-user :flip-anonymity :edit-user :vote-comment-up :edit-user :create-new-user :edit-comment-text :edit-comment-text :flip-anonymity :edit-comment-text :edit-board :flip-anonymity :edit-board :edit-comment-text :edit-user :create-new-user :flip-anonymity]
# (last (gen/sample ordered-actions 100))
[:create-new-user :edit-user :edit-user :create-new-board :edit-board :edit-user :create-new-anonymous-comment :edit-comment-text :edit-board :edit-user :edit-user :vote-comment-up :edit-comment-text :create-new-signed-comment :edit-comment-text :create-new-board :edit-comment-text :edit-comment-text :edit-comment-text :vote-comment-up :vote-comment-up :edit-board :edit-comment-text-and-flip-anonymity :create-new-signed-comment :create-new-anonymous-comment :create-new-signed-comment :edit-user :create-new-anonymous-comment :edit-board :create-new-board :create-new-anonymous-comment :create-new-board :flip-anonymity :create-new-anonymous-comment :edit-board :vote-comment-up :vote-comment-down :edit-board :edit-comment-text :edit-user :edit-comment-text :flip-anonymity :create-new-signed-comment :vote-comment-up :edit-comment-text-and-flip-anonymity :vote-comment-up :create-new-signed-comment :edit-comment-text :create-new-signed-comment :create-new-anonymous-comment :edit-board :create-new-anonymous-comment]ACTIONS是一个映射,其中键是操作的名称,值是该操作的(基于OR的)依赖项。例如,您必须先执行:create-new-user,然后才能执行任何操作,必须先执行:create-new-board,然后才能执行:edit-board,并且必须至少有一个:create-new-*-comment才能执行:edit-comment-text。
上面的代码似乎可以工作,但它很难看。1)我不喜欢filter-actions-into-logical-order代码必须对:create-new-user有一个特定的异常。2)我不喜欢我基本上采用随机操作的列表,并将其过滤,直到这些操作有顺序的意义。
我想知道其他人是如何使用test.check生成这样的一系列动作的?肯定有一种只使用生成器就能做到这一点的方法?
发布于 2015-12-29 10:02:34
使用使用gen/bind的递归生成器来实现这一点并不太难(例如,首先生成操作列表的大小,然后使用gen/bind在该大小上使用递归,以便在每一步都有先前生成的操作)。这种方法的最大缺点是,gen/bind在收缩方面的工作相当糟糕,因此您可能会得到几乎根本不能收缩的长序列操作。
我真的很想为此想出更好的办法。
发布于 2014-12-16 08:23:03
可以说,如果改用reduce,filter-into-logical-order可能会更干净
(defn filter-into-logical-order [as]
(last (reduce
(fn [[seen accepted-as] action]
(let[needed (get ACTIONS action)]
(if (or (empty? needed) (some seen needed))
[(conj seen action) (conj accepted-as action)]
[seen accepted-as]))
)
[#{} []]
as)))但这仍然为我提供了大约30%的空向量,而且它不是一个生成器。不过,我不确定文档中的组合子是否真的支持您想要的内容。gen/vector似乎不支持将构造中的向量传递给它的内部生成器,这样它就可以知道允许什么值,这是您的需求所需的某种结构。
https://stackoverflow.com/questions/27464157
复制相似问题