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 来确保生成正确的 seq。

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" 本身工作?或者有没有更好的方法修改字符串来接受多个参数?

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

评论由: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-tries 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 提供

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

0

评论由:m0smith 提供

忽略那个补丁。我的 master 版本已经过时了。新的补丁在途中

0

评论由:m0smith 提供

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

0
评论者:m0smith

我还想过如何使一个函数表现得像生成器。   可以在一个函数中添加一个 :generator-factory 元数据

(defn to-string
  "生成 element-gen 字符串,默认为 char"
   {: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 ","})

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