Skip to content

Commit f92873d

Browse files
committed
add tests and docs and use test_msg
1 parent 06668f8 commit f92873d

File tree

4 files changed

+46
-14
lines changed

4 files changed

+46
-14
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "ChainRulesTestUtils"
22
uuid = "cdddcdb0-9152-4a09-a978-84456f9df70a"
3-
version = "1.3.1"
3+
version = "1.4.0"
44

55
[deps]
66
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"

docs/src/index.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,13 @@ For information about ChainRules, including how to write rules, refer to the gen
99
[![](https://img.shields.io/badge/docs-main-blue.svg)](https://JuliaDiff.github.io/ChainRulesCore.jl/dev)
1010
[![](https://img.shields.io/badge/docs-stable-blue.svg)](https://JuliaDiff.github.io/ChainRulesCore.jl/stable)
1111

12-
## Canonical example
12+
## Testing Method Table Sensibility
13+
A basic feature of ChainRulesTestUtils is it's ability to check that the method table for `rrule` and `frule` remains sensible.
14+
This searches the method table for methods that should not exist and when it fails tells you where they were defined.
15+
By calling [`test_method_tables_sensibility`](@ref) ChainRulesTestUtils will check for things such as having attracted a rule to `DataType` rather than attaching it to a constructor.
16+
Basically all packages using ChainRulesTestUtils can use [`test_method_tables_sensibility`](@ref), as it is independent of what rules you have written.
17+
18+
## Canonical example of testing frule and rrule
1319

1420
Let's suppose a custom transformation has been defined
1521
```jldoctest ex
@@ -274,3 +280,4 @@ Test.DefaultTestSet("test_rrule: abs on Float64", Any[], 5, false, false)
274280

275281
This behavior can also be overridden globally by setting the environment variable `CHAINRULES_TEST_INFERRED` before ChainRulesTestUtils is loaded or by changing `ChainRulesTestUtils.TEST_INFERRED[]` from inside Julia.
276282
ChainRulesTestUtils can detect whether a test is run as part of [PkgEval](https://github.com/JuliaCI/PkgEval.jl) and in this case disables inference tests automatically. Packages can use [`@maybe_inferred`](@ref) to get the same behavior for other inference tests.
283+

src/global_checks.jl

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ This would then actually define `rrule(::DataType, x)`. (or `UnionAll` if `Foo`
1919
was parametric, or `Union` if `Foo` was a type alias for a `Union`)
2020
"""
2121
function test_method_tables_sensibility()
22-
@testset "Make sure methods haven't been added to DataType/UnionAll/Union" begin
22+
@testset "Sensible Constructors" begin
2323
# if someone wrote e.g. `rrule(::typeof(Foo), x)` rather than
2424
# `rrule(::Type{<:Foo}, x)` then that would actually define `rrule(::DataType, x)`
2525
# which would be bad. This test checks for that and fails if such a method exists.
@@ -32,12 +32,11 @@ function test_method_tables_sensibility()
3232
nothing
3333
end
3434

35-
if function_type (DataType, UnionAll Union)
36-
@error "Bad constructor rrule. typeof(T)` not `Type{T}`" method
37-
@test false
38-
end
35+
@test_msg(
36+
"Bad constructor rrule. typeof(T) used rather than `Type{T}`. $method",
37+
function_type (DataType, UnionAll, Union)
38+
)
3939
end
40-
4140
# frule
4241
for method in methods(frule)
4342
function_type = if method.sig <: Tuple{Any, RuleConfig, Any, Type, Vararg}
@@ -47,10 +46,11 @@ function test_method_tables_sensibility()
4746
else
4847
nothing
4948
end
50-
51-
if function_type (DataType, UnionAll Union)
52-
@error "Bad constructor frule. typeof(T)` not `Type{T}`" method
53-
@test false
54-
end
49+
50+
@test_msg(
51+
"Bad constructor frule. typeof(T) used rather than `Type{T}`. $method",
52+
function_type (DataType, UnionAll, Union)
53+
)
5554
end
55+
end
5656
end

test/global_checks.jl

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,29 @@
1+
struct BadConstructor
2+
x
3+
end
4+
15
@testset "global_checks.jl" begin
2-
# Just check it doesn't error.
36
test_method_tables_sensibility()
7+
8+
ChainRulesCore.rrule(::typeof(BadConstructor), x) = nothing
9+
@test fails(test_method_tables_sensibility)
10+
Base.delete_method(Base.which(Tuple{typeof(rrule), DataType, Any}))
11+
test_method_tables_sensibility() # make sure delete worked
12+
13+
ChainRulesCore.rrule(::RuleConfig, ::typeof(BadConstructor), x) = nothing
14+
@test fails(test_method_tables_sensibility)
15+
Base.delete_method(Base.which(Tuple{typeof(rrule), RuleConfig, DataType, Any}))
16+
test_method_tables_sensibility() # make sure delete worked
17+
18+
19+
20+
ChainRulesCore.frule(::Any, ::typeof(BadConstructor), x) = nothing
21+
@test fails(test_method_tables_sensibility)
22+
Base.delete_method(Base.which(Tuple{typeof(frule), Any, DataType, Any}))
23+
test_method_tables_sensibility() # make sure delete worked
24+
25+
ChainRulesCore.frule(::RuleConfig, ::Any, ::typeof(BadConstructor), x) = nothing
26+
@test fails(test_method_tables_sensibility)
27+
Base.delete_method(Base.which(Tuple{typeof(frule), RuleConfig, Any, DataType, Any}))
28+
test_method_tables_sensibility() # make sure delete worked
429
end

0 commit comments

Comments
 (0)