2024年Clojure状态调查中分享您的想法!

欢迎!请查看关于页面以了解更多关于这个页面的信息。

0
Spec

摘要

1) 给定一个被测函数 {{map-f}},它会被懒调用,例如作为 {{(def ls (map map-f (range)))}}。
2) 还有给定的被测函数 {{varargs-f}},一个可以使用可变数量参数的函数。当你将一个 {{LazySeq}} 传递给 {{varargs-f}} 时,一些或全部元素都会因为匹配而实现。
3) 问题:当调用 {{(apply varargs-f ls)}} 时,一些无效的对 {{map-f}} 的调用可能会被忽视。

复现示例

在下面的代码中,{{map-f}} 被预期在用其他类型而不是 {{Symbol}} 调用时会抛出异常。然而,调用 {{map-f}} 用一个 {{String}} 被通过了。

`
(ns repro
(:require
[clojure.spec.alpha :as s]
[clojure.spec.test.alpha :as stest]))

(defn map-f [x]
(println "用类型" (type x) "调用了我的函数")
(println (deref #'clojure.spec.test.alpha/instrument-enabled))
{x 1})

(s/fdef map-f :args (s/cat :x symbol?))

(defn varargs-f [& maps]
true)

(s/fdef varargs-f :args (s/cat :maps (s/* map?)))

(defn repro [& args]
(apply varargs-f (map map-f args)))

(stest/instrument)

(repro 'foo 'bar "baz")
`

输出

用类型 clojure.lang.Symbol 调用了 my-fn true 用类型 clojure.lang.Symbol 调用了 my-fn true 用类型 java.lang.String ;; <--- nil

原因

当 {{varargs-f}} 的参数Because{{varargs-f}}'s arguments被作为结果实现时,在 {{with-instrument-disabled}} 的作用域内,一些对 {{map-fn}} 的调用被执行。参见代码:[https://github.com/clojure/spec.alpha/blob/f23ea614b3cb658cff0044a027cacdd76831edcf/src/main/clojure/clojure/spec/test/alpha.clj#L140](https://github.com/clojure/spec.alpha/blob/f23ea614b3cb658cff0044a027cacdd76831edcf/src/main/clojure/clojure/spec/test/alpha.clj#L140)

背景

我在对 {{merge-with}} 进行spec'ing时遇到了这个问题。在某个测试命名空间中的spec'ed函数不再抛出异常,因为clojure.test中的这行代码与上述描述的spec问题类似:https://github.com/clojure/clojure/blob/28efe345d5e995dc152a0286fb0be81443a0d9ac/src/clj/clojure/test.clj#L775

CLJ-2443.patch 包含了一个修复,但我意识到它可能还不是完美的。因此我提供了一个 CLJ-2443-test.patch,它只包含一个可以被用来测试替代方案的单元测试。

4 个回答

0

评论者:borkdude

CLJ-2443.patch 通过使 with-instrument-disabled 范围之外的 Cons 类型参数符合条件来修复此问题。
已提供测试。修正此补丁与 speculative (https://github.com/slipset/speculative) 一起工作。

0

评论者:borkdude

CLJ-2443-test 只包含测试,不包括修复本身。

0

评论者:borkdude

使用 CLJ-2443-test.patch 更新了描述。

0
参考:https://clojure.atlassian.net/browse/CLJ-2443 (由 borkdude 提出)
...