Suppressor.jl
Suppressor.jl copied to clipboard
Suppressor.jl don't capture all `stdout` from `CBinding`ed function
I'm making a package called LibTeXPrintf.jl in which I need to capture stdout
to define some variables.
But @capture_out
doesn't capture all the output unless I had run already a printing operation without capturing it. I'll upload a MWE and an asciinema once I have both.
Here is the asciinema https://asciinema.org/a/523250.
Here is a little testing script, similar to https://github.com/JuliaDocs/IOCapture.jl/issues/16#issuecomment-1630698066:
Test script
using Suppressor, Test
nbytes = [10^0, 10^1, 10^2, 10^3, 10^4, 10^5, 10^6]
function test_print(str)
out = @capture_out begin
print(str)
end
# save in a bool to avoid printing long strings when test fails
cap_output_equals_str = out == str
@test cap_output_equals_str
end
function test_puts(str)
retval = 0
out = @capture_out begin
retval = @ccall puts(str::Cstring)::Cint
end
@test retval == length(str) + 1
# save in a bool to avoid printing long strings when test fails
cap_output_equals_str = out == str * "\n"
@test cap_output_equals_str
end
function test_puts_flush(str)
retval = 0
out = @capture_out begin
retval = @ccall puts(str::Cstring)::Cint
Libc.flush_cstdio()
end
@test retval == length(str) + 1
# save in a bool to avoid printing long strings when test fails
cap_output_equals_str = out == str * "\n"
@test cap_output_equals_str
end
function run_testset(fn::Function)
@testset verbose=true "$fn" begin
for (i, n) in enumerate(nbytes)
# print different letters for each test
c = collect('A':'Z')[i]
@testset "$n" begin
fn(c^n)
end
end
end
end
@testset "Suppressor cstdio" verbose=true begin
run_testset(test_print)
run_testset(test_puts)
run_testset(test_puts_flush)
end
Test script output
Test Summary: | Pass Fail Total Time
Suppressor cstdio | 22 13 35 3.1s
test_print | 7 7 0.1s
1 | 1 1 0.1s
10 | 1 1 0.0s
100 | 1 1 0.0s
1000 | 1 1 0.0s
10000 | 1 1 0.0s
100000 | 1 1 0.0s
1000000 | 1 1 0.0s
test_puts | 5 9 14 2.1s
1 | 1 1 2 2.0s
10 | 1 1 2 0.0s
100 | 1 1 2 0.0s
1000 | 1 1 2 0.0s
10000 | 1 1 2 0.0s
100000 | 2 2 0.0s
1000000 | 2 2 0.0s
test_puts_flush | 10 4 14 0.0s
1 | 2 2 0.0s
10 | 2 2 0.0s
100 | 2 2 0.0s
1000 | 2 2 0.0s
10000 | 2 2 0.0s
100000 | 2 2 0.0s
1000000 | 2 2 0.0s
If you look at the errors, you can see that with Libc.flush_cstdio()
it works for sizes 10k bytes and below, but fails for larger outputs.
From these results it seems to me that just adding a single Libc.flush_cstdio()
as is done in #47 would help and work correctly for short cstdio outputs, but for longer outputs one would have to additionally keep on reading from the pipe so it doesn't fill up.
Interesting, I need to look at it to know how to correct it for good. Thanks for the test script.