1
(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是一个映射,其中键是操作的名称,值是该操作的(或基于)依赖项。举个例子,你必须: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 生成这样的一系列动作?当然必须有一种方法可以只使用生成器吗?

4

2 回答 2

2

使用递归生成器执行此操作并不难gen/bind(例如,首先生成动作列表的大小,然后在该大小上使用递归,gen/bind以便您在每一步都有先前生成的动作)。这种方法的最大缺点是gen/bind在收缩时效果不佳,因此您可能最终会得到一连串几乎根本无法收缩的动作。

我真的很想为此想出更好的东西。

于 2015-12-29T02:02:33.863 回答
1

好吧,filter-into-logical-order可以说是更清洁的开关reduce

(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似乎不支持将构造中的向量交给其内部生成器,因此它可以知道允许哪些值,这有点像您的要求所需的结构。

于 2014-12-16T00:23:03.160 回答