Open omus opened 4 years ago
Would it make sense for @test_nolog
to take a vector of pairs for each level => regex
?
I'm not sure I would require that power. I think what I want is:
@test_nolog LOGGER <code>
Which would validate that no logs are emitted from the executed code. Alternatively:
@test_nolog LOGGER ("warn", "notice", "info") <code>
could mean that no logs of that level are emitted. The one problem I see with this however is that we use a tuple in the message part to indicate an AND operation while this would indicate an OR.
Looks like base does something closer to the pairs interface, but with tuples.
If we also wanted to test the debug messages, these need to be enabled with the min_level keyword:
@test_logs (:info,"Doing foo with n=2") (:debug,"Iteration 1") (:debug,"Iteration 2") min_level=Debug foo(2)
Alright, looks like the base implementation is pretty hacky, so I'll just go with @test_nolog <logger> <msg> <expr>
for now.
I found myself wanting this again. I was in a scenario where I wanted to test for two different log messages but only call the function once:
@test_log LOGGER "warn" "one" begin
@test_log LOGGER "warn" "two" begin
slow_call()
end
end
I ended up writing this as a more generic way of testing for logs. It may be useful to do some iteration on this design:
using Memento: DefaultFormatter, Handler, Logger, Record, gethandlers, setpropagating!
using Test
struct RecordHandler{F} <: Handler{F}
records::Vector{Record}
end
RecordHandler() = RecordHandler{DefaultFormatter}(Record[])
function RecordHandler(body::Function, logger::Logger)
handler = RecordHandler()
original_handlers = copy(gethandlers(logger))
try
logger.handlers = Dict{Any, Handler}()
push!(logger, handler)
setpropagating!(logger, false) do
body()
end
finally
logger.handlers = original_handlers
end
return handler
end
function Base.log(handler::RecordHandler, rec::Record)
push!(handler.records, rec)
end
###
rh = RecordHandler(BidDelivery.LOGGER) do
slow_call()
end
@test rh.records[1].level == "warn"
@test occursin("one", rc.records[1].msg)
@test rh.records[2].level == "warn"
@test occursin("two", rc.records[2].msg)
Hmmm, that's pretty close to what already happens internally. I'm not sure how much I like the accessing of nested fields, but I wonder if we could break this up into 4 separate API changes... which could individually be useful in other circumstances.
I encountered a scenario where I wanted to ensure my function which could emit different levels of logs under different conditions was not emitting any logging information under one specific scenario. For this test I needed to write:
It would be nice to have a more straight-forward way of writing this.