2024年度Clojure调查!中分享您的想法。

欢迎!请查看关于页面以获取更多关于如何使用本站的信息。

0
Spec
问题陈述:某些规范实现返回没有生成器但返回nil,在它们的gen*实现中,当它们的*recursion-limit*达到时(例如s/or)。规范实现组合其他规范时,有时会从其他规范的gen*中接收无生成器,并相应地调整自己的gen*的行为,有时甚至会什么也不返回(例如s/or的gen*,如果其中的所有分支规范也没有生成器,则返回nil,否则只使用它获得的那些生成器)。但是,有许多规范不尊重从gen*接收无生成器(例如s/every,s/map-of),它们是许多实际递归规范的基本构建块。然后它们最终抛出“无法构建gen...”异常。

以下是一个具有实际规范的问题的简化示例(不是实际用例的说明)


;; A ::B是一个通过::B递归的分支进行s/or的规范
(s/def ::B (s/or :A ::A))

;; 一个::A是一个关键字到::Bs的映射(或者它为空,作为递归终止)

(s/def ::A (s/map-of keyword? ::B :gen-max 3))
                     :gen-max 3))

(gen/sample (s/gen ::A))

ExceptionInfo 在以下位置无法构建gen: [1 :A 1 :A 1 :A 1 :A 1] for: :spec.examples.tree/B  clojure.core/ex-info (core.clj:4725)


规范的上述有效值(我可以发给您一个实际用例,该用例强制执行上述模式,其中我们解析内部查询 DSL)是:{}、{:a {}}、{:foo {:bar {}}}等。

当前规范实现无法为上述规范生成值的缺陷在于,当::B的gen*返回nil时,::A的map-of不会生成一个空映射,而是抛出异常。s/every和所有派生规范都受此影响,可能还有其他规范。

建议的修复:规范的gen*实现必须始终尊重其他规范gen*返回nil,不通过抛出异常,而是通过调整返回的gen或自行返回nil,以便不返回gen的行为传播回调用方,此时应抛出异常。

1 个答案

0
参考: https://clojure.atlassian.net/browse/CLJ-1980 (由lgs32a报告)
...