Skip to content

Commit b36650b

Browse files
Kenoclaude
andauthored
Test: Add io argument to internal testset printing functions (JuliaLang#59357)
This adds io arguments to various test printing helpers. This is useful when implementing custom testsets that should not print to stdout. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Keno Fischer <[email protected]> Co-authored-by: Claude <[email protected]>
1 parent fc1fb41 commit b36650b

File tree

2 files changed

+66
-32
lines changed

2 files changed

+66
-32
lines changed

stdlib/Test/src/Test.jl

Lines changed: 41 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,34 +1302,43 @@ record(ts::DefaultTestSet, t::AbstractTestSet) = push!(ts.results, t)
13021302
@specialize
13031303

13041304
"""
1305-
print_test_errors(::AbstractTestSet)
1305+
print_test_errors([io::IO], ts::AbstractTestSet)
13061306
13071307
Prints the errors that were recorded by this `AbstractTestSet` after it
1308-
was `finish`ed.
1308+
was `finish`ed. If `io` is not provided, defaults to `stdout`.
13091309
"""
13101310
function print_test_errors(ts::AbstractTestSet)
1311+
print_test_errors(stdout, ts)
1312+
end
1313+
1314+
function print_test_errors(io::IO, ts::AbstractTestSet)
13111315
for t in results(ts)
13121316
if isa(t, Error) || isa(t, Fail)
1313-
println("Error in testset $(ts.description):")
1314-
show(t)
1315-
println()
1317+
println(io, "Error in testset $(ts.description):")
1318+
show(io, t)
1319+
println(io)
13161320
elseif isa(t, AbstractTestSet)
1317-
print_test_errors(t)
1321+
print_test_errors(io, t)
13181322
end
13191323
end
13201324
end
13211325

13221326
"""
1323-
print_test_results(ts::AbstractTestSet, depth_pad=0)
1327+
print_test_results([io::IO], ts::AbstractTestSet, depth_pad=0)
13241328
13251329
Print the results of an `AbstractTestSet` as a formatted table.
13261330
13271331
`depth_pad` refers to how much padding should be added in front of all output.
1332+
If `io` is not provided, defaults to `stdout`.
13281333
13291334
Called inside of `Test.finish`, if the `finish`ed testset is the topmost
13301335
testset.
13311336
"""
13321337
function print_test_results(ts::AbstractTestSet, depth_pad=0)
1338+
print_test_results(stdout, ts, depth_pad)
1339+
end
1340+
1341+
function print_test_results(io::IO, ts::AbstractTestSet, depth_pad=0)
13331342
# Calculate the overall number for each type so each of
13341343
# the test result types are aligned
13351344
tc = get_test_counts(ts)
@@ -1355,34 +1364,34 @@ function print_test_results(ts::AbstractTestSet, depth_pad=0)
13551364
# recursively walking the tree of test sets
13561365
align = max(get_alignment(ts, depth_pad), textwidth("Test Summary:"))
13571366
# Print the outer test set header once
1358-
printstyled(rpad("Test Summary:", align, " "), " |", " "; bold=true)
1367+
printstyled(io, rpad("Test Summary:", align, " "), " |", " "; bold=true)
13591368
if pass_width > 0
1360-
printstyled(lpad("Pass", pass_width, " "), " "; bold=true, color=:green)
1369+
printstyled(io, lpad("Pass", pass_width, " "), " "; bold=true, color=:green)
13611370
end
13621371
if fail_width > 0
1363-
printstyled(lpad("Fail", fail_width, " "), " "; bold=true, color=Base.error_color())
1372+
printstyled(io, lpad("Fail", fail_width, " "), " "; bold=true, color=Base.error_color())
13641373
end
13651374
if error_width > 0
1366-
printstyled(lpad("Error", error_width, " "), " "; bold=true, color=Base.error_color())
1375+
printstyled(io, lpad("Error", error_width, " "), " "; bold=true, color=Base.error_color())
13671376
end
13681377
if broken_width > 0
1369-
printstyled(lpad("Broken", broken_width, " "), " "; bold=true, color=Base.warn_color())
1378+
printstyled(io, lpad("Broken", broken_width, " "), " "; bold=true, color=Base.warn_color())
13701379
end
13711380
if total_width > 0 || total == 0
1372-
printstyled(lpad("Total", total_width, " "), " "; bold=true, color=Base.info_color())
1381+
printstyled(io, lpad("Total", total_width, " "), " "; bold=true, color=Base.info_color())
13731382
end
13741383
timing = isdefined(ts, :showtiming) ? ts.showtiming : false
13751384
if timing
1376-
printstyled(lpad("Time", duration_width, " "); bold=true)
1385+
printstyled(io, lpad("Time", duration_width, " "); bold=true)
13771386
end
1378-
println()
1387+
println(io)
13791388
# Recursively print a summary at every level
1380-
print_counts(ts, depth_pad, align, pass_width, fail_width, error_width, broken_width, total_width, duration_width, timing)
1389+
print_counts(io, ts, depth_pad, align, pass_width, fail_width, error_width, broken_width, total_width, duration_width, timing)
13811390
# Print the RNG of the outer testset if there are failures
13821391
if total != total_pass + total_broken
13831392
rng = get_rng(ts)
13841393
if !isnothing(rng)
1385-
println("RNG of the outermost testset: ", rng)
1394+
println(io, "RNG of the outermost testset: ", rng)
13861395
end
13871396
end
13881397
end
@@ -1572,7 +1581,7 @@ results(::AbstractTestSet) = ()
15721581

15731582
# Recursive function that prints out the results at each level of
15741583
# the tree of test sets
1575-
function print_counts(ts::AbstractTestSet, depth, align,
1584+
function print_counts(io::IO, ts::AbstractTestSet, depth, align,
15761585
pass_width, fail_width, error_width, broken_width, total_width, duration_width, showtiming)
15771586
# Count results by each type at this level, and recursively
15781587
# through any child test sets
@@ -1582,58 +1591,58 @@ function print_counts(ts::AbstractTestSet, depth, align,
15821591
tc.cumulative_passes + tc.cumulative_fails + tc.cumulative_errors + tc.cumulative_broken
15831592
# Print test set header, with an alignment that ensures all
15841593
# the test results appear above each other
1585-
print(rpad(string(" "^depth, ts.description), align, " "), " | ")
1594+
print(io, rpad(string(" "^depth, ts.description), align, " "), " | ")
15861595

15871596
n_passes = tc.passes + tc.cumulative_passes
15881597
if n_passes > 0
1589-
printstyled(lpad(string(n_passes), pass_width, " "), " ", color=:green)
1598+
printstyled(io, lpad(string(n_passes), pass_width, " "), " ", color=:green)
15901599
elseif pass_width > 0
15911600
# No passes at this level, but some at another level
1592-
printstyled(lpad(fallbackstr, pass_width, " "), " ", color=:green)
1601+
printstyled(io, lpad(fallbackstr, pass_width, " "), " ", color=:green)
15931602
end
15941603

15951604
n_fails = tc.fails + tc.cumulative_fails
15961605
if n_fails > 0
1597-
printstyled(lpad(string(n_fails), fail_width, " "), " ", color=Base.error_color())
1606+
printstyled(io, lpad(string(n_fails), fail_width, " "), " ", color=Base.error_color())
15981607
elseif fail_width > 0
15991608
# No fails at this level, but some at another level
1600-
printstyled(lpad(fallbackstr, fail_width, " "), " ", color=Base.error_color())
1609+
printstyled(io, lpad(fallbackstr, fail_width, " "), " ", color=Base.error_color())
16011610
end
16021611

16031612
n_errors = tc.errors + tc.cumulative_errors
16041613
if n_errors > 0
1605-
printstyled(lpad(string(n_errors), error_width, " "), " ", color=Base.error_color())
1614+
printstyled(io, lpad(string(n_errors), error_width, " "), " ", color=Base.error_color())
16061615
elseif error_width > 0
16071616
# No errors at this level, but some at another level
1608-
printstyled(lpad(fallbackstr, error_width, " "), " ", color=Base.error_color())
1617+
printstyled(io, lpad(fallbackstr, error_width, " "), " ", color=Base.error_color())
16091618
end
16101619

16111620
n_broken = tc.broken + tc.cumulative_broken
16121621
if n_broken > 0
1613-
printstyled(lpad(string(n_broken), broken_width, " "), " ", color=Base.warn_color())
1622+
printstyled(io, lpad(string(n_broken), broken_width, " "), " ", color=Base.warn_color())
16141623
elseif broken_width > 0
16151624
# None broken at this level, but some at another level
1616-
printstyled(lpad(fallbackstr, broken_width, " "), " ", color=Base.warn_color())
1625+
printstyled(io, lpad(fallbackstr, broken_width, " "), " ", color=Base.warn_color())
16171626
end
16181627

16191628
if n_passes == 0 && n_fails == 0 && n_errors == 0 && n_broken == 0
16201629
total_str = tc.customized ? string(subtotal) : "?"
1621-
printstyled(lpad(total_str, total_width, " "), " ", color=Base.info_color())
1630+
printstyled(io, lpad(total_str, total_width, " "), " ", color=Base.info_color())
16221631
else
1623-
printstyled(lpad(string(subtotal), total_width, " "), " ", color=Base.info_color())
1632+
printstyled(io, lpad(string(subtotal), total_width, " "), " ", color=Base.info_color())
16241633
end
16251634

16261635
if showtiming
1627-
printstyled(lpad(tc.duration, duration_width, " "))
1636+
printstyled(io, lpad(tc.duration, duration_width, " "))
16281637
end
1629-
println()
1638+
println(io)
16301639

16311640
# Only print results at lower levels if we had failures or if the user
16321641
# wants. Requires the given `AbstractTestSet` to have a vector of results
16331642
if ((n_passes + n_broken != subtotal) || print_verbose(ts))
16341643
for t in results(ts)
16351644
if isa(t, AbstractTestSet)
1636-
print_counts(t, depth + 1, align,
1645+
print_counts(io, t, depth + 1, align,
16371646
pass_width, fail_width, error_width, broken_width, total_width, duration_width, ts.showtiming)
16381647
end
16391648
end

stdlib/Test/test/runtests.jl

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2008,3 +2008,28 @@ end
20082008
@test occursin("(x, y) = (42, \"hello\")", recorded_error2.context)
20092009
end
20102010
end
2011+
2012+
@testset "io argument for Test output functions" begin
2013+
# Test print_test_results and print_test_errors with io redirection
2014+
io = IOBuffer()
2015+
2016+
# Create a testset with passing and failing tests
2017+
ts = Test.DefaultTestSet("IO Test")
2018+
Test.record(ts, Test.Pass(:test, nothing, nothing, nothing, LineNumberNode(1), false))
2019+
fail = Test.Fail(:test, "1 == 2", nothing, nothing, LineNumberNode(2, Symbol("test.jl")))
2020+
push!(ts.results, fail)
2021+
2022+
# Test print_test_results with io
2023+
Test.print_test_results(io, ts)
2024+
output = String(take!(io))
2025+
@test occursin("Test Summary:", output)
2026+
@test occursin("IO Test", output)
2027+
@test occursin("Pass", output)
2028+
@test occursin("Fail", output)
2029+
2030+
# Test print_test_errors with io
2031+
Test.print_test_errors(io, ts)
2032+
output = String(take!(io))
2033+
@test occursin("Error in testset", output)
2034+
@test occursin("1 == 2", output)
2035+
end

0 commit comments

Comments
 (0)