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)。当我思考这个问题时, seems like writing a composable generator to enforce length restraints might make more sense than trying to retro fit all the generators that produce sequence-like structures.

短暂检查 generators.cljc 显示列表、hashtable 以及基于数组的一些生成器可以使用最小和最大选项。

0
by

评论者: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
by
_评论者:gfredericks_

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

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

事后,我不确定这是否是我作过的最好选择,因为它太令人困惑了。我曾向 David MacIver 询问在 hypothesis(一个类似的 python 库)中他是如何处理的,他说他没有任何原始的生成器,只有返回生成器的函数(有时未带任何参数)。我喜欢这种方法的统一性,但这显然会对 test.check(尽管有一些技巧可以保持向后兼容性)造成很大的破坏)。

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

现在您让我想到这一点,我越来越专注于一个大型的破坏性 API 变更的想法,使用一些技巧来保持几代版本的向后兼容性,以清理大量不一致性。但这个问题显然大于这个条目。

如果我们不能想出一个清晰的短期方法,我接受东西的标准在 [test.chuck|https://github.com/gfredericks/test.chuck] 中要宽松得多 ☺。

0
by

评论者: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 carrot])) {: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

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

0

评论者:m0smith

忽略那个补丁。我的master版本太旧了。新补丁在路上

0

评论者:m0smith

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

0
_由:m0smith_发表的评论

我还想到了如何让一个函数像一个生成器一样被处理。可以将元数据 :generator-factory 添加到函数中,例如

(defn to-string
  "生成 element-gen 的字符串,默认为字符"
   {: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_发表的评论

此外,在 to-string 中,clojure.string/join 支持分隔符,可以轻松地将其作为附加选项添加

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

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