2024 年 Clojure 调查问卷 中分享您的想法!

欢迎!请参阅关于页面以了解更多关于此功能的详细信息。

0 投票
test.check

有许多生成器返回序列(列表、向量、元组、映射、字符串等)。有时在生成的序列上设置最小或最大大小限制是有用的。有一个接受序列生成器并确保序列是特定长度的生成器会很好。以下有三个例子:
(of-length min max gen)
(of-max-length max gen) => (of-length 0 max gen)
(of-min-length min gen) => (of-length min nil gen)

of-length 检查生成序列的长度。如果长度太小,使用 (take min (cycle s)) 来扩展序列长度。
如果长度太长,则使用 (take max s) 来返回最大长度
需要小心以返回它接收到的相同类型。
如果没有接收序列,则将其视为一个元素序列。
如果 min 不是 0,则使用 such-that not nil 来确保生成适当的序列。

22 个答案

0 投票

评论来自:gfredericks

大多数集合生成器已经接受用于控制其大小的选项;您是否有这样的用例,其中这些控制不足?

0 投票

评论来自:m0smith

我完全忽略了那些接受 :min 和 :max 选项的。

特别是我在查看基于字符串的生成器,因为我需要填充数据库表格,所以字符串必须与列定义匹配,例如非空和varchar(15)。当我考虑这个问题时,编写一个可组合的生成器来强制长度限制,似乎比尝试为所有产生类似结构序列的生成器进行逆向改造更有意义。

简要检查了 generators.cljc 文件后,发现列表、哈希表甚至基于数组的一些生成器都可以使用最小和最大选项。

0 投票

评论来自:m0smith

如果我尝试将一个字符串从 def 更新到 defn,以便允许为大小允许多个参数,如下所示:

(defn string ([] (fmap clojure.string/join (vector char))) ([size] (fmap clojure.string/join (vector char size))) ([min max] (fmap clojure.string/join (vector char min max))))

那么 (sample string) 就不再工作了,但 (sample (string)) (sample (string 5)) (sample (string 3 7)) 都可以正常工作。

有什么技巧可以让仅“string”正常运行吗?或者有更好的方法修改 string 以接受多个参数?

0 投票
评论者:gfredericks

我认为没有干净的方法来解决你提到的问题,这也是我没有在这里找到明显解决方案的原因之一。

我在创建 {{large-integer}} 和 {{double}} 生成器时遇到了这个问题,我决定创建两个生成器:{{large-integer}} 是一个具有默认行为的生成器,而 {{large-integer*}} 是一个接受选项并返回生成器的函数。

回想起来,我不知道这样是否是最好的选择,因为这样很容易造成混乱。我向 David MacIver 询问他在 hypothesis(一个类似的 python 库)中如何处理这个问题,他说他没有任何原始的生成器,只有返回生成器的函数(有时不带任何参数)。我非常喜欢这种方法的一致性,但它显然会对 test.check 实现产生巨大的破坏性变化(尽管有一些骇客技巧可以保留向下兼容性)。

这个问题比这个票据要大。就您提供的代码而言,我认为我更喜欢更接近 {{gen/set}} 的 API,使用选项映射而不是位置参数。

因此,我开始关注这个念头,即使用一些技巧在几个版本中保留向后兼容性,以清洁许多不一致性,但这些都是更大的变化。

如果我们不能提出一个干净的短期解决方案,我在 [test.chuck|https://github.com/gfredericks/test.chuck] 的标准将比以前更加宽松☺。

0 投票

评论来自:m0smith

您更喜欢哪种方式?添加类似of-length的功能来限制现有的序列生成果器,或者创建(def string ...)和(defn string* ...)?我刚刚完成了TCHECK-97的Unicode实现,因此我会遵循我们决定的模式。

0 投票

评论来自:gfredericks

我们不是至少有三个字符串生成器吗?您是否在考虑为每个生成器提供替代方案?

0 投票
评论者:m0smith_

我对提出这个请求的思考。我们真的想将字符串生成器的数量加倍吗?更不用说其他像数组等的事情。

另一种想法是添加一个新的生成器,to-string,它可以接受不同的字符生成器,并使用它根据自己的元素生成器创建字符串


 (defn to-string
   ([element-gen] (to-string element-gen {})))
   ([element-gen [{:keys [num-elements min-elements max-elements max-tries ] :or {num-elements nil min-elements 0 max-elements nil max-retries 10}}]
                   (fmap clojure.string/join (vector char-gen ==apply-options==))))


我省略了处理选项的代码,但希望您能理解。

它可以这样调用: (to-string char {:min-elements 5 :max-elements 10})  或 (to-string char-ascii {:num-elements 5})

这样就可以添加新的字符生成器,这些生成器可以轻松地转换为字符串。
0 投票
评论者:m0smith_

看看它,coll-distinct-by几乎做到了我需要的功能,除了allow-dups?标志没有按我的预期工作。

(sample (coll-distinct-by [] identity true  false (elements [\a \b \c \d \e ]) {:num-elements 4}))总是返回不同的元素,即使allow-dups?是true
0 投票

评论来自:gfredericks

{{coll-distinct-by}}相当特殊,可能在这里不相关。

我认为您可以将(link: num-elements min-elements max-elements)轻松地翻译成与gen/vector接受的参数。不应对max-retries进行应用。

类似于{{to-string}}的东西可能很好,特别是如果它与您对TCHECK-97的考虑相匹配(例如,TCHECK-97提供了可用于{{to-string}}的参数)。

0 投票

评论来自:m0smith

https://github.com/m0smith/test.check.git上使用git --no-pager diff master feature/TCHECK-99生成的补丁文件。

0 投票

评论来自:m0smith

忽略那个补丁。我对主分支已经过时了。新补丁即将到来

0 投票

评论来自:m0smith

TCHECK-99-2.patch是在将test.check与我的分支同步后生成的。应该是最新版本。

0 投票
评论者:m0smith_

我对如何让一个函数像生成器一样被处理也有一些想法。添加类似于以下内容的:对函数添加:generator-factory元数据

(defn to-string
  "生成字符串序列,默认为字符"'
   {:generator-factory to-string}
   ([] (to-string char {})))
   ([element-gen] (to-string element-gen {})))
   ([element-gen [{:keys [num-elements min-elements max-elements]}]
                   (fmap clojure.string/join (vector char-gen ==apply-options==))))


然后生成器可以更新,以接受任何具有:generator-factory元数据的对象
call-gen更新后可以查找新的元数据,如果存在,则调用相关函数,并将结果作为生成器使用

0 投票

评论来自:gfredericks

是的,这就是我想保持向后兼容的基本想法——元数据生成器将以某种方式附上某种形式的弃用警告。

0 投票
评论者:m0smith_

此外,在字符串化操作中,clojure.string/join 支持分隔符,可以轻松添加为附加选项,例如

(to-string int {:sep ","})

如果您同意,我将更新补丁。
...