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) 来返回最大长度
需要小心返回它接收到的相同类型。
如果没有接收序列,则将其视为一个元素序列。
如果最小值不是0,则使用 not nil 的 such-that 确保正确生成序列。

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 库) 中是如何处理的,他说他没有任何原始生成器,只是返回生成器的函数(有时带有 0 个参数)。我喜欢这种方法的一致性,但是这无疑会对 test.check 产生巨大破坏性变化(尽管有一些技巧可以保留向后兼容性)。

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

现在让我思考这个问题,我开始着迷于一种大型的、利用技巧在几版中保留向后兼容性的 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? 为真
0

评论者:gfredericks

Flamel Joan by {{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
  "生成元素元素-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 ","})

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