Skip to content

Commit

Permalink
Add predicates for call argument matching (#15)
Browse files Browse the repository at this point in the history
  • Loading branch information
christopher-dG authored Nov 6, 2020
1 parent 9dba33a commit 4ee3c0d
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 15 deletions.
8 changes: 6 additions & 2 deletions .github/workflows/TagBot.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
name: TagBot
on:
schedule:
- cron: 0 0 * * *
issue_comment:
types:
- created
workflow_dispatch:
jobs:
TagBot:
if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot'
runs-on: ubuntu-latest
steps:
- uses: JuliaRegistries/TagBot@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
ssh: ${{ secrets.DOCUMENTER_KEY }}
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "SimpleMock"
uuid = "a896ed2c-15a5-4479-b61d-a0e88e2a1d25"
authors = ["Chris de Graaf <[email protected]>"]
version = "1.1.4"
version = "1.2.0"

[deps]
Cassette = "7057c7e9-c182-5462-911a-8362d720325c"
Expand Down
37 changes: 27 additions & 10 deletions docs/Manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
[[Base64]]
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"

[[Cassette]]
git-tree-sha1 = "ff6f5109371926beb67ec3101be17d2c211e497d"
uuid = "7057c7e9-c182-5462-911a-8362d720325c"
version = "0.3.3"

[[Dates]]
deps = ["Printf"]
uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"
Expand All @@ -13,25 +18,31 @@ uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b"

[[DocStringExtensions]]
deps = ["LibGit2", "Markdown", "Pkg", "Test"]
git-tree-sha1 = "88bb0edb352b16608036faadcc071adda068582a"
git-tree-sha1 = "50ddf44c53698f5e784bbebb3f4b21c5807401b1"
uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
version = "0.8.1"
version = "0.8.3"

[[Documenter]]
deps = ["Base64", "Dates", "DocStringExtensions", "InteractiveUtils", "JSON", "LibGit2", "Logging", "Markdown", "REPL", "Test", "Unicode"]
git-tree-sha1 = "646ebc3db49889ffeb4c36f89e5d82c6a26295ff"
deps = ["Base64", "Dates", "DocStringExtensions", "IOCapture", "InteractiveUtils", "JSON", "LibGit2", "Logging", "Markdown", "REPL", "Test", "Unicode"]
git-tree-sha1 = "71e35e069daa9969b8af06cef595a1add76e0a11"
uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
version = "0.24.7"
version = "0.25.3"

[[IOCapture]]
deps = ["Logging"]
git-tree-sha1 = "377252859f740c217b936cebcd918a44f9b53b59"
uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89"
version = "0.1.1"

[[InteractiveUtils]]
deps = ["Markdown"]
uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"

[[JSON]]
deps = ["Dates", "Mmap", "Parsers", "Unicode"]
git-tree-sha1 = "b34d7cef7b337321e97d22242c3c2b91f476748e"
git-tree-sha1 = "81690084b6198a2e1da36fcfda16eeca9f9f24e4"
uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
version = "0.21.0"
version = "0.21.1"

[[LibGit2]]
deps = ["Printf"]
Expand All @@ -51,10 +62,10 @@ uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"
uuid = "a63ad114-7e13-5084-954f-fe012c677804"

[[Parsers]]
deps = ["Dates", "Test"]
git-tree-sha1 = "0c16b3179190d3046c073440d94172cfc3bb0553"
deps = ["Dates"]
git-tree-sha1 = "6fa4202675c05ba0f8268a6ddf07606350eda3ce"
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
version = "0.3.12"
version = "1.0.11"

[[Pkg]]
deps = ["Dates", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "UUIDs"]
Expand All @@ -78,6 +89,12 @@ uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"
[[Serialization]]
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"

[[SimpleMock]]
deps = ["Cassette"]
path = ".."
uuid = "a896ed2c-15a5-4479-b61d-a0e88e2a1d25"
version = "1.2.0"

[[Sockets]]
uuid = "6462fe0b-24de-5631-8697-dd941f90decc"

Expand Down
1 change: 1 addition & 0 deletions docs/Project.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
[deps]
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
SimpleMock = "a896ed2c-15a5-4479-b61d-a0e88e2a1d25"
1 change: 1 addition & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Call
has_call
has_calls
reset!
Predicate
```

## The `mock` Function
Expand Down
1 change: 1 addition & 0 deletions src/SimpleMock.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ using Cassette: Cassette, Context, overdub, posthook, prehook, recurse, @context
export
Call,
Mock,
Predicate,
mock,
calls,
last_call,
Expand Down
37 changes: 35 additions & 2 deletions src/mock_type.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,29 @@ struct Call{T<:Tuple, P<:Pairs}
Call(args...; kwargs...) = new{typeof(args), typeof(kwargs)}(args, kwargs)
end

"""
Predicate(f)
A predicate that can be used instead of literal call arguments,
useful for situations where the exact value of arguments is not known.
The function `f` is called with the observed argument, and must return a `Bool`.
## Example
```julia
m = Mock()
m(rand(1:10))
@assert called_with(m, Predicate(in(1:10)))
```
"""
struct Predicate{F}
f::F
end

Base.show(io::IO, ::MIME"text/plain", p::Predicate) = print(io, "Predicate(", p.f, ")")

(p::Predicate)(x) = p.f(x)

Base.:(==)(a::Call{T1, P1}, b::Call{T2, P2}) where {T1, P1, T2, P2} = false
Base.:(==)(a::Call{T, P}, b::Call{T, P}) where {T, P} =
a.args == b.args && a.kwargs == b.kwargs
Expand Down Expand Up @@ -123,7 +146,7 @@ called_once_with(m::Mock, args...; kwargs...) =
Similiar to [`called_with`](@ref), but using a [`Call`](@ref).
"""
has_call(m::Mock, c::Call) = c in calls(m)
has_call(m::Mock, c::Call) = any(call -> call_matches(c, call), calls(m))

"""
has_calls(::Mock, ::Call...) -> Bool
Expand All @@ -137,7 +160,7 @@ function has_calls(m::Mock, cs::Call...)
cs = collect(cs) # Omitting this causes a segfault?!
n = length(cs) - 1
for i in 1:(length(existing) - n)
existing[i:i+n] == cs && return true
all(ab -> call_matches(ab...), zip(cs, existing[i:i+n])) && return true
end
return false
end
Expand All @@ -161,3 +184,13 @@ function do_effect(xs::Vector, args...; kwargs...)
x = popfirst!(xs)
return x isa Vector ? x : do_effect(x, args...; kwargs...)
end

# Match call arguments.
call_matches(expected, observed) =
length(expected.args) == length(observed.args) &&
issetequal(keys(expected.kwargs), keys(observed.kwargs)) &&
all(ab -> arg_matches(ab...), zip(expected.args, observed.args)) &&
all(k -> arg_matches(expected.kwargs[k], observed.kwargs[k]), keys(expected.kwargs))

arg_matches(expected, observed) = expected == observed
arg_matches(pred::Predicate, observed) = pred(observed)
32 changes: 32 additions & 0 deletions test/mock_type.jl
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ end

m = Mock()
@test sprint(show, mime, m) == "Mock(id=$(m.id))"

p = Predicate(iseven)
@test sprint(show, mime, p) == "Predicate(iseven)"
end

@testset "Equality" begin
Expand All @@ -127,3 +130,32 @@ end
@test Mock() != Mock()
@test Mock(1) != Mock(1)
end

@testset "Predicates" begin
p = Predicate(iseven)

m = Mock()
@test !has_call(m, Call(p))
m(1)
@test !has_call(m, Call(p))
m(2)
@test has_call(m, Call(p))

m = Mock()
@test !has_call(m, Call(; x=p))
m(; x=1)
@test !has_call(m, Call(; x=p))
m(; x=2)
@test has_call(m, Call(; x=p))

m = Mock()
m(1, 2, 3; a=1, b=2, c=3)
@test !has_call(m, Call(1, 2, p; a=1, b=2, c=3))
@test !has_call(m, Call(1, 2, 3; a=1, b=2, c=p))
@test has_call(m, Call(1, p, 3; a=1, b=p, c=3))

m = Mock()
foreach(m, 1:10)
@test !has_calls(m, Call(1), Call(Predicate(==(3))))
@test has_calls(m, Call(Predicate(==(5))), Call(Predicate(iseven)))
end

2 comments on commit 4ee3c0d

@christopher-dG
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator register

Release notes:
You can now do "fuzzy" call argument matching with the new Predicate type.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/24237

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v1.2.0 -m "<description of version>" 4ee3c0dea7238349be2a1ce157684118cb55e135
git push origin v1.2.0

Please sign in to comment.