请在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,则使用这样的not nil来确保正确生成序列。

22 个回答

0

评论:gfredericks

大多数集合生成器已经接受用于控制它们大小的选项;您是否有任何使用这些控制不充分的用例?

0

评论:m0smith

我完全错过了那些接受:max和:分配选项的生成器。

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

简要检查generators.cljc后,发现列表、哈希表甚至是基于数组的生成器都可以使用最小(min)和最大(max)选项。

0

评论:m0smith

如果我尝试从def更新字符串为defn,试图允许大小传递多个参数,例如:

然后(sample string)不再起作用,但(sample (string))、(sample (string 5))、(sample (string 3 7))都起作用。

是否有让“字符串”工作时的小窍门?或者是否有更好的方法来修改字符串以接受多个参数?

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 发表评论_

我提出这个请求的考虑。我们真的想将字符串生成器的数量增加一倍吗?更不用说其他事物,比如数组等。

另一个想法是在这里添加一个单个新生成器,到-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

使用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 发表评论_

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

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

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