请分享您的想法,参与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)。当我思考这个问题时,似乎编写一个可组合的生成器来强制执行长度限制,比尝试对所有生成序列结构的生成器进行回溯式修改更有意义。

简单检查了一下生成的.cljc文件,发现list、hash-map,以及基于数组的生成器都可以使用最小和最大选项。

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,使用选项映射而不是位置参数。

现在让我思考一下这个问题,我开始迷上这个想法:进行大型的破坏性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 posti htions :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
"生成元素-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

是的,这基本上是我为保留向后兼容性的想法 -- 元数据生成器将以某种方式附带.warn.description。

0
_注释由:m0smith_

关于 to-string,clojure.string/join 支持添加一个分隔符,可以很容易地作为附加选项添加,例如:

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

如果没问题的话,我将更新补丁。
...