From 38deabab1567be98ac6a2a39744ec582f9047e3e Mon Sep 17 00:00:00 2001 From: Spencer Russell Date: Fri, 6 Jul 2018 02:52:07 +0100 Subject: [PATCH] updates for 0.7 and more systematic test output (#26) * updates for 0.7 and more systematic test output * updates capitalization in README --- README.md | 2 +- src/Suppressor.jl | 106 ++++++++++++++++++++-------- test/runtests.jl | 176 ++++++++++++++++++++++++++++++---------------- 3 files changed, 195 insertions(+), 89 deletions(-) diff --git a/README.md b/README.md index 9383675..8cc7638 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Travis](https://travis-ci.org/JuliaIO/Suppressor.jl.svg?branch=master)](https://travis-ci.org/JuliaIO/Suppressor.jl) [![Build status](https://ci.appveyor.com/api/projects/status/e3uuqon84kt97402/branch/master?svg=true)](https://ci.appveyor.com/project/SalchiPapa/suppressor-jl/branch/master) [![CoverAlls](https://coveralls.io/repos/github/JuliaIO/Suppressor.jl/badge.svg?branch=master)](https://coveralls.io/github/JuliaIO/Suppressor.jl?branch=master) [![CodeCov](https://codecov.io/gh/JuliaIO/Suppressor.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/JuliaIO/Suppressor.jl) -Julia macros for suppressing and/or capturing output (STDOUT), warnings (STDERR) or both streams at the same time. +Julia macros for suppressing and/or capturing output (`stdout`), warnings (`stderr`) or both streams at the same time. ## Installation diff --git a/src/Suppressor.jl b/src/Suppressor.jl index 591aba7..49abdb2 100644 --- a/src/Suppressor.jl +++ b/src/Suppressor.jl @@ -7,32 +7,50 @@ export @suppress, @suppress_out, @suppress_err export @capture_out, @capture_err export @color_output +haslogging() = isdefined(Base, :CoreLogging) + """ @suppress expr -Suppress the STDOUT and STDERR streams for the given expression. +Suppress the `stdout` and `stderr` streams for the given expression. """ macro suppress(block) quote if ccall(:jl_generating_output, Cint, ()) == 0 - ORIGINAL_STDOUT = STDOUT + original_stdout = stdout out_rd, out_wr = redirect_stdout() - out_reader = @schedule read(out_rd, String) + out_reader = @async read(out_rd, String) - ORIGINAL_STDERR = STDERR + original_stderr = stderr err_rd, err_wr = redirect_stderr() - err_reader = @schedule read(err_rd, String) + err_reader = @async read(err_rd, String) + + # approach adapted from https://github.com/JuliaLang/IJulia.jl/pull/667/files + if haslogging() + logstate = Base.CoreLogging._global_logstate + logger = logstate.logger + if logger.stream == original_stderr + new_logstate = Base.CoreLogging.LogState(typeof(logger)(err_wr, logger.min_level)) + Core.eval(Base.CoreLogging, Expr(:(=), :(_global_logstate), new_logstate)) + end + end end try $(esc(block)) finally if ccall(:jl_generating_output, Cint, ()) == 0 - redirect_stdout(ORIGINAL_STDOUT) + redirect_stdout(original_stdout) close(out_wr) - redirect_stderr(ORIGINAL_STDERR) + redirect_stderr(original_stderr) close(err_wr) + + if haslogging() + if logger.stream == stderr + Core.eval(Base.CoreLogging, Expr(:(=), :(_global_logstate), logstate)) + end + end end end end @@ -41,21 +59,21 @@ end """ @suppress_out expr -Suppress the STDOUT stream for the given expression. +Suppress the `stdout` stream for the given expression. """ macro suppress_out(block) quote if ccall(:jl_generating_output, Cint, ()) == 0 - ORIGINAL_STDOUT = STDOUT + original_stdout = stdout out_rd, out_wr = redirect_stdout() - out_reader = @schedule read(out_rd, String) + out_reader = @async read(out_rd, String) end try $(esc(block)) finally if ccall(:jl_generating_output, Cint, ()) == 0 - redirect_stdout(ORIGINAL_STDOUT) + redirect_stdout(original_stdout) close(out_wr) end end @@ -65,22 +83,38 @@ end """ @suppress_err expr -Suppress the STDERR stream for the given expression. +Suppress the `stderr` stream for the given expression. """ macro suppress_err(block) quote if ccall(:jl_generating_output, Cint, ()) == 0 - ORIGINAL_STDERR = STDERR + original_stderr = stderr err_rd, err_wr = redirect_stderr() - err_reader = @schedule read(err_rd, String) + err_reader = @async read(err_rd, String) + + # approach adapted from https://github.com/JuliaLang/IJulia.jl/pull/667/files + if haslogging() + logstate = Base.CoreLogging._global_logstate + logger = logstate.logger + if logger.stream == original_stderr + new_logstate = Base.CoreLogging.LogState(typeof(logger)(err_wr, logger.min_level)) + Core.eval(Base.CoreLogging, Expr(:(=), :(_global_logstate), new_logstate)) + end + end end try $(esc(block)) finally if ccall(:jl_generating_output, Cint, ()) == 0 - redirect_stderr(ORIGINAL_STDERR) + redirect_stderr(original_stderr) close(err_wr) + + if haslogging() + if logger.stream == stderr + Core.eval(Base.CoreLogging, Expr(:(=), :(_global_logstate), logstate)) + end + end end end end @@ -90,27 +124,27 @@ end """ @capture_out expr -Capture the STDOUT stream for the given expression. +Capture the `stdout` stream for the given expression. """ macro capture_out(block) quote if ccall(:jl_generating_output, Cint, ()) == 0 - ORIGINAL_STDOUT = STDOUT + original_stdout = stdout out_rd, out_wr = redirect_stdout() - out_reader = @schedule read(out_rd, String) + out_reader = @async read(out_rd, String) end try $(esc(block)) finally if ccall(:jl_generating_output, Cint, ()) == 0 - redirect_stdout(ORIGINAL_STDOUT) + redirect_stdout(original_stdout) close(out_wr) end end if ccall(:jl_generating_output, Cint, ()) == 0 - wait(out_reader) + fetch(out_reader) else "" end @@ -120,27 +154,43 @@ end """ @capture_err expr -Capture the STDERR stream for the given expression. +Capture the `stderr` stream for the given expression. """ macro capture_err(block) quote if ccall(:jl_generating_output, Cint, ()) == 0 - ORIGINAL_STDERR = STDERR + original_stderr = stderr err_rd, err_wr = redirect_stderr() - err_reader = @schedule read(err_rd, String) + err_reader = @async read(err_rd, String) + + if haslogging() + # approach adapted from https://github.com/JuliaLang/IJulia.jl/pull/667/files + logstate = Base.CoreLogging._global_logstate + logger = logstate.logger + if logger.stream == original_stderr + new_logstate = Base.CoreLogging.LogState(typeof(logger)(err_wr, logger.min_level)) + Core.eval(Base.CoreLogging, Expr(:(=), :(_global_logstate), new_logstate)) + end + end end try $(esc(block)) finally if ccall(:jl_generating_output, Cint, ()) == 0 - redirect_stderr(ORIGINAL_STDERR) + redirect_stderr(original_stderr) close(err_wr) + + if haslogging() + if logger.stream == stderr + Core.eval(Base.CoreLogging, Expr(:(=), :(_global_logstate), logstate)) + end + end end end if ccall(:jl_generating_output, Cint, ()) == 0 - wait(err_reader) + fetch(err_reader) else "" end @@ -157,7 +207,7 @@ combination with the `@capture_*` macros: @color_output false begin output = @capture_err begin - warn("should get captured, not printed") + @warn "should get captured, not printed" end end @test output == "WARNING: should get captured, not printed\n" @@ -165,9 +215,9 @@ end macro color_output(enabled::Bool, block) quote prev_color = Base.have_color - eval(Base, :(have_color = $$enabled)) + Core.eval(Base, :(have_color = $$enabled)) retval = $(esc(block)) - eval(Base, Expr(:(=), :have_color, prev_color)) + Core.eval(Base, Expr(:(=), :have_color, prev_color)) retval end diff --git a/test/runtests.jl b/test/runtests.jl index c77747b..528adda 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,94 +1,150 @@ using Suppressor -using Base.Test +using Compat.Test: @testset, @test, @test_throws +using Compat: stderr, stdout +using Compat: @info +using Compat: printstyled @testset "Suppressor" begin -output = @capture_out begin - println("should get captured, not printed") -end -@test output == "should get captured, not printed\n" +# everything that prints to stdout and stderr should be prefixed with an +# incrementing number so we can check that the output is as expected -# test both with and without color -@color_output false begin - output = @capture_err begin - warn("should get captured, not printed") +@testset "stdout capture" begin + output = @capture_out begin + println("CAPTURED STDOUT") + println(stderr, "01 PRINTED STDERR") end + @test output == "CAPTURED STDOUT\n" + println("02 PRINTED STDOUT") end -@test output == "WARNING: should get captured, not printed\n" -@color_output true begin +@testset "stderr capture" begin output = @capture_err begin - warn("should get captured, not printed") + println("03 PRINTED STDOUT") + println(stderr, "CAPTURED STDERR") end + @test output == "CAPTURED STDERR\n" + println(stderr, "04 PRINTED STDERR") end -if VERSION >= v"0.6.0" - @test output == "\e[1m\e[33mWARNING: \e[39m\e[22m\e[33mshould get captured, not printed\e[39m\n" -else - @test output == "\e[1m\e[31mWARNING: should get captured, not printed\e[0m\n" -end +# we're assuming the global context here has color enabled +@testset "disabling color" begin + printstyled("05 PRINTED GREEN STDOUT\n", color=:green) + printstyled(stderr, "06 PRINTED GREEN STDERR\n", color=:green) -@test @suppress begin - println("This string doesn't get printed!") - warn("This warning is ignored.") - 42 -end == 42 + @color_output false begin + printstyled("07 PRINTED NORMAL STDOUT\n", color=:green) + printstyled(stderr, "08 PRINTED NORMAL STDERR\n", color=:green) + end -@test @suppress_out begin - println("This string doesn't get printed!") - warn("This warning is important") - 42 -end == 42 -# WARNING: This warning is important + printstyled("09 PRINTED GREEN STDOUT\n", color=:green) + printstyled(stderr, "10 PRINTED GREEN STDERR\n", color=:green) +end -@test @suppress_err begin - println("This string gets printed!") - warn("This warning is unimportant") - 42 -end == 42 +@testset "enabling color" begin + @color_output false begin + printstyled("11 PRINTED NORMAL STDOUT\n", color=:green) + printstyled(stderr, "12 PRINTED NORMAL STDERR\n", color=:green) -# This string gets printed! + @color_output true begin + printstyled("13 PRINTED GREEN STDOUT\n", color=:green) + printstyled(stderr, "14 PRINTED GREEN STDERR\n", color=:green) + end -@test_throws ErrorException @suppress begin - println("This string doesn't get printed!") - warn("This warning is ignored.") - error("errors would normally get printed but are caught here by @test_throws") + printstyled("15 PRINTED NORMAL STDOUT\n", color=:green) + printstyled(stderr, "16 PRINTED NORMAL STDERR\n", color=:green) + end end -# test that the macros work inside a function -function f1() - @suppress println("should not get printed") - 42 +@testset "stdout suppression" begin + @test @suppress_out begin + println("SUPPRESSED STDOUT") + println(stderr, "17 PRINTED STDERR") + 42 + end == 42 + println("18 PRINTED STDOUT") end -@test f1() == 42 +@testset "stderr suppression" begin + @test @suppress_err begin + println("19 PRINTED STDOUT") + println(stderr, "SUPPRESSED STDERR") + 42 + end == 42 + println(stderr, "20 PRINTED STDERR") +end -function f2() - @suppress_out println("should not get printed") - 42 +@testset "stderr and stdout suppression" begin + @test @suppress begin + println("SUPPRESSED STDOUT") + println(stderr, "SUPPRESSED STDERR") + 42 + end == 42 + println("21 PRINTED STDOUT") + println(stderr, "22 PRINTED STDERR") end -@test f2() == 42 +# make sure that things still work after an exception is thrown +@testset "exception cleanup" begin + try + @capture_out throw(ErrorException("")) + catch + end + println("23 PRINTED STDOUT") + println(stderr, "24 PRINTED STDERR") -function f3() - @suppress_err println("should get printed") - 42 -end + try + @capture_err throw(ErrorException("")) + catch + end + println("25 PRINTED STDOUT") + println(stderr, "26 PRINTED STDERR") -@test f3() == 42 + try + @suppress throw(ErrorException("")) + catch + end + println("27 PRINTED STDOUT") + println(stderr, "28 PRINTED STDERR") -function f4() - @capture_out println("should not get printed") - 42 + try + @suppress_out throw(ErrorException("")) + catch + end + println("29 PRINTED STDOUT") + println(stderr, "30 PRINTED STDERR") + + try + @suppress_err throw(ErrorException("")) + catch + end + println("31 PRINTED STDOUT") + println(stderr, "32 PRINTED STDERR") end -@test f4() == 42 +@test_throws ErrorException @suppress begin + println("SUPPRESSED STDOUT") + println(stderr, "SUPPRESSED STDERR") + error("errors would normally get printed but are caught here by @test_throws") +end -function f5() - @capture_err println("should get printed") - 42 +@testset "logging capture" begin + output = @capture_err @info "CAPTURED LOGINFO" + # 0.6.2 output: + if isdefined(Base, :CoreLogging) + @test output == "[ Info: CAPTURED LOGINFO\n" + else + @test output == "\e[1m\e[36mInfo: \e[39m\e[22m\e[36mCAPTURED LOGINFO\n\e[39m" + end + @info "33 PRINTED LOGINFO" end -@test f5() == 42 +@testset "logging suppression" begin + @suppress_err @info "SUPPRESSED LOGINFO" + @info "34 PRINTED LOGINFO" + @suppress @info "SUPPRESSED LOGINFO" + @info "35 PRINTED LOGINFO" end + +end # @testset "Suppressor"