mirror of
https://github.com/julia-actions/julia-runtest.git
synced 2026-02-12 02:56:55 +08:00
Add test failure annotations on v1.8+ (#58)
Co-authored-by: Dilum Aluthge <dilum@aluthge.com>
This commit is contained in:
97
test_logger.jl
Normal file
97
test_logger.jl
Normal file
@@ -0,0 +1,97 @@
|
||||
module TestLogger
|
||||
using Pkg
|
||||
|
||||
function parse_file_line(failed_line)
|
||||
# The bits like `\e[91m\e[1m` are color codes that get printed by `Pkg.test`. We
|
||||
# match with or without them.
|
||||
r = r"(\e\[91m\e\[1m)?Test Failed(\e\[22m\e\[39m)? at (\e\[39m\e\[1m)?(?<path>[^\s\e]+)(\e\[22m)?"
|
||||
m = match(r, failed_line)
|
||||
m === nothing && return (nothing, nothing)
|
||||
|
||||
if m[:path] === nothing
|
||||
return (nothing, nothing)
|
||||
else
|
||||
path_split_results = rsplit(m[:path], ":", limit=2)
|
||||
if length(path_split_results) == 1
|
||||
return (m[:path], nothing)
|
||||
else
|
||||
path, line_no = path_split_results
|
||||
|
||||
# Try to make sure line number is parseable to avoid false positives
|
||||
line_no = tryparse(Int, line_no) === nothing ? nothing : line_no
|
||||
return (path, line_no)
|
||||
end
|
||||
end
|
||||
return (nothing, nothing)
|
||||
end
|
||||
|
||||
function readlines_until(f, stream; keep_lines=true, io)
|
||||
lines = String[]
|
||||
while true
|
||||
line = readline(stream; keep=true)
|
||||
print(io, line)
|
||||
|
||||
# with `keep=true`, this should only happen when we're done?
|
||||
# I think so...
|
||||
if line == ""
|
||||
return line, lines
|
||||
end
|
||||
if f(line)
|
||||
return line, lines
|
||||
else
|
||||
keep_lines && push!(lines, line)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function has_test_failure(line)
|
||||
contains(line, "Test Failed") || return false
|
||||
file, line_no = parse_file_line(line)
|
||||
return !isnothing(file) && !isnothing(line_no)
|
||||
end
|
||||
|
||||
function build_stream(io)
|
||||
stream = Base.BufferStream()
|
||||
t = @async begin
|
||||
while !eof(stream)
|
||||
# Iterate through and print until we get to "Test Failed" and can parse it
|
||||
failed_line, _ = readlines_until(has_test_failure, stream; keep_lines=false, io)
|
||||
@label found_failed_line
|
||||
# Parse file and line out
|
||||
file, line_no = parse_file_line(failed_line)
|
||||
|
||||
# Grab everything until the stacktrace, OR we hit another `Test Failed`
|
||||
stopped_line, msg_lines = readlines_until(stream; io) do line
|
||||
contains(line, "Stacktrace:") || has_test_failure(line)
|
||||
end
|
||||
|
||||
# If we stopped because we hit a 2nd test failure,
|
||||
# let's assume somehow the stacktrace didn't show up for the first one.
|
||||
# Let's continue by trying to find the info for this one, by jumping back.
|
||||
if has_test_failure(stopped_line)
|
||||
failed_line = stopped_line
|
||||
@goto found_failed_line
|
||||
end
|
||||
|
||||
if !isempty(msg_lines)
|
||||
msg = string("Test Failed\n", chomp(join(msg_lines)))
|
||||
# Now log it out
|
||||
@error msg _file=file _line=line_no
|
||||
end
|
||||
end
|
||||
end
|
||||
return stream, t
|
||||
end
|
||||
|
||||
|
||||
function test(args...; kwargs...)
|
||||
stream, t = build_stream(stdout)
|
||||
Base.errormonitor(t)
|
||||
return try
|
||||
Pkg.test(args...; kwargs..., io=stream)
|
||||
finally
|
||||
close(stream)
|
||||
end
|
||||
end
|
||||
|
||||
end # module
|
||||
Reference in New Issue
Block a user