JuliaTesting / SimpleMock.jl

A basic mocking module
https://juliatesting.github.io/SimpleMock.jl
MIT License
21 stars 4 forks source link

Single, more efficient context type #10

Open christopher-dG opened 4 years ago

christopher-dG commented 4 years ago

This has no effect on user API, but I think we can make things faster.

Currently, we abuse @eval to create a new Context type and implement a bunch of overdub methods every time you run mock (unless you specify otherwise). It's really slow because of all that compilation.

Instead of creating new types and implementing overdubs for that type, we could try something like this:

@context Ctx  # The one context for ALL mocks

struct Metadata{Fs}  # Fs is the union of function types that will be mocked
    mocks::Dict

    Metadata(mocks...) =  # Just like the current type: Metadata((f, sig) => mock, ...)
        new{Union{map(p -> typeof(first(first(p))), mocks)...}}(Dict(mocks))
end

# This one overdub method catches all the mocked methods
# for the particular metadata instance.
Cassette.overdub(ctx::Ctx{Metadata{Fs}}, f::F, args...) where {Fs, F <: Fs} =
    ctx.metadata.mocks[f](args...)

Filters would be the same as before, but the specific method mocks (e.g. mock((+, Int, Int))) will be more complicated (previously the methods we implemented were only for the specified signature, so dispatch took care of it for us), as well as keyword arguments. I think for kwargs we would still have to eval new methods because Cassette can't handle the general kwftype trick.