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 选项的

尤其是我正在关注基于字符串的生成器,因为我需要填充数据库表,因此字符串必须与列定义相匹配,例如非空(not null)和字符变量(varchar, 15)。在思考这个问题时,我认为编写一个可组合的生成器来强制实施长度限制可能比试图对所有产生类似结构序列的生成器进行修改更有意义。

简要检查了 generators.cljc,显示列表、散列映射(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拖拉机]) {: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
  "生成元素生成的字符串,默认为字符"
   {: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 可以更新为查找新元数据,如果存在,则调用相关函数并使用结果作为 Generator。

0

评论由:gfredericks 提出

是的,这基本上是我考虑的向后兼容的方案 — 元数据生成器将以某种方式附上弃用警告。

0
_由m0smith发表的评论_

此外,关于 to-string,clojure.string/join 支持分隔符,我们可以轻松将其作为附加选项添加:

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

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