Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions src/ParallelTestRunner.jl
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ function print_test_failed(record::AbstractTestRecord, wrkr, test, ctx::TestIOCo

if ctx.verbose
init_time_str = @sprintf("%7.2f", base.total_time - base.time)
printstyled(ctx.stdout, lpad(init_time_str, ctx.elapsed_align + 1, " "), " │ ", color = :red)
printstyled(ctx.stderr, lpad(init_time_str, ctx.elapsed_align + 1, " "), " │ ", color = :red)
end

failed_str = "failed at $(now())\n"
Expand Down Expand Up @@ -313,6 +313,14 @@ function print_test_crashed(::Type{<:AbstractTestRecord}, wrkr, test, ctx::TestI
end
end

# Truncate `line` to at most `max_width` characters, appending "..." when truncated.
function truncate_line(line::AbstractString, max_width::Int)
if length(line) > max_width
line = first(line, max(0, max_width - 3)) * "..."
end
return line
end

# Adapted from `Malt._stdio_loop`
function stdio_loop(worker::Malt.Worker, io::Lockable)
Threads.@spawn while !eof(worker.stdout) && Malt.isrunning(worker)
Expand Down Expand Up @@ -1191,9 +1199,7 @@ function _runtests(mod::Module, args::ParsedArgs;
line2 = "Running: " * join(status_parts, ", ")
## truncate
max_width = displaysize(io_ctx.stdout)[2]
if length(line2) > max_width
line2 = line2[1:max_width-3] * "..."
end
line2 = truncate_line(line2, max_width)

# line 3: progress + ETA
line3 = "Progress: $completed/$total tests completed"
Expand Down
44 changes: 44 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,30 @@ end
@test contains(str, "1 == 2")
end

@testset "failed test row printed entirely to stderr" begin
testsuite = Dict(
"failing test" => quote
@test 1 == 2
end
)

# use separate streams: the whole row of a failed test must go to stderr
out = IOBuffer()
err = IOBuffer()
@test_throws Test.FallbackTestSetException("Test run finished with errors") begin
runtests(ParallelTestRunner, ["--verbose"]; testsuite, stdout=out, stderr=err)
end

outs = String(take!(out))
errs = String(take!(err))
m = match(r"failing test[^\n]*failed at", errs)
@test m !== nothing
# in verbose mode the row has three cell separators (time, init time) on
# stderr; the init-time cell used to leak to stdout instead
@test m !== nothing && count("│", m.match) == 3
@test !contains(outs, "failed at")
end

@testset "nested failure" begin
testsuite = Dict(
"nested" => quote
Expand Down Expand Up @@ -884,6 +908,26 @@ end
@test any(contains("--color=yes"), exe.exec)
end

@testset "truncate_line" begin
# short lines are untouched
@test ParallelTestRunner.truncate_line("short", 80) == "short"
@test ParallelTestRunner.truncate_line("x"^80, 80) == "x"^80

truncated = ParallelTestRunner.truncate_line("x"^100, 80)
@test length(truncated) == 80
@test endswith(truncated, "...")

# multi-byte characters must not break the cut: with byte indexing these
# would throw a StringIndexError when the cut lands mid-character
truncated = ParallelTestRunner.truncate_line("t" * "α"^100, 80)
@test length(truncated) == 80
@test endswith(truncated, "...")

truncated = ParallelTestRunner.truncate_line("€"^100, 40)
@test length(truncated) == 40
@test endswith(truncated, "...")
end

@testset "TestHistoryEntry" begin
flow = ParallelTestRunner.TestHistoryEntry(1,true)
fhigh = ParallelTestRunner.TestHistoryEntry(10,true)
Expand Down